Change all structure names to the unified ones.
[ahxm.git] / midi_song.c
blobcad48ec8cb5adaa85e7d1ae6614fdf17950be646
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 {
45 song_ev_type type; /* event type */
46 int msecs; /* time in milliseconds */
47 int trk_id; /* track id */
48 int channel; /* MIDI channel */
49 int note; /* MIDI note */
50 int vel; /* velocity (volume) */
51 int program; /* MIDI program number */
54 /* the MIDI song stream */
56 static struct midi_ev *midi_song = NULL;
57 static int n_midi_ev = 0;
59 /* the MIDI tracks: just a track/channel table */
61 #define MIDI_TRACK_NUM 256
62 static int track_channel[MIDI_TRACK_NUM];
64 /* MIDI message types */
66 #define MIDI_MSG_NOTE_ON 0x90
67 #define MIDI_MSG_NOTE_OFF 0x80
68 #define MIDI_MSG_CONTROLLER 0xB0
69 #define MIDI_MSG_PROGRAM 0xC0
71 /* MIDI device fd */
72 int midi_fd = -1;
75 /*******************
76 Code
77 ********************/
79 static void add_midi_ev(struct midi_ev *e)
80 /* adds a MIDI song event */
82 if (e->channel < 0)
83 return;
85 GROW(midi_song, n_midi_ev, struct midi_ev);
87 /* store */
88 memcpy(&midi_song[n_midi_ev], e, sizeof(struct midi_ev));
90 n_midi_ev++;
94 static int midi_ev_cmp_by_time(const void *v1, const void *v2)
95 /* MIDI song event compare function for qsort(), by time (for playing) */
97 struct midi_ev *e1;
98 struct midi_ev *e2;
100 e1 = (struct midi_ev *) v1;
101 e2 = (struct midi_ev *) v2;
103 if (e1->msecs == e2->msecs)
104 return e1->type - e2->type;
106 return e1->msecs - e2->msecs;
110 static void midi_song_convert_events(void)
111 /* converts generic song_ev events to MIDI events */
113 union song_ev *e;
114 struct midi_ev me;
115 int msecs, msecs_ac, f_msecs;
116 double time_ac, time_ac_m;
117 int num, den;
118 double mspw;
119 int n;
121 /* resets the MIDI stream */
122 if (midi_song != NULL) {
123 free(midi_song);
124 midi_song = NULL;
127 n_midi_ev = 0;
129 /* sorts the song */
130 song_sort();
132 mspw = 0;
133 msecs = msecs_ac = f_msecs = 0;
134 time_ac = time_ac_m = 0;
135 num = den = 4;
137 /* by default, all channels are 'mute' until
138 a channel is explicitly set */
139 for (n = 0; n < MIDI_TRACK_NUM; n++)
140 track_channel[n] = -1;
142 /* travels the song events generating MIDI song events */
143 for (n = 0; n < n_song_ev; n++) {
144 /* gets the song event */
145 e = &song[n];
147 /* calculates the msecs */
148 msecs = ((e->generic.time - time_ac) * mspw) + msecs_ac;
150 /* generic event data */
151 me.type = e->generic.type;
152 me.msecs = msecs;
153 me.trk_id = e->generic.trk_id;
155 /* if it's not a generic message, set MIDI channel */
156 if (e->generic.trk_id >= 0)
157 me.channel = track_channel[e->generic.trk_id];
159 switch (e->generic.type) {
160 case SONG_EV_TEMPO:
162 /* updates accumulations */
163 msecs_ac = msecs;
164 time_ac = e->generic.time;
166 /* calculates milliseconds-per-whole based on new tempo */
167 mspw = 1000.0 * 60.0;
168 mspw /= (e->tempo.tempo / 4.0);
170 break;
172 case SONG_EV_METER:
174 /* just store the values */
175 num = e->meter.num;
176 den = e->meter.den;
177 time_ac_m = e->meter.time;
179 break;
181 case SONG_EV_MEASURE:
183 song_test_measure_boundary(e->measure.time - time_ac_m,
184 num, den, e->measure.line);
185 break;
187 case SONG_EV_MIDI_CHANNEL:
189 /* stores the channel for this track */
190 track_channel[e->midi_channel.trk_id] = e->midi_channel.channel;
191 break;
193 case SONG_EV_NOTE:
195 /* convert to note on / off pairs */
197 me.type = SONG_EV_NOTE_ON;
198 me.note = e->note.note;
199 me.vel = (int) (e->note.vol * 127.0);
201 add_midi_ev(&me);
203 msecs += (int) (e->note.len * mspw);
205 me.type = SONG_EV_NOTE_OFF;
206 me.msecs = msecs;
208 add_midi_ev(&me);
209 break;
211 case SONG_EV_BACK:
213 /* move the cursor back */
214 msecs_ac -= (int) (e->back.len * mspw);
215 break;
217 case SONG_EV_MIDI_PROGRAM:
219 /* set MIDI program (instrument) */
220 me.program = e->midi_program.program;
222 add_midi_ev(&me);
223 break;
225 case SONG_EV_SS_PITCH_STRETCH:
226 case SONG_EV_SS_PRINT_WAVE_TEMPO:
227 case SONG_EV_SS_WAV:
228 case SONG_EV_SS_PAT:
229 case SONG_EV_SS_SUSTAIN:
230 case SONG_EV_SS_ATTACK:
231 case SONG_EV_SS_VIBRATO:
232 case SONG_EV_SS_PORTAMENTO:
233 case SONG_EV_SS_CHANNEL:
234 case SONG_EV_SS_EFF_DELAY:
235 case SONG_EV_SS_EFF_ECHO:
236 case SONG_EV_SS_EFF_COMB:
237 case SONG_EV_SS_EFF_ALLPASS:
238 case SONG_EV_SS_EFF_FLANGER:
239 case SONG_EV_SS_EFF_WOBBLE:
240 case SONG_EV_SS_EFF_SQWOBBLE:
241 case SONG_EV_SS_EFF_HFWOBBLE:
242 case SONG_EV_SS_EFF_FADER:
243 case SONG_EV_SS_EFF_REVERB:
244 case SONG_EV_SS_EFF_FOLDBACK:
245 case SONG_EV_SS_EFF_ATAN:
246 case SONG_EV_SS_EFF_DISTORT:
247 case SONG_EV_SS_EFF_OVERDRIVE:
248 case SONG_EV_SS_EFF_OFF:
250 /* softsynth events are ignored */
251 break;
253 case SONG_EV_SONG_INFO:
255 /* song info should be used */
256 break;
258 case SONG_EV_EOT:
260 /* end of track; trigger possible cleaning */
261 break;
263 case SONG_EV_NOTE_ON:
264 case SONG_EV_NOTE_OFF:
265 case SONG_EV_END:
267 /* never found in generic song streams */
268 break;
271 /* store the further time seen */
272 if (f_msecs < msecs)
273 f_msecs = msecs;
276 /* generates an end of event mark, a time after the last one */
277 me.type = SONG_EV_END;
278 me.msecs = f_msecs + 1000;
279 add_midi_ev(&me);
283 int midi_song_play(int skip_secs)
285 struct midi_ev *e;
286 int msecs, msecs_p, msecs_d;
287 int go;
288 struct timespec ts;
289 unsigned char midimsg[1024];
290 int mi;
291 int skip_msecs;
293 /* convert the song to MIDI events */
294 midi_song_convert_events();
296 /* sort by time */
297 qsort(midi_song, n_midi_ev, sizeof(struct midi_ev), midi_ev_cmp_by_time);
299 msecs = msecs_p = 0;
300 go = 1;
301 e = midi_song;
303 /* calculate the millisecond to start playing */
304 skip_msecs = skip_secs * 1000;
306 /* loop the events */
307 while (go) {
308 /* clear buffer */
309 mi = 0;
311 if (verbose >= 1) {
312 if (msecs % 1000 == 0) {
313 int m = msecs / 1000;
314 printf("[%02d:%02d]\r", m / 60, m % 60);
315 fflush(stdout);
319 /* process all events for this exact time */
320 while (e->msecs == msecs) {
321 switch (e->type) {
322 case SONG_EV_NOTE_ON:
324 midimsg[mi++] = MIDI_MSG_NOTE_ON | e->channel;
325 midimsg[mi++] = e->note;
326 midimsg[mi++] = e->vel;
328 break;
330 case SONG_EV_NOTE_OFF:
332 midimsg[mi++] = MIDI_MSG_NOTE_OFF | e->channel;
333 midimsg[mi++] = e->note;
334 midimsg[mi++] = 0;
336 break;
338 case SONG_EV_MIDI_PROGRAM:
340 midimsg[mi++] = MIDI_MSG_PROGRAM | e->channel;
341 midimsg[mi++] = e->program;
343 break;
345 case SONG_EV_END:
347 go = 0;
348 break;
350 default:
351 /* ignore the rest */
352 break;
355 /* next event */
356 e++;
359 if (!go)
360 break;
362 /* get time of next event */
363 msecs_p = msecs;
364 msecs = e->msecs;
365 msecs_d = msecs - msecs_p;
367 if (msecs >= skip_msecs) {
368 /* if there are pending messages, write them */
369 if (mi)
370 write(midi_fd, midimsg, mi);
372 /* calculate the time to sleep */
373 ts.tv_sec = (time_t) msecs_d / 1000;
374 ts.tv_nsec = (long) ((msecs_d * 1000000) % 1000000000);
376 nanosleep(&ts, NULL);
380 if (verbose >= 1)
381 printf("\n");
383 return 0;
387 int midi_device_open(char *devfile)
389 if (devfile == NULL)
390 devfile = "/dev/midi";
392 return (midi_fd = open(devfile, O_WRONLY));
396 void midi_device_close(void)
398 close(midi_fd);