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