Added SONG_EV_SS_PRINT_WAVE_TEMPO case to MIDI song converting to
[ahxm.git] / midi_song.c
blobe890f92c3a465af11062c348519b22118b49e5e7
1 /*
3 Ann Hell Ex Machina - Music Software
4 Copyright (C) 2003/2005 Angel Ortega <angel@triptico.com>
6 midi_song.c - MIDI song event stream management
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 http://www.triptico.com
26 #include "config.h"
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <math.h>
32 #include <time.h>
33 #include <unistd.h>
35 #include "annhell.h"
37 /*******************
38 Data
39 ********************/
41 struct midi_ev_generic
43 song_ev_type type; /* event type */
44 int msecs; /* time in milliseconds */
45 int trk_id; /* track id */
46 int channel; /* MIDI channel */
49 struct midi_ev_program
51 song_ev_type type; /* SONG_EV_MIDI_PROGRAM */
52 int msecs;
53 int trk_id;
54 int channel;
55 int program; /* MIDI program number */
58 struct midi_ev_note_off
60 song_ev_type type; /* SONG_EV_NOTE_OFF */
61 int msecs;
62 int trk_id;
63 int channel;
64 int note; /* MIDI note */
67 struct midi_ev_note_on
69 song_ev_type type; /* SONG_EV_NOTE_ON */
70 int msecs;
71 int trk_id;
72 int channel;
73 int note; /* MIDI note */
74 int vel; /* velocity (volume) */
77 union midi_ev
79 struct midi_ev_generic generic;
80 struct midi_ev_program midi_program;
81 struct midi_ev_note_on note_on;
82 struct midi_ev_note_off note_off;
86 /* the MIDI song stream */
88 static union midi_ev * midi_song=NULL;
89 static int n_midi_ev=0;
91 /* the MIDI tracks: just a track/channel table */
93 #define MIDI_TRACK_NUM 256
94 static int track_channel[MIDI_TRACK_NUM];
96 /* MIDI message types */
98 #define MIDI_MSG_NOTE_ON 0x90
99 #define MIDI_MSG_NOTE_OFF 0x80
100 #define MIDI_MSG_CONTROLLER 0xB0
101 #define MIDI_MSG_PROGRAM 0xC0
103 /* MIDI device fd */
104 int midi_fd=2;
107 /*******************
108 Code
109 ********************/
111 static void add_midi_ev(union midi_ev * e)
112 /* adds a MIDI song event */
114 if(e->generic.channel < 0)
115 return;
117 /* reallocs */
118 midi_song=(union midi_ev *)realloc(midi_song,
119 (n_midi_ev + 1) * sizeof(union midi_ev));
121 /* store */
122 memcpy(&midi_song[n_midi_ev], e, sizeof(union midi_ev));
124 n_midi_ev++;
128 static int midi_ev_cmp_by_time(const void * v1, const void * v2)
129 /* MIDI song event compare function for qsort(), by time (for playing) */
131 struct midi_ev_generic * e1;
132 struct midi_ev_generic * e2;
134 e1=(struct midi_ev_generic *)v1; e2=(struct midi_ev_generic *)v2;
136 if(e1->msecs == e2->msecs)
137 return(e1->type - e2->type);
139 return(e1->msecs - e2->msecs);
143 static int midi_song_convert_events(void)
144 /* converts generic song_ev events to MIDI events */
146 union song_ev * e;
147 union midi_ev me;
148 int msecs, msecs_ac, f_msecs;
149 double time_ac, time_ac_m;
150 int num, den;
151 double mspw;
152 int n;
153 int b_track=-1;
155 /* resets the MIDI stream */
156 if(midi_song != NULL)
158 free(midi_song);
159 midi_song=NULL;
162 n_midi_ev=0;
164 /* sorts the song */
165 song_sort();
167 mspw=0;
168 msecs=msecs_ac=f_msecs=0;
169 time_ac=time_ac_m=0;
170 num=den=4;
172 /* by default, all channels are 'mute' until
173 a channel is explicitly set */
174 for(n=0;n < MIDI_TRACK_NUM;n++)
175 track_channel[n]=-1;
177 /* travels the song events generating MIDI song events */
178 for(n=0;n < n_song_ev;n++)
180 /* gets the song event */
181 e=&song[n];
183 /* calculates the msecs */
184 msecs=((e->generic.time - time_ac) * mspw) + msecs_ac;
186 /* generic event data */
187 me.generic.type=e->generic.type;
188 me.generic.msecs=msecs;
189 me.generic.trk_id=e->generic.trk_id;
191 /* if it's not a generic message, set MIDI channel */
192 if(e->generic.trk_id >= 0)
193 me.generic.channel=track_channel[e->generic.trk_id];
195 /* account the biggest track number seen */
196 if(b_track < e->generic.trk_id) b_track=e->generic.trk_id;
198 switch(e->generic.type)
200 case SONG_EV_TEMPO:
202 /* updates accumulations */
203 msecs_ac += msecs;
204 time_ac += e->generic.time;
206 /* calculates milliseconds-per-whole based on new tempo */
207 mspw = 1000.0 * 60.0;
208 mspw /= (e->tempo.tempo / 4.0);
210 break;
212 case SONG_EV_METER:
214 /* just store the values */
215 num=e->meter.num;
216 den=e->meter.den;
217 time_ac_m=e->meter.time;
219 break;
221 case SONG_EV_MEASURE:
223 song_test_measure_boundary(e->measure.time - time_ac_m,
224 num, den, e->measure.line);
225 break;
227 case SONG_EV_MIDI_CHANNEL:
229 /* stores the channel for this track */
230 track_channel[e->midi_channel.trk_id]=
231 e->midi_channel.channel;
232 break;
234 case SONG_EV_NOTE:
236 /* convert to note on / off pairs */
238 me.note_on.type=SONG_EV_NOTE_ON;
239 me.note_on.note=e->note.note;
240 me.note_on.vel=(int)(e->note.vol * 127.0);
242 add_midi_ev(&me);
244 msecs += (int)(e->note.len * mspw);
246 me.note_off.type=SONG_EV_NOTE_OFF;
247 me.note_off.msecs=msecs;
249 add_midi_ev(&me);
250 break;
252 case SONG_EV_MIDI_PROGRAM:
254 /* set MIDI program (instrument) */
255 me.midi_program.program=e->midi_program.program;
257 add_midi_ev(&me);
258 break;
260 case SONG_EV_SS_PITCH_STRETCH:
261 case SONG_EV_SS_PRINT_WAVE_TEMPO:
262 case SONG_EV_SS_WAV:
263 case SONG_EV_SS_PAT:
264 case SONG_EV_SS_SUSTAIN:
265 case SONG_EV_SS_VIBRATO:
266 case SONG_EV_SS_CHANNEL:
267 case SONG_EV_SS_EFF_DELAY:
268 case SONG_EV_SS_EFF_ECHO:
269 case SONG_EV_SS_EFF_COMB:
270 case SONG_EV_SS_EFF_ALLPASS:
271 case SONG_EV_SS_EFF_FLANGER:
272 case SONG_EV_SS_EFF_WOBBLE:
273 case SONG_EV_SS_EFF_SQWOBBLE:
274 case SONG_EV_SS_EFF_FADER:
275 case SONG_EV_SS_EFF_REVERB:
276 case SONG_EV_SS_EFF_OFF:
278 /* softsynth events are ignored */
279 break;
281 case SONG_EV_NOTE_ON:
282 case SONG_EV_NOTE_OFF:
283 case SONG_EV_END:
285 /* never found in generic song streams */
286 break;
289 /* store the further time seen */
290 if(f_msecs < msecs) f_msecs=msecs;
293 /* generates an end of event mark, a time after the last one */
294 me.generic.type=SONG_EV_END;
295 me.generic.msecs=f_msecs + 1000;
296 add_midi_ev(&me);
298 /* return the number of tracks */
299 return(b_track + 1);
303 int midi_song_play(int skip_secs)
305 union midi_ev * e;
306 int msecs, msecs_p, msecs_d;
307 int go;
308 int n_tracks;
309 struct timespec ts;
310 unsigned char midimsg[1024];
311 int mi;
312 int skip_msecs;
314 /* convert the song to MIDI events */
315 n_tracks=midi_song_convert_events();
317 /* sort by time */
318 qsort(midi_song, n_midi_ev, sizeof(union midi_ev), midi_ev_cmp_by_time);
320 msecs=msecs_p=0;
321 go=1;
322 e=midi_song;
324 /* calculate the millisecond to start playing */
325 skip_msecs=skip_secs * 1000;
327 /* loop the events */
328 while(go)
330 /* clear buffer */
331 mi=0;
333 /* process all events for this exact time */
334 while(e->generic.msecs == msecs)
336 switch(e->generic.type)
338 case SONG_EV_NOTE_ON:
340 midimsg[mi++]=MIDI_MSG_NOTE_ON|e->note_on.channel;
341 midimsg[mi++]=e->note_on.note;
342 midimsg[mi++]=e->note_on.vel;
344 break;
346 case SONG_EV_NOTE_OFF:
348 midimsg[mi++]=MIDI_MSG_NOTE_OFF|e->note_off.channel;
349 midimsg[mi++]=e->note_off.note;
350 midimsg[mi++]=0;
352 break;
354 case SONG_EV_MIDI_PROGRAM:
356 midimsg[mi++]=MIDI_MSG_PROGRAM|e->midi_program.channel;
357 midimsg[mi++]=e->midi_program.program;
359 break;
361 case SONG_EV_END:
363 go=0;
364 break;
366 default:
367 /* ignore the rest */
368 break;
371 /* next event */
372 e++;
375 if(!go)
376 break;
378 /* get time of next event */
379 msecs_p=msecs;
380 msecs=e->generic.msecs;
381 msecs_d=msecs - msecs_p;
383 if(msecs >= skip_msecs)
385 /* if there are pending messages, write them */
386 if(mi)
387 write(midi_fd, midimsg, mi);
389 /* calculate the time to sleep */
390 ts.tv_sec=(time_t) msecs_d / 1000;
391 ts.tv_nsec=(long) ((msecs_d * 1000000) % 1000000000);
393 nanosleep(&ts, NULL);
397 return(0);