3 Ann Hell Ex Machina - Music Software
4 Copyright (C) 2003/2008 Angel Ortega <angel@triptico.com>
6 song.c - Device-independent 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
39 /* the song event stream */
40 struct song_ev
*song
= NULL
;
42 /* number of song events */
45 /* number of tracks in song */
46 int n_song_tracks
= 0;
53 * add_event - Adds an event to an event list.
54 * @song: A pointer to an event list (dynamically allocated)
55 * @count: A pointer to an integer (number of elements)
57 * Increments the @song event list to fit @count number of
58 * elements, probably reallocating its memory.
60 * Returns a pointer to the new element.
62 struct song_ev
* add_event(struct song_ev
**song
, int *count
)
66 GROW(*song
, *count
, struct song_ev
);
69 memset(r
, '\0', sizeof(struct song_ev
));
78 * copy_event - Appends an event to an event list.
79 * @song: the event list
80 * @count: a pointer to the number of elements
81 * @e: the event to be copied
83 * Appends the @e event to the @song event list.
85 struct song_ev
* copy_event(struct song_ev
**song
, int *count
, const struct song_ev
*e
)
87 struct song_ev
* r
= add_event(song
, count
);
89 memcpy(r
, e
, sizeof(struct song_ev
));
96 * song_clear - Clears the song stream
98 * Clears the song stream.
100 void song_clear(void)
111 static char * event_name(song_ev_type t
)
113 char * ptr
= "UNKNOWN";
116 case SONG_EV_TEMPO
: ptr
= "TEMPO--"; break;
117 case SONG_EV_METER
: ptr
= "METER--"; break;
118 case SONG_EV_MEASURE
: ptr
= "MEASURE"; break;
119 case SONG_EV_SS_SUSTAIN
: ptr
= "SUSTAIN"; break;
120 case SONG_EV_SS_ATTACK
: ptr
= "ATTACK-"; break;
121 case SONG_EV_SS_VIBRATO
: ptr
= "VIBRATO"; break;
122 case SONG_EV_SS_PORTAMENTO
: ptr
= "PORTMNT"; break;
123 case SONG_EV_SS_CHANNEL
: ptr
= "CHANNEL"; break;
124 case SONG_EV_SS_WAV
: ptr
= "WAV----"; break;
125 case SONG_EV_SS_PAT
: ptr
= "PAT----"; break;
126 case SONG_EV_SS_SF2
: ptr
= "SF2----"; break;
127 case SONG_EV_SS_EFF_OFF
: ptr
= "OFF----"; break;
128 case SONG_EV_SS_EFF_DELAY
: ptr
= "DELAY--"; break;
129 case SONG_EV_SS_EFF_ECHO
: ptr
= "ECHO---"; break;
130 case SONG_EV_SS_EFF_COMB
: ptr
= "COMB---"; break;
131 case SONG_EV_SS_EFF_ALLPASS
: ptr
= "ALLPASS"; break;
132 case SONG_EV_SS_EFF_FLANGER
: ptr
= "FLANGER"; break;
133 case SONG_EV_SS_EFF_WOBBLE
: ptr
= "WOBBLE-"; break;
134 case SONG_EV_SS_EFF_SQWOBBLE
: ptr
= "SQWOBBL"; break;
135 case SONG_EV_SS_EFF_HFWOBBLE
: ptr
= "HFWOBBL"; break;
136 case SONG_EV_SS_EFF_FADER
: ptr
= "FADER--"; break;
137 case SONG_EV_SS_EFF_REVERB
: ptr
= "REVERB-"; break;
138 case SONG_EV_SS_EFF_FOLDBACK
: ptr
= "FOLDBCK"; break;
139 case SONG_EV_SS_EFF_ATAN
: ptr
= "ATAN---"; break;
140 case SONG_EV_SS_EFF_DISTORT
: ptr
= "DISTORT"; break;
141 case SONG_EV_SS_EFF_OVERDRIVE
: ptr
= "OVERDRV"; break;
142 case SONG_EV_MIDI_CHANNEL
: ptr
= "MIDICHN"; break;
143 case SONG_EV_MIDI_PROGRAM
: ptr
= "MIDIPRG"; break;
144 case SONG_EV_BACK
: ptr
= "BACK---"; break;
145 case SONG_EV_NOTE_OFF
: ptr
= "NOTEOFF"; break;
146 case SONG_EV_NOTE
: ptr
= "NOTE---"; break;
147 case SONG_EV_SS_PITCH_STRETCH
: ptr
= "PTCHSTR"; break;
148 case SONG_EV_SS_PRINT_WAVE_TEMPO
: ptr
= "PRNTMPO"; break;
149 case SONG_EV_SS_MASTER_VOLUME
: ptr
= "MASTRVL"; break;
150 case SONG_EV_SONG_INFO
: ptr
= "SONGNFO"; break;
151 case SONG_EV_EOT
: ptr
= "EOT----"; break;
152 case SONG_EV_END
: ptr
= "END----"; break;
153 case SONG_EV_NOP
: ptr
= "NOP----"; break;
160 void dump_song_event(const struct song_ev
*e
)
163 printf("FRM: %8d ", e
->frame
);
166 printf("MS: %8d ", e
->msecs
);
168 printf("%7.3lf %7s TRK: %2d ID: %4d",
169 e
->time
, event_name(e
->type
), e
->trk_id
, e
->event_id
);
172 printf(" VAL: %3d", e
->value
);
175 printf(" NOTE: %3d", e
->note_id
);
177 if (e
->min
|| e
->max
)
178 printf(" [%d,%d]", e
->min
, e
->max
);
180 printf(" CHN: %d", e
->channel
);
182 if (e
->skip_channels
)
183 printf(" SKIP: %d", e
->skip_channels
);
186 printf(" VOL: %5.3lf", e
->vol
);
189 printf(" AMOUNT: %7.3lf", e
->amount
);
192 printf(" LEN: %7.3lf", e
->len
);
195 printf(" NAME: '%s'", e
->name
);
198 printf(" STR2: '%s'", e
->str2
);
204 void dump_song_events(const struct song_ev
*song
, int n_song_ev
)
206 const struct song_ev
*e
;
209 for (n
= 0, e
= song
; n
< n_song_ev
; n
++, e
++)
216 static int time_type_eventid_cmp(const void *v1
, const void *v2
)
217 /* sorts events by time, then type, then event_id */
223 e1
= (struct song_ev
*) v1
;
224 e2
= (struct song_ev
*) v2
;
226 ret
= (int) ((e1
->time
* 10000.0) - (e2
->time
* 10000.0));
228 /* same time? order by type of event */
230 ret
= e1
->type
- e2
->type
;
232 /* same time and same event? order by event id */
234 ret
= e1
->event_id
- e2
->event_id
;
240 static void count_tracks(void)
241 /* sets n_song_tracks */
247 for(n
= 0; n
< n_song_ev
; n
++) {
252 if (n_song_tracks
< e
->trk_id
+ 1)
253 n_song_tracks
= e
->trk_id
+ 1;
258 static void add_eot_events(void)
259 /* travels all events and adds EOT ones */
263 for (n
= 0; n
< n_song_tracks
; n
++) {
267 for (m
= 0; m
< n_song_ev
; m
++) {
270 /* if this is the track we're looking for
271 and this event time is bigger, store it */
272 if (e
->trk_id
== n
&& e
->time
> t
)
276 /* now t has the biggest time; add an EOT event with t */
277 e
= add_event(&song
, &n_song_ev
);
279 e
->type
= SONG_EV_EOT
;
282 e
->event_id
= n_song_ev
- 1;
288 * mute_tracks - Converts track events to NOPs.
289 * @trk_id: Track to be muted. If negative, all buts this will be muted
291 * Converts events to NOP. If @trk_id is positive, all events for that
292 * track id will be converted to NOP; if it's negative, all events BUT
293 * for the ones in that track will be muted.
295 void mute_tracks(int trk_id
)
299 for (n
= 0; n
< n_song_ev
; n
++) {
304 /* try only 'real' tracks */
305 if (e
->trk_id
>= 0) {
307 if (e
->trk_id
== trk_id
)
308 e
->type
= SONG_EV_NOP
;
311 if (e
->trk_id
!= -trk_id
)
312 e
->type
= SONG_EV_NOP
;
320 * song_sort - Sorts the song stream
322 * Sorts the song stream.
329 /* sorts by time, type and event_id */
330 qsort(song
, n_song_ev
, sizeof(struct song_ev
), time_type_eventid_cmp
);
333 printf("\n** GENERIC SONG EVENT DUMP **\n\n");
334 dump_song_events(song
, n_song_ev
);
340 * song_test_measure_boundary - Does a measure boundary check
341 * @ev_time: event time
342 * @num: meter numerator
343 * @den: meter denominator
345 * Does a measure boundary check. Returns 0 if the event time falls
346 * exactly between two measures, or nonzero otherwise.
348 int song_test_measure_boundary(double ev_time
, int num
, int den
, int line
)
352 if ((ret
= ((int) (ev_time
* (double) den
)) % num
))
353 printf("Measure boundary check failed in line %d\n", line
);