Import upstream version 0.99.2
[fmit.git] / libs / Music / ScoreGenerator.h
1 // Copyright 2004 "Gilles Degottex"
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 _ScoreGenerator_h_
21 #define _ScoreGenerator_h_
22
23 #include <assert.h>
24 #include <vector>
25 #include <deque>
26 #include <iostream>
27 #include <algorithm>
28 using namespace std;
29
30 #include <CppAddons/Math.h>
31 #include <CppAddons/Random.h>
32 //#include <CppAddons/String.h>
33
34 #include "Music.h"
35 #include "Instrument.h"
36
37 namespace Music
38 {
39
40 //! generate a randomly generated score with \ref Instrument
41 /*!
42  * \param buffer the outputed wave
43  * \param score the corresponding outputed score
44  * \param instrs the instruments
45  * \param lenght lenght of the score in seconds         : R+*
46  * \param dataBySecond number of data by second         : ~{11000, 22000, 44100}
47  * \param AFreq frequency of the A3                                     : ~440.0
48  * \param minHT minimum halftone                                        : Z             // TODO <0
49  * \param maxHT maximum halftone                                        : Z
50  * \param nbNotes maximum number of notes in lenght                     : N*
51  * \param nbInstr maximum number of instruments played at the same time         : N*
52 */
53 inline void GenerateScoreFromInstruments(
54                 deque<double>& buffer,
55                 vector< vector<int> >& score,
56                 vector<Instrument*>& instrs,
57                 double lenght,
58                 int dataBySecond,
59                 double AFreq,
60                 int minHT,
61                 int maxHT,
62                 int nbNotes,
63                 int nbInstr)
64 {
65         int size = int(lenght*dataBySecond);
66         int nbHT = maxHT-minHT+1;
67         int note_size = size / nbNotes;
68         //              cout << "AFreq=" << AFreq << " dataBySecond=" << dataBySecond << endl;
69         //              cout << "nbNotes=" << nbNotes << " lenght=" << lenght << " minHT=" << minHT << " maxHT=" << maxHT << endl;
70         //              cout << "size=" << size << " nbHT=" << nbHT << endl;
71
72         // TODO compute upHT so every harm are present in the range of minHT maxHT
73         //      int maxNbHarm = 0;
74         //      for(int i=0; i<instrs.size(); i++)
75         //      {
76         //              if(instrs[i]->getFreqs()!=NULL)
77         //              {
78         //                      int n = instrs[i]->getFreqs()->size();
79         //                      maxNbHarm = std::max(maxNbHarm, n);
80         //              }
81         //      }
82         //      int upHT = (int)f2h(AFreq*(maxNbHarm+1), AFreq);
83         //      if(upHT>maxHT-minHT)    throw string("not enough HT for covering all harmonics");
84         //      cout << upHT << endl;
85
86         //      cout << "make score ... " << instrs.size() << endl;
87         int t=0;
88         if(score.size()!=(size_t)(nbNotes*note_size))
89                 score.resize(nbNotes*note_size);
90
91         assert((size_t)nbInstr<=instrs.size());
92
93         for(int i=0; i<nbNotes; i++)
94         {
95                 vector<int> hs(instrs.size());
96                 vector< Math::polar<double> > ps(instrs.size());
97                 vector<bool> play(instrs.size());
98                 for(size_t w=0; w<play.size(); w++)     play[w] = false;
99                 int count_playing=0;
100                 while(count_playing<nbInstr)
101                 {
102                         int index = int(Random::s_random.nextDouble()*play.size());
103                         if(!play[index])
104                         {
105                                 play[index] = true;
106                                 count_playing++;
107                         }
108                 }
109                 for(size_t v=0; v<hs.size(); v++)
110                 {
111 //                      if(play[v])
112                         {
113 //                      hs[v] = minHT+g_random.nextInt(maxHT-minHT+1);
114 //                      hs[v] = minHT+g_random.nextInt(maxHT-minHT-upHT+1);
115 // TODO !!!!!!!!!!!!!!
116 //                      int up = (int)f2h(AFreq*(instrs[v]->getFreqs()->size()), AFreq);
117 //                      int up = instrs[v]->getFreqs()->size();
118                         int up = 36;
119 //                      cout << "up=" << up << endl;
120 //                      assert(up<maxHT-minHT);
121                         hs[v] = minHT+Random::s_random.nextInt(maxHT-minHT-up+1);
122 //                      hs[v] = minHT+g_random.nextInt(maxHT-minHT+1);
123                         ps[v] = Math::polar<double>(Random::s_random.nextDouble()/nbInstr, Random::s_random.nextDouble()*2*Math::Pi);
124 //                      ps[v] = Math::polar<double>(1.0/nbInstr, g_random.nextDouble()*2*Math::Pi);
125 //                      cout << "halftone choosen " << hs[v] << endl;
126                         }
127
128 //                      cout << ps[v].mod << " ";
129                 }
130 //              cout << endl;
131
132 //              if(i==5)hs[0]=-12;
133 //              else    hs[0]=-48;
134
135 //              for(int v=0; v<hs.size(); v++)
136 //                      cout << "halftone choosen " << hs[v] << " play=" << play[v] << endl;
137
138                 for(int j=0; j<note_size; j++)
139                 {
140                         double buff = 0.0;
141                         for(size_t v=0; v<instrs.size(); v++)
142                                 if(play[v])
143                                         buff += ps[v].mod*instrs[v]->gen_value(hs[v], ps[v].arg);
144
145                         buffer.push_back(buff);
146
147                         vector<int> score_at(nbHT);
148                         for(size_t h=0; h<score_at.size(); h++)
149                                 score_at[h] = 0;
150
151                         for(size_t v=0; v<instrs.size(); v++)
152                                 if(play[v] && ps[v].mod>0.05)                                     // TODO 0.1: note is here if we hear it !
153                                         score_at[hs[v]-minHT]++;
154
155                         score[t] = score_at;
156                         t++;
157                 }
158         }
159 }
160
161 //! generate a randomly generated sinusoid score
162 /*!
163  * \param buffer the outputed wave
164  * \param score the outputed score
165  * \param lenght lenght of the score in seconds         : R+*
166  * \param dataBySecond number of data by second         : ~{11000, 22000, 44100}
167  * \param AFreq frequency of the A3                                     : ~440.0
168  * \param minHT minimum halftone                                        : Z             // TODO <0
169  * \param maxHT maximum halftone                                        : Z
170  * \param nbNotes number of notes in lenght                     : N*
171  * \param nbVoice number of voices                                      : N*
172 */
173 inline void GenerateScore(      deque<double>& buffer,
174                 vector< vector<int> >& score,
175                 double lenght,
176                 int dataBySecond,
177                 double AFreq,
178                 int minHT,
179                 int maxHT,
180                 int nbNotes,
181                 int nbVoice)
182 {
183         int size = int(lenght*dataBySecond);
184         int nbHT = maxHT-minHT+1;
185         int note_size = size / nbNotes;
186         //      cout << "AFreq=" << AFreq << " dataBySecond=" << dataBySecond << endl;
187         //      cout << "nbNotes=" << nbNotes << " lenght=" << lenght << " minHT=" << minHT << " maxHT=" << maxHT << endl;
188         //      cout << "size=" << size << " nbHT=" << nbHT << " nbVoice=" << nbVoice << endl;
189
190         //      cout << "make score ... \t\t" << flush;
191 //      int n=0;
192         for(int i=0; i<nbNotes; i++)
193         {
194                 vector<int> hs(nbVoice);
195                 for(size_t v=0; v<hs.size(); v++)
196                 {
197                         hs[v] = minHT+Random::s_random.nextInt(maxHT-minHT+1);
198                         //                      cout << "halftone choosen " << hs[v] << endl;
199                 }
200
201                 vector<double> decals(nbVoice);
202                 for(size_t v=0; v<decals.size(); v++)
203                         decals[v] = Random::s_random.nextDouble()*Math::Pi/2;
204                 //                      decals[v] = g_random.nextDouble()*2*Math::Pi;
205
206                 //              cout << "halftone selected=" << h << " freq=" << freq << endl;
207                 for(int j=0; j<note_size; j++)
208                 {
209                         double buff = 0.0;
210                         for(size_t v=0; v<hs.size(); v++)
211                                 buff += sin( ((2.0*Math::Pi)/dataBySecond)*h2f(hs[v], AFreq)*double(j) + decals[v]);
212
213 //                      int index = i*note_size+j;
214                         // add data index and wav value
215
216                         buffer.push_back(buff);
217                         // add score halftones (solution)
218                         vector<int> score_at(nbHT);
219                         for(int vh=0; vh<nbHT; vh++)
220                         {
221                                 int ampl = 0;
222                                 for(size_t v=0; v<hs.size(); v++)
223                                         if(hs[v]==vh+minHT)
224                                                 ampl++;
225                                 score_at[vh] = ampl;
226                         }
227                         score.push_back(score_at);
228                         //                      n = String::undoable_out_percent(cout, 100.0f*index/size, n);
229                 }
230         }
231         //      String::undoable_out_clear(cout, n);
232         //      cout << "done   " << endl;
233 }
234
235 }
236
237 #endif // _ScoreGenerator_h_
238