Updated ss_song_convert_events() to the new way of copying events.
[ahxm.git] / midi_song.c
blobd1903b6f0f0ce4932b26cfb5e450ac03a4c98f23
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 /* the MIDI song stream */
46 static struct song_ev *midi_song = NULL;
47 static int n_midi_ev = 0;
49 /* the MIDI tracks: just a track/channel table */
51 #define MIDI_TRACK_NUM 256
52 static int track_channel[MIDI_TRACK_NUM];
54 /* MIDI message types */
56 #define MIDI_MSG_NOTE_ON 0x90
57 #define MIDI_MSG_NOTE_OFF 0x80
58 #define MIDI_MSG_CONTROLLER 0xB0
59 #define MIDI_MSG_PROGRAM 0xC0
61 /* MIDI device fd */
62 int midi_fd = -1;
65 /*******************
66 Code
67 ********************/
69 static struct song_ev * add_midi_ev(struct song_ev *e)
70 /* adds a MIDI song event */
72 if (e->channel < 0)
73 return NULL;
75 return append_event(&midi_song, &n_midi_ev, e);
79 static int msecs_type_cmp(const void *v1, const void *v2)
80 /* MIDI song event compare function for qsort(), by time (for playing) */
82 struct song_ev *e1;
83 struct song_ev *e2;
85 e1 = (struct song_ev *) v1;
86 e2 = (struct song_ev *) v2;
88 if (e1->msecs == e2->msecs)
89 return e1->type - e2->type;
91 return e1->msecs - e2->msecs;
95 static void midi_song_convert_events(void)
96 /* converts generic song_ev events to MIDI events */
98 struct song_ev *e;
99 struct song_ev me;
100 int msecs, msecs_ac, f_msecs;
101 double time_ac, time_ac_m;
102 int num, den;
103 double mspw;
104 int n;
106 /* resets the MIDI stream */
107 if (midi_song != NULL) {
108 free(midi_song);
109 midi_song = NULL;
112 n_midi_ev = 0;
114 /* sorts the song */
115 song_sort();
117 mspw = 0;
118 msecs = msecs_ac = f_msecs = 0;
119 time_ac = time_ac_m = 0;
120 num = den = 4;
122 /* by default, all channels are 'mute' until
123 a channel is explicitly set */
124 for (n = 0; n < MIDI_TRACK_NUM; n++)
125 track_channel[n] = -1;
127 /* travels the song events generating MIDI song events */
128 for (n = 0; n < n_song_ev; n++) {
129 /* gets the song event */
130 e = &song[n];
132 /* calculates the msecs */
133 msecs = ((e->time - time_ac) * mspw) + msecs_ac;
135 /* generic event data */
136 me.type = e->type;
137 me.msecs = msecs;
138 me.trk_id = e->trk_id;
140 /* if it's not a generic message, set MIDI channel */
141 if (e->trk_id >= 0)
142 me.channel = track_channel[e->trk_id];
144 switch (e->type) {
145 case SONG_EV_TEMPO:
147 /* updates accumulations */
148 msecs_ac = msecs;
149 time_ac = e->time;
151 /* calculates milliseconds-per-whole based on new tempo */
152 mspw = 1000.0 * 60.0;
153 mspw /= (e->amount / 4.0);
155 break;
157 case SONG_EV_METER:
159 /* just store the values */
160 num = e->min;
161 den = e->max;
162 time_ac_m = e->time;
164 break;
166 case SONG_EV_MEASURE:
168 song_test_measure_boundary(e->time - time_ac_m,
169 num, den, e->value);
170 break;
172 case SONG_EV_MIDI_CHANNEL:
174 /* stores the channel for this track */
175 track_channel[e->trk_id] = e->channel;
176 break;
178 case SONG_EV_NOTE:
180 /* convert to note on / off pairs */
182 me.type = SONG_EV_NOTE_ON;
183 me.value = e->value;
184 me.vel = (int) (e->vol * 127.0);
186 add_midi_ev(&me);
188 msecs += (int) (e->len * mspw);
190 me.type = SONG_EV_NOTE_OFF;
191 me.msecs = msecs;
193 add_midi_ev(&me);
194 break;
196 case SONG_EV_BACK:
198 /* move the cursor back */
199 msecs_ac -= (int) (e->len * mspw);
200 break;
202 case SONG_EV_MIDI_PROGRAM:
204 /* set MIDI program (instrument) */
205 me.value = e->value;
207 add_midi_ev(&me);
208 break;
210 case SONG_EV_SS_PITCH_STRETCH:
211 case SONG_EV_SS_PRINT_WAVE_TEMPO:
212 case SONG_EV_SS_WAV:
213 case SONG_EV_SS_PAT:
214 case SONG_EV_SS_SUSTAIN:
215 case SONG_EV_SS_ATTACK:
216 case SONG_EV_SS_VIBRATO:
217 case SONG_EV_SS_PORTAMENTO:
218 case SONG_EV_SS_CHANNEL:
219 case SONG_EV_SS_EFF_DELAY:
220 case SONG_EV_SS_EFF_ECHO:
221 case SONG_EV_SS_EFF_COMB:
222 case SONG_EV_SS_EFF_ALLPASS:
223 case SONG_EV_SS_EFF_FLANGER:
224 case SONG_EV_SS_EFF_WOBBLE:
225 case SONG_EV_SS_EFF_SQWOBBLE:
226 case SONG_EV_SS_EFF_HFWOBBLE:
227 case SONG_EV_SS_EFF_FADER:
228 case SONG_EV_SS_EFF_REVERB:
229 case SONG_EV_SS_EFF_FOLDBACK:
230 case SONG_EV_SS_EFF_ATAN:
231 case SONG_EV_SS_EFF_DISTORT:
232 case SONG_EV_SS_EFF_OVERDRIVE:
233 case SONG_EV_SS_EFF_OFF:
235 /* softsynth events are ignored */
236 break;
238 case SONG_EV_SONG_INFO:
240 /* song info should be used */
241 break;
243 case SONG_EV_EOT:
245 /* end of track; trigger possible cleaning */
246 break;
248 case SONG_EV_NOTE_ON:
249 case SONG_EV_NOTE_OFF:
250 case SONG_EV_END:
252 /* never found in generic song streams */
253 break;
256 /* store the further time seen */
257 if (f_msecs < msecs)
258 f_msecs = msecs;
261 /* generates an end of event mark, a time after the last one */
262 me.type = SONG_EV_END;
263 me.msecs = f_msecs + 1000;
264 add_midi_ev(&me);
268 int midi_song_play(int skip_secs)
270 struct song_ev *e;
271 int msecs, msecs_p, msecs_d;
272 int go;
273 struct timespec ts;
274 unsigned char midimsg[1024];
275 int mi;
276 int skip_msecs;
278 /* convert the song to MIDI events */
279 midi_song_convert_events();
281 /* sort by time */
282 qsort(midi_song, n_midi_ev, sizeof(struct song_ev), msecs_type_cmp);
284 msecs = msecs_p = 0;
285 go = 1;
286 e = midi_song;
288 /* calculate the millisecond to start playing */
289 skip_msecs = skip_secs * 1000;
291 /* loop the events */
292 while (go) {
293 /* clear buffer */
294 mi = 0;
296 if (verbose >= 1 && msecs % 1000 == 0) {
297 int m = msecs / 1000;
298 printf("[%02d:%02d]\r", m / 60, m % 60);
299 fflush(stdout);
302 /* process all events for this exact time */
303 while (e->msecs == msecs) {
304 switch (e->type) {
305 case SONG_EV_NOTE_ON:
307 midimsg[mi++] = MIDI_MSG_NOTE_ON | e->channel;
308 midimsg[mi++] = e->value;
309 midimsg[mi++] = e->vel;
311 break;
313 case SONG_EV_NOTE_OFF:
315 midimsg[mi++] = MIDI_MSG_NOTE_OFF | e->channel;
316 midimsg[mi++] = e->value;
317 midimsg[mi++] = 0;
319 break;
321 case SONG_EV_MIDI_PROGRAM:
323 midimsg[mi++] = MIDI_MSG_PROGRAM | e->channel;
324 midimsg[mi++] = e->value;
326 break;
328 case SONG_EV_END:
330 go = 0;
331 break;
333 default:
334 /* ignore the rest */
335 break;
338 /* next event */
339 e++;
342 if (!go)
343 break;
345 /* get time of next event */
346 msecs_p = msecs;
347 msecs = e->msecs;
348 msecs_d = msecs - msecs_p;
350 if (msecs >= skip_msecs) {
351 /* if there are pending messages, write them */
352 if (mi)
353 write(midi_fd, midimsg, mi);
355 /* calculate the time to sleep */
356 ts.tv_sec = (time_t) msecs_d / 1000;
357 ts.tv_nsec = (long) ((msecs_d * 1000000) % 1000000000);
359 nanosleep(&ts, NULL);
363 if (verbose >= 1)
364 printf("\n");
366 return 0;
370 int midi_device_open(char *devfile)
372 if (devfile == NULL)
373 devfile = "/dev/midi";
375 return (midi_fd = open(devfile, O_WRONLY));
379 void midi_device_close(void)
381 close(midi_fd);