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
29 #include <CppAddons/CAMath.h>
30 #include <CppAddons/StringAddons.h>
36 enum NotesName{LOCAL_ANGLO, LOCAL_LATIN};
37 extern NotesName s_notes_name;
38 inline NotesName GetNotesName() {return s_notes_name;}
39 inline void SetNotesName(NotesName type) {s_notes_name = type;}
41 extern int s_tonality;
42 inline int GetTonality() {return s_tonality;}
43 inline void SetTonality(int tonality) {s_tonality = tonality;}
45 enum Tuning{CHROMATIC,WERCKMEISTER3,KIRNBERGER3,DIATONIC,MEANTONE};
46 extern Tuning s_tuning;
47 extern double s_semitones[13];
48 inline Tuning GetTuning() {return s_tuning;}
49 void SetTuning(Tuning tuning);
52 extern int s_sampling_rate;
53 inline int GetSamplingRate() {return s_sampling_rate;}
54 void SetSamplingRate(int sampling_rate);
56 extern double s_AFreq;
57 inline double GetAFreq() {return s_AFreq;}
58 void SetAFreq(double AFreq);
60 extern const int UNDEFINED_SEMITONE;
61 extern int s_semitone_min;
62 extern int s_semitone_max;
63 inline int GetSemitoneMin() {return s_semitone_min;}
64 inline int GetSemitoneMax() {return s_semitone_max;}
65 inline int GetNbSemitones() {return s_semitone_max-s_semitone_min+1;}
66 void SetSemitoneBounds(int semitone_min, int semitone_max);
68 struct SettingsListener
70 virtual void samplingRateChanged() {}
71 virtual void AFreqChanged() {}
72 virtual void semitoneBoundsChanged() {}
75 virtual ~SettingsListener();
78 extern list<SettingsListener*> s_settings_listeners;
79 void AddSettingsListener(SettingsListener* l);
80 void RemoveSettingsListener(SettingsListener* l);
82 //! convert frequency to a float number of chromatic half-tones from A3
84 * \param freq the frequency to convert to \f$\in R+\f$ {Hz}
85 * \param AFreq tuning frequency of the A3 (Usualy 440) {Hz}
86 * \return the float number of half-tones from A3 \f$\in R\f$
88 inline double f2hf(double freq, double AFreq=GetAFreq())
90 return 17.3123404906675624 * log(freq/AFreq); //12.0*(log(freq)-log(AFreq))/log(2.0)
92 //! find the halftone in the array for non-chromatic tunings
94 // Decide wether the step from 12/2 for linar search to log_2(12) for a
95 // binary search really matters in a FFT-bound program
97 * \param relFreq the frequency divided by the frequency of the next lower A
98 * \return the number of halftones above this A
100 inline int f2h_find(double relFreq)
102 if (relFreq < s_semitones[1])
104 if (s_semitones[1] / relFreq > relFreq / s_semitones[0])
116 for (i = 2; i < 12; i += 1)
118 if (relFreq < s_semitones[i]) { break; }
120 if (s_semitones[i] / relFreq > relFreq / s_semitones[i - 1])
131 // le ht doit �re le ht le plus proche de freq !! et pas un simple arrondi en dessous de la valeur r�l !!
132 //! convert frequency to number of half-tones from A3
134 * \param freq the frequency to convert to \f$\in R+\f$ {Hz}
135 * \param AFreq tuning frequency of the A3 (Usualy 440) {Hz}
136 * \return the number of half-tones from A3. Rounded to the nearest half-tones(
137 * not a simple integer convertion of \ref f2hf ) \f$\in R\f$
139 inline int f2h(double freq, double AFreq=GetAFreq(), int tuning=GetTuning())
141 if (CHROMATIC == tuning)
143 double ht = f2hf(freq, AFreq);
144 if(ht>0) return int(ht+0.5);
145 if(ht<0) return int(ht-0.5);
150 if (freq <= 1.0) return UNDEFINED_SEMITONE;
152 while (freq < AFreq) { freq *= 2.0; oct -= 1; }
153 while (freq >= 2.0 * AFreq) { freq /= 2.0; oct += 1; }
154 int ht = f2h_find(freq/AFreq);
155 return (12 * oct + ht);
158 //! convert number of chromatic half-tones to frequency
160 * \param ht number of half-tones to convert to \f
161 * \param AFreq tuning frequency of the A3 (Usualy 440) {Hz}
162 * \return the converted frequency
164 inline double h2f(double ht, double AFreq=GetAFreq())
166 return AFreq * pow(2.0, ht/12.0);
168 //! convert number of half-tones to frequency
170 * \param ht number of half-tones to convert to \f$\in Z\f$
171 * \param AFreq tuning frequency of the A3 (Usualy 440) {Hz}
172 * \return the converted frequency
174 inline double h2cf(int ht, double AFreq=GetAFreq(), int tuning=GetTuning())
176 if (CHROMATIC == tuning)
178 return AFreq * pow(2.0, ht/12.0);
180 else if (ht >= s_semitone_min)
193 return AFreq * pow(2.0, oct) * s_semitones[ht];
200 //! convert frequency to the frequency of the nearest half tone
202 * \param freq the frequency to convert to \f$\in R+\f$ {Hz}
203 * \param AFreq tuning frequency of the A3 (Usualy 440) {Hz}
204 * \return the converted frequency
206 inline double f2cf(double freq, double AFreq=GetAFreq(), int tuning=GetTuning())
208 return h2cf(f2h(freq, AFreq, tuning), AFreq, tuning);
211 //! convert half-tones from A3 to the corresponding note name
213 * \param ht number of half-tone to convert to \f$\in Z\f$
215 * \return its name (Do, Re, Mi, Fa, Sol, La, Si; with '#' or 'b' if needed)
217 inline string h2n(int ht, NotesName local=GetNotesName(), int tonality=GetTonality(), int tunig=GetTuning(), bool show_oct=true)
233 if(ht>2) oct++; // octave start from C
234 // if(oct<=0) oct--; // skip 0-octave in occidental notations ??
237 // sprintf(coct, "%d", oct);
238 // string soct = coct;
242 soct = StringAddons::toString(oct);
244 if(local==LOCAL_ANGLO)
246 if(ht==0) return "A"+soct;
247 else if(ht==1) return "Bb"+soct;
248 else if(ht==2) return "B"+soct;
249 else if(ht==3) return "C"+soct;
250 else if(ht==4) return "C#"+soct;
251 else if(ht==5) return "D"+soct;
252 else if(ht==6) return "Eb"+soct;
253 else if(ht==7) return "E"+soct;
254 else if(ht==8) return "F"+soct;
255 else if(ht==9) return "F#"+soct;
256 else if(ht==10) return "G"+soct;
257 else if(ht==11) return "G#"+soct;
261 if(ht==0) return "La"+soct;
262 else if(ht==1) return "Sib"+soct;
263 else if(ht==2) return "Si"+soct;
264 else if(ht==3) return "Do"+soct;
265 else if(ht==4) return "Do#"+soct;
266 else if(ht==5) return "Re"+soct;
267 else if(ht==6) return "Mib"+soct;
268 else if(ht==7) return "Mi"+soct;
269 else if(ht==8) return "Fa"+soct;
270 else if(ht==9) return "Fa#"+soct;
271 else if(ht==10) return "Sol"+soct;
272 else if(ht==11) return "Sol#"+soct;
278 inline int n2h(const std::string& note, NotesName local=LOCAL_ANGLO, int tonality=GetTonality())
284 std::vector<double> conv(const std::vector<double>& u, const std::vector<double>& v);
286 // TODO freq reffinement