smflite

view src/smf_tempo.c @ 0:4264abea8b06

smf-lite initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 26 Jan 2012 11:25:11 +0200
parents
children
line source
1 /*-
2 * Copyright (c) 2007, 2008 Edward Tomasz NapieraƂa <trasz@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * ALTHOUGH THIS SOFTWARE IS MADE OF WIN AND SCIENCE, IT IS PROVIDED BY THE
15 * AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
16 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
17 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
18 * THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
20 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
21 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 */
28 /**
29 * \file
30 *
31 * Tempo map related part.
32 *
33 */
35 #include <stdlib.h>
36 #include <assert.h>
37 #include <math.h>
38 #include <string.h>
39 #include "smf.h"
40 #include "smf_private.h"
42 static double seconds_from_pulses(const smf_t *smf, int pulses);
44 /**
45 * If there is tempo starting at "pulses" already, return it. Otherwise,
46 * allocate new one, fill it with values from previous one (or default ones,
47 * if there is no previous one) and attach it to "smf".
48 */
49 static smf_tempo_t *
50 new_tempo(smf_t *smf, int pulses)
51 {
52 smf_tempo_t *tempo, *previous_tempo = NULL;
54 if (smf->tempo_array->len > 0) {
55 previous_tempo = smf_get_last_tempo(smf);
57 /* If previous tempo starts at the same time as new one, reuse it, updating in place. */
58 if (previous_tempo->time_pulses == pulses)
59 return (previous_tempo);
60 }
62 tempo = malloc(sizeof(smf_tempo_t));
63 if (tempo == NULL) {
64 fg_critical("Cannot allocate smf_tempo_t.");
65 return (NULL);
66 }
68 tempo->time_pulses = pulses;
70 if (previous_tempo != NULL) {
71 tempo->microseconds_per_quarter_note = previous_tempo->microseconds_per_quarter_note;
72 tempo->numerator = previous_tempo->numerator;
73 tempo->denominator = previous_tempo->denominator;
74 tempo->clocks_per_click = previous_tempo->clocks_per_click;
75 tempo->notes_per_note = previous_tempo->notes_per_note;
76 } else {
77 tempo->microseconds_per_quarter_note = 500000; /* Initial tempo is 120 BPM. */
78 tempo->numerator = 4;
79 tempo->denominator = 4;
80 tempo->clocks_per_click = -1;
81 tempo->notes_per_note = -1;
82 }
84 fg_ptr_array_add(smf->tempo_array, tempo);
86 if (pulses == 0)
87 tempo->time_seconds = 0.0;
88 else
89 tempo->time_seconds = seconds_from_pulses(smf, pulses);
91 return (tempo);
92 }
94 static int
95 add_tempo(smf_t *smf, int pulses, int tempo)
96 {
97 smf_tempo_t *smf_tempo = new_tempo(smf, pulses);
98 if (smf_tempo == NULL)
99 return (-1);
101 smf_tempo->microseconds_per_quarter_note = tempo;
103 return (0);
104 }
106 static int
107 add_time_signature(smf_t *smf, int pulses, int numerator, int denominator, int clocks_per_click, int notes_per_note)
108 {
109 smf_tempo_t *smf_tempo = new_tempo(smf, pulses);
110 if (smf_tempo == NULL)
111 return (-1);
113 smf_tempo->numerator = numerator;
114 smf_tempo->denominator = denominator;
115 smf_tempo->clocks_per_click = clocks_per_click;
116 smf_tempo->notes_per_note = notes_per_note;
118 return (0);
119 }
121 /**
122 * \internal
123 */
124 void
125 maybe_add_to_tempo_map(smf_event_t *event)
126 {
127 if (!smf_event_is_metadata(event))
128 return;
130 assert(event->track != NULL);
131 assert(event->track->smf != NULL);
132 assert(event->midi_buffer_length >= 1);
134 /* Tempo Change? */
135 if (event->midi_buffer[1] == 0x51) {
136 int new_tempo = (event->midi_buffer[3] << 16) + (event->midi_buffer[4] << 8) + event->midi_buffer[5];
137 if (new_tempo <= 0) {
138 fg_critical("Ignoring invalid tempo change.");
139 return;
140 }
142 add_tempo(event->track->smf, event->time_pulses, new_tempo);
143 }
145 /* Time Signature? */
146 if (event->midi_buffer[1] == 0x58) {
147 int numerator, denominator, clocks_per_click, notes_per_note;
149 if (event->midi_buffer_length < 7) {
150 fg_critical("Time Signature event seems truncated.");
151 return;
152 }
154 numerator = event->midi_buffer[3];
155 denominator = (int)pow(2, event->midi_buffer[4]);
156 clocks_per_click = event->midi_buffer[5];
157 notes_per_note = event->midi_buffer[6];
159 add_time_signature(event->track->smf, event->time_pulses, numerator, denominator, clocks_per_click, notes_per_note);
160 }
162 return;
163 }
165 /**
166 * \internal
167 *
168 * This is an internal function, called from smf_track_remove_event when tempo-related
169 * event being removed does not require recreation of tempo map, i.e. there are no events
170 * after that one.
171 */
172 void
173 remove_last_tempo_with_pulses(smf_t *smf, int pulses)
174 {
175 smf_tempo_t *tempo;
177 /* XXX: This is a partial workaround for the following problem: we have two tempo-related
178 events, A and B, that occur at the same time. We remove B, then try to remove
179 A. However, both tempo changes got coalesced in new_tempo(), so it is impossible
180 to remove B. */
181 if (smf->tempo_array->len == 0)
182 return;
184 tempo = smf_get_last_tempo(smf);
186 /* Workaround part two. */
187 if (tempo->time_pulses != pulses)
188 return;
190 memset(tempo, 0, sizeof(smf_tempo_t));
191 free(tempo);
193 fg_ptr_array_remove_index(smf->tempo_array, smf->tempo_array->len - 1);
194 }
196 static double
197 seconds_from_pulses(const smf_t *smf, int pulses)
198 {
199 double seconds;
200 smf_tempo_t *tempo;
202 tempo = smf_get_tempo_by_pulses(smf, pulses);
203 assert(tempo);
204 assert(tempo->time_pulses <= pulses);
206 seconds = tempo->time_seconds + (double)(pulses - tempo->time_pulses) *
207 (tempo->microseconds_per_quarter_note / ((double)smf->ppqn * 1000000.0));
209 return (seconds);
210 }
212 static int
213 pulses_from_seconds(const smf_t *smf, double seconds)
214 {
215 int pulses = 0;
216 smf_tempo_t *tempo;
218 tempo = smf_get_tempo_by_seconds(smf, seconds);
219 assert(tempo);
220 assert(tempo->time_seconds <= seconds);
222 pulses = tempo->time_pulses + (seconds - tempo->time_seconds) *
223 ((double)smf->ppqn * 1000000.0 / tempo->microseconds_per_quarter_note);
225 return (pulses);
226 }
228 /**
229 * \internal
230 *
231 * Computes value of event->time_seconds for all events in smf.
232 * Warning: rewinds the smf.
233 */
234 void
235 smf_create_tempo_map_and_compute_seconds(smf_t *smf)
236 {
237 smf_event_t *event;
239 smf_rewind(smf);
240 smf_init_tempo(smf);
242 for (;;) {
243 event = smf_get_next_event(smf);
245 if (event == NULL)
246 return;
248 maybe_add_to_tempo_map(event);
250 event->time_seconds = seconds_from_pulses(smf, event->time_pulses);
251 }
253 /* Not reached. */
254 }
256 smf_tempo_t *
257 smf_get_tempo_by_number(const smf_t *smf, int number)
258 {
259 assert(number >= 0);
261 if (number >= smf->tempo_array->len)
262 return (NULL);
264 return (fg_ptr_array_index(smf->tempo_array, number));
265 }
267 /**
268 * Return last tempo (i.e. tempo with greatest time_pulses) that happens before "pulses".
269 */
270 smf_tempo_t *
271 smf_get_tempo_by_pulses(const smf_t *smf, int pulses)
272 {
273 int i;
274 smf_tempo_t *tempo;
276 assert(pulses >= 0);
278 if (pulses == 0)
279 return (smf_get_tempo_by_number(smf, 0));
281 assert(smf->tempo_array != NULL);
283 for (i = smf->tempo_array->len - 1; i >= 0; i--) {
284 tempo = smf_get_tempo_by_number(smf, i);
286 assert(tempo);
287 if (tempo->time_pulses < pulses)
288 return (tempo);
289 }
291 return (NULL);
292 }
294 /**
295 * Return last tempo (i.e. tempo with greatest time_seconds) that happens before "seconds".
296 */
297 smf_tempo_t *
298 smf_get_tempo_by_seconds(const smf_t *smf, double seconds)
299 {
300 int i;
301 smf_tempo_t *tempo;
303 assert(seconds >= 0.0);
305 if (seconds == 0.0)
306 return (smf_get_tempo_by_number(smf, 0));
308 assert(smf->tempo_array != NULL);
310 for (i = smf->tempo_array->len - 1; i >= 0; i--) {
311 tempo = smf_get_tempo_by_number(smf, i);
313 assert(tempo);
314 if (tempo->time_seconds < seconds)
315 return (tempo);
316 }
318 return (NULL);
319 }
322 /**
323 * Return last tempo.
324 */
325 smf_tempo_t *
326 smf_get_last_tempo(const smf_t *smf)
327 {
328 smf_tempo_t *tempo;
330 tempo = smf_get_tempo_by_number(smf, smf->tempo_array->len - 1);
331 assert(tempo);
333 return (tempo);
334 }
336 /**
337 * \internal
338 *
339 * Remove all smf_tempo_t structures from SMF.
340 */
341 void
342 smf_fini_tempo(smf_t *smf)
343 {
344 smf_tempo_t *tempo;
346 while (smf->tempo_array->len > 0) {
347 tempo = fg_ptr_array_index(smf->tempo_array, smf->tempo_array->len - 1);
348 assert(tempo);
350 memset(tempo, 0, sizeof(smf_tempo_t));
351 free(tempo);
353 fg_ptr_array_remove_index(smf->tempo_array, smf->tempo_array->len - 1);
354 }
356 assert(smf->tempo_array->len == 0);
357 }
359 /**
360 * \internal
361 *
362 * Remove any existing tempos and add default one.
363 *
364 * \bug This will abort (by calling fg_error) if new_tempo() (memory allocation there) fails.
365 */
366 void
367 smf_init_tempo(smf_t *smf)
368 {
369 smf_tempo_t *tempo;
371 smf_fini_tempo(smf);
373 tempo = new_tempo(smf, 0);
374 if (tempo == NULL)
375 fg_error("tempo_init failed, sorry.");
376 }
378 /**
379 * Returns ->time_pulses of last event on the given track, or 0, if track is empty.
380 */
381 static int
382 last_event_pulses(const smf_track_t *track)
383 {
384 /* Get time of last event on this track. */
385 if (track->number_of_events > 0) {
386 smf_event_t *previous_event = smf_track_get_last_event(track);
387 assert(previous_event);
388 assert(previous_event->time_pulses >= 0);
390 return (previous_event->time_pulses);
391 }
393 return (0);
394 }
396 /**
397 * Adds event to the track at the time "pulses" clocks from the previous event in this track.
398 * The remaining two time fields will be computed automatically based on the third argument
399 * and current tempo map. Note that ->delta_pulses is computed by smf.c:smf_track_add_event,
400 * not here.
401 */
402 void
403 smf_track_add_event_delta_pulses(smf_track_t *track, smf_event_t *event, int delta)
404 {
405 assert(delta >= 0);
406 assert(event->time_pulses == -1);
407 assert(event->time_seconds == -1.0);
408 assert(track->smf != NULL);
410 smf_track_add_event_pulses(track, event, last_event_pulses(track) + delta);
411 }
413 /**
414 * Adds event to the track at the time "pulses" clocks from the start of song.
415 * The remaining two time fields will be computed automatically based on the third argument
416 * and current tempo map.
417 */
418 void
419 smf_track_add_event_pulses(smf_track_t *track, smf_event_t *event, int pulses)
420 {
421 assert(pulses >= 0);
422 assert(event->time_pulses == -1);
423 assert(event->time_seconds == -1.0);
424 assert(track->smf != NULL);
426 event->time_pulses = pulses;
427 event->time_seconds = seconds_from_pulses(track->smf, pulses);
428 smf_track_add_event(track, event);
429 }
431 /**
432 * Adds event to the track at the time "seconds" seconds from the start of song.
433 * The remaining two time fields will be computed automatically based on the third argument
434 * and current tempo map.
435 */
436 void
437 smf_track_add_event_seconds(smf_track_t *track, smf_event_t *event, double seconds)
438 {
439 assert(seconds >= 0.0);
440 assert(event->time_pulses == -1);
441 assert(event->time_seconds == -1.0);
442 assert(track->smf != NULL);
444 event->time_seconds = seconds;
445 event->time_pulses = pulses_from_seconds(track->smf, seconds);
446 smf_track_add_event(track, event);
447 }