3 Ann Hell Ex Machina - Music Software
4 Copyright (C) 2003/2007 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
)
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_EFF_OFF
: ptr
= "OFF----"; break;
127 case SONG_EV_SS_EFF_DELAY
: ptr
= "DELAY--"; break;
128 case SONG_EV_SS_EFF_ECHO
: ptr
= "ECHO---"; break;
129 case SONG_EV_SS_EFF_COMB
: ptr
= "COMB---"; break;
130 case SONG_EV_SS_EFF_ALLPASS
: ptr
= "ALLPASS"; break;
131 case SONG_EV_SS_EFF_FLANGER
: ptr
= "FLANGER"; break;
132 case SONG_EV_SS_EFF_WOBBLE
: ptr
= "WOBBLE-"; break;
133 case SONG_EV_SS_EFF_SQWOBBLE
: ptr
= "SQWOBBL"; break;
134 case SONG_EV_SS_EFF_HFWOBBLE
: ptr
= "HFWOBBL"; break;
135 case SONG_EV_SS_EFF_FADER
: ptr
= "FADER--"; break;
136 case SONG_EV_SS_EFF_REVERB
: ptr
= "REVERB-"; break;
137 case SONG_EV_SS_EFF_FOLDBACK
: ptr
= "FOLDBCK"; break;
138 case SONG_EV_SS_EFF_ATAN
: ptr
= "ATAN---"; break;
139 case SONG_EV_SS_EFF_DISTORT
: ptr
= "DISTORT"; break;
140 case SONG_EV_SS_EFF_OVERDRIVE
: ptr
= "OVERDRV"; break;
141 case SONG_EV_MIDI_CHANNEL
: ptr
= "MIDICHN"; break;
142 case SONG_EV_MIDI_PROGRAM
: ptr
= "MIDIPRG"; break;
143 case SONG_EV_BACK
: ptr
= "BACK---"; break;
144 case SONG_EV_NOTE_OFF
: ptr
= "NOTEOFF"; break;
145 case SONG_EV_NOTE
: ptr
= "NOTE---"; break;
146 case SONG_EV_SS_PITCH_STRETCH
: ptr
= "PTCHSTR"; break;
147 case SONG_EV_SS_PRINT_WAVE_TEMPO
: ptr
= "PRNTMPO"; break;
148 case SONG_EV_SONG_INFO
: ptr
= "SONGNFO"; break;
149 case SONG_EV_EOT
: ptr
= "EOT----"; break;
150 case SONG_EV_END
: ptr
= "END----"; break;
151 case SONG_EV_NOP
: ptr
= "NOP----"; break;
152 default: ptr
= "UNKNOWN"; break;
159 void dump_song_event(const struct song_ev
*e
)
162 printf("FRM: %8d ", e
->frame
);
165 printf("MS: %8d ", e
->msecs
);
167 printf("%7.3lf %7s TRK: %2d ID: %4d",
168 e
->time
, event_name(e
->type
), e
->trk_id
, e
->event_id
);
171 printf(" VAL: %3d", e
->value
);
174 printf(" NOTE: %3d", e
->note_id
);
176 if (e
->min
|| e
->max
)
177 printf(" [%d,%d]", e
->min
, e
->max
);
179 printf(" CHN: %d", e
->channel
);
181 if (e
->skip_channels
)
182 printf(" SKIP: %d", e
->skip_channels
);
185 printf(" VOL: %5.3lf", e
->vol
);
188 printf(" AMOUNT: %7.3lf", e
->amount
);
191 printf(" LEN: %7.3lf", e
->len
);
194 printf(" NAME: '%s'", e
->name
);
196 if (e
->author
!= NULL
)
197 printf(" AUTHOR: '%s'", e
->author
);
203 void dump_song_events(const struct song_ev
*song
, int n_song_ev
)
205 const struct song_ev
*e
;
208 for (n
= 0, e
= song
; n
< n_song_ev
; n
++, e
++)
215 static int time_type_eventid_cmp(const void *v1
, const void *v2
)
216 /* sorts events by time, then type, then event_id */
222 e1
= (struct song_ev
*) v1
;
223 e2
= (struct song_ev
*) v2
;
225 ret
= (int) ((e1
->time
* 10000.0) - (e2
->time
* 10000.0));
227 /* same time? order by type of event */
229 ret
= e1
->type
- e2
->type
;
231 /* same time and same event? order by event id */
233 ret
= e1
->event_id
- e2
->event_id
;
239 static void count_tracks(void)
240 /* sets n_song_tracks */
246 for(n
= 0; n
< n_song_ev
; n
++) {
251 if (n_song_tracks
< e
->trk_id
+ 1)
252 n_song_tracks
= e
->trk_id
+ 1;
257 static void add_eot_events(void)
258 /* travels all events and adds EOT ones */
262 for (n
= 0; n
< n_song_tracks
; n
++) {
266 for (m
= 0; m
< n_song_ev
; m
++) {
269 /* if this is the track we're looking for
270 and this event time is bigger, store it */
271 if (e
->trk_id
== n
&& e
->time
> t
)
275 /* now t has the biggest time; add an EOT event with t */
276 e
= add_event(&song
, &n_song_ev
);
278 e
->type
= SONG_EV_EOT
;
281 e
->event_id
= n_song_ev
- 1;
287 * mute_tracks - Converts track events to NOPs.
288 * @trk_id: Track to be muted. If negative, all buts this will be muted
290 * Converts events to NOP. If @trk_id is positive, all events for that
291 * track id will be converted to NOP; if it's negative, all events BUT
292 * for the ones in that track will be muted.
294 void mute_tracks(int trk_id
)
298 for (n
= 0; n
< n_song_ev
; n
++) {
303 /* try only 'real' tracks */
304 if (e
->trk_id
>= 0) {
306 if (e
->trk_id
== trk_id
)
307 e
->type
= SONG_EV_NOP
;
310 if (e
->trk_id
!= -trk_id
)
311 e
->type
= SONG_EV_NOP
;
319 * song_sort - Sorts the song stream
321 * Sorts the song stream.
328 /* sorts by time, type and event_id */
329 qsort(song
, n_song_ev
, sizeof(struct song_ev
), time_type_eventid_cmp
);
332 printf("\n** GENERIC SONG EVENT DUMP **\n\n");
333 dump_song_events(song
, n_song_ev
);
339 * song_test_measure_boundary - Does a measure boundary check
340 * @ev_time: event time
341 * @num: meter numerator
342 * @den: meter denominator
344 * Does a measure boundary check. Returns 0 if the event time falls
345 * exactly between two measures, or nonzero otherwise.
347 int song_test_measure_boundary(double ev_time
, int num
, int den
, int line
)
351 if ((ret
= ((int) (ev_time
* (double) den
)) % num
))
352 printf("Measure boundary check failed in line %d\n", line
);