More coding style changes.
[ahxm.git] / midi_song.c
blob9711d4f9cdb1c01b6ddd9787d8b7b03886b20268
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 {
45 song_ev_type type; /* event type */
46 int msecs; /* time in milliseconds */
47 int trk_id; /* track id */
48 int channel; /* MIDI channel */
51 struct midi_ev_program {
52 song_ev_type type; /* SONG_EV_MIDI_PROGRAM */
53 int msecs;
54 int trk_id;
55 int channel;
56 int program; /* MIDI program number */
59 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 {
68 song_ev_type type; /* SONG_EV_NOTE_ON */
69 int msecs;
70 int trk_id;
71 int channel;
72 int note; /* MIDI note */
73 int vel; /* velocity (volume) */
76 union midi_ev {
77 struct midi_ev_generic generic;
78 struct midi_ev_program midi_program;
79 struct midi_ev_note_on note_on;
80 struct midi_ev_note_off note_off;
84 /* the MIDI song stream */
86 static union midi_ev *midi_song = NULL;
87 static int n_midi_ev = 0;
89 /* the MIDI tracks: just a track/channel table */
91 #define MIDI_TRACK_NUM 256
92 static int track_channel[MIDI_TRACK_NUM];
94 /* MIDI message types */
96 #define MIDI_MSG_NOTE_ON 0x90
97 #define MIDI_MSG_NOTE_OFF 0x80
98 #define MIDI_MSG_CONTROLLER 0xB0
99 #define MIDI_MSG_PROGRAM 0xC0
101 /* MIDI device fd */
102 int midi_fd = -1;
105 /*******************
106 Code
107 ********************/
109 static void add_midi_ev(union midi_ev *e)
110 /* adds a MIDI song event */
112 if (e->generic.channel < 0)
113 return;
115 GROW(midi_song, n_midi_ev, union midi_ev);
117 /* store */
118 memcpy(&midi_song[n_midi_ev], e, sizeof(union midi_ev));
120 n_midi_ev++;
124 static int midi_ev_cmp_by_time(const void *v1, const void *v2)
125 /* MIDI song event compare function for qsort(), by time (for playing) */
127 struct midi_ev_generic *e1;
128 struct midi_ev_generic *e2;
130 e1 = (struct midi_ev_generic *) v1;
131 e2 = (struct midi_ev_generic *) v2;
133 if (e1->msecs == e2->msecs)
134 return e1->type - e2->type;
136 return e1->msecs - e2->msecs;
140 static void midi_song_convert_events(void)
141 /* converts generic song_ev events to MIDI events */
143 union song_ev *e;
144 union midi_ev me;
145 int msecs, msecs_ac, f_msecs;
146 double time_ac, time_ac_m;
147 int num, den;
148 double mspw;
149 int n;
151 /* resets the MIDI stream */
152 if (midi_song != NULL) {
153 free(midi_song);
154 midi_song = NULL;
157 n_midi_ev = 0;
159 /* sorts the song */
160 song_sort();
162 mspw = 0;
163 msecs = msecs_ac = f_msecs = 0;
164 time_ac = time_ac_m = 0;
165 num = den = 4;
167 /* by default, all channels are 'mute' until
168 a channel is explicitly set */
169 for (n = 0; n < MIDI_TRACK_NUM; n++)
170 track_channel[n] = -1;
172 /* travels the song events generating MIDI song events */
173 for (n = 0; n < n_song_ev; n++) {
174 /* gets the song event */
175 e = &song[n];
177 /* calculates the msecs */
178 msecs = ((e->generic.time - time_ac) * mspw) + msecs_ac;
180 /* generic event data */
181 me.generic.type = e->generic.type;
182 me.generic.msecs = msecs;
183 me.generic.trk_id = e->generic.trk_id;
185 /* if it's not a generic message, set MIDI channel */
186 if (e->generic.trk_id >= 0)
187 me.generic.channel = track_channel[e->generic.trk_id];
189 switch (e->generic.type) {
190 case SONG_EV_TEMPO:
192 /* updates accumulations */
193 msecs_ac = msecs;
194 time_ac = e->generic.time;
196 /* calculates milliseconds-per-whole based on new tempo */
197 mspw = 1000.0 * 60.0;
198 mspw /= (e->tempo.tempo / 4.0);
200 break;
202 case SONG_EV_METER:
204 /* just store the values */
205 num = e->meter.num;
206 den = e->meter.den;
207 time_ac_m = e->meter.time;
209 break;
211 case SONG_EV_MEASURE:
213 song_test_measure_boundary(e->measure.time - time_ac_m,
214 num, den, e->measure.line);
215 break;
217 case SONG_EV_MIDI_CHANNEL:
219 /* stores the channel for this track */
220 track_channel[e->midi_channel.trk_id] = e->midi_channel.channel;
221 break;
223 case SONG_EV_NOTE:
225 /* convert to note on / off pairs */
227 me.note_on.type = SONG_EV_NOTE_ON;
228 me.note_on.note = e->note.note;
229 me.note_on.vel = (int) (e->note.vol * 127.0);
231 add_midi_ev(&me);
233 msecs += (int) (e->note.len * mspw);
235 me.note_off.type = SONG_EV_NOTE_OFF;
236 me.note_off.msecs = msecs;
238 add_midi_ev(&me);
239 break;
241 case SONG_EV_BACK:
243 /* move the cursor back */
244 msecs_ac -= (int) (e->back.len * mspw);
245 break;
247 case SONG_EV_MIDI_PROGRAM:
249 /* set MIDI program (instrument) */
250 me.midi_program.program = e->midi_program.program;
252 add_midi_ev(&me);
253 break;
255 case SONG_EV_SS_PITCH_STRETCH:
256 case SONG_EV_SS_PRINT_WAVE_TEMPO:
257 case SONG_EV_SS_WAV:
258 case SONG_EV_SS_PAT:
259 case SONG_EV_SS_SUSTAIN:
260 case SONG_EV_SS_ATTACK:
261 case SONG_EV_SS_VIBRATO:
262 case SONG_EV_SS_PORTAMENTO:
263 case SONG_EV_SS_CHANNEL:
264 case SONG_EV_SS_EFF_DELAY:
265 case SONG_EV_SS_EFF_ECHO:
266 case SONG_EV_SS_EFF_COMB:
267 case SONG_EV_SS_EFF_ALLPASS:
268 case SONG_EV_SS_EFF_FLANGER:
269 case SONG_EV_SS_EFF_WOBBLE:
270 case SONG_EV_SS_EFF_SQWOBBLE:
271 case SONG_EV_SS_EFF_HFWOBBLE:
272 case SONG_EV_SS_EFF_FADER:
273 case SONG_EV_SS_EFF_REVERB:
274 case SONG_EV_SS_EFF_FOLDBACK:
275 case SONG_EV_SS_EFF_ATAN:
276 case SONG_EV_SS_EFF_DISTORT:
277 case SONG_EV_SS_EFF_OVERDRIVE:
278 case SONG_EV_SS_EFF_OFF:
280 /* softsynth events are ignored */
281 break;
283 case SONG_EV_SONG_INFO:
285 /* song info should be used */
286 break;
288 case SONG_EV_EOT:
290 /* end of track; trigger possible cleaning */
291 break;
293 case SONG_EV_NOTE_ON:
294 case SONG_EV_NOTE_OFF:
295 case SONG_EV_END:
297 /* never found in generic song streams */
298 break;
301 /* store the further time seen */
302 if (f_msecs < msecs)
303 f_msecs = msecs;
306 /* generates an end of event mark, a time after the last one */
307 me.generic.type = SONG_EV_END;
308 me.generic.msecs = f_msecs + 1000;
309 add_midi_ev(&me);
313 int midi_song_play(int skip_secs)
315 union midi_ev *e;
316 int msecs, msecs_p, msecs_d;
317 int go;
318 struct timespec ts;
319 unsigned char midimsg[1024];
320 int mi;
321 int skip_msecs;
323 /* convert the song to MIDI events */
324 midi_song_convert_events();
326 /* sort by time */
327 qsort(midi_song, n_midi_ev, sizeof(union midi_ev), midi_ev_cmp_by_time);
329 msecs = msecs_p = 0;
330 go = 1;
331 e = midi_song;
333 /* calculate the millisecond to start playing */
334 skip_msecs = skip_secs * 1000;
336 /* loop the events */
337 while (go) {
338 /* clear buffer */
339 mi = 0;
341 if (verbose >= 1) {
342 if (msecs % 1000 == 0) {
343 int m = msecs / 1000;
344 printf("[%02d:%02d]\r", m / 60, m % 60);
345 fflush(stdout);
349 /* process all events for this exact time */
350 while (e->generic.msecs == msecs) {
351 switch (e->generic.type) {
352 case SONG_EV_NOTE_ON:
354 midimsg[mi++] = MIDI_MSG_NOTE_ON | e->note_on.channel;
355 midimsg[mi++] = e->note_on.note;
356 midimsg[mi++] = e->note_on.vel;
358 break;
360 case SONG_EV_NOTE_OFF:
362 midimsg[mi++] = MIDI_MSG_NOTE_OFF | e->note_off.channel;
363 midimsg[mi++] = e->note_off.note;
364 midimsg[mi++] = 0;
366 break;
368 case SONG_EV_MIDI_PROGRAM:
370 midimsg[mi++] = MIDI_MSG_PROGRAM | e->midi_program.channel;
371 midimsg[mi++] = e->midi_program.program;
373 break;
375 case SONG_EV_END:
377 go = 0;
378 break;
380 default:
381 /* ignore the rest */
382 break;
385 /* next event */
386 e++;
389 if (!go)
390 break;
392 /* get time of next event */
393 msecs_p = msecs;
394 msecs = e->generic.msecs;
395 msecs_d = msecs - msecs_p;
397 if (msecs >= skip_msecs) {
398 /* if there are pending messages, write them */
399 if (mi)
400 write(midi_fd, midimsg, mi);
402 /* calculate the time to sleep */
403 ts.tv_sec = (time_t) msecs_d / 1000;
404 ts.tv_nsec = (long) ((msecs_d * 1000000) % 1000000000);
406 nanosleep(&ts, NULL);
410 if (verbose >= 1)
411 printf("\n");
413 return 0;
417 int midi_device_open(char *devfile)
419 if (devfile == NULL)
420 devfile = "/dev/midi";
422 return (midi_fd = open(devfile, O_WRONLY));
426 void midi_device_close(void)
428 close(midi_fd);