1 /*
2 * Copyright (C) 2002 - David W. Durham
3 *
4 * This file is part of ReZound, an audio editing application.
5 *
6 * ReZound is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published
8 * by the Free Software Foundation; either version 2 of the License,
9 * or (at your option) any later version.
10 *
11 * ReZound is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 */
20
21 #ifndef __unit_conv_h__
22 #define __unit_conv_h__
23
24
25 #include "../../config/common.h"
26
27 /*
28 * Unit conversion functions
29 */
30
31 #include <math.h>
32 #include <stdexcept>
33 #include <algorithm>
34 #include <istring>
35 #include "CSound_defs.h"
36
37 // volume
scalar_to_dB(const double scalar)38 static inline const double scalar_to_dB(const double scalar) { return 20.0*log10(scalar); }
dB_to_scalar(const double dB)39 static inline const double dB_to_scalar(const double dB) { return pow(10.0,dB/20.0); }
40
percent_to_amp(const double percent)41 static inline const mix_sample_t percent_to_amp(const double percent) { return (mix_sample_t)(percent*MAX_SAMPLE/100.0); }
42 // ??? if I use this function should I abs the amp value?
amp_to_percent(const mix_sample_t amp)43 static inline const double amp_to_percent(const mix_sample_t amp) { return (double)amp*100.0/(double)MAX_SAMPLE; }
44
45
46
dBFS_to_amp(const double dBFS,const type maxSample)47 template<class type> static inline const type dBFS_to_amp(const double dBFS,const type maxSample) { return (type)(maxSample*pow(10.0,dBFS/20.0)); }
dBFS_to_amp(const double dBFS)48 static inline const mix_sample_t dBFS_to_amp(const double dBFS) { return (mix_sample_t)(MAX_SAMPLE*pow(10.0,dBFS/20.0)); }
49
amp_to_dBFS(const type amp,const type maxSample)50 template<class type> static inline const double amp_to_dBFS(const type amp,const type maxSample) { return 20.0*log10(fabs((double)amp/maxSample)); }
amp_to_dBFS(const mix_sample_t amp)51 static inline const double amp_to_dBFS(const mix_sample_t amp) { return 20.0*log10(fabs((double)amp/MAX_SAMPLE)); }
52
53
54 // rate
55
56
57 // times
ms_to_samples(const sample_fpos_t ms,const unsigned sampleRate)58 static inline const sample_pos_t ms_to_samples(const sample_fpos_t ms,const unsigned sampleRate) { return (sample_pos_t)sample_fpos_floor(((sample_fpos_t)sampleRate*ms/1000.0)+0.5); }
s_to_samples(const sample_fpos_t s,const unsigned sampleRate)59 static inline const sample_pos_t s_to_samples(const sample_fpos_t s,const unsigned sampleRate) { return (sample_pos_t)sample_fpos_floor(((sample_fpos_t)sampleRate*s)+0.5); }
samples_to_ms(const sample_pos_t samples,const unsigned sampleRate)60 static inline const sample_fpos_t samples_to_ms(const sample_pos_t samples,const unsigned sampleRate) { return (sample_fpos_t)samples/(sample_fpos_t)sampleRate*1000.0; }
samples_to_s(const sample_pos_t samples,const unsigned sampleRate)61 static inline const sample_fpos_t samples_to_s(const sample_pos_t samples,const unsigned sampleRate) { return (sample_fpos_t)samples/(sample_fpos_t)sampleRate; }
s_to_samples_offset(const float s,const unsigned sampleRate)62 static inline const int s_to_samples_offset(const float s,const unsigned sampleRate) { return (int)floor(((float)sampleRate*s)+0.5); }
63
64 // sTime is in seconds
65 static inline const string seconds_to_string(const sample_fpos_t sTime,int secondsDecimalPlaces=0,bool includeUnits=false)
66 {
67 string time;
68
69 if(sTime>=3600)
70 { // make it HH:MM:SS.sss
71 const int hours=(int)(sTime/3600);
72 const int mins=(int)((sTime-(hours*3600))/60);
73 const double secs=sTime-((hours*3600)+(mins*60));
74
75 time=istring(hours,2,true)+":"+istring(mins,2,true)+":"+istring(secs,(secondsDecimalPlaces>0 ? 3+secondsDecimalPlaces : 2),secondsDecimalPlaces,true);
76 }
77 else
78 { // make it MM:SS.sss
79 int mins=(int)(sTime/60);
80 double secs=sTime-(mins*60);
81
82 /*
83 * if it's going to render (because of rounding in istring) as 3:60.000
84 * then make that 4:00.000 which would happen if the seconds had come out
85 * to 59.995 or more so that's (60 - .005) which is (60 - 5/(10^deciplaces))
86 * (this probably needs to be done slimiarly in the HH:MM:SS.sss case too)
87 */
88 if(secs >= 60.0-(5.0/pow(10.0,secondsDecimalPlaces)))
89 {
90 mins++;
91 secs=0;
92 }
93
94 time=istring(mins,2,true)+":"+istring(secs,(secondsDecimalPlaces>0 ? 3+secondsDecimalPlaces : 2),secondsDecimalPlaces,true);
95 }
96
97 if(includeUnits)
98 return(time+"s");
99 else
100 return(time);
101 }
102
103
104 // angles
degrees_to_radians(const double degrees)105 static inline const double degrees_to_radians(const double degrees) { return degrees*(2.0*M_PI)/360.0; }
radians_to_degrees(const double radians)106 static inline const double radians_to_degrees(const double radians) { return radians*360.0/(2.0*M_PI); }
107
108
109 // frequency
110 static inline const double freq_to_fraction(const double frequency,const unsigned sampleRate,bool throwOnError=false) { if(throwOnError && (frequency<0.0 || frequency>sampleRate/2)) {throw runtime_error(string(__func__)+" -- frequency out of range, "+istring(frequency)+", for sample rate of, "+istring(sampleRate)); } return max(0.0,min(0.5,frequency/(double)sampleRate)); }
111 static inline const double fraction_to_freq(const double fraction,const unsigned sampleRate,bool throwOnError=false) { if(throwOnError && (fraction<0.0 || fraction>0.5)) { throw runtime_error(string(__func__)+" -- fraction out of range, "+istring(fraction)); } return max(0.0,min(sampleRate/2.0,fraction*(double)sampleRate)); }
112
113 /* no longer used because I wanted to have evenly spaced octaves rather than going precisely from 0 to SR/2
114 // given x [0,1] this returns a frequency in Hz except curved for human interface use on the frontend
115 static inline const double unitRange_to_curvedFreq(const double x,const unsigned sampleRate) { return pow(x,3.0)*(sampleRate/2.0); }
116 static inline const double curvedFreq_to_unitRange(const double freq,const unsigned sampleRate) { return pow(2.0*freq/sampleRate,1.0/3.0); }
117 */
118
119 // maps a given (real) octave number [0,number of octaves] to a frequency in Hz where the octave 0 returns the given baseFrequency
octave_to_freq(const double octave,const double baseFrequency)120 static inline const double octave_to_freq(const double octave,const double baseFrequency) { return baseFrequency*pow(2.0,octave); }
freq_to_octave(const double freq,const double baseFrequency)121 static inline const double freq_to_octave(const double freq,const double baseFrequency) { return log(freq/baseFrequency)/log(2.0); }
122
123
124 // range conversions -- generally for user interface convenience
125
126 // [0,1] -> [0,1] patterned after f(x)=x^2
unitRange_to_unitRange_squared(const double x)127 static inline const double unitRange_to_unitRange_squared(const double x) { return pow(x,2.0); }
unitRange_to_unitRange_unsquared(const double x)128 static inline const double unitRange_to_unitRange_unsquared(const double x) { return sqrt(x); } // inverse of previous
129
130 // NOTE: this is a little different than ..._squared ??? I'm not sure if it's working right it seems to be recip-sym
131 // [0,1] -> [0,1] with more accuracy near 0.5 patterned after f(x)=x^3
unitRange_to_unitRange_cubed(const double x)132 static inline const double unitRange_to_unitRange_cubed(const double x) { return (pow(2.0*x-1.0,3.0)+1.0)/2.0; }
unitRange_to_unitRange_uncubed(const double x)133 static inline const double unitRange_to_unitRange_uncubed(const double x) { return (cbrt(2.0*x-1.0)+1.0)/2.0; } // inverse of previous
134
135 // [0,1] -> [1/a,a] with exponential behavior .. recipsym means reciprocally symetric as the range of the function is reciprocally symetric around 1
unitRange_to_recipsymRange_exp(const double x,const double a)136 static inline const double unitRange_to_recipsymRange_exp(const double x,const double a) { return pow(a,2.0*x-1.0); }
recipsymRange_to_unitRange_exp(const double x,const double a)137 static inline const double recipsymRange_to_unitRange_exp(const double x,const double a) { return 0.5*log(x)/log(a)+0.5; } // inverse of previous
138
139 // [0,1] -> [a,b] with linear behavior
unitRange_to_otherRange_linear(const double x,const double a,const double b)140 static inline const double unitRange_to_otherRange_linear(const double x,const double a,const double b) { return a+((b-a)*x); }
otherRange_to_unitRange_linear(const double x,const double a,const double b)141 static inline const double otherRange_to_unitRange_linear(const double x,const double a,const double b) { return (x-a)/(b-a); } // inverse of previous
142
143 #endif
144