// Copyright 2004 "Gilles Degottex", 2007 "Florian Hars" // This file is part of "Music" // "Music" is free software; you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation; either version 2.1 of the License, or // (at your option) any later version. // // "Music" is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #ifndef _Music_h_ #define _Music_h_ #include #include #include #include #include using namespace std; #include #include #include namespace Music { enum NotesName{LOCAL_ANGLO, LOCAL_LATIN}; extern NotesName s_notes_name; inline NotesName GetNotesName() {return s_notes_name;} inline void SetNotesName(NotesName type) {s_notes_name = type;} extern int s_tonality; 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); extern double s_AFreq; inline double GetAFreq() {return s_AFreq;} void SetAFreq(double AFreq); extern const int UNDEFINED_SEMITONE; extern int s_semitone_min; extern int s_semitone_max; inline int GetSemitoneMin() {return s_semitone_min;} inline int GetSemitoneMax() {return s_semitone_max;} inline int GetNbSemitones() {return s_semitone_max-s_semitone_min+1;} void SetSemitoneBounds(int semitone_min, int semitone_max); struct SettingsListener { virtual void samplingRateChanged() {} virtual void AFreqChanged() {} virtual void semitoneBoundsChanged() {} SettingsListener(); virtual ~SettingsListener(); }; extern list s_settings_listeners; void AddSettingsListener(SettingsListener* l); void RemoveSettingsListener(SettingsListener* l); //! 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()) { return AFreq * pow(2.0, ht/12.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 h2cf(int ht, double AFreq=GetAFreq(), int tuning=GetTuning()) { 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); } //! 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; int oct = 4; while(ht<0) { ht += 12; oct--; } while(ht>11) { ht -= 12; oct++; } if(ht>2) oct++; // octave start from C // if(oct<=0) oct--; // skip 0-octave in occidental notations ?? // 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"; } 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); // TODO freq reffinement } #endif // _Music_h_