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