1 // Copyright 2004 "Gilles Degottex", 2007 "Florian Hars"
3 // This file is part of "Music"
5 // "Music" is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU Lesser General Public License as published by
7 // the Free Software Foundation; either version 2.1 of the License, or
8 // (at your option) any later version.
10 // "Music" is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Lesser General Public License for more details.
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include <CppAddons/CAMath.h>
31 #include <CppAddons/StringAddons.h>
37 enum NotesName{LOCAL_ANGLO, LOCAL_LATIN};
38 extern NotesName s_notes_name;
39 inline NotesName GetNotesName() {return s_notes_name;}
40 inline void SetNotesName(NotesName type) {s_notes_name = type;}
42 extern int s_tonality;
43 inline int GetTonality() {return s_tonality;}
44 inline void SetTonality(int tonality) {s_tonality = tonality;}
46 enum Tuning{CHROMATIC,WERCKMEISTER3,KIRNBERGER3,DIATONIC,MEANTONE};
47 extern Tuning s_tuning;
48 extern double s_semitones[13];
49 inline Tuning GetTuning() {return s_tuning;}
50 void SetTuning(Tuning tuning);
53 extern int s_sampling_rate;
54 inline int GetSamplingRate() {return s_sampling_rate;}
55 void SetSamplingRate(int sampling_rate);
57 extern double s_AFreq;
58 inline double GetAFreq() {return s_AFreq;}
59 void SetAFreq(double AFreq);
61 extern const int UNDEFINED_SEMITONE;
62 extern int s_semitone_min;
63 extern int s_semitone_max;
64 inline int GetSemitoneMin() {return s_semitone_min;}
65 inline int GetSemitoneMax() {return s_semitone_max;}
66 inline int GetNbSemitones() {return s_semitone_max-s_semitone_min+1;}
67 void SetSemitoneBounds(int semitone_min, int semitone_max);
69 struct SettingsListener
71 virtual void samplingRateChanged() {}
72 virtual void AFreqChanged() {}
73 virtual void semitoneBoundsChanged() {}
76 virtual ~SettingsListener();
79 extern list<SettingsListener*> s_settings_listeners;
80 void AddSettingsListener(SettingsListener* l);
81 void RemoveSettingsListener(SettingsListener* l);
83 //! convert frequency to a float number of chromatic half-tones from A3
85 * \param freq the frequency to convert to \f$\in R+\f$ {Hz}
86 * \param AFreq tuning frequency of the A3 (Usualy 440) {Hz}
87 * \return the float number of half-tones from A3 \f$\in R\f$
89 inline double f2hf(double freq, double AFreq=GetAFreq())
91 return 17.3123404906675624 * log(freq/AFreq); //12.0*(log(freq)-log(AFreq))/log(2.0)
93 //! find the halftone in the array for non-chromatic tunings
95 // Decide wether the step from 12/2 for linar search to log_2(12) for a
96 // binary search really matters in a FFT-bound program
98 * \param relFreq the frequency divided by the frequency of the next lower A
99 * \return the number of halftones above this A
101 inline int f2h_find(double relFreq)
103 if (relFreq < s_semitones[1])
105 if (s_semitones[1] / relFreq > relFreq / s_semitones[0])
113 for (i = 2; i < 12; i += 1)
114 if (relFreq < s_semitones[i]) { break; }
116 if (s_semitones[i] / relFreq > relFreq / s_semitones[i - 1])
123 // le ht doit �re le ht le plus proche de freq !! et pas un simple arrondi en dessous de la valeur r�l !!
124 //! convert frequency to number of half-tones from A3
126 * \param freq the frequency to convert to \f$\in R+\f$ {Hz}
127 * \param AFreq tuning frequency of the A3 (Usualy 440) {Hz}
128 * \return the number of half-tones from A3. Rounded to the nearest half-tones(
129 * not a simple integer convertion of \ref f2hf ) \f$\in R\f$
131 inline int f2h(double freq, double AFreq=GetAFreq(), int tuning=GetTuning())
133 if (CHROMATIC == tuning)
135 double ht = f2hf(freq, AFreq);
136 if(ht>0) return int(ht+0.5);
137 if(ht<0) return int(ht-0.5);
142 if (freq <= 1.0) return UNDEFINED_SEMITONE;
144 while (freq < AFreq) { freq *= 2.0; oct -= 1; }
145 while (freq >= 2.0 * AFreq) { freq /= 2.0; oct += 1; }
146 int ht = f2h_find(freq/AFreq);
147 return (12 * oct + ht);
150 //! convert number of chromatic half-tones to frequency
152 * \param ht number of half-tones to convert to \f
153 * \param AFreq tuning frequency of the A3 (Usualy 440) {Hz}
154 * \return the converted frequency
156 inline double h2f(double ht, double AFreq=GetAFreq())
158 return AFreq * pow(2.0, ht/12.0);
160 //! convert number of half-tones to frequency
162 * \param ht number of half-tones to convert to \f$\in Z\f$
163 * \param AFreq tuning frequency of the A3 (Usualy 440) {Hz}
164 * \return the converted frequency
166 inline double h2cf(int ht, double AFreq=GetAFreq(), int tuning=GetTuning())
168 if (CHROMATIC == tuning)
170 return AFreq * pow(2.0, ht/12.0);
172 else if (ht >= s_semitone_min)
185 return AFreq * pow(2.0, oct) * s_semitones[ht];
192 //! convert frequency to the frequency of the nearest half tone
194 * \param freq the frequency to convert to \f$\in R+\f$ {Hz}
195 * \param AFreq tuning frequency of the A3 (Usualy 440) {Hz}
196 * \return the converted frequency
198 inline double f2cf(double freq, double AFreq=GetAFreq(), int tuning=GetTuning())
200 return h2cf(f2h(freq, AFreq, tuning), AFreq, tuning);
203 //! convert half-tones from A3 to the corresponding note name
205 * \param ht number of half-tone to convert to \f$\in Z\f$
207 * \return its name (Do, Re, Mi, Fa, Sol, La, Si; with '#' or 'b' if needed)
209 inline string h2n(int ht, NotesName local=GetNotesName(), int tonality=GetTonality(), int tunig=GetTuning(), bool show_oct=true)
225 if(ht>2) oct++; // octave start from C
226 // if(oct<=0) oct--; // skip 0-octave in occidental notations ??
229 // sprintf(coct, "%d", oct);
230 // string soct = coct;
234 soct = StringAddons::toString(oct);
236 if(local==LOCAL_ANGLO)
238 if(ht==0) return "A"+soct;
239 else if(ht==1) return "Bb"+soct;
240 else if(ht==2) return "B"+soct;
241 else if(ht==3) return "C"+soct;
242 else if(ht==4) return "C#"+soct;
243 else if(ht==5) return "D"+soct;
244 else if(ht==6) return "Eb"+soct;
245 else if(ht==7) return "E"+soct;
246 else if(ht==8) return "F"+soct;
247 else if(ht==9) return "F#"+soct;
248 else if(ht==10) return "G"+soct;
249 else if(ht==11) return "G#"+soct;
253 if(ht==0) return "La"+soct;
254 else if(ht==1) return "Sib"+soct;
255 else if(ht==2) return "Si"+soct;
256 else if(ht==3) return "Do"+soct;
257 else if(ht==4) return "Do#"+soct;
258 else if(ht==5) return "Re"+soct;
259 else if(ht==6) return "Mib"+soct;
260 else if(ht==7) return "Mi"+soct;
261 else if(ht==8) return "Fa"+soct;
262 else if(ht==9) return "Fa#"+soct;
263 else if(ht==10) return "Sol"+soct;
264 else if(ht==11) return "Sol#"+soct;
270 inline int n2h(const std::string& note, NotesName local=LOCAL_ANGLO, int tonality=GetTonality())
276 //! convert amplitude to dB
280 return 20*log10(abs(value));
281 // return 20*log10(abs(value)+numeric_limits<TYPE>::epsilon());
284 //! convert dB to amplitude
285 // TODO cannot create a template so easily because the pow10 is not defined for all types
286 inline double invlp(double value)
288 return pow10(value/20.0);
289 // return pow(TYPE(10), value/TYPE(20));
292 std::vector<double> conv(const std::vector<double>& u, const std::vector<double>& v);
294 // TODO freq reffinement