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 */
27
28 /**
29 * \file
30 *
31 * Tempo map related part.
32 *
33 */
34
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"
41
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".
46 */
47 static smf_tempo_t *
new_tempo(smf_t * smf,size_t pulses)48 new_tempo(smf_t *smf, size_t pulses)
49 {
50 smf_tempo_t *tempo, *previous_tempo = NULL;
51
52 if (smf->tempo_array->len > 0) {
53 previous_tempo = smf_get_last_tempo(smf);
54
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);
58 }
59
60 tempo = (smf_tempo_t*)malloc(sizeof(smf_tempo_t));
61 if (tempo == NULL) {
62 g_warning("Cannot allocate smf_tempo_t.");
63 return (NULL);
64 }
65
66 tempo->time_pulses = pulses;
67
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 = 24;
79 tempo->notes_per_note = 8;
80 }
81
82 g_ptr_array_add(smf->tempo_array, tempo);
83
84 return (tempo);
85 }
86
87 static int
add_tempo(smf_t * smf,int pulses,int tempo)88 add_tempo(smf_t *smf, int pulses, int tempo)
89 {
90 smf_tempo_t *smf_tempo = new_tempo(smf, pulses);
91 if (smf_tempo == NULL)
92 return (-1);
93
94 smf_tempo->microseconds_per_quarter_note = tempo;
95
96 return (0);
97 }
98
99 static int
add_time_signature(smf_t * smf,int pulses,int numerator,int denominator,int clocks_per_click,int notes_per_note)100 add_time_signature(smf_t *smf, int pulses, int numerator, int denominator, int clocks_per_click, int notes_per_note)
101 {
102 smf_tempo_t *smf_tempo = new_tempo(smf, pulses);
103 if (smf_tempo == NULL)
104 return (-1);
105
106 smf_tempo->numerator = numerator;
107 smf_tempo->denominator = denominator;
108 smf_tempo->clocks_per_click = clocks_per_click;
109 smf_tempo->notes_per_note = notes_per_note;
110
111 return (0);
112 }
113
114 /**
115 * \internal
116 */
117 void
maybe_add_to_tempo_map(smf_event_t * event)118 maybe_add_to_tempo_map(smf_event_t *event)
119 {
120 if (!smf_event_is_metadata(event))
121 return;
122
123 assert(event->track != NULL);
124 assert(event->track->smf != NULL);
125 assert(event->midi_buffer_length >= 1);
126
127 /* Tempo Change? */
128 if (event->midi_buffer[1] == 0x51) {
129 if (event->midi_buffer_length < 6) {
130 g_warning("Ignoring incomplete tempo change event.");
131 return;
132 }
133 int ntempo = (event->midi_buffer[3] << 16) + (event->midi_buffer[4] << 8) + event->midi_buffer[5];
134 if (ntempo <= 0) {
135 g_warning("Ignoring invalid tempo change.");
136 return;
137 }
138
139 add_tempo(event->track->smf, event->time_pulses, ntempo);
140 }
141
142 /* Time Signature? */
143 if (event->midi_buffer[1] == 0x58) {
144 int numerator, denominator, clocks_per_click, notes_per_note;
145
146 if (event->midi_buffer_length < 7) {
147 g_warning("Time Signature event seems truncated.");
148 return;
149 }
150
151 numerator = event->midi_buffer[3];
152 denominator = (int)pow((double)2, event->midi_buffer[4]);
153 clocks_per_click = event->midi_buffer[5];
154 notes_per_note = event->midi_buffer[6];
155
156 add_time_signature(event->track->smf, event->time_pulses, numerator, denominator, clocks_per_click, notes_per_note);
157 }
158
159 return;
160 }
161
162 /**
163 * \internal
164 *
165 * This is an internal function, called from smf_track_remove_event when tempo-related
166 * event being removed does not require recreation of tempo map, i.e. there are no events
167 * after that one.
168 */
169 void
remove_last_tempo_with_pulses(smf_t * smf,size_t pulses)170 remove_last_tempo_with_pulses(smf_t *smf, size_t pulses)
171 {
172 smf_tempo_t *tempo;
173
174 /* XXX: This is a partial workaround for the following problem: we have two tempo-related
175 events, A and B, that occur at the same time. We remove B, then try to remove
176 A. However, both tempo changes got coalesced in new_tempo(), so it is impossible
177 to remove B. */
178 if (smf->tempo_array->len == 0)
179 return;
180
181 tempo = smf_get_last_tempo(smf);
182
183 /* Workaround part two. */
184 if (tempo->time_pulses != pulses)
185 return;
186
187 memset(tempo, 0, sizeof(smf_tempo_t));
188 free(tempo);
189
190 g_ptr_array_remove_index(smf->tempo_array, smf->tempo_array->len - 1);
191 }
192
193 /**
194 * \internal
195 *
196 * Computes value of event->time_seconds for all events in smf.
197 * Warning: rewinds the smf.
198 */
199 void
smf_create_tempo_map_and_compute_seconds(smf_t * smf)200 smf_create_tempo_map_and_compute_seconds(smf_t *smf)
201 {
202 smf_event_t *event;
203
204 smf_rewind(smf);
205 smf_init_tempo(smf);
206
207 for (;;) {
208 event = smf_get_next_event(smf);
209
210 if (event == NULL)
211 return;
212
213 maybe_add_to_tempo_map(event);
214 }
215
216 /* Not reached. */
217 }
218
219 int
smf_get_tempo_count(const smf_t * smf)220 smf_get_tempo_count (const smf_t *smf)
221 {
222 if (!smf->tempo_array) {
223 return 0;
224 }
225
226 return smf->tempo_array->len;
227 }
228
229 smf_tempo_t *
smf_get_tempo_by_number(const smf_t * smf,size_t number)230 smf_get_tempo_by_number(const smf_t *smf, size_t number)
231 {
232 if (number >= smf->tempo_array->len)
233 return (NULL);
234
235 return ((smf_tempo_t*)g_ptr_array_index(smf->tempo_array, number));
236 }
237
238 /**
239 * Return last tempo (i.e. tempo with greatest time_pulses) that happens before "pulses".
240 */
241 smf_tempo_t *
smf_get_tempo_by_pulses(const smf_t * smf,size_t pulses)242 smf_get_tempo_by_pulses(const smf_t *smf, size_t pulses)
243 {
244 size_t i;
245 smf_tempo_t *tempo;
246
247 if (pulses == 0)
248 return (smf_get_tempo_by_number(smf, 0));
249
250 assert(smf->tempo_array != NULL);
251
252 for (i = smf->tempo_array->len; i > 0; i--) {
253 tempo = smf_get_tempo_by_number(smf, i - 1);
254
255 assert(tempo);
256 if (tempo->time_pulses < pulses)
257 return (tempo);
258 }
259
260 return (NULL);
261 }
262
263 /**
264 * Return last tempo.
265 */
266 smf_tempo_t *
smf_get_last_tempo(const smf_t * smf)267 smf_get_last_tempo(const smf_t *smf)
268 {
269 smf_tempo_t *tempo;
270
271 assert(smf->tempo_array->len > 0);
272 tempo = smf_get_tempo_by_number(smf, smf->tempo_array->len - 1);
273 assert(tempo);
274
275 return (tempo);
276 }
277
278 /**
279 * \internal
280 *
281 * Remove all smf_tempo_t structures from SMF.
282 */
283 void
smf_fini_tempo(smf_t * smf)284 smf_fini_tempo(smf_t *smf)
285 {
286 smf_tempo_t *tempo;
287
288 while (smf->tempo_array->len > 0) {
289 tempo = (smf_tempo_t*)g_ptr_array_index(smf->tempo_array, smf->tempo_array->len - 1);
290 assert(tempo);
291
292 memset(tempo, 0, sizeof(smf_tempo_t));
293 free(tempo);
294
295 g_ptr_array_remove_index(smf->tempo_array, smf->tempo_array->len - 1);
296 }
297
298 assert(smf->tempo_array->len == 0);
299 }
300
301 /**
302 * \internal
303 *
304 * Remove any existing tempos and add default one.
305 *
306 * \bug This will abort (by calling g_warning) if new_tempo() (memory allocation there) fails.
307 */
308 void
smf_init_tempo(smf_t * smf)309 smf_init_tempo(smf_t *smf)
310 {
311 smf_tempo_t *tempo;
312
313 smf_fini_tempo(smf);
314
315 tempo = new_tempo(smf, 0);
316 if (tempo == NULL) {
317 g_warning("tempo_init failed, sorry.");
318 }
319 }
320
321 /**
322 * Returns ->time_pulses of last event on the given track, or 0, if track is empty.
323 */
324 static int
last_event_pulses(const smf_track_t * track)325 last_event_pulses(const smf_track_t *track)
326 {
327 /* Get time of last event on this track. */
328 if (track->number_of_events > 0) {
329 smf_event_t *previous_event = smf_track_get_last_event(track);
330 assert(previous_event);
331
332 return (previous_event->time_pulses);
333 }
334
335 return (0);
336 }
337
338 /**
339 * Adds event to the track at the time "pulses" clocks from the previous event in this track.
340 * The remaining two time fields will be computed automatically based on the third argument
341 * and current tempo map. Note that ->delta_pulses is computed by smf.c:smf_track_add_event,
342 * not here.
343 */
344 void
smf_track_add_event_delta_pulses(smf_track_t * track,smf_event_t * event,uint32_t delta)345 smf_track_add_event_delta_pulses(smf_track_t *track, smf_event_t *event, uint32_t delta)
346 {
347 assert(track->smf != NULL);
348
349 if (!smf_event_is_valid(event)) {
350 g_warning("Added event is invalid");
351 }
352
353 smf_track_add_event_pulses(track, event, last_event_pulses(track) + delta);
354 }
355
356 /**
357 * Adds event to the track at the time "pulses" clocks from the start of song.
358 * The remaining two time fields will be computed automatically based on the third argument
359 * and current tempo map.
360 */
361 void
smf_track_add_event_pulses(smf_track_t * track,smf_event_t * event,size_t pulses)362 smf_track_add_event_pulses(smf_track_t *track, smf_event_t *event, size_t pulses)
363 {
364 assert(track->smf != NULL);
365
366 event->time_pulses = pulses;
367 smf_track_add_event(track, event);
368 }
369