Update to upstream version 0.97.7
[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 using namespace std;
29 #include <CppAddons/CAMath.h>
30 #include <CppAddons/StringAddons.h>
31
32 #include <iostream>
33
34 namespace Music
35 {
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;}
40
41         extern int s_tonality;
42         inline int GetTonality()                                                {return s_tonality;}
43         inline void SetTonality(int tonality)                   {s_tonality = tonality;}
44
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);
50
51
52         extern int s_sampling_rate;
53         inline int GetSamplingRate()                                    {return s_sampling_rate;}
54         void SetSamplingRate(int sampling_rate);
55
56         extern double s_AFreq;
57         inline double GetAFreq()                                                {return s_AFreq;}
58         void SetAFreq(double AFreq);
59
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);
67
68         struct SettingsListener
69         {
70                 virtual void samplingRateChanged()                      {}
71                 virtual void AFreqChanged()                                     {}
72                 virtual void semitoneBoundsChanged()            {}
73
74                 SettingsListener();
75                 virtual ~SettingsListener();
76         };
77
78         extern list<SettingsListener*>  s_settings_listeners;
79         void AddSettingsListener(SettingsListener* l);
80         void RemoveSettingsListener(SettingsListener* l);
81
82         //! convert frequency to a float number of chromatic half-tones from A3
83         /*!
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$
87         */
88         inline double f2hf(double freq, double AFreq=GetAFreq())
89         {
90                         return 17.3123404906675624 * log(freq/AFreq); //12.0*(log(freq)-log(AFreq))/log(2.0)
91         }
92         //! find the halftone in the array for non-chromatic tunings
93         // TODO:
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
96         /*!
97         * \param relFreq the frequency divided by the frequency of the next lower A
98         * \return the number of halftones above this A
99         */
100         inline int f2h_find(double relFreq)
101         {
102                 if (relFreq < s_semitones[1])
103                 {
104                         if (s_semitones[1] / relFreq > relFreq / s_semitones[0])
105                         {
106                                 return 0;
107                         }
108                         else
109                         {
110                                 return 1;
111                         }
112                 }
113                 else
114                 {
115                         int i;
116                         for (i = 2; i < 12; i += 1)
117                         {
118                                 if (relFreq < s_semitones[i]) { break; }
119                         }
120                         if (s_semitones[i] / relFreq > relFreq / s_semitones[i - 1])
121                         {
122                                 return i - 1;
123                         }
124                         else
125                         {
126                                 return i;
127                         }
128                 }
129         }
130         // TODO VERIF
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
133         /*!
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$
138         */
139         inline int f2h(double freq, double AFreq=GetAFreq(), int tuning=GetTuning())
140         {
141                 if (CHROMATIC == tuning)
142                 {
143                         double ht = f2hf(freq, AFreq);
144                         if(ht>0)        return int(ht+0.5);
145                         if(ht<0)        return int(ht-0.5);
146                         return  0;
147                 }
148                 else
149                 {
150                         if (freq <= 1.0) return UNDEFINED_SEMITONE;
151                         int oct = 0;
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);
156                 }
157         }
158         //! convert number of chromatic half-tones to frequency
159         /*!
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
163         */
164         inline double h2f(double ht, double AFreq=GetAFreq())
165         {
166                 return AFreq * pow(2.0, ht/12.0);
167         }
168         //! convert number of half-tones to frequency
169         /*!
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
173         */
174         inline double h2cf(int ht, double AFreq=GetAFreq(), int tuning=GetTuning())
175         {
176                 if (CHROMATIC == tuning)
177                 {
178                         return AFreq * pow(2.0, ht/12.0);
179                 }
180                 else if (ht >= s_semitone_min)
181                 {
182                         int oct = 0;
183                         while(ht<0)
184                         {
185                                 ht += 12;
186                                 oct--;
187                         }
188                         while(ht>11)
189                         {
190                                 ht -= 12;
191                                 oct++;
192                         }
193                         return AFreq * pow(2.0, oct) * s_semitones[ht];
194                 }
195                 else
196                 {
197                         return 0.0;
198                 }
199         }
200         //! convert frequency to the frequency of the nearest half tone
201         /*!
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
205         */
206         inline double f2cf(double freq, double AFreq=GetAFreq(), int tuning=GetTuning())
207         {
208                 return h2cf(f2h(freq, AFreq, tuning), AFreq, tuning);
209         }
210
211         //! convert half-tones from A3 to the corresponding note name
212         /*!
213         * \param ht number of half-tone to convert to \f$\in Z\f$
214         * \param local
215         * \return its name (Do, Re, Mi, Fa, Sol, La, Si; with '#' or 'b' if needed)
216         */
217         inline string h2n(int ht, NotesName local=GetNotesName(), int tonality=GetTonality(), int tunig=GetTuning(), bool show_oct=true)
218         {
219                 ht += tonality;
220
221                 int oct = 4;
222                 while(ht<0)
223                 {
224                         ht += 12;
225                         oct--;
226                 }
227                 while(ht>11)
228                 {
229                         ht -= 12;
230                         oct++;
231                 }
232
233                 if(ht>2)        oct++;  // octave start from C
234         //      if(oct<=0)      oct--;  // skip 0-octave in occidental notations ??
235
236         //      char coct[3];
237         //      sprintf(coct, "%d", oct);
238         //      string soct = coct;
239
240                 string soct;
241                 if(show_oct)
242                         soct = StringAddons::toString(oct);
243
244                 if(local==LOCAL_ANGLO)
245                 {
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;
258                 }
259                 else
260                 {
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;
273                 }
274
275                 return "Th#1138";
276         }
277
278         inline int n2h(const std::string& note, NotesName local=LOCAL_ANGLO, int tonality=GetTonality())
279         {
280                 // TODO
281                 return -1;
282         }
283
284         std::vector<double> conv(const std::vector<double>& u, const std::vector<double>& v);
285
286         // TODO freq reffinement
287 }
288
289 #endif // _Music_h_