SIGSEGV crashes seem fixed (Closes: #1145).
[ahxm.git] / song.c
blob3b3c22c1a77f8ee591d6f7c7cd94fd6e26769915
1 /*
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
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 /*******************
36 Data
37 ********************/
39 /* the song event stream */
40 struct song_ev *song = NULL;
42 /* number of song events */
43 int n_song_ev = 0;
45 /* number of tracks in song */
46 int n_song_tracks = 0;
48 /*******************
49 Code
50 ********************/
52 /**
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)
64 struct song_ev * r;
66 GROW(*song, *count, struct song_ev);
68 r = *song + *count;
69 memset(r, '\0', sizeof(struct song_ev));
71 (*count)++;
73 return r;
77 /**
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, struct song_ev *e)
87 struct song_ev * r = add_event(song, count);
89 memcpy(r, e, sizeof(struct song_ev));
91 return r;
95 /**
96 * song_clear - Clears the song stream
98 * Clears the song stream.
100 void song_clear(void)
102 if (song != NULL) {
103 free(song);
104 song = NULL;
107 n_song_ev = 0;
111 static char * event_name(song_ev_type t)
113 char * ptr;
115 switch (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 = "PORTAMENTO"; 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 = "SQWOBBLE"; break;
134 case SONG_EV_SS_EFF_HFWOBBLE: ptr = "HFWOBBLE"; 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 = "FOLDBACK"; 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 = "OVERDRIVE"; break;
141 case SONG_EV_MIDI_CHANNEL: ptr = "MIDI_CHANNEL"; break;
142 case SONG_EV_MIDI_PROGRAM: ptr = "MIDI_PROGRAM"; break;
143 case SONG_EV_BACK: ptr = "BACK"; break;
144 case SONG_EV_NOTE: ptr = "NOTE"; break;
145 case SONG_EV_SS_PITCH_STRETCH: ptr = "PITCH_STRETCH"; break;
146 case SONG_EV_SS_PRINT_WAVE_TEMPO: ptr = "PRINT_WAVE_TEMPO"; break;
147 case SONG_EV_SONG_INFO: ptr = "SONG_INFO"; break;
148 case SONG_EV_NOTE_OFF: ptr = "NOTE_OFF"; break;
149 case SONG_EV_NOTE_ON: ptr = "NOTE_ON"; break;
150 case SONG_EV_EOT: ptr = "EOT"; break;
151 case SONG_EV_END: ptr = "END"; break;
152 case SONG_EV_NOP: ptr = "NOP"; break;
153 default: ptr = "UNKNOWN?"; break;
156 return ptr;
160 void dump_song_event(struct song_ev *e)
162 if (e->frame)
163 printf("FRM: %8d ", e->frame);
165 if (e->msecs)
166 printf("MS: %8d ", e->msecs);
168 printf("%7.3lf %8s TRK: %2d ID: %4d",
169 e->time, event_name(e->type), e->trk_id, e->event_id);
171 if (e->value)
172 printf(" VAL: %3d", e->value);
174 if (e->note_id)
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);
185 if (e->vol > 0.0)
186 printf(" VOL: %5.3lf", e->vol);
188 if (e->amount > 0.0)
189 printf(" AMOUNT: %7.3lf", e->amount);
191 if (e->len > 0.0)
192 printf(" LEN: %7.3lf", e->len);
194 if (e->name != NULL)
195 printf(" NAME: '%s'", e->name);
197 if (e->author != NULL)
198 printf(" AUTHOR: '%s'", e->author);
200 printf("\n");
204 void dump_song_events(struct song_ev *song, int n_song_ev)
206 struct song_ev *e;
207 int n;
209 for (n = 0, e = song; n < n_song_ev; n++, e++)
210 dump_song_event(e);
212 printf("\n");
216 static int time_type_eventid_cmp(const void *v1, const void *v2)
217 /* sorts events by time, then type, then event_id */
219 struct song_ev *e1;
220 struct song_ev *e2;
221 int ret;
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 */
229 if (ret == 0)
230 ret = e1->type - e2->type;
232 /* same time and same event? order by event id */
233 if (ret == 0)
234 ret = e1->event_id - e2->event_id;
236 return ret;
240 static void count_tracks(void)
241 /* sets n_song_tracks */
243 int n;
245 n_song_tracks = 0;
247 for(n = 0; n < n_song_ev; n++) {
248 struct song_ev *e;
250 e = &song[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 */
261 int n, m;
263 for (n = 0; n < n_song_tracks; n++) {
264 struct song_ev *e;
265 double t = -1;
267 for (m = 0; m < n_song_ev; m++) {
268 e = &song[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)
273 t = e->time;
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;
280 e->time = t;
281 e->trk_id = n;
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)
297 int n;
299 for (n = 0; n < n_song_ev; n++) {
300 struct song_ev *e;
302 e = &song[n];
304 /* try only 'real' tracks */
305 if (e->trk_id >= 0) {
306 if (trk_id > 0) {
307 if (e->trk_id == trk_id)
308 e->type = SONG_EV_NOP;
310 else {
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.
324 void song_sort(void)
326 count_tracks();
327 add_eot_events();
329 /* sorts by time, type and event_id */
330 qsort(song, n_song_ev, sizeof(struct song_ev), time_type_eventid_cmp);
332 if (trace) {
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)
350 int ret;
352 if ((ret = ((int) (ev_time * (double) den)) % num))
353 printf("Measure boundary check failed in line %d\n", line);
355 return ret;