Added 'win32dist' Makefile target.
[ahxm.git] / midi_song.c
blob2be1f338d2bab4ab9d13673c82deca32557f6451
1 /*
3 Ann Hell Ex Machina - Music Software
4 Copyright (C) 2003/2008 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"
41 /** data **/
43 /* the MIDI song stream */
45 static struct song_ev *midi_song = NULL;
46 static int n_midi_ev = 0;
48 /* the MIDI tracks: just a track/channel table */
50 #define MIDI_TRACK_NUM 256
51 static int track_channel[MIDI_TRACK_NUM];
53 /* MIDI message types */
55 #define MIDI_MSG_NOTE_ON 0x90
56 #define MIDI_MSG_NOTE_OFF 0x80
57 #define MIDI_MSG_CONTROLLER 0xB0
58 #define MIDI_MSG_PROGRAM 0xC0
60 /* MIDI device fd */
61 int midi_fd = -1;
64 /** code **/
66 static struct song_ev *add_midi_ev(struct song_ev *e)
67 /* adds a MIDI song event */
69 if (e->channel < 0)
70 return NULL;
72 return copy_event(&midi_song, &n_midi_ev, e);
76 static int msecs_type_cmp(const void *v1, const void *v2)
77 /* MIDI song event compare function for qsort(), by time (for playing) */
79 struct song_ev *e1;
80 struct song_ev *e2;
82 e1 = (struct song_ev *) v1;
83 e2 = (struct song_ev *) v2;
85 if (e1->msecs == e2->msecs)
86 return e1->type - e2->type;
88 return e1->msecs - e2->msecs;
92 static void midi_song_convert_events(void)
93 /* converts generic song_ev events to MIDI events */
95 struct song_ev *e;
96 int msecs, msecs_ac, f_msecs;
97 double time_ac, time_ac_m;
98 int num, den;
99 double mspw;
100 int n;
102 /* resets the MIDI stream */
103 if (midi_song != NULL) {
104 free(midi_song);
105 midi_song = NULL;
108 n_midi_ev = 0;
110 /* sorts the song */
111 song_sort();
113 mspw = 0;
114 msecs = msecs_ac = f_msecs = 0;
115 time_ac = time_ac_m = 0;
116 num = den = 4;
118 /* by default, all channels are 'mute' until
119 a channel is explicitly set */
120 for (n = 0; n < MIDI_TRACK_NUM; n++)
121 track_channel[n] = -1;
123 /* travels the song events generating MIDI song events */
124 for (n = 0; n < n_song_ev; n++) {
125 /* gets the song event */
126 e = &song[n];
128 /* calculates the msecs */
129 msecs = ((e->time - time_ac) * mspw) + msecs_ac;
130 e->msecs = msecs;
132 /* if it's not a generic message, set MIDI channel */
133 if (e->trk_id >= 0)
134 e->channel = track_channel[e->trk_id];
136 switch (e->type) {
137 case SONG_EV_TEMPO:
139 /* updates accumulations */
140 msecs_ac = msecs;
141 time_ac = e->time;
143 /* calculates milliseconds-per-whole based on new tempo */
144 mspw = 1000.0 * 60.0;
145 mspw /= (e->amount / 4.0);
147 break;
149 case SONG_EV_METER:
151 /* just store the values */
152 num = e->min;
153 den = e->max;
154 time_ac_m = e->time;
156 break;
158 case SONG_EV_MEASURE:
160 song_test_measure_boundary(e->time - time_ac_m,
161 num, den, e->value);
162 break;
164 case SONG_EV_MIDI_CHANNEL:
166 /* stores the channel for this track */
167 track_channel[e->trk_id] = e->channel;
168 break;
170 case SONG_EV_NOTE:
172 /* convert to note on / off pairs */
174 e->vel = (int) (e->vol * 127.0);
176 add_midi_ev(e);
178 e = add_midi_ev(e);
179 e->type = SONG_EV_NOTE_OFF;
181 msecs += (int) (e->len * mspw);
182 e->msecs = msecs;
184 break;
186 case SONG_EV_BACK:
188 /* move the cursor back */
189 msecs_ac -= (int) (e->len * mspw);
190 break;
192 case SONG_EV_MIDI_PROGRAM:
194 add_midi_ev(e);
195 break;
197 case SONG_EV_SS_PITCH_STRETCH:
198 case SONG_EV_SS_PRINT_WAVE_TEMPO:
199 case SONG_EV_SS_WAV:
200 case SONG_EV_SS_PAT:
201 case SONG_EV_SS_SF2:
202 case SONG_EV_SS_SUSTAIN:
203 case SONG_EV_SS_ATTACK:
204 case SONG_EV_SS_VIBRATO:
205 case SONG_EV_SS_PORTAMENTO:
206 case SONG_EV_SS_CHANNEL:
207 case SONG_EV_SS_EFF_DELAY:
208 case SONG_EV_SS_EFF_ECHO:
209 case SONG_EV_SS_EFF_COMB:
210 case SONG_EV_SS_EFF_ALLPASS:
211 case SONG_EV_SS_EFF_FLANGER:
212 case SONG_EV_SS_EFF_WOBBLE:
213 case SONG_EV_SS_EFF_SQWOBBLE:
214 case SONG_EV_SS_EFF_HFWOBBLE:
215 case SONG_EV_SS_EFF_FADER:
216 case SONG_EV_SS_EFF_REVERB:
217 case SONG_EV_SS_EFF_FOLDBACK:
218 case SONG_EV_SS_EFF_ATAN:
219 case SONG_EV_SS_EFF_DISTORT:
220 case SONG_EV_SS_EFF_OVERDRIVE:
221 case SONG_EV_SS_EFF_OFF:
222 case SONG_EV_SS_MASTER_VOLUME:
223 case SONG_EV_NOP:
225 /* ignored */
226 break;
228 case SONG_EV_SONG_INFO:
230 /* song info should be used */
231 break;
233 case SONG_EV_EOT:
235 /* end of track; trigger possible cleaning */
236 break;
238 case SONG_EV_NOTE_OFF:
239 case SONG_EV_END:
241 /* never found in generic song streams */
242 break;
245 /* store the further time seen */
246 if (f_msecs < msecs)
247 f_msecs = msecs;
250 /* generates an end of event mark, a time after the last one */
251 e = add_event(&midi_song, &n_midi_ev);
253 e->type = SONG_EV_END;
254 e->msecs = f_msecs + 1000;
258 int midi_song_play(int skip_secs)
260 #ifdef CONFOPT_NANOSLEEP
261 struct song_ev *e;
262 int msecs, msecs_p, msecs_d;
263 int go;
264 struct timespec ts;
265 unsigned char midimsg[1024];
266 int mi;
267 int skip_msecs;
269 /* convert the song to MIDI events */
270 midi_song_convert_events();
272 /* sort by time */
273 qsort(midi_song, n_midi_ev, sizeof(struct song_ev), msecs_type_cmp);
275 msecs = msecs_p = 0;
276 go = 1;
277 e = midi_song;
279 /* calculate the millisecond to start playing */
280 skip_msecs = skip_secs * 1000;
282 /* loop the events */
283 while (go) {
284 /* clear buffer */
285 mi = 0;
287 if (verbose >= 1 && msecs % 1000 == 0) {
288 int m = msecs / 1000;
289 printf("[%02d:%02d]\r", m / 60, m % 60);
290 fflush(stdout);
293 /* process all events for this exact time */
294 while (e->msecs == msecs) {
295 switch (e->type) {
296 case SONG_EV_NOTE:
298 midimsg[mi++] = MIDI_MSG_NOTE_ON | e->channel;
299 midimsg[mi++] = e->value;
300 midimsg[mi++] = e->vel;
302 break;
304 case SONG_EV_NOTE_OFF:
306 midimsg[mi++] = MIDI_MSG_NOTE_OFF | e->channel;
307 midimsg[mi++] = e->value;
308 midimsg[mi++] = 0;
310 break;
312 case SONG_EV_MIDI_PROGRAM:
314 midimsg[mi++] = MIDI_MSG_PROGRAM | e->channel;
315 midimsg[mi++] = e->value;
317 break;
319 case SONG_EV_END:
321 go = 0;
322 break;
324 default:
325 /* ignore the rest */
326 break;
329 /* next event */
330 e++;
333 if (!go)
334 break;
336 /* get time of next event */
337 msecs_p = msecs;
338 msecs = e->msecs;
339 msecs_d = msecs - msecs_p;
341 if (msecs >= skip_msecs) {
342 /* if there are pending messages, write them */
343 if (mi)
344 write(midi_fd, midimsg, mi);
346 /* calculate the time to sleep */
347 ts.tv_sec = (time_t) msecs_d / 1000;
348 ts.tv_nsec = (long) ((msecs_d * 1000000) % 1000000000);
350 nanosleep(&ts, NULL);
354 if (verbose >= 1)
355 printf("\n");
357 #endif /* CONFOPT_NANOSLEEP */
359 return 0;
363 int midi_device_open(char *devfile)
365 if (devfile == NULL)
366 devfile = "/dev/midi";
368 return (midi_fd = open(devfile, O_WRONLY));
372 void midi_device_close(void)
374 close(midi_fd);