ardour
smf_tempo.c
Go to the documentation of this file.
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 
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 static double seconds_from_pulses(const smf_t *smf, size_t pulses);
43 
49 static smf_tempo_t *
50 new_tempo(smf_t *smf, size_t pulses)
51 {
52  smf_tempo_t *tempo, *previous_tempo = NULL;
53 
54  if (smf->tempo_array->len > 0) {
55  previous_tempo = smf_get_last_tempo(smf);
56 
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  }
61 
62  tempo = (smf_tempo_t*)malloc(sizeof(smf_tempo_t));
63  if (tempo == NULL) {
64  g_critical("Cannot allocate smf_tempo_t.");
65  return (NULL);
66  }
67 
68  tempo->time_pulses = pulses;
69 
70  if (previous_tempo != NULL) {
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  }
83 
84  g_ptr_array_add(smf->tempo_array, tempo);
85 
86  if (pulses == 0)
87  tempo->time_seconds = 0.0;
88  else
89  tempo->time_seconds = seconds_from_pulses(smf, pulses);
90 
91  return (tempo);
92 }
93 
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);
100 
101  smf_tempo->microseconds_per_quarter_note = tempo;
102 
103  return (0);
104 }
105 
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);
112 
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;
117 
118  return (0);
119 }
120 
124 void
126 {
127  if (!smf_event_is_metadata(event))
128  return;
129 
130  assert(event->track != NULL);
131  assert(event->track->smf != NULL);
132  assert(event->midi_buffer_length >= 1);
133 
134  /* Tempo Change? */
135  if (event->midi_buffer[1] == 0x51) {
136  int ntempo = (event->midi_buffer[3] << 16) + (event->midi_buffer[4] << 8) + event->midi_buffer[5];
137  if (ntempo <= 0) {
138  g_critical("Ignoring invalid tempo change.");
139  return;
140  }
141 
142  add_tempo(event->track->smf, event->time_pulses, ntempo);
143  }
144 
145  /* Time Signature? */
146  if (event->midi_buffer[1] == 0x58) {
147  int numerator, denominator, clocks_per_click, notes_per_note;
148 
149  if (event->midi_buffer_length < 7) {
150  g_critical("Time Signature event seems truncated.");
151  return;
152  }
153 
154  numerator = event->midi_buffer[3];
155  denominator = (int)pow((double)2, event->midi_buffer[4]);
156  clocks_per_click = event->midi_buffer[5];
157  notes_per_note = event->midi_buffer[6];
158 
159  add_time_signature(event->track->smf, event->time_pulses, numerator, denominator, clocks_per_click, notes_per_note);
160  }
161 
162  return;
163 }
164 
172 void
174 {
175  smf_tempo_t *tempo;
176 
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;
183 
184  tempo = smf_get_last_tempo(smf);
185 
186  /* Workaround part two. */
187  if (tempo->time_pulses != pulses)
188  return;
189 
190  memset(tempo, 0, sizeof(smf_tempo_t));
191  free(tempo);
192 
193  g_ptr_array_remove_index(smf->tempo_array, smf->tempo_array->len - 1);
194 }
195 
196 static double
197 seconds_from_pulses(const smf_t *smf, size_t pulses)
198 {
199  double seconds;
200  smf_tempo_t *tempo;
201 
202  tempo = smf_get_tempo_by_pulses(smf, pulses);
203  assert(tempo);
204  assert(tempo->time_pulses <= pulses);
205 
206  seconds = tempo->time_seconds + (double)(pulses - tempo->time_pulses) *
207  (tempo->microseconds_per_quarter_note / ((double)smf->ppqn * 1000000.0));
208 
209  return (seconds);
210 }
211 
212 static int
213 pulses_from_seconds(const smf_t *smf, double seconds)
214 {
215  int pulses = 0;
216  smf_tempo_t *tempo;
217 
218  tempo = smf_get_tempo_by_seconds(smf, seconds);
219  assert(tempo);
220  assert(tempo->time_seconds <= seconds);
221 
222  pulses = tempo->time_pulses + (seconds - tempo->time_seconds) *
223  ((double)smf->ppqn * 1000000.0 / tempo->microseconds_per_quarter_note);
224 
225  return (pulses);
226 }
227 
234 void
236 {
237  smf_event_t *event;
238 
239  smf_rewind(smf);
240  smf_init_tempo(smf);
241 
242  for (;;) {
243  event = smf_get_next_event(smf);
244 
245  if (event == NULL)
246  return;
247 
248  maybe_add_to_tempo_map(event);
249 
250  event->time_seconds = seconds_from_pulses(smf, event->time_pulses);
251  }
252 
253  /* Not reached. */
254 }
255 
256 smf_tempo_t *
257 smf_get_tempo_by_number(const smf_t *smf, size_t number)
258 {
259  if (number >= smf->tempo_array->len)
260  return (NULL);
261 
262  return ((smf_tempo_t*)g_ptr_array_index(smf->tempo_array, number));
263 }
264 
268 smf_tempo_t *
269 smf_get_tempo_by_pulses(const smf_t *smf, size_t pulses)
270 {
271  size_t i;
272  smf_tempo_t *tempo;
273 
274  if (pulses == 0)
275  return (smf_get_tempo_by_number(smf, 0));
276 
277  assert(smf->tempo_array != NULL);
278 
279  for (i = smf->tempo_array->len; i > 0; i--) {
280  tempo = smf_get_tempo_by_number(smf, i - 1);
281 
282  assert(tempo);
283  if (tempo->time_pulses < pulses)
284  return (tempo);
285  }
286 
287  return (NULL);
288 }
289 
293 smf_tempo_t *
294 smf_get_tempo_by_seconds(const smf_t *smf, double seconds)
295 {
296  size_t i;
297  smf_tempo_t *tempo;
298 
299  assert(seconds >= 0.0);
300 
301  if (seconds == 0.0)
302  return (smf_get_tempo_by_number(smf, 0));
303 
304  assert(smf->tempo_array != NULL);
305 
306  for (i = smf->tempo_array->len; i > 0; i--) {
307  tempo = smf_get_tempo_by_number(smf, i - 1);
308 
309  assert(tempo);
310  if (tempo->time_seconds < seconds)
311  return (tempo);
312  }
313 
314  return (NULL);
315 }
316 
317 
321 smf_tempo_t *
323 {
324  smf_tempo_t *tempo;
325 
326  assert(smf->tempo_array->len > 0);
327  tempo = smf_get_tempo_by_number(smf, smf->tempo_array->len - 1);
328  assert(tempo);
329 
330  return (tempo);
331 }
332 
338 void
340 {
341  smf_tempo_t *tempo;
342 
343  while (smf->tempo_array->len > 0) {
344  tempo = (smf_tempo_t*)g_ptr_array_index(smf->tempo_array, smf->tempo_array->len - 1);
345  assert(tempo);
346 
347  memset(tempo, 0, sizeof(smf_tempo_t));
348  free(tempo);
349 
350  g_ptr_array_remove_index(smf->tempo_array, smf->tempo_array->len - 1);
351  }
352 
353  assert(smf->tempo_array->len == 0);
354 }
355 
363 void
365 {
366  smf_tempo_t *tempo;
367 
368  smf_fini_tempo(smf);
369 
370  tempo = new_tempo(smf, 0);
371  if (tempo == NULL) {
372  g_error("tempo_init failed, sorry.");
373  }
374 }
375 
379 static int
381 {
382  /* Get time of last event on this track. */
383  if (track->number_of_events > 0) {
384  smf_event_t *previous_event = smf_track_get_last_event(track);
385  assert(previous_event);
386 
387  return (previous_event->time_pulses);
388  }
389 
390  return (0);
391 }
392 
399 void
401 {
402  assert(event->time_seconds == -1.0);
403  assert(track->smf != NULL);
404 
405  if (!smf_event_is_valid(event)) {
406  g_critical("Added event is invalid");
407  }
408 
409  smf_track_add_event_pulses(track, event, last_event_pulses(track) + delta);
410 }
411 
417 void
418 smf_track_add_event_pulses(smf_track_t *track, smf_event_t *event, size_t pulses)
419 {
420  assert(event->time_seconds == -1.0);
421  assert(track->smf != NULL);
422 
423  event->time_pulses = pulses;
424  event->time_seconds = seconds_from_pulses(track->smf, pulses);
425  smf_track_add_event(track, event);
426 }
427 
433 void
434 smf_track_add_event_seconds(smf_track_t *track, smf_event_t *event, double seconds)
435 {
436  assert(seconds >= 0.0);
437  assert(event->time_seconds == -1.0);
438  assert(track->smf != NULL);
439 
440  event->time_seconds = seconds;
441  event->time_pulses = pulses_from_seconds(track->smf, seconds);
442  smf_track_add_event(track, event);
443 }
444 
void smf_rewind(smf_t *smf)
Definition: smf.c:908
static int add_time_signature(smf_t *smf, int pulses, int numerator, int denominator, int clocks_per_click, int notes_per_note)
Definition: smf_tempo.c:107
int clocks_per_click
Definition: smf.h:269
double time_seconds
Definition: smf.h:265
void remove_last_tempo_with_pulses(smf_t *smf, size_t pulses)
Definition: smf_tempo.c:173
int smf_event_is_valid(const smf_event_t *event) WARN_UNUSED_RESULT
Definition: smf_load.c:770
void smf_track_add_event(smf_track_t *track, smf_event_t *event)
Definition: smf.c:449
void smf_track_add_event_delta_pulses(smf_track_t *track, smf_event_t *event, uint32_t delta)
Definition: smf_tempo.c:400
int numerator
Definition: smf.h:267
GPtrArray * tempo_array
Definition: smf.h:257
smf_tempo_t * smf_get_tempo_by_pulses(const smf_t *smf, size_t pulses)
Definition: smf_tempo.c:269
static int pulses_from_seconds(const smf_t *smf, double seconds)
Definition: smf_tempo.c:213
size_t midi_buffer_length
Definition: smf.h:324
int smf_event_is_metadata(const smf_event_t *event) WARN_UNUSED_RESULT
Definition: smf_decode.c:57
int denominator
Definition: smf.h:268
void smf_track_add_event_seconds(smf_track_t *track, smf_event_t *event, double seconds)
Definition: smf_tempo.c:434
int notes_per_note
Definition: smf.h:270
static int last_event_pulses(const smf_track_t *track)
Definition: smf_tempo.c:380
static double seconds_from_pulses(const smf_t *smf, size_t pulses)
Definition: smf_tempo.c:197
void smf_init_tempo(smf_t *smf)
Definition: smf_tempo.c:364
void smf_create_tempo_map_and_compute_seconds(smf_t *smf)
Definition: smf_tempo.c:235
smf_t * smf
Definition: smf.h:277
void maybe_add_to_tempo_map(smf_event_t *event)
Definition: smf_tempo.c:125
uint16_t ppqn
Definition: smf.h:239
size_t time_pulses
Definition: smf.h:312
smf_tempo_t * smf_get_last_tempo(const smf_t *smf)
Definition: smf_tempo.c:322
static smf_tempo_t * new_tempo(smf_t *smf, size_t pulses)
Definition: smf_tempo.c:50
void smf_track_add_event_pulses(smf_track_t *track, smf_event_t *event, size_t pulses)
Definition: smf_tempo.c:418
size_t number_of_events
Definition: smf.h:280
static int add_tempo(smf_t *smf, int pulses, int tempo)
Definition: smf_tempo.c:95
size_t time_pulses
Definition: smf.h:264
void smf_fini_tempo(smf_t *smf)
Definition: smf_tempo.c:339
double time_seconds
Definition: smf.h:315
int microseconds_per_quarter_note
Definition: smf.h:266
smf_tempo_t * smf_get_tempo_by_number(const smf_t *smf, size_t number)
Definition: smf_tempo.c:257
smf_event_t * smf_track_get_last_event(const smf_track_t *track)
Definition: smf.c:798
smf_tempo_t * smf_get_tempo_by_seconds(const smf_t *smf, double seconds)
Definition: smf_tempo.c:294
uint8_t * midi_buffer
Definition: smf.h:321
smf_track_t * track
Definition: smf.h:302
smf_t * smf
Definition: smfsh.c:51
smf_event_t * smf_get_next_event(smf_t *smf)
Definition: smf.c:845