Import upstream version 0.99.2
[fmit.git] / libs / Music / Instrument.h
diff --git a/libs/Music/Instrument.h b/libs/Music/Instrument.h
new file mode 100644 (file)
index 0000000..38ae9fc
--- /dev/null
@@ -0,0 +1,259 @@
+// Copyright 2004 "Gilles Degottex"
+
+// 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 _Instrument_h_
+#define _Instrument_h_
+
+#include <assert.h>
+#include <vector>
+#include <iostream>
+#include <fstream>
+using namespace std;
+#include <CppAddons/Math.h>
+using namespace Math;
+#include "Music.h"
+
+namespace Music
+{
+
+#define MAX_NB_FREQ 24
+#define MAX_NB_HARM 7
+#define MAX_RDM_HT -12
+#define MIN_RDM_HT 12
+
+//! an abstract instrument
+struct Instrument
+{
+       virtual vector< Math::polar<double> >* getFreqs(){return NULL;}
+
+       virtual double gen_value(int k, double phase=0.0)=0;
+
+       virtual ~Instrument(){}
+};
+
+//! an harmonic instrument
+/*!
+ * une fondamentale choisie dans un interval et des composantes harmoniques
+ */
+struct HarmInstrument : Instrument
+{
+       int m_dataBySecond;
+       double m_time;
+       vector< Math::polar<double> > m_freqs;
+       int m_base_ht;
+       double m_base_freq;
+
+       HarmInstrument(int dataBySecond, double AFreq, int nb_harm=int((rand()/RAND_MAX)*MAX_NB_HARM), int min_rdm_ht=-12, int max_rdm_ht=12)
+       : m_dataBySecond(dataBySecond)
+       , m_time(0.0)
+       , m_freqs(nb_harm+1)
+       , m_base_ht(int(min_rdm_ht+(rand()/RAND_MAX)*(max_rdm_ht-min_rdm_ht+1)))
+       , m_base_freq(h2f(m_base_ht, AFreq))
+       {
+               for(size_t i=0; i<m_freqs.size(); i++)
+                       m_freqs[i] = Math::polar<double>(Random::s_random.nextDouble(), 2*Math::Pi*Random::s_random.nextDouble());
+
+               // s'il n'y a pas de composantes, ça ne sert à rien de choisir une amplitude au hazard pour la fondamentale
+               if(m_freqs.size()==1)
+                       m_freqs[0].mod = 1.0;
+
+               // la fondamentale doit avoir une amplitude minimale
+               m_freqs[0].mod = m_freqs[0].mod*0.8 + 0.2;
+       }
+
+       HarmInstrument(int dataBySecond, vector< Math::polar<double> >& freqs, double base_freq)
+       : m_dataBySecond(dataBySecond)
+       , m_time(0.0)
+       , m_freqs(freqs)
+       , m_base_freq(base_freq)
+       {
+       }
+
+       virtual vector< Math::polar<double> >* getFreqs(){return &m_freqs;}
+
+       virtual double gen_value(int k, double phase=0.0)
+       {
+               double value = 0.0;
+
+               for(size_t i=0; i<m_freqs.size(); i++)
+                       value += m_freqs[i].mod * sin(h2f(k, m_base_freq)*(i+1)*m_time+m_freqs[i].arg + phase);
+
+               m_time += 2*Math::Pi/m_dataBySecond;
+
+               return value;
+       }
+};
+
+inline ostream& operator<<(ostream& out, const HarmInstrument& instr)
+{
+       cout << "HarmInstrument (mod:arg)" << endl;
+       for(size_t i=0; i<instr.m_freqs.size(); i++)
+               out << "\t" << instr.m_base_freq*(i+1) << " (" << instr.m_freqs[i].mod << ":" << instr.m_freqs[i].arg << ")" << endl;
+
+       return out;
+}
+
+/* basé sur un motif pré-enregistré
+*/
+struct WaveInstrument : Instrument
+{
+       vector<double> m_data;
+
+       double m_time;
+       
+       int m_dataBySecond;
+       double m_AFreq;
+
+       WaveInstrument(int dataBySecond, double AFreq, const string& file_name)
+       : m_time(0.0)
+       , m_dataBySecond(dataBySecond)
+       , m_AFreq(AFreq)
+       {
+               ifstream file(file_name.c_str());
+
+               assert(file.is_open());
+
+               double index;
+               double value;
+               file >> index;
+               file >> value;
+               while(!file.eof())
+               {
+                       m_data.push_back(value);
+
+                       file >> index;
+                       file >> value;
+               }
+       }
+
+       WaveInstrument(int dataBySecond, double AFreq, const deque<double>& data)
+       : m_data(data.size())
+       , m_time(0.0)
+       , m_dataBySecond(dataBySecond)
+       , m_AFreq(AFreq)
+       {
+               for(size_t i=0; i<data.size(); i++)
+                       m_data[i] = data[i];
+       }
+
+       WaveInstrument(int dataBySecond, double AFreq, const vector<double>& data)
+       : m_data(data)
+       , m_time(0.0)
+       , m_dataBySecond(dataBySecond)
+       , m_AFreq(AFreq)
+       {
+       }
+
+       virtual double gen_value(int k, double phase=0.0)
+       {
+               double f = h2f(k, m_AFreq);
+
+               int i = int(f*(m_time+phase)*m_data.size()/(2*Math::Pi))%m_data.size();
+
+               m_time += 2*Math::Pi/m_dataBySecond;
+
+               return m_data[i];
+       }
+};
+
+/* faux instrument: les composantes devraient toujours être des harmoniques
+*/
+struct FreqInstrument : Instrument
+{
+       static double get_freq(double lowest_freq, int i, double AFreq)
+       {
+               return h2f(int(f2h(lowest_freq, AFreq)+i), AFreq);
+       }
+
+       int m_dataBySecond;
+       double m_AFreq;
+       double m_time;
+       vector< Math::polar<double> > m_freqs;
+       double m_lowest_freq;
+
+       virtual vector< Math::polar<double> >* getFreqs(){return &m_freqs;}
+
+       FreqInstrument(int dataBySecond, double AFreq, double lowest_freq, int nb_freq=int((rand()/RAND_MAX)*MAX_NB_FREQ))
+       : m_dataBySecond(dataBySecond)
+       , m_AFreq(AFreq)
+       , m_time(0.0)
+       , m_freqs(nb_freq)
+       , m_lowest_freq(lowest_freq)
+       {
+               //              cout << "FreqInstrument::FreqInstrument" << endl;
+
+               for(size_t i=0; i<m_freqs.size(); i++)
+                       m_freqs[i] = Math::polar<double>((rand()/RAND_MAX), Math::Pi*(rand()/RAND_MAX));
+
+               // s'il n'y a pas de composantes, ça ne sert à rien de choisir une amplitude au hazard pour la fondamentale
+               if(m_freqs.size()==1)
+                       m_freqs[0].mod = 1.0;
+
+               m_freqs[1].mod = 0.0;           // TEMP
+
+               // la fondamentale doit avoir une amplitude minimale
+               m_freqs[0].mod = m_freqs[0].mod*0.8 + 0.2;
+
+               // rajoute un bruit sur la vitesse
+               double upper_freq = h2f(1, m_lowest_freq);
+               double lower_freq = h2f(-1, m_lowest_freq);
+               cout << "m_lowest_freq=" << m_lowest_freq << " upper_freq="<<upper_freq<<" lower_freq="<<lower_freq;
+               m_lowest_freq += (rand()/RAND_MAX)*(upper_freq-lower_freq)/16 - (m_lowest_freq-lower_freq)/16;
+               cout << " => " << m_lowest_freq << endl;
+
+               //              cout << "/FreqInstrument::FreqInstrument" << endl;
+       }
+
+       FreqInstrument(int dataBySecond, double AFreq, vector< Math::polar<double> >& freqs, double lowest_freq)
+       : m_dataBySecond(dataBySecond)
+       , m_AFreq(AFreq)
+       , m_time(0.0)
+       , m_freqs(freqs)
+       , m_lowest_freq(lowest_freq)
+       {
+       }
+
+       virtual double gen_value(int k, double phase=0.0)
+       {
+               //              cout << "FreqInstrument::gen_value" << endl;
+
+               double value = 0.0;
+
+               for(size_t i=0; i<m_freqs.size(); i++)
+                       value += m_freqs[i].mod * sin(get_freq(m_lowest_freq,i+k,m_AFreq)*m_time + m_freqs[i].arg);
+
+               m_time += 2*Math::Pi/m_dataBySecond;
+
+               return value;
+       }
+};
+
+inline ostream& operator<<(ostream& out, const FreqInstrument& instr)
+{
+       cout << "FreqInstrument (mod:arg)" << endl;
+       for(size_t i=0; i<instr.m_freqs.size(); i++)
+               out << "\t" << FreqInstrument::get_freq(instr.m_lowest_freq,i,instr.m_AFreq) << " (" << instr.m_freqs[i].mod << ":" << instr.m_freqs[i].arg << ")" << endl;
+
+       return out;
+}
+
+}
+
+#endif // _Instrument_h_
+