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, LOCAL_GERMAN, LOCAL_HINDUSTANI, LOCAL_BYZANTINE}; 38 extern NotesName s_notes_name; GetNotesName()39 inline NotesName GetNotesName() {return s_notes_name;} SetNotesName(NotesName type)40 inline void SetNotesName(NotesName type) {s_notes_name = type;} 41 42 extern int s_transposition; GetTransposition()43 inline int GetTransposition() {return s_transposition;} SetTransposition(int transposition)44 inline void SetTransposition(int transposition) {s_transposition = transposition;} 45 46 enum Tuning{CHROMATIC,WERCKMEISTER3,KIRNBERGER3,DIATONIC,MEANTONE}; 47 extern Tuning s_tuning; 48 extern double s_semitones[13]; GetTuning()49 inline Tuning GetTuning() {return s_tuning;} 50 void SetTuning(Tuning tuning); 51 52 53 extern int s_sampling_rate; GetSamplingRate()54 inline int GetSamplingRate() {return s_sampling_rate;} 55 void SetSamplingRate(int sampling_rate); 56 57 extern double s_AFreq; GetAFreq()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; GetSemitoneMin()64 inline int GetSemitoneMin() {return s_semitone_min;} GetSemitoneMax()65 inline int GetSemitoneMax() {return s_semitone_max;} GetNbSemitones()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 { samplingRateChangedSettingsListener71 virtual void samplingRateChanged() {} AFreqChangedSettingsListener72 virtual void AFreqChanged() {} semitoneBoundsChangedSettingsListener73 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 */ f2h_find(double relFreq)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 transposition=GetTransposition(), int tunig=GetTuning(), bool show_oct=true) 210 { 211 (void)tunig; 212 213 ht += transposition; 214 215 int oct = 4; 216 while(ht<0) 217 { 218 ht += 12; 219 oct--; 220 } 221 while(ht>11) 222 { 223 ht -= 12; 224 oct++; 225 } 226 227 if(ht>2) oct++; // octave start from C 228 // if(oct<=0) oct--; // skip 0-octave in occidental notations ?? 229 230 // char coct[3]; 231 // sprintf(coct, "%d", oct); 232 // string soct = coct; 233 234 string soct; 235 if(show_oct) 236 soct = StringAddons::toString(oct); 237 238 if(local==LOCAL_ANGLO) 239 { 240 if(ht==0) return "A"+soct; 241 else if(ht==1) return "B♭"+soct; 242 else if(ht==2) return "B"+soct; 243 else if(ht==3) return "C"+soct; 244 else if(ht==4) return "C♯"+soct; 245 else if(ht==5) return "D"+soct; 246 else if(ht==6) return "E♭"+soct; 247 else if(ht==7) return "E"+soct; 248 else if(ht==8) return "F"+soct; 249 else if(ht==9) return "F♯"+soct; 250 else if(ht==10) return "G"+soct; 251 else if(ht==11) return "G♯"+soct; 252 } 253 else if(local==LOCAL_LATIN) 254 { 255 if(ht==0) return "La"+soct; 256 else if(ht==1) return "Si♭"+soct; 257 else if(ht==2) return "Si"+soct; 258 else if(ht==3) return "Do"+soct; 259 else if(ht==4) return "Do♯"+soct; 260 else if(ht==5) return "Re"+soct; 261 else if(ht==6) return "Mi♭"+soct; 262 else if(ht==7) return "Mi"+soct; 263 else if(ht==8) return "Fa"+soct; 264 else if(ht==9) return "Fa♯"+soct; 265 else if(ht==10) return "Sol"+soct; 266 else if(ht==11) return "Sol♯"+soct; 267 } 268 else if(local==LOCAL_GERMAN) 269 { 270 if(ht==0) return "A"+soct; 271 else if(ht==1) return "B"+soct; 272 else if(ht==2) return "H"+soct; 273 else if(ht==3) return "C"+soct; 274 else if(ht==4) return "C♯"+soct; 275 else if(ht==5) return "D"+soct; 276 else if(ht==6) return "E♭"+soct; 277 else if(ht==7) return "E"+soct; 278 else if(ht==8) return "F"+soct; 279 else if(ht==9) return "F♯"+soct; 280 else if(ht==10) return "G"+soct; 281 else if(ht==11) return "G♯"+soct; 282 } 283 else if(local==LOCAL_HINDUSTANI) 284 { 285 if(ht==0) return "D"+soct; 286 else if(ht==1) return "n"+soct; 287 else if(ht==2) return "N"+soct; 288 else if(ht==3) return "S"+soct; 289 else if(ht==4) return "r"+soct; 290 else if(ht==5) return "R"+soct; 291 else if(ht==6) return "g"+soct; 292 else if(ht==7) return "G"+soct; 293 else if(ht==8) return "m"+soct; 294 else if(ht==9) return "M"+soct; 295 else if(ht==10) return "P"+soct; 296 else if(ht==11) return "d"+soct; 297 } 298 else if(local==LOCAL_BYZANTINE) 299 { 300 if(ht==0) return "Ke"+soct; 301 else if(ht==1) return "Zo♭"+soct; 302 else if(ht==2) return "Zo"+soct; 303 else if(ht==3) return "Ni"+soct; 304 else if(ht==4) return "Ni♯"+soct; 305 else if(ht==5) return "Pa"+soct; 306 else if(ht==6) return "Vou♭"+soct; 307 else if(ht==7) return "Vou"+soct; 308 else if(ht==8) return "Ga"+soct; 309 else if(ht==9) return "Ga♯"+soct; 310 else if(ht==10) return "Di"+soct; 311 else if(ht==11) return "Di♯"+soct; 312 } 313 314 return "Th#1138"; 315 } 316 317 // inline int n2h(const std::string& note, NotesName local=LOCAL_ANGLO, int transposition=GetTransposition()) 318 // { 319 // // TODO 320 // return -1; 321 // } 322 323 //! convert amplitude to dB 324 template<class TYPE> lp(TYPE value)325 TYPE lp(TYPE value) 326 { 327 return 20*log10(abs(value)); 328 // return 20*log10(abs(value)+numeric_limits<TYPE>::epsilon()); 329 } 330 331 //! convert dB to amplitude 332 // TODO cannot create a template so easily because the pow10 is not defined for all types invlp(double value)333 inline double invlp(double value) 334 { 335 return std::pow(10, value/20.0); 336 // return pow(TYPE(10), value/TYPE(20)); 337 } 338 339 std::vector<double> conv(const std::vector<double>& u, const std::vector<double>& v); 340 341 // TODO freq reffinement 342 } 343 344 #endif // _Music_h_ 345