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 */
179 e
->type
= SONG_EV_NOTE_ON
;
180 e
->vel
= (int) (e
->vol
* 127.0);
182 msecs
+= (int) (e
->len
* mspw
);
186 e
->type
= SONG_EV_NOTE_OFF
;
193 /* move the cursor back */
194 msecs_ac
-= (int) (e
->len
* mspw
);
197 case SONG_EV_MIDI_PROGRAM
:
202 case SONG_EV_SS_PITCH_STRETCH
:
203 case SONG_EV_SS_PRINT_WAVE_TEMPO
:
206 case SONG_EV_SS_SUSTAIN
:
207 case SONG_EV_SS_ATTACK
:
208 case SONG_EV_SS_VIBRATO
:
209 case SONG_EV_SS_PORTAMENTO
:
210 case SONG_EV_SS_CHANNEL
:
211 case SONG_EV_SS_EFF_DELAY
:
212 case SONG_EV_SS_EFF_ECHO
:
213 case SONG_EV_SS_EFF_COMB
:
214 case SONG_EV_SS_EFF_ALLPASS
:
215 case SONG_EV_SS_EFF_FLANGER
:
216 case SONG_EV_SS_EFF_WOBBLE
:
217 case SONG_EV_SS_EFF_SQWOBBLE
:
218 case SONG_EV_SS_EFF_HFWOBBLE
:
219 case SONG_EV_SS_EFF_FADER
:
220 case SONG_EV_SS_EFF_REVERB
:
221 case SONG_EV_SS_EFF_FOLDBACK
:
222 case SONG_EV_SS_EFF_ATAN
:
223 case SONG_EV_SS_EFF_DISTORT
:
224 case SONG_EV_SS_EFF_OVERDRIVE
:
225 case SONG_EV_SS_EFF_OFF
:
231 case SONG_EV_SONG_INFO
:
233 /* song info should be used */
238 /* end of track; trigger possible cleaning */
241 case SONG_EV_NOTE_ON
:
242 case SONG_EV_NOTE_OFF
:
245 /* never found in generic song streams */
249 /* store the further time seen */
254 /* generates an end of event mark, a time after the last one */
255 e
= add_event(&midi_song
, &n_midi_ev
);
257 e
->type
= SONG_EV_END
;
258 e
->msecs
= f_msecs
+ 1000;
262 int midi_song_play(int skip_secs
)
265 int msecs
, msecs_p
, msecs_d
;
268 unsigned char midimsg
[1024];
272 /* convert the song to MIDI events */
273 midi_song_convert_events();
276 qsort(midi_song
, n_midi_ev
, sizeof(struct song_ev
), msecs_type_cmp
);
282 /* calculate the millisecond to start playing */
283 skip_msecs
= skip_secs
* 1000;
285 /* loop the events */
290 if (verbose
>= 1 && msecs
% 1000 == 0) {
291 int m
= msecs
/ 1000;
292 printf("[%02d:%02d]\r", m
/ 60, m
% 60);
296 /* process all events for this exact time */
297 while (e
->msecs
== msecs
) {
299 case SONG_EV_NOTE_ON
:
301 midimsg
[mi
++] = MIDI_MSG_NOTE_ON
| e
->channel
;
302 midimsg
[mi
++] = e
->value
;
303 midimsg
[mi
++] = e
->vel
;
307 case SONG_EV_NOTE_OFF
:
309 midimsg
[mi
++] = MIDI_MSG_NOTE_OFF
| e
->channel
;
310 midimsg
[mi
++] = e
->value
;
315 case SONG_EV_MIDI_PROGRAM
:
317 midimsg
[mi
++] = MIDI_MSG_PROGRAM
| e
->channel
;
318 midimsg
[mi
++] = e
->value
;
328 /* ignore the rest */
339 /* get time of next event */
342 msecs_d
= msecs
- msecs_p
;
344 if (msecs
>= skip_msecs
) {
345 /* if there are pending messages, write them */
347 write(midi_fd
, midimsg
, mi
);
349 /* calculate the time to sleep */
350 ts
.tv_sec
= (time_t) msecs_d
/ 1000;
351 ts
.tv_nsec
= (long) ((msecs_d
* 1000000) % 1000000000);
353 nanosleep(&ts
, NULL
);
364 int midi_device_open(char *devfile
)
367 devfile
= "/dev/midi";
369 return (midi_fd
= open(devfile
, O_WRONLY
));
373 void midi_device_close(void)