X-Git-Url: http://git.johnwright.org/?p=fmit.git;a=blobdiff_plain;f=libs%2FMusic%2FMusic.h;h=e319851675bed20cc2f73e7c7e6f345705fa7630;hp=18bbd4edde88a1fffe3e6bac9721b9db6f0cb980;hb=adfba0402927438a1869f1e716bcf0e25574ce1e;hpb=4b957a098b637ebe4d07827a80aeae157791a148 diff --git a/libs/Music/Music.h b/libs/Music/Music.h index 18bbd4e..e319851 100644 --- a/libs/Music/Music.h +++ b/libs/Music/Music.h @@ -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 #include +#include + 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 conv(const std::vector& u, const std::vector& v); + std::vector conv(const std::vector& u, const std::vector& v); // TODO freq reffinement }