Update to upstream version 0.97.7
[fmit.git] / libs / Music / Music.h
index 18bbd4e..e319851 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2004 "Gilles Degottex"
+// Copyright 2004 "Gilles Degottex", 2007 "Florian Hars"
 
 // This file is part of "Music"
 
@@ -29,6 +29,8 @@ using namespace std;
 #include <CppAddons/CAMath.h>
 #include <CppAddons/StringAddons.h>
 
+#include <iostream>
+
 namespace Music
 {
        enum NotesName{LOCAL_ANGLO, LOCAL_LATIN};
@@ -40,6 +42,13 @@ namespace Music
        inline int GetTonality()                                                {return s_tonality;}
        inline void SetTonality(int tonality)                   {s_tonality = tonality;}
 
+       enum Tuning{CHROMATIC,WERCKMEISTER3,KIRNBERGER3,DIATONIC,MEANTONE};
+       extern Tuning s_tuning;
+       extern double s_semitones[13];
+       inline Tuning GetTuning()                                               {return s_tuning;}
+       void SetTuning(Tuning tuning);
+
+
        extern int s_sampling_rate;
        inline int GetSamplingRate()                                    {return s_sampling_rate;}
        void SetSamplingRate(int sampling_rate);
@@ -70,111 +79,209 @@ namespace Music
        void AddSettingsListener(SettingsListener* l);
        void RemoveSettingsListener(SettingsListener* l);
 
-//! convert frequency to a float number of half-tones from A3
-/*!
- * \param freq the frequency to convert to \f$\in R+\f$ {Hz}
- * \param AFreq tuning frequency of the A3 (Usualy 440) {Hz}
- * \return the float number of half-tones from A3 \f$\in R\f$
- */
-inline double f2hf(double freq, double AFreq=GetAFreq())               {return 12.0*(log(freq)-log(AFreq))/log(2.0);}
-// TODO VERIF
-// le ht doit �re le ht le plus proche de freq !! et pas un simple arrondi en dessous de la valeur r�l !!
-//! convert frequency to number of half-tones from A3
-/*!
- * \param freq the frequency to convert to \f$\in R+\f$ {Hz}
- * \param AFreq tuning frequency of the A3 (Usualy 440) {Hz}
- * \return the number of half-tones from A3. Rounded to the nearest half-tones(
- * not a simple integer convertion of \ref f2hf ) \f$\in R\f$
- */
-inline int f2h(double freq, double AFreq=GetAFreq())
-{
-       double ht = f2hf(freq, AFreq);
-       if(ht>0)        return int(ht+0.5);
-       if(ht<0)        return int(ht-0.5);
-       return  0;
-}
-//! convert number of half-tones to frequency
-/*!
- * \param ht number of half-tones to convert to \f$\in Z\f$
- * \param AFreq tuning frequency of the A3 (Usualy 440) {Hz}
- * \return the converted frequency
- */
-inline double h2f(double ht, double AFreq=GetAFreq())                  {return AFreq * pow(2.0, ht/12.0);}
-
-//! convert half-tones from A3 to the corresponding note name
-/*!
- * \param ht number of half-tones to convert to \f$\in Z\f$
- * \param local
- * \return his name (Do, Re, Mi, Fa, Sol, La, Si; with '#' if needed)
- */
-inline string h2n(int ht, NotesName local=GetNotesName(), int tonality=GetTonality(), bool show_oct=true)
-{
-       ht += tonality;
-
-       int oct = 4;
-       while(ht<0)
+       //! convert frequency to a float number of chromatic half-tones from A3
+       /*!
+       * \param freq the frequency to convert to \f$\in R+\f$ {Hz}
+       * \param AFreq tuning frequency of the A3 (Usualy 440) {Hz}
+       * \return the float number of half-tones from A3 \f$\in R\f$
+       */
+       inline double f2hf(double freq, double AFreq=GetAFreq())
+       {
+                       return 17.3123404906675624 * log(freq/AFreq); //12.0*(log(freq)-log(AFreq))/log(2.0)
+       }
+       //! find the halftone in the array for non-chromatic tunings
+       // TODO:
+       // Decide wether the step from 12/2 for linar search to log_2(12) for a
+       // binary search really matters in a FFT-bound program
+       /*!
+       * \param relFreq the frequency divided by the frequency of the next lower A
+       * \return the number of halftones above this A
+       */
+       inline int f2h_find(double relFreq)
+       {
+               if (relFreq < s_semitones[1])
+               {
+                       if (s_semitones[1] / relFreq > relFreq / s_semitones[0])
+                       {
+                               return 0;
+                       }
+                       else
+                       {
+                               return 1;
+                       }
+               }
+               else
+               {
+                       int i;
+                       for (i = 2; i < 12; i += 1)
+                       {
+                               if (relFreq < s_semitones[i]) { break; }
+                       }
+                       if (s_semitones[i] / relFreq > relFreq / s_semitones[i - 1])
+                       {
+                               return i - 1;
+                       }
+                       else
+                       {
+                               return i;
+                       }
+               }
+       }
+       // TODO VERIF
+       // le ht doit �re le ht le plus proche de freq !! et pas un simple arrondi en dessous de la valeur r�l !!
+       //! convert frequency to number of half-tones from A3
+       /*!
+       * \param freq the frequency to convert to \f$\in R+\f$ {Hz}
+       * \param AFreq tuning frequency of the A3 (Usualy 440) {Hz}
+       * \return the number of half-tones from A3. Rounded to the nearest half-tones(
+       * not a simple integer convertion of \ref f2hf ) \f$\in R\f$
+       */
+       inline int f2h(double freq, double AFreq=GetAFreq(), int tuning=GetTuning())
+       {
+               if (CHROMATIC == tuning)
+               {
+                       double ht = f2hf(freq, AFreq);
+                       if(ht>0)        return int(ht+0.5);
+                       if(ht<0)        return int(ht-0.5);
+                       return  0;
+               }
+               else
+               {
+                       if (freq <= 1.0) return UNDEFINED_SEMITONE;
+                       int oct = 0;
+                       while (freq < AFreq)        { freq *= 2.0; oct -= 1; }
+                       while (freq >= 2.0 * AFreq) { freq /= 2.0; oct += 1; }
+                       int ht = f2h_find(freq/AFreq);
+                       return (12 * oct + ht);
+               }
+       }
+       //! convert number of chromatic half-tones to frequency
+       /*!
+       * \param ht number of half-tones to convert to \f
+       * \param AFreq tuning frequency of the A3 (Usualy 440) {Hz}
+       * \return the converted frequency
+       */
+       inline double h2f(double ht, double AFreq=GetAFreq())
        {
-               ht += 12;
-               oct--;
+               return AFreq * pow(2.0, ht/12.0);
        }
-       while(ht>11)
+       //! convert number of half-tones to frequency
+       /*!
+       * \param ht number of half-tones to convert to \f$\in Z\f$
+       * \param AFreq tuning frequency of the A3 (Usualy 440) {Hz}
+       * \return the converted frequency
+       */
+       inline double h2cf(int ht, double AFreq=GetAFreq(), int tuning=GetTuning())
        {
-               ht -= 12;
-               oct++;
+               if (CHROMATIC == tuning)
+               {
+                       return AFreq * pow(2.0, ht/12.0);
+               }
+               else if (ht >= s_semitone_min)
+               {
+                       int oct = 0;
+                       while(ht<0)
+                       {
+                               ht += 12;
+                               oct--;
+                       }
+                       while(ht>11)
+                       {
+                               ht -= 12;
+                               oct++;
+                       }
+                       return AFreq * pow(2.0, oct) * s_semitones[ht];
+               }
+               else
+               {
+                       return 0.0;
+               }
+       }
+       //! convert frequency to the frequency of the nearest half tone
+       /*!
+       * \param freq the frequency to convert to \f$\in R+\f$ {Hz}
+       * \param AFreq tuning frequency of the A3 (Usualy 440) {Hz}
+       * \return the converted frequency
+       */
+       inline double f2cf(double freq, double AFreq=GetAFreq(), int tuning=GetTuning())
+       {
+               return h2cf(f2h(freq, AFreq, tuning), AFreq, tuning);
        }
 
-       if(ht>2)        oct++;  // octave start from C
-//     if(oct<=0)      oct--;  // skip 0-octave in occidental notations ??
+       //! convert half-tones from A3 to the corresponding note name
+       /*!
+       * \param ht number of half-tone to convert to \f$\in Z\f$
+       * \param local
+       * \return its name (Do, Re, Mi, Fa, Sol, La, Si; with '#' or 'b' if needed)
+       */
+       inline string h2n(int ht, NotesName local=GetNotesName(), int tonality=GetTonality(), int tunig=GetTuning(), bool show_oct=true)
+       {
+               ht += tonality;
 
-//     char coct[3];
-//     sprintf(coct, "%d", oct);
-//     string soct = coct;
+               int oct = 4;
+               while(ht<0)
+               {
+                       ht += 12;
+                       oct--;
+               }
+               while(ht>11)
+               {
+                       ht -= 12;
+                       oct++;
+               }
 
-       string soct;
-       if(show_oct)
-               soct = StringAddons::toString(oct);
+               if(ht>2)        oct++;  // octave start from C
+       //      if(oct<=0)      oct--;  // skip 0-octave in occidental notations ??
 
-       if(local==LOCAL_ANGLO)
-       {
-               if(ht==0)               return "A"+soct;
-               else if(ht==1)  return "A#"+soct;
-               else if(ht==2)  return "B"+soct;
-               else if(ht==3)  return "C"+soct;
-               else if(ht==4)  return "C#"+soct;
-               else if(ht==5)  return "D"+soct;
-               else if(ht==6)  return "D#"+soct;
-               else if(ht==7)  return "E"+soct;
-               else if(ht==8)  return "F"+soct;
-               else if(ht==9)  return "F#"+soct;
-               else if(ht==10) return "G"+soct;
-               else if(ht==11) return "G#"+soct;
+       //      char coct[3];
+       //      sprintf(coct, "%d", oct);
+       //      string soct = coct;
+
+               string soct;
+               if(show_oct)
+                       soct = StringAddons::toString(oct);
+
+               if(local==LOCAL_ANGLO)
+               {
+                       if(ht==0)       return "A"+soct;
+                       else if(ht==1)  return "Bb"+soct;
+                       else if(ht==2)  return "B"+soct;
+                       else if(ht==3)  return "C"+soct;
+                       else if(ht==4)  return "C#"+soct;
+                       else if(ht==5)  return "D"+soct;
+                       else if(ht==6)  return "Eb"+soct;
+                       else if(ht==7)  return "E"+soct;
+                       else if(ht==8)  return "F"+soct;
+                       else if(ht==9)  return "F#"+soct;
+                       else if(ht==10) return "G"+soct;
+                       else if(ht==11) return "G#"+soct;
+               }
+               else
+               {
+                       if(ht==0)       return "La"+soct;
+                       else if(ht==1)  return "Sib"+soct;
+                       else if(ht==2)  return "Si"+soct;
+                       else if(ht==3)  return "Do"+soct;
+                       else if(ht==4)  return "Do#"+soct;
+                       else if(ht==5)  return "Re"+soct;
+                       else if(ht==6)  return "Mib"+soct;
+                       else if(ht==7)  return "Mi"+soct;
+                       else if(ht==8)  return "Fa"+soct;
+                       else if(ht==9)  return "Fa#"+soct;
+                       else if(ht==10) return "Sol"+soct;
+                       else if(ht==11) return "Sol#"+soct;
+               }
+
+               return "Th#1138";
        }
-       else
+
+       inline int n2h(const std::string& note, NotesName local=LOCAL_ANGLO, int tonality=GetTonality())
        {
-               if(ht==0)               return "La"+soct;
-               else if(ht==1)  return "La#"+soct;
-               else if(ht==2)  return "Si"+soct;
-               else if(ht==3)  return "Do"+soct;
-               else if(ht==4)  return "Do#"+soct;
-               else if(ht==5)  return "Re"+soct;
-               else if(ht==6)  return "Re#"+soct;
-               else if(ht==7)  return "Mi"+soct;
-               else if(ht==8)  return "Fa"+soct;
-               else if(ht==9)  return "Fa#"+soct;
-               else if(ht==10) return "Sol"+soct;
-               else if(ht==11) return "Sol#"+soct;
+               // TODO
+               return -1;
        }
 
-       return "Th#1138";
-}
-
-inline int n2h(const std::string& note, NotesName local=LOCAL_ANGLO, int tonality=GetTonality())
-{
-       // TODO
-       return -1;
-}
-
-std::vector<double> conv(const std::vector<double>& u, const std::vector<double>& v);
+       std::vector<double> conv(const std::vector<double>& u, const std::vector<double>& v);
 
        // TODO freq reffinement
 }