Use const in ss_output.c where possible.
[ahxm.git] / song.c
blob456a4cd2a845824a2bf4432901ab00ddabdf5790
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, const 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 = "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;
155 return ptr;
159 void dump_song_event(const struct song_ev *e)
161 if (e->frame)
162 printf("FRM: %8d ", e->frame);
164 if (e->msecs)
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);
170 if (e->value)
171 printf(" VAL: %3d", e->value);
173 if (e->note_id)
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);
184 if (e->vol > 0.0)
185 printf(" VOL: %5.3lf", e->vol);
187 if (e->amount > 0.0)
188 printf(" AMOUNT: %7.3lf", e->amount);
190 if (e->len > 0.0)
191 printf(" LEN: %7.3lf", e->len);
193 if (e->name != NULL)
194 printf(" NAME: '%s'", e->name);
196 if (e->author != NULL)
197 printf(" AUTHOR: '%s'", e->author);
199 printf("\n");
203 void dump_song_events(const struct song_ev *song, int n_song_ev)
205 const struct song_ev *e;
206 int n;
208 for (n = 0, e = song; n < n_song_ev; n++, e++)
209 dump_song_event(e);
211 printf("\n");
215 static int time_type_eventid_cmp(const void *v1, const void *v2)
216 /* sorts events by time, then type, then event_id */
218 struct song_ev *e1;
219 struct song_ev *e2;
220 int ret;
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 */
228 if (ret == 0)
229 ret = e1->type - e2->type;
231 /* same time and same event? order by event id */
232 if (ret == 0)
233 ret = e1->event_id - e2->event_id;
235 return ret;
239 static void count_tracks(void)
240 /* sets n_song_tracks */
242 int n;
244 n_song_tracks = 0;
246 for(n = 0; n < n_song_ev; n++) {
247 struct song_ev *e;
249 e = &song[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 */
260 int n, m;
262 for (n = 0; n < n_song_tracks; n++) {
263 struct song_ev *e;
264 double t = -1;
266 for (m = 0; m < n_song_ev; m++) {
267 e = &song[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)
272 t = e->time;
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;
279 e->time = t;
280 e->trk_id = n;
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)
296 int n;
298 for (n = 0; n < n_song_ev; n++) {
299 struct song_ev *e;
301 e = &song[n];
303 /* try only 'real' tracks */
304 if (e->trk_id >= 0) {
305 if (trk_id > 0) {
306 if (e->trk_id == trk_id)
307 e->type = SONG_EV_NOP;
309 else {
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.
323 void song_sort(void)
325 count_tracks();
326 add_eot_events();
328 /* sorts by time, type and event_id */
329 qsort(song, n_song_ev, sizeof(struct song_ev), time_type_eventid_cmp);
331 if (trace) {
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)
349 int ret;
351 if ((ret = ((int) (ev_time * (double) den)) % num))
352 printf("Measure boundary check failed in line %d\n", line);
354 return ret;