main.cxx

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2004 MUSIC TECHNOLOGY GROUP (MTG)
00003  *                         UNIVERSITAT POMPEU FABRA
00004  *
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  *
00020  */
00021 
00022 #include "MIDIEvent.hxx"
00023 #include "MIDITrack.hxx"
00024 #include "MIDISong.hxx"
00025 #include "MIDIReader.hxx"
00026 #include "MIDISongPlayer.hxx"
00027 
00028 
00029 using namespace MIDI;
00030 
00031 #include "MIDITempo.hxx"
00032 
00033 #include <math.h>
00034 #include <stdio.h>
00035 
00036 class SimpleSynth
00037 {
00038 /* a very very simple synthesizer */
00039 private:
00040         struct note
00041         {
00042                 int chn;
00043                 int key;
00044                 int vel;
00045                 float phase;
00046                 float amp;
00047                 float env;
00048         };
00049 
00050         note notes[256]; /* max 256 notes simultanious */
00051         int  nnotes;
00052         
00053         float dphase[128]; /* table to convert midi key to phase increment */
00054 
00055         FILE* file;
00056 
00057         int findnote(int chn,int key)
00058         /* find an running (vel!=0) note with chn and key */
00059         {
00060                 int i = 0;
00061                 while (i<nnotes)
00062                 {
00063                         if (notes[i].chn==chn && notes[i].key==key && notes[i].vel!=0) return i;
00064                         i++;
00065                 }
00066                 return i;
00067         }
00068         
00069 public:
00070         SimpleSynth()
00071         {
00072                 nnotes = 0;
00073                 for (int i=0;i<128;i++)
00074                 {
00075                         float f = pow( 2. , ( float(i) - 69. ) / 12. ) * 440.;
00076                         dphase[i] = (M_PI*2.)*f / 44100.;
00077         }
00078                 file = fopen("output.raw","wb");
00079         }
00080         
00081         ~SimpleSynth()
00082         {
00083                 fclose(file);
00084         }
00085 
00086         void setnote(int chn,int key,int vel) /* turn not on/off */
00087         {
00088                 if (vel==0)
00089                 {
00090                         /* turn off */
00091                         int i = findnote(chn,key);
00092                         if (i!=nnotes) {
00093                                 notes[i].vel = 0;
00094                         }
00095                         return;
00096                 }
00097                 /* turn on: add a new note */
00098                 notes[nnotes].chn = chn;
00099                 notes[nnotes].key = key;
00100                 notes[nnotes].vel = vel;
00101                 notes[nnotes].phase = 0;
00102                 notes[nnotes].env = 0;
00103                 notes[nnotes].amp = float(vel)/128.;
00104                 nnotes++;
00105         }
00106         
00107         void synthesize(void)
00108         {
00109                 short buf[44];
00110                 for (int j=0;j<44;j++)
00111                 {
00112                         buf[j] = 0;
00113                         float out = 0;
00114                         int i;
00115                         for (i=0;i<nnotes;i++)
00116                         {
00117                                 if (notes[i].vel)
00118                                 {
00119                                         if (notes[i].env<1.) notes[i].env+=0.002; /* attack */
00120                                 }else{
00121                                         if (notes[i].env>0.) notes[i].env-=0.001; /* release */
00122                                 }
00123                                 
00124                                 /* a simple FM synthesizer */
00125                                 out += sin(notes[i].phase+sin(notes[i].phase)*2.)
00126                                         *notes[i].env*notes[i].amp;
00127                                         
00128                                 notes[i].phase += dphase[notes[i].key];
00129                                 if (notes[i].phase>2.*M_PI) notes[i].phase -= 2.*M_PI;
00130                         }
00131                         
00132                         /* remove "dead" notes: notes that have finished the release */
00133                         for (i=0;i<nnotes;)
00134                         {
00135                                 if (notes[i].vel==0 && notes[i].env<0.001)
00136                                 {
00137                                         nnotes--;
00138                                         notes[i] = notes[nnotes];
00139                                 }else{
00140                                         i++;
00141                                 }
00142                         }
00143                         
00144                         buf[j] = (short)(out*2000.);
00145                 }
00146                 fwrite(buf,2,44,file);
00147         }
00148 };
00149 
00150 int main(int argc,char** argv)
00151 {
00152         /* an example of reading a midi file */
00153         Reader r(argc>1 ? argv[1] : "test.mid");
00154         Song s;
00155         r.Read(s);
00156         
00157         Tempo t(&s);
00158 
00159 #ifdef DOPRINT
00160         fprintf(stderr,"song has %d tracks\n",s.Tracks());
00161 #endif
00162         
00163         int trackId;
00164         Event ev;
00165         
00166         SongPlayer sp(&s); /* to traverse the song's events */
00167         
00168         int last = 0;
00169 
00170         SimpleSynth synth; /* a simple synthesizer */
00171 
00172         while (sp.GetEvent(ev,trackId))
00173         {
00174 #ifdef DOPRINT
00175                 fprintf(stderr,"%d %d %d %02x %02x %02x\n",
00176                 ev.mTicks,
00177                 t.TicksToTime(ev.mTicks),
00178                 trackId,
00179                 ev.mMessage[0],
00180                 ev.mMessage[1],
00181                 ev.mMessage[2]);
00182 #endif
00183                 if ((ev[0] & 0xF0)==0x90 || (ev[0] & 0xF0)==0x80) // note on / note off
00184                 {
00185                         int now = t.TicksToTime(ev.GetTicks());
00186                         while (last<now)
00187                         {
00188                                 synth.synthesize();
00189                                 last++;
00190                         }
00191                         {
00192                                 synth.setnote(ev[0]&0x0F, ev[1], (ev[0] & 0xF0)==0x90 ? ev[2] : 0);
00193                         }
00194                 }
00195         }
00196 
00197         for (int k=0;k<1000;k++) synth.synthesize();
00198 
00199         return 0;
00200 }
00201 
Generated by  doxygen 1.6.3