3 Ann Hell Ex Machina - Music Software
4 Copyright (C) 2003/2008 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>
43 /* the MIDI song stream */
45 static struct song_ev
*midi_song
= NULL
;
46 static int n_midi_ev
= 0;
48 /* the MIDI tracks: just a track/channel table */
50 #define MIDI_TRACK_NUM 256
51 static int track_channel
[MIDI_TRACK_NUM
];
53 /* MIDI message types */
55 #define MIDI_MSG_NOTE_ON 0x90
56 #define MIDI_MSG_NOTE_OFF 0x80
57 #define MIDI_MSG_CONTROLLER 0xB0
58 #define MIDI_MSG_PROGRAM 0xC0
66 static struct song_ev
*add_midi_ev(struct song_ev
*e
)
67 /* adds a MIDI song event */
72 return copy_event(&midi_song
, &n_midi_ev
, e
);
76 static int msecs_type_cmp(const void *v1
, const void *v2
)
77 /* MIDI song event compare function for qsort(), by time (for playing) */
82 e1
= (struct song_ev
*) v1
;
83 e2
= (struct song_ev
*) v2
;
85 if (e1
->msecs
== e2
->msecs
)
86 return e1
->type
- e2
->type
;
88 return e1
->msecs
- e2
->msecs
;
92 static void midi_song_convert_events(void)
93 /* converts generic song_ev events to MIDI events */
96 int msecs
, msecs_ac
, f_msecs
;
97 double time_ac
, time_ac_m
;
102 /* resets the MIDI stream */
103 if (midi_song
!= NULL
) {
114 msecs
= msecs_ac
= f_msecs
= 0;
115 time_ac
= time_ac_m
= 0;
118 /* by default, all channels are 'mute' until
119 a channel is explicitly set */
120 for (n
= 0; n
< MIDI_TRACK_NUM
; n
++)
121 track_channel
[n
] = -1;
123 /* travels the song events generating MIDI song events */
124 for (n
= 0; n
< n_song_ev
; n
++) {
125 /* gets the song event */
128 /* calculates the msecs */
129 msecs
= ((e
->time
- time_ac
) * mspw
) + msecs_ac
;
132 /* if it's not a generic message, set MIDI channel */
134 e
->channel
= track_channel
[e
->trk_id
];
139 /* updates accumulations */
143 /* calculates milliseconds-per-whole based on new tempo */
144 mspw
= 1000.0 * 60.0;
145 mspw
/= (e
->amount
/ 4.0);
151 /* just store the values */
158 case SONG_EV_MEASURE
:
160 song_test_measure_boundary(e
->time
- time_ac_m
,
164 case SONG_EV_MIDI_CHANNEL
:
166 /* stores the channel for this track */
167 track_channel
[e
->trk_id
] = e
->channel
;
172 /* convert to note on / off pairs */
174 e
->vel
= (int) (e
->vol
* 127.0);
179 e
->type
= SONG_EV_NOTE_OFF
;
181 msecs
+= (int) (e
->len
* mspw
);
188 /* move the cursor back */
189 msecs_ac
-= (int) (e
->len
* mspw
);
192 case SONG_EV_MIDI_PROGRAM
:
197 case SONG_EV_SS_PITCH_STRETCH
:
198 case SONG_EV_SS_PRINT_WAVE_TEMPO
:
202 case SONG_EV_SS_SUSTAIN
:
203 case SONG_EV_SS_ATTACK
:
204 case SONG_EV_SS_VIBRATO
:
205 case SONG_EV_SS_PORTAMENTO
:
206 case SONG_EV_SS_CHANNEL
:
207 case SONG_EV_SS_EFF_DELAY
:
208 case SONG_EV_SS_EFF_ECHO
:
209 case SONG_EV_SS_EFF_COMB
:
210 case SONG_EV_SS_EFF_ALLPASS
:
211 case SONG_EV_SS_EFF_FLANGER
:
212 case SONG_EV_SS_EFF_WOBBLE
:
213 case SONG_EV_SS_EFF_SQWOBBLE
:
214 case SONG_EV_SS_EFF_HFWOBBLE
:
215 case SONG_EV_SS_EFF_FADER
:
216 case SONG_EV_SS_EFF_REVERB
:
217 case SONG_EV_SS_EFF_FOLDBACK
:
218 case SONG_EV_SS_EFF_ATAN
:
219 case SONG_EV_SS_EFF_DISTORT
:
220 case SONG_EV_SS_EFF_OVERDRIVE
:
221 case SONG_EV_SS_EFF_OFF
:
222 case SONG_EV_SS_MASTER_VOLUME
:
228 case SONG_EV_SONG_INFO
:
230 /* song info should be used */
235 /* end of track; trigger possible cleaning */
238 case SONG_EV_NOTE_OFF
:
241 /* never found in generic song streams */
245 /* store the further time seen */
250 /* generates an end of event mark, a time after the last one */
251 e
= add_event(&midi_song
, &n_midi_ev
);
253 e
->type
= SONG_EV_END
;
254 e
->msecs
= f_msecs
+ 1000;
258 int midi_song_play(int skip_secs
)
260 #ifdef CONFOPT_NANOSLEEP
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
);
357 #endif /* CONFOPT_NANOSLEEP */
363 int midi_device_open(char *devfile
)
366 devfile
= "/dev/midi";
368 return (midi_fd
= open(devfile
, O_WRONLY
));
372 void midi_device_close(void)