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
34 #include <sys/types.h>
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
69 static struct song_ev
* add_midi_ev(struct song_ev
*e
)
70 /* adds a MIDI song event */
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) */
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 */
100 int msecs
, msecs_ac
, f_msecs
;
101 double time_ac
, time_ac_m
;
106 /* resets the MIDI stream */
107 if (midi_song
!= NULL
) {
118 msecs
= msecs_ac
= f_msecs
= 0;
119 time_ac
= time_ac_m
= 0;
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 */
132 /* calculates the msecs */
133 msecs
= ((e
->time
- time_ac
) * mspw
) + msecs_ac
;
135 /* generic event data */
138 me
.trk_id
= e
->trk_id
;
140 /* if it's not a generic message, set MIDI channel */
142 me
.channel
= track_channel
[e
->trk_id
];
147 /* updates accumulations */
151 /* calculates milliseconds-per-whole based on new tempo */
152 mspw
= 1000.0 * 60.0;
153 mspw
/= (e
->amount
/ 4.0);
159 /* just store the values */
166 case SONG_EV_MEASURE
:
168 song_test_measure_boundary(e
->time
- time_ac_m
,
172 case SONG_EV_MIDI_CHANNEL
:
174 /* stores the channel for this track */
175 track_channel
[e
->trk_id
] = e
->channel
;
180 /* convert to note on / off pairs */
182 me
.type
= SONG_EV_NOTE_ON
;
184 me
.vel
= (int) (e
->vol
* 127.0);
188 msecs
+= (int) (e
->len
* mspw
);
190 me
.type
= SONG_EV_NOTE_OFF
;
198 /* move the cursor back */
199 msecs_ac
-= (int) (e
->len
* mspw
);
202 case SONG_EV_MIDI_PROGRAM
:
204 /* set MIDI program (instrument) */
210 case SONG_EV_SS_PITCH_STRETCH
:
211 case SONG_EV_SS_PRINT_WAVE_TEMPO
:
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 */
238 case SONG_EV_SONG_INFO
:
240 /* song info should be used */
245 /* end of track; trigger possible cleaning */
248 case SONG_EV_NOTE_ON
:
249 case SONG_EV_NOTE_OFF
:
252 /* never found in generic song streams */
256 /* store the further time seen */
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;
268 int midi_song_play(int skip_secs
)
271 int msecs
, msecs_p
, msecs_d
;
274 unsigned char midimsg
[1024];
278 /* convert the song to MIDI events */
279 midi_song_convert_events();
282 qsort(midi_song
, n_midi_ev
, sizeof(struct song_ev
), msecs_type_cmp
);
288 /* calculate the millisecond to start playing */
289 skip_msecs
= skip_secs
* 1000;
291 /* loop the events */
296 if (verbose
>= 1 && msecs
% 1000 == 0) {
297 int m
= msecs
/ 1000;
298 printf("[%02d:%02d]\r", m
/ 60, m
% 60);
302 /* process all events for this exact time */
303 while (e
->msecs
== msecs
) {
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
;
313 case SONG_EV_NOTE_OFF
:
315 midimsg
[mi
++] = MIDI_MSG_NOTE_OFF
| e
->channel
;
316 midimsg
[mi
++] = e
->value
;
321 case SONG_EV_MIDI_PROGRAM
:
323 midimsg
[mi
++] = MIDI_MSG_PROGRAM
| e
->channel
;
324 midimsg
[mi
++] = e
->value
;
334 /* ignore the rest */
345 /* get time of next event */
348 msecs_d
= msecs
- msecs_p
;
350 if (msecs
>= skip_msecs
) {
351 /* if there are pending messages, write them */
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
);
370 int midi_device_open(char *devfile
)
373 devfile
= "/dev/midi";
375 return (midi_fd
= open(devfile
, O_WRONLY
));
379 void midi_device_close(void)