Import of jack-smf-utils 1.0.
[jack-smf-utils.git] / libsmf / smf_tempo.c
blob8431c7dc6659603b44edb60c4c8d4b04920c8bb9
1 /*-
2 * Copyright (c) 2007, 2008 Edward Tomasz NapieraƂa <trasz@FreeBSD.org>
3 * All rights reserved.
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.
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.
29 * This is Standard MIDI File format implementation, tempo map related part.
31 * For questions and comments, contact Edward Tomasz Napierala <trasz@FreeBSD.org>.
34 #include <stdlib.h>
35 #include <assert.h>
36 #include <math.h>
37 #include "smf.h"
38 #include "smf_private.h"
40 static double seconds_from_pulses(const smf_t *smf, int pulses);
42 /**
43 * If there is tempo starting at "pulses" already, return it. Otherwise,
44 * allocate new one, fill it with values from previous one (or default ones,
45 * if there is no previous one) and attach it to "smf".
47 static smf_tempo_t *
48 new_tempo(smf_t *smf, int pulses)
50 smf_tempo_t *tempo, *previous_tempo = NULL;
52 if (smf->tempo_array->len > 0) {
53 previous_tempo = smf_get_last_tempo(smf);
55 /* If previous tempo starts at the same time as new one, reuse it, updating in place. */
56 if (previous_tempo->time_pulses == pulses)
57 return previous_tempo;
60 tempo = malloc(sizeof(smf_tempo_t));
61 if (tempo == NULL) {
62 g_critical("Cannot allocate smf_tempo_t.");
63 return NULL;
66 tempo->time_pulses = pulses;
68 if (previous_tempo != NULL) {
69 tempo->microseconds_per_quarter_note = previous_tempo->microseconds_per_quarter_note;
70 tempo->numerator = previous_tempo->numerator;
71 tempo->denominator = previous_tempo->denominator;
72 tempo->clocks_per_click = previous_tempo->clocks_per_click;
73 tempo->notes_per_note = previous_tempo->notes_per_note;
74 } else {
75 tempo->microseconds_per_quarter_note = 500000; /* Initial tempo is 120 BPM. */
76 tempo->numerator = 4;
77 tempo->denominator = 4;
78 tempo->clocks_per_click = -1;
79 tempo->notes_per_note = -1;
82 g_ptr_array_add(smf->tempo_array, tempo);
84 if (pulses == 0)
85 tempo->time_seconds = 0.0;
86 else
87 tempo->time_seconds = seconds_from_pulses(smf, pulses);
89 return tempo;
92 static int
93 add_tempo(smf_t *smf, int pulses, int tempo)
95 smf_tempo_t *smf_tempo = new_tempo(smf, pulses);
96 if (smf_tempo == NULL)
97 return -1;
99 smf_tempo->microseconds_per_quarter_note = tempo;
101 return 0;
104 static int
105 add_time_signature(smf_t *smf, int pulses, int numerator, int denominator, int clocks_per_click, int notes_per_note)
107 smf_tempo_t *smf_tempo = new_tempo(smf, pulses);
108 if (smf_tempo == NULL)
109 return -1;
111 smf_tempo->numerator = numerator;
112 smf_tempo->denominator = denominator;
113 smf_tempo->clocks_per_click = clocks_per_click;
114 smf_tempo->notes_per_note = notes_per_note;
116 return 0;
119 void
120 maybe_add_to_tempo_map(smf_event_t *event)
122 if (!smf_event_is_metadata(event))
123 return;
125 assert(event->track != NULL);
126 assert(event->track->smf != NULL);
127 assert(event->midi_buffer_length >= 1);
129 /* Tempo Change? */
130 if (event->midi_buffer[1] == 0x51) {
131 int new_tempo = (event->midi_buffer[3] << 16) + (event->midi_buffer[4] << 8) + event->midi_buffer[5];
132 if (new_tempo <= 0) {
133 g_critical("Ignoring invalid tempo change.");
134 return;
137 add_tempo(event->track->smf, event->time_pulses, new_tempo);
140 /* Time Signature? */
141 if (event->midi_buffer[1] == 0x58) {
142 int numerator, denominator, clocks_per_click, notes_per_note;
144 if (event->midi_buffer_length < 7) {
145 g_critical("Time Signature event seems truncated.");
146 return;
149 numerator = event->midi_buffer[3];
150 denominator = (int)pow(2, event->midi_buffer[4]);
151 clocks_per_click = event->midi_buffer[5];
152 notes_per_note = event->midi_buffer[6];
154 add_time_signature(event->track->smf, event->time_pulses, numerator, denominator, clocks_per_click, notes_per_note);
157 return;
161 * This is an internal function, called from smf_track_remove_event when tempo-related
162 * event being removed does not require recreation of tempo map, i.e. there are no events
163 * after that one.
165 void
166 remove_last_tempo_with_pulses(smf_t *smf, int pulses)
168 smf_tempo_t *tempo;
170 /* XXX: This is a workaround for the following problem: we have two tempo-related
171 events, A and B, that occur at the same time. We remove B, then try to remove
172 A. However, both tempo changes got coalesced in new_tempo(), so it is impossible
173 to remove B. */
174 if (smf->tempo_array->len == 0)
175 return;
177 tempo = smf_get_last_tempo(smf);
179 /* Workaround part two. */
180 if (tempo->time_pulses != pulses)
181 return;
183 free(tempo);
185 g_ptr_array_remove_index(smf->tempo_array, smf->tempo_array->len - 1);
188 static double
189 seconds_from_pulses(const smf_t *smf, int pulses)
191 double seconds;
192 smf_tempo_t *tempo;
194 tempo = smf_get_tempo_by_pulses(smf, pulses);
195 assert(tempo);
196 assert(tempo->time_pulses <= pulses);
198 seconds = tempo->time_seconds + (double)(pulses - tempo->time_pulses) *
199 (tempo->microseconds_per_quarter_note / ((double)smf->ppqn * 1000000.0));
201 return seconds;
204 static int
205 pulses_from_seconds(const smf_t *smf, double seconds)
207 int pulses = 0;
208 smf_tempo_t *tempo;
210 tempo = smf_get_tempo_by_seconds(smf, seconds);
211 assert(tempo);
212 assert(tempo->time_seconds <= seconds);
214 pulses = tempo->time_pulses + (seconds - tempo->time_seconds) *
215 ((double)smf->ppqn * 1000000.0 / tempo->microseconds_per_quarter_note);
217 return pulses;
221 * Computes value of event->time_seconds for all events in smf.
222 * Warning: rewinds the smf.
225 smf_create_tempo_map_and_compute_seconds(smf_t *smf)
227 smf_event_t *event;
229 smf_rewind(smf);
230 smf_init_tempo(smf);
232 for (;;) {
233 event = smf_get_next_event(smf);
235 if (event == NULL)
236 return 0;
238 maybe_add_to_tempo_map(event);
240 event->time_seconds = seconds_from_pulses(smf, event->time_pulses);
243 /* Not reached. */
244 return -1;
247 smf_tempo_t *
248 smf_get_tempo_by_number(const smf_t *smf, int number)
250 assert(number >= 0);
252 if (number >= smf->tempo_array->len)
253 return NULL;
255 return g_ptr_array_index(smf->tempo_array, number);
259 * Return last tempo (i.e. tempo with greatest time_pulses) that happens before "pulses".
261 smf_tempo_t *
262 smf_get_tempo_by_pulses(const smf_t *smf, int pulses)
264 int i;
265 smf_tempo_t *tempo;
267 assert(pulses >= 0);
269 if (pulses == 0)
270 return smf_get_tempo_by_number(smf, 0);
272 assert(smf->tempo_array != NULL);
274 for (i = smf->tempo_array->len - 1; i >= 0; i--) {
275 tempo = smf_get_tempo_by_number(smf, i);
277 assert(tempo);
278 if (tempo->time_pulses < pulses)
279 return tempo;
282 return NULL;
286 * Return last tempo (i.e. tempo with greatest time_seconds) that happens before "seconds".
288 smf_tempo_t *
289 smf_get_tempo_by_seconds(const smf_t *smf, double seconds)
291 int i;
292 smf_tempo_t *tempo;
294 assert(seconds >= 0.0);
296 if (seconds == 0.0)
297 return smf_get_tempo_by_number(smf, 0);
299 assert(smf->tempo_array != NULL);
301 for (i = smf->tempo_array->len - 1; i >= 0; i--) {
302 tempo = smf_get_tempo_by_number(smf, i);
304 assert(tempo);
305 if (tempo->time_seconds < seconds)
306 return tempo;
309 return NULL;
314 * Return last tempo.
316 smf_tempo_t *
317 smf_get_last_tempo(const smf_t *smf)
319 smf_tempo_t *tempo;
321 tempo = smf_get_tempo_by_number(smf, smf->tempo_array->len - 1);
322 assert(tempo);
324 return tempo;
328 * Remove any existing tempos and add default one.
331 smf_init_tempo(smf_t *smf)
333 smf_tempo_t *tempo;
335 while (smf->tempo_array->len > 0) {
336 smf_tempo_t *tempo = g_ptr_array_index(smf->tempo_array, smf->tempo_array->len - 1);
337 assert(tempo);
338 free(tempo);
339 g_ptr_array_remove_index(smf->tempo_array, smf->tempo_array->len - 1);
342 assert(smf->tempo_array->len == 0);
344 tempo = new_tempo(smf, 0);
345 if (tempo == NULL)
346 return -1;
348 return 0;
352 * Returns ->time_pulses of last event on the given track, or 0, if track is empty.
354 static int
355 last_event_pulses(const smf_track_t *track)
357 /* Get time of last event on this track. */
358 if (track->number_of_events > 0) {
359 smf_event_t *previous_event = smf_track_get_last_event(track);
360 assert(previous_event);
361 assert(previous_event->time_pulses >= 0);
363 return previous_event->time_pulses;
366 return 0;
370 * Adds event to the track at the time "pulses" clocks from the previous event in this track.
371 * The remaining two time fields will be computed automatically based on the third argument
372 * and current tempo map. Note that ->delta_pulses is computed by smf.c:smf_track_add_event,
373 * not here.
375 void
376 smf_track_add_event_delta_pulses(smf_track_t *track, smf_event_t *event, int delta)
378 assert(delta >= 0);
379 assert(event->time_pulses == -1);
380 assert(event->time_seconds == -1.0);
381 assert(track->smf != NULL);
383 smf_track_add_event_pulses(track, event, last_event_pulses(track) + delta);
387 * Adds event to the track at the time "pulses" clocks from the start of song.
388 * The remaining two time fields will be computed automatically based on the third argument
389 * and current tempo map.
391 void
392 smf_track_add_event_pulses(smf_track_t *track, smf_event_t *event, int pulses)
394 assert(pulses >= 0);
395 assert(event->time_pulses == -1);
396 assert(event->time_seconds == -1.0);
397 assert(track->smf != NULL);
399 event->time_pulses = pulses;
400 event->time_seconds = seconds_from_pulses(track->smf, pulses);
401 smf_track_add_event(track, event);
405 * Adds event to the track at the time "seconds" seconds from the start of song.
406 * The remaining two time fields will be computed automatically based on the third argument
407 * and current tempo map.
409 void
410 smf_track_add_event_seconds(smf_track_t *track, smf_event_t *event, double seconds)
412 assert(seconds >= 0.0);
413 assert(event->time_pulses == -1);
414 assert(event->time_seconds == -1.0);
415 assert(track->smf != NULL);
417 event->time_seconds = seconds;
418 event->time_pulses = pulses_from_seconds(track->smf, seconds);
419 smf_track_add_event(track, event);