CLAM-Development
1.1
|
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