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 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 */
56 int program
; /* MIDI program number */
59 struct midi_ev_note_off
{
60 song_ev_type type
; /* SONG_EV_NOTE_OFF */
64 int note
; /* MIDI note */
67 struct midi_ev_note_on
{
68 song_ev_type type
; /* SONG_EV_NOTE_ON */
72 int note
; /* MIDI note */
73 int vel
; /* velocity (volume) */
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
107 ********************/
109 static void add_midi_ev(union midi_ev
*e
)
110 /* adds a MIDI song event */
112 if (e
->generic
.channel
< 0)
115 GROW(midi_song
, n_midi_ev
, union midi_ev
);
118 memcpy(&midi_song
[n_midi_ev
], e
, sizeof(union 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 */
145 int msecs
, msecs_ac
, f_msecs
;
146 double time_ac
, time_ac_m
;
151 /* resets the MIDI stream */
152 if (midi_song
!= NULL
) {
163 msecs
= msecs_ac
= f_msecs
= 0;
164 time_ac
= time_ac_m
= 0;
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 */
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
) {
192 /* updates accumulations */
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);
204 /* just store the values */
207 time_ac_m
= e
->meter
.time
;
211 case SONG_EV_MEASURE
:
213 song_test_measure_boundary(e
->measure
.time
- time_ac_m
,
214 num
, den
, e
->measure
.line
);
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
;
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);
233 msecs
+= (int) (e
->note
.len
* mspw
);
235 me
.note_off
.type
= SONG_EV_NOTE_OFF
;
236 me
.note_off
.msecs
= msecs
;
243 /* move the cursor back */
244 msecs_ac
-= (int) (e
->back
.len
* mspw
);
247 case SONG_EV_MIDI_PROGRAM
:
249 /* set MIDI program (instrument) */
250 me
.midi_program
.program
= e
->midi_program
.program
;
255 case SONG_EV_SS_PITCH_STRETCH
:
256 case SONG_EV_SS_PRINT_WAVE_TEMPO
:
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 */
283 case SONG_EV_SONG_INFO
:
285 /* song info should be used */
290 /* end of track; trigger possible cleaning */
293 case SONG_EV_NOTE_ON
:
294 case SONG_EV_NOTE_OFF
:
297 /* never found in generic song streams */
301 /* store the further time seen */
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;
313 int midi_song_play(int skip_secs
)
316 int msecs
, msecs_p
, msecs_d
;
319 unsigned char midimsg
[1024];
323 /* convert the song to MIDI events */
324 midi_song_convert_events();
327 qsort(midi_song
, n_midi_ev
, sizeof(union midi_ev
), midi_ev_cmp_by_time
);
333 /* calculate the millisecond to start playing */
334 skip_msecs
= skip_secs
* 1000;
336 /* loop the events */
342 if (msecs
% 1000 == 0) {
343 int m
= msecs
/ 1000;
344 printf("[%02d:%02d]\r", m
/ 60, m
% 60);
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
;
360 case SONG_EV_NOTE_OFF
:
362 midimsg
[mi
++] = MIDI_MSG_NOTE_OFF
| e
->note_off
.channel
;
363 midimsg
[mi
++] = e
->note_off
.note
;
368 case SONG_EV_MIDI_PROGRAM
:
370 midimsg
[mi
++] = MIDI_MSG_PROGRAM
| e
->midi_program
.channel
;
371 midimsg
[mi
++] = e
->midi_program
.program
;
381 /* ignore the rest */
392 /* get time of next event */
394 msecs
= e
->generic
.msecs
;
395 msecs_d
= msecs
- msecs_p
;
397 if (msecs
>= skip_msecs
) {
398 /* if there are pending messages, write them */
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
);
417 int midi_device_open(char *devfile
)
420 devfile
= "/dev/midi";
422 return (midi_fd
= open(devfile
, O_WRONLY
));
426 void midi_device_close(void)