Import upstream version 0.99.2
[fmit.git] / libs / Music / Music.h
1 // Copyright 2004 "Gilles Degottex", 2007 "Florian Hars"
2
3 // This file is part of "Music"
4
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.
9 //
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.
14 //
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
18
19
20 #ifndef _Music_h_
21 #define _Music_h_
22
23 #include <assert.h>
24 #include <cmath>
25 #include <string>
26 #include <list>
27 #include <vector>
28 #include <limits>
29 using namespace std;
30 #include <CppAddons/CAMath.h>
31 #include <CppAddons/StringAddons.h>
32
33 #include <iostream>
34
35 namespace Music
36 {
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;}
41
42         extern int s_tonality;
43         inline int GetTonality()                                                {return s_tonality;}
44         inline void SetTonality(int tonality)                   {s_tonality = tonality;}
45
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);
51
52
53         extern int s_sampling_rate;
54         inline int GetSamplingRate()                                    {return s_sampling_rate;}
55         void SetSamplingRate(int sampling_rate);
56
57         extern double s_AFreq;
58         inline double GetAFreq()                                                {return s_AFreq;}
59         void SetAFreq(double AFreq);
60
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);
68
69         struct SettingsListener
70         {
71                 virtual void samplingRateChanged()                      {}
72                 virtual void AFreqChanged()                                     {}
73                 virtual void semitoneBoundsChanged()            {}
74
75                 SettingsListener();
76                 virtual ~SettingsListener();
77         };
78
79         extern list<SettingsListener*>  s_settings_listeners;
80         void AddSettingsListener(SettingsListener* l);
81         void RemoveSettingsListener(SettingsListener* l);
82
83         //! convert frequency to a float number of chromatic half-tones from A3
84         /*!
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$
88         */
89         inline double f2hf(double freq, double AFreq=GetAFreq())
90         {
91                         return 17.3123404906675624 * log(freq/AFreq); //12.0*(log(freq)-log(AFreq))/log(2.0)
92         }
93         //! find the halftone in the array for non-chromatic tunings
94         // TODO:
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
97         /*!
98         * \param relFreq the frequency divided by the frequency of the next lower A
99         * \return the number of halftones above this A
100         */
101         inline int f2h_find(double relFreq)
102         {
103                 if (relFreq < s_semitones[1])
104                 {
105                         if (s_semitones[1] / relFreq > relFreq / s_semitones[0])
106                                 return 0;
107                         else
108                                 return 1;
109                 }
110                 else
111                 {
112                         int i;
113                         for (i = 2; i < 12; i += 1)
114                                 if (relFreq < s_semitones[i]) { break; }
115
116                         if (s_semitones[i] / relFreq > relFreq / s_semitones[i - 1])
117                                 return i - 1;
118                         else
119                                 return i;
120                 }
121         }
122         // TODO VERIF
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
125         /*!
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$
130         */
131         inline int f2h(double freq, double AFreq=GetAFreq(), int tuning=GetTuning())
132         {
133                 if (CHROMATIC == tuning)
134                 {
135                         double ht = f2hf(freq, AFreq);
136                         if(ht>0)        return int(ht+0.5);
137                         if(ht<0)        return int(ht-0.5);
138                         return  0;
139                 }
140                 else
141                 {
142                         if (freq <= 1.0) return UNDEFINED_SEMITONE;
143                         int oct = 0;
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);
148                 }
149         }
150         //! convert number of chromatic half-tones to frequency
151         /*!
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
155         */
156         inline double h2f(double ht, double AFreq=GetAFreq())
157         {
158                 return AFreq * pow(2.0, ht/12.0);
159         }
160         //! convert number of half-tones to frequency
161         /*!
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
165         */
166         inline double h2cf(int ht, double AFreq=GetAFreq(), int tuning=GetTuning())
167         {
168                 if (CHROMATIC == tuning)
169                 {
170                         return AFreq * pow(2.0, ht/12.0);
171                 }
172                 else if (ht >= s_semitone_min)
173                 {
174                         int oct = 0;
175                         while(ht<0)
176                         {
177                                 ht += 12;
178                                 oct--;
179                         }
180                         while(ht>11)
181                         {
182                                 ht -= 12;
183                                 oct++;
184                         }
185                         return AFreq * pow(2.0, oct) * s_semitones[ht];
186                 }
187                 else
188                 {
189                         return 0.0;
190                 }
191         }
192         //! convert frequency to the frequency of the nearest half tone
193         /*!
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
197         */
198         inline double f2cf(double freq, double AFreq=GetAFreq(), int tuning=GetTuning())
199         {
200                 return h2cf(f2h(freq, AFreq, tuning), AFreq, tuning);
201         }
202
203         //! convert half-tones from A3 to the corresponding note name
204         /*!
205         * \param ht number of half-tone to convert to \f$\in Z\f$
206         * \param local
207         * \return its name (Do, Re, Mi, Fa, Sol, La, Si; with '#' or 'b' if needed)
208         */
209         inline string h2n(int ht, NotesName local=GetNotesName(), int tonality=GetTonality(), int tunig=GetTuning(), bool show_oct=true)
210         {
211                 ht += tonality;
212
213                 int oct = 4;
214                 while(ht<0)
215                 {
216                         ht += 12;
217                         oct--;
218                 }
219                 while(ht>11)
220                 {
221                         ht -= 12;
222                         oct++;
223                 }
224
225                 if(ht>2)        oct++;  // octave start from C
226         //      if(oct<=0)      oct--;  // skip 0-octave in occidental notations ??
227
228         //      char coct[3];
229         //      sprintf(coct, "%d", oct);
230         //      string soct = coct;
231
232                 string soct;
233                 if(show_oct)
234                         soct = StringAddons::toString(oct);
235
236                 if(local==LOCAL_ANGLO)
237                 {
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;
250                 }
251                 else
252                 {
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;
265                 }
266
267                 return "Th#1138";
268         }
269
270         inline int n2h(const std::string& note, NotesName local=LOCAL_ANGLO, int tonality=GetTonality())
271         {
272                 // TODO
273                 return -1;
274         }
275
276     //! convert amplitude to dB
277     template<class TYPE>
278     TYPE lp(TYPE value)
279     {
280         return 20*log10(abs(value));
281 //         return 20*log10(abs(value)+numeric_limits<TYPE>::epsilon());
282     }
283
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)
287     {
288         return pow10(value/20.0);
289 //         return pow(TYPE(10), value/TYPE(20));
290     }
291
292     std::vector<double> conv(const std::vector<double>& u, const std::vector<double>& v);
293
294         // TODO freq reffinement
295 }
296
297 #endif // _Music_h_