More reformatting.
[ahxm.git] / song.c
blob4a701eaff96e6c6de95ed3c4a15a3ec32b25229d
1 /*
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
26 #include "config.h"
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <math.h>
33 #include "ahxm.h"
35 /** data **/
37 /* the song event stream */
38 struct song_ev *song = NULL;
40 /* number of song events */
41 int n_song_ev = 0;
43 /* number of tracks in song */
44 int n_song_tracks = 0;
47 /** code **/
49 /**
50 * add_event - Adds an event to an event list.
51 * @song: A pointer to an event list (dynamically allocated)
52 * @count: A pointer to an integer (number of elements)
54 * Increments the @song event list to fit @count number of
55 * elements, probably reallocating its memory.
57 * Returns a pointer to the new element.
59 struct song_ev *add_event(struct song_ev **song, int *count)
61 struct song_ev *r;
63 GROW(*song, *count, struct song_ev);
65 r = *song + *count;
66 memset(r, '\0', sizeof(struct song_ev));
68 (*count)++;
70 return r;
74 /**
75 * copy_event - Appends an event to an event list.
76 * @song: the event list
77 * @count: a pointer to the number of elements
78 * @e: the event to be copied
80 * Appends the @e event to the @song event list.
82 struct song_ev *copy_event(struct song_ev **song, int *count,
83 const struct song_ev *e)
85 struct song_ev *r = add_event(song, count);
87 memcpy(r, e, sizeof(struct song_ev));
89 return r;
93 /**
94 * song_clear - Clears the song stream
96 * Clears the song stream.
98 void song_clear(void)
100 if (song != NULL) {
101 free(song);
102 song = NULL;
105 n_song_ev = 0;
109 static char *event_name(song_ev_type t)
111 char *ptr = "UNKNOWN";
113 switch (t) {
114 case SONG_EV_TEMPO:
115 ptr = "TEMPO--";
116 break;
118 case SONG_EV_METER:
119 ptr = "METER--";
120 break;
122 case SONG_EV_MEASURE:
123 ptr = "MEASURE";
124 break;
126 case SONG_EV_SS_SUSTAIN:
127 ptr = "SUSTAIN";
128 break;
130 case SONG_EV_SS_ATTACK:
131 ptr = "ATTACK-";
132 break;
134 case SONG_EV_SS_VIBRATO:
135 ptr = "VIBRATO";
136 break;
138 case SONG_EV_SS_PORTAMENTO:
139 ptr = "PORTMNT";
140 break;
142 case SONG_EV_SS_CHANNEL:
143 ptr = "CHANNEL";
144 break;
146 case SONG_EV_SS_WAV:
147 ptr = "WAV----";
148 break;
150 case SONG_EV_SS_PAT:
151 ptr = "PAT----";
152 break;
154 case SONG_EV_SS_SF2:
155 ptr = "SF2----";
156 break;
158 case SONG_EV_SS_EFF_OFF:
159 ptr = "OFF----";
160 break;
162 case SONG_EV_SS_EFF_DELAY:
163 ptr = "DELAY--";
164 break;
166 case SONG_EV_SS_EFF_ECHO:
167 ptr = "ECHO---";
168 break;
170 case SONG_EV_SS_EFF_COMB:
171 ptr = "COMB---";
172 break;
174 case SONG_EV_SS_EFF_ALLPASS:
175 ptr = "ALLPASS";
176 break;
178 case SONG_EV_SS_EFF_FLANGER:
179 ptr = "FLANGER";
180 break;
182 case SONG_EV_SS_EFF_WOBBLE:
183 ptr = "WOBBLE-";
184 break;
186 case SONG_EV_SS_EFF_SQWOBBLE:
187 ptr = "SQWOBBL";
188 break;
190 case SONG_EV_SS_EFF_HFWOBBLE:
191 ptr = "HFWOBBL";
192 break;
194 case SONG_EV_SS_EFF_FADER:
195 ptr = "FADER--";
196 break;
198 case SONG_EV_SS_EFF_REVERB:
199 ptr = "REVERB-";
200 break;
202 case SONG_EV_SS_EFF_FOLDBACK:
203 ptr = "FOLDBCK";
204 break;
206 case SONG_EV_SS_EFF_ATAN:
207 ptr = "ATAN---";
208 break;
210 case SONG_EV_SS_EFF_DISTORT:
211 ptr = "DISTORT";
212 break;
214 case SONG_EV_SS_EFF_OVERDRIVE:
215 ptr = "OVERDRV";
216 break;
218 case SONG_EV_MIDI_CHANNEL:
219 ptr = "MIDICHN";
220 break;
222 case SONG_EV_MIDI_PROGRAM:
223 ptr = "MIDIPRG";
224 break;
226 case SONG_EV_BACK:
227 ptr = "BACK---";
228 break;
230 case SONG_EV_NOTE_OFF:
231 ptr = "NOTEOFF";
232 break;
234 case SONG_EV_NOTE:
235 ptr = "NOTE---";
236 break;
238 case SONG_EV_SS_PITCH_STRETCH:
239 ptr = "PTCHSTR";
240 break;
242 case SONG_EV_SS_PRINT_WAVE_TEMPO:
243 ptr = "PRNTMPO";
244 break;
246 case SONG_EV_SS_MASTER_VOLUME:
247 ptr = "MASTRVL";
248 break;
250 case SONG_EV_SONG_INFO:
251 ptr = "SONGNFO";
252 break;
254 case SONG_EV_EOT:
255 ptr = "EOT----";
256 break;
258 case SONG_EV_END:
259 ptr = "END----";
260 break;
262 case SONG_EV_NOP:
263 ptr = "NOP----";
264 break;
267 return ptr;
271 void dump_song_event(const struct song_ev *e)
273 if (e->frame)
274 printf("FRM: %8d ", e->frame);
276 if (e->msecs)
277 printf("MS: %8d ", e->msecs);
279 printf("%7.3lf %7s TRK: %2d ID: %4d",
280 e->time, event_name(e->type), e->trk_id, e->event_id);
282 if (e->value)
283 printf(" VAL: %3d", e->value);
285 if (e->note_id)
286 printf(" NOTE: %3d", e->note_id);
288 if (e->min || e->max)
289 printf(" [%d,%d]", e->min, e->max);
291 printf(" CHN: %d", e->channel);
293 if (e->skip_channels)
294 printf(" SKIP: %d", e->skip_channels);
296 if (e->vol > 0.0)
297 printf(" VOL: %5.3lf", e->vol);
299 if (e->amount > 0.0)
300 printf(" AMOUNT: %7.3lf", e->amount);
302 if (e->len > 0.0)
303 printf(" LEN: %7.3lf", e->len);
305 if (e->name != NULL)
306 printf(" NAME: '%s'", e->name);
308 if (e->str2 != NULL)
309 printf(" STR2: '%s'", e->str2);
311 printf("\n");
315 void dump_song_events(const struct song_ev *song, int n_song_ev)
317 const struct song_ev *e;
318 int n;
320 for (n = 0, e = song; n < n_song_ev; n++, e++)
321 dump_song_event(e);
323 printf("\n");
327 static int time_type_eventid_cmp(const void *v1, const void *v2)
328 /* sorts events by time, then type, then event_id */
330 struct song_ev *e1;
331 struct song_ev *e2;
332 int ret;
334 e1 = (struct song_ev *) v1;
335 e2 = (struct song_ev *) v2;
337 ret = (int) ((e1->time * 10000.0) - (e2->time * 10000.0));
339 /* same time? order by type of event */
340 if (ret == 0)
341 ret = e1->type - e2->type;
343 /* same time and same event? order by event id */
344 if (ret == 0)
345 ret = e1->event_id - e2->event_id;
347 return ret;
351 static void count_tracks(void)
352 /* sets n_song_tracks */
354 int n;
356 n_song_tracks = 0;
358 for (n = 0; n < n_song_ev; n++) {
359 struct song_ev *e;
361 e = &song[n];
363 if (n_song_tracks < e->trk_id + 1)
364 n_song_tracks = e->trk_id + 1;
369 static void add_eot_events(void)
370 /* travels all events and adds EOT ones */
372 int n, m;
374 for (n = 0; n < n_song_tracks; n++) {
375 struct song_ev *e;
376 double t = -1;
378 for (m = 0; m < n_song_ev; m++) {
379 e = &song[m];
381 /* if this is the track we're looking for
382 and this event time is bigger, store it */
383 if (e->trk_id == n && e->time > t)
384 t = e->time;
387 /* now t has the biggest time; add an EOT event with t */
388 e = add_event(&song, &n_song_ev);
390 e->type = SONG_EV_EOT;
391 e->time = t;
392 e->trk_id = n;
393 e->event_id = n_song_ev - 1;
399 * mute_tracks - Converts track events to NOPs.
400 * @trk_id: Track to be muted. If negative, all buts this will be muted
402 * Converts events to NOP. If @trk_id is positive, all events for that
403 * track id will be converted to NOP; if it's negative, all events BUT
404 * for the ones in that track will be muted.
406 void mute_tracks(int trk_id)
408 int n;
410 for (n = 0; n < n_song_ev; n++) {
411 struct song_ev *e;
413 e = &song[n];
415 /* try only 'real' tracks */
416 if (e->trk_id >= 0) {
417 if (trk_id > 0) {
418 if (e->trk_id == trk_id)
419 e->type = SONG_EV_NOP;
421 else {
422 if (e->trk_id != -trk_id)
423 e->type = SONG_EV_NOP;
431 * song_sort - Sorts the song stream
433 * Sorts the song stream.
435 void song_sort(void)
437 count_tracks();
438 add_eot_events();
440 /* sorts by time, type and event_id */
441 qsort(song, n_song_ev, sizeof(struct song_ev), time_type_eventid_cmp);
443 if (trace) {
444 printf("\n** GENERIC SONG EVENT DUMP **\n\n");
445 dump_song_events(song, n_song_ev);
451 * song_test_measure_boundary - Does a measure boundary check
452 * @ev_time: event time
453 * @num: meter numerator
454 * @den: meter denominator
456 * Does a measure boundary check. Returns 0 if the event time falls
457 * exactly between two measures, or nonzero otherwise.
459 int song_test_measure_boundary(double ev_time, int num, int den, int line)
461 int ret;
463 if ((ret = ((int) (ev_time * (double) den)) % num))
464 printf("Measure boundary check failed in line %d\n", line);
466 return ret;