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 copy_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 */
99 int msecs
, msecs_ac
, f_msecs
;
100 double time_ac
, time_ac_m
;
105 /* resets the MIDI stream */
106 if (midi_song
!= NULL
) {
117 msecs
= msecs_ac
= f_msecs
= 0;
118 time_ac
= time_ac_m
= 0;
121 /* by default, all channels are 'mute' until
122 a channel is explicitly set */
123 for (n
= 0; n
< MIDI_TRACK_NUM
; n
++)
124 track_channel
[n
] = -1;
126 /* travels the song events generating MIDI song events */
127 for (n
= 0; n
< n_song_ev
; n
++) {
128 /* gets the song event */
131 /* calculates the msecs */
132 msecs
= ((e
->time
- time_ac
) * mspw
) + msecs_ac
;
135 /* if it's not a generic message, set MIDI channel */
137 e
->channel
= track_channel
[e
->trk_id
];
142 /* updates accumulations */
146 /* calculates milliseconds-per-whole based on new tempo */
147 mspw
= 1000.0 * 60.0;
148 mspw
/= (e
->amount
/ 4.0);
154 /* just store the values */
161 case SONG_EV_MEASURE
:
163 song_test_measure_boundary(e
->time
- time_ac_m
,
167 case SONG_EV_MIDI_CHANNEL
:
169 /* stores the channel for this track */
170 track_channel
[e
->trk_id
] = e
->channel
;
175 /* convert to note on / off pairs */
177 e
->vel
= (int) (e
->vol
* 127.0);
182 e
->type
= SONG_EV_NOTE_OFF
;
184 msecs
+= (int) (e
->len
* mspw
);
191 /* move the cursor back */
192 msecs_ac
-= (int) (e
->len
* mspw
);
195 case SONG_EV_MIDI_PROGRAM
:
200 case SONG_EV_SS_PITCH_STRETCH
:
201 case SONG_EV_SS_PRINT_WAVE_TEMPO
:
204 case SONG_EV_SS_SUSTAIN
:
205 case SONG_EV_SS_ATTACK
:
206 case SONG_EV_SS_VIBRATO
:
207 case SONG_EV_SS_PORTAMENTO
:
208 case SONG_EV_SS_CHANNEL
:
209 case SONG_EV_SS_EFF_DELAY
:
210 case SONG_EV_SS_EFF_ECHO
:
211 case SONG_EV_SS_EFF_COMB
:
212 case SONG_EV_SS_EFF_ALLPASS
:
213 case SONG_EV_SS_EFF_FLANGER
:
214 case SONG_EV_SS_EFF_WOBBLE
:
215 case SONG_EV_SS_EFF_SQWOBBLE
:
216 case SONG_EV_SS_EFF_HFWOBBLE
:
217 case SONG_EV_SS_EFF_FADER
:
218 case SONG_EV_SS_EFF_REVERB
:
219 case SONG_EV_SS_EFF_FOLDBACK
:
220 case SONG_EV_SS_EFF_ATAN
:
221 case SONG_EV_SS_EFF_DISTORT
:
222 case SONG_EV_SS_EFF_OVERDRIVE
:
223 case SONG_EV_SS_EFF_OFF
:
229 case SONG_EV_SONG_INFO
:
231 /* song info should be used */
236 /* end of track; trigger possible cleaning */
239 case SONG_EV_NOTE_OFF
:
242 /* never found in generic song streams */
246 /* store the further time seen */
251 /* generates an end of event mark, a time after the last one */
252 e
= add_event(&midi_song
, &n_midi_ev
);
254 e
->type
= SONG_EV_END
;
255 e
->msecs
= f_msecs
+ 1000;
259 int midi_song_play(int skip_secs
)
262 int msecs
, msecs_p
, msecs_d
;
265 unsigned char midimsg
[1024];
269 /* convert the song to MIDI events */
270 midi_song_convert_events();
273 qsort(midi_song
, n_midi_ev
, sizeof(struct song_ev
), msecs_type_cmp
);
279 /* calculate the millisecond to start playing */
280 skip_msecs
= skip_secs
* 1000;
282 /* loop the events */
287 if (verbose
>= 1 && msecs
% 1000 == 0) {
288 int m
= msecs
/ 1000;
289 printf("[%02d:%02d]\r", m
/ 60, m
% 60);
293 /* process all events for this exact time */
294 while (e
->msecs
== msecs
) {
298 midimsg
[mi
++] = MIDI_MSG_NOTE_ON
| e
->channel
;
299 midimsg
[mi
++] = e
->value
;
300 midimsg
[mi
++] = e
->vel
;
304 case SONG_EV_NOTE_OFF
:
306 midimsg
[mi
++] = MIDI_MSG_NOTE_OFF
| e
->channel
;
307 midimsg
[mi
++] = e
->value
;
312 case SONG_EV_MIDI_PROGRAM
:
314 midimsg
[mi
++] = MIDI_MSG_PROGRAM
| e
->channel
;
315 midimsg
[mi
++] = e
->value
;
325 /* ignore the rest */
336 /* get time of next event */
339 msecs_d
= msecs
- msecs_p
;
341 if (msecs
>= skip_msecs
) {
342 /* if there are pending messages, write them */
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
);
361 int midi_device_open(char *devfile
)
364 devfile
= "/dev/midi";
366 return (midi_fd
= open(devfile
, O_WRONLY
));
370 void midi_device_close(void)