Changed year in copyright notices.
[ahxm.git] / midi_song.c
blobd2360874bdbbbc2f6d7902a4059f3fb3eceb6508
1 /*
3 Ann Hell Ex Machina - Music Software
4 Copyright (C) 2003/2007 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>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
38 #include "ahxm.h"
40 /*******************
41 Data
42 ********************/
44 struct midi_ev_generic
46 song_ev_type type; /* event type */
47 int msecs; /* time in milliseconds */
48 int trk_id; /* track id */
49 int channel; /* MIDI channel */
52 struct midi_ev_program
54 song_ev_type type; /* SONG_EV_MIDI_PROGRAM */
55 int msecs;
56 int trk_id;
57 int channel;
58 int program; /* MIDI program number */
61 struct midi_ev_note_off
63 song_ev_type type; /* SONG_EV_NOTE_OFF */
64 int msecs;
65 int trk_id;
66 int channel;
67 int note; /* MIDI note */
70 struct midi_ev_note_on
72 song_ev_type type; /* SONG_EV_NOTE_ON */
73 int msecs;
74 int trk_id;
75 int channel;
76 int note; /* MIDI note */
77 int vel; /* velocity (volume) */
80 union midi_ev
82 struct midi_ev_generic generic;
83 struct midi_ev_program midi_program;
84 struct midi_ev_note_on note_on;
85 struct midi_ev_note_off note_off;
89 /* the MIDI song stream */
91 static union midi_ev * midi_song = NULL;
92 static int n_midi_ev = 0;
94 /* the MIDI tracks: just a track/channel table */
96 #define MIDI_TRACK_NUM 256
97 static int track_channel[MIDI_TRACK_NUM];
99 /* MIDI message types */
101 #define MIDI_MSG_NOTE_ON 0x90
102 #define MIDI_MSG_NOTE_OFF 0x80
103 #define MIDI_MSG_CONTROLLER 0xB0
104 #define MIDI_MSG_PROGRAM 0xC0
106 /* MIDI device fd */
107 int midi_fd = -1;
110 /*******************
111 Code
112 ********************/
114 static void add_midi_ev(union midi_ev * e)
115 /* adds a MIDI song event */
117 if(e->generic.channel < 0)
118 return;
120 GROW(midi_song, n_midi_ev, union midi_ev);
122 /* store */
123 memcpy(&midi_song[n_midi_ev], e, sizeof(union midi_ev));
125 n_midi_ev++;
129 static int midi_ev_cmp_by_time(const void * v1, const void * v2)
130 /* MIDI song event compare function for qsort(), by time (for playing) */
132 struct midi_ev_generic * e1;
133 struct midi_ev_generic * e2;
135 e1 = (struct midi_ev_generic *)v1; e2=(struct midi_ev_generic *)v2;
137 if(e1->msecs == e2->msecs)
138 return(e1->type - e2->type);
140 return(e1->msecs - e2->msecs);
144 static void midi_song_convert_events(void)
145 /* converts generic song_ev events to MIDI events */
147 union song_ev * e;
148 union midi_ev me;
149 int msecs, msecs_ac, f_msecs;
150 double time_ac, time_ac_m;
151 int num, den;
152 double mspw;
153 int n;
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 switch(e->generic.type)
197 case SONG_EV_TEMPO:
199 /* updates accumulations */
200 msecs_ac = msecs;
201 time_ac = e->generic.time;
203 /* calculates milliseconds-per-whole based on new tempo */
204 mspw = 1000.0 * 60.0;
205 mspw /= (e->tempo.tempo / 4.0);
207 break;
209 case SONG_EV_METER:
211 /* just store the values */
212 num = e->meter.num;
213 den = e->meter.den;
214 time_ac_m = e->meter.time;
216 break;
218 case SONG_EV_MEASURE:
220 song_test_measure_boundary(e->measure.time - time_ac_m,
221 num, den, e->measure.line);
222 break;
224 case SONG_EV_MIDI_CHANNEL:
226 /* stores the channel for this track */
227 track_channel[e->midi_channel.trk_id] =
228 e->midi_channel.channel;
229 break;
231 case SONG_EV_NOTE:
233 /* convert to note on / off pairs */
235 me.note_on.type = SONG_EV_NOTE_ON;
236 me.note_on.note = e->note.note;
237 me.note_on.vel = (int)(e->note.vol * 127.0);
239 add_midi_ev(&me);
241 msecs += (int)(e->note.len * mspw);
243 me.note_off.type = SONG_EV_NOTE_OFF;
244 me.note_off.msecs = msecs;
246 add_midi_ev(&me);
247 break;
249 case SONG_EV_BACK:
251 /* move the cursor back */
252 msecs_ac -= (int)(e->back.len * mspw);
253 break;
255 case SONG_EV_MIDI_PROGRAM:
257 /* set MIDI program (instrument) */
258 me.midi_program.program = e->midi_program.program;
260 add_midi_ev(&me);
261 break;
263 case SONG_EV_SS_PITCH_STRETCH:
264 case SONG_EV_SS_PRINT_WAVE_TEMPO:
265 case SONG_EV_SS_WAV:
266 case SONG_EV_SS_PAT:
267 case SONG_EV_SS_SUSTAIN:
268 case SONG_EV_SS_ATTACK:
269 case SONG_EV_SS_VIBRATO:
270 case SONG_EV_SS_PORTAMENTO:
271 case SONG_EV_SS_CHANNEL:
272 case SONG_EV_SS_EFF_DELAY:
273 case SONG_EV_SS_EFF_ECHO:
274 case SONG_EV_SS_EFF_COMB:
275 case SONG_EV_SS_EFF_ALLPASS:
276 case SONG_EV_SS_EFF_FLANGER:
277 case SONG_EV_SS_EFF_WOBBLE:
278 case SONG_EV_SS_EFF_SQWOBBLE:
279 case SONG_EV_SS_EFF_HFWOBBLE:
280 case SONG_EV_SS_EFF_FADER:
281 case SONG_EV_SS_EFF_REVERB:
282 case SONG_EV_SS_EFF_FOLDBACK:
283 case SONG_EV_SS_EFF_ATAN:
284 case SONG_EV_SS_EFF_DISTORT:
285 case SONG_EV_SS_EFF_OVERDRIVE:
286 case SONG_EV_SS_EFF_OFF:
288 /* softsynth events are ignored */
289 break;
291 case SONG_EV_SONG_INFO:
293 /* song info should be used */
294 break;
296 case SONG_EV_EOT:
298 /* end of track; trigger possible cleaning */
299 break;
301 case SONG_EV_NOTE_ON:
302 case SONG_EV_NOTE_OFF:
303 case SONG_EV_END:
305 /* never found in generic song streams */
306 break;
309 /* store the further time seen */
310 if(f_msecs < msecs) f_msecs = msecs;
313 /* generates an end of event mark, a time after the last one */
314 me.generic.type = SONG_EV_END;
315 me.generic.msecs = f_msecs + 1000;
316 add_midi_ev(&me);
320 int midi_song_play(int skip_secs)
322 union midi_ev * e;
323 int msecs, msecs_p, msecs_d;
324 int go;
325 struct timespec ts;
326 unsigned char midimsg[1024];
327 int mi;
328 int skip_msecs;
330 /* convert the song to MIDI events */
331 midi_song_convert_events();
333 /* sort by time */
334 qsort(midi_song, n_midi_ev, sizeof(union midi_ev), midi_ev_cmp_by_time);
336 msecs = msecs_p = 0;
337 go = 1;
338 e = midi_song;
340 /* calculate the millisecond to start playing */
341 skip_msecs = skip_secs * 1000;
343 /* loop the events */
344 while(go)
346 /* clear buffer */
347 mi = 0;
349 if(verbose >= 1)
351 if(msecs % 1000 == 0)
353 int m = msecs / 1000;
354 printf("[%02d:%02d]\r", m / 60, m % 60);
355 fflush(stdout);
359 /* process all events for this exact time */
360 while(e->generic.msecs == msecs)
362 switch(e->generic.type)
364 case SONG_EV_NOTE_ON:
366 midimsg[mi++] = MIDI_MSG_NOTE_ON|e->note_on.channel;
367 midimsg[mi++] = e->note_on.note;
368 midimsg[mi++] = e->note_on.vel;
370 break;
372 case SONG_EV_NOTE_OFF:
374 midimsg[mi++] = MIDI_MSG_NOTE_OFF|e->note_off.channel;
375 midimsg[mi++] = e->note_off.note;
376 midimsg[mi++] = 0;
378 break;
380 case SONG_EV_MIDI_PROGRAM:
382 midimsg[mi++] = MIDI_MSG_PROGRAM|e->midi_program.channel;
383 midimsg[mi++] = e->midi_program.program;
385 break;
387 case SONG_EV_END:
389 go = 0;
390 break;
392 default:
393 /* ignore the rest */
394 break;
397 /* next event */
398 e++;
401 if(!go)
402 break;
404 /* get time of next event */
405 msecs_p = msecs;
406 msecs = e->generic.msecs;
407 msecs_d = msecs - msecs_p;
409 if(msecs >= skip_msecs)
411 /* if there are pending messages, write them */
412 if(mi)
413 write(midi_fd, midimsg, mi);
415 /* calculate the time to sleep */
416 ts.tv_sec = (time_t) msecs_d / 1000;
417 ts.tv_nsec = (long) ((msecs_d * 1000000) % 1000000000);
419 nanosleep(&ts, NULL);
423 if(verbose >= 1) printf("\n");
425 return(0);
429 int midi_device_open(char * devfile)
431 if(devfile == NULL)
432 devfile = "/dev/midi";
434 return((midi_fd = open(devfile, O_WRONLY)));
438 void midi_device_close(void)
440 close(midi_fd);