Remove unused libsmf seconds/time API
This significantly speeds up parsing MIDI files with complex tempo-maps. e.g. "Black MIDI Trilogy_2.mid" has 24134 Tempo changes. Prior to this commit parsing that file took over 5 minutes. now it loads in under one seconds (libsmf only; libardour still add overhead, and now needs about 30-40 seconds, previously it took about 10 mins). The problem was that every call to `smf_track_add_event_pulses()` calls `seconds_from_pulses()` which calls `smf_get_tempo_by_seconds()` which iterates over the tempo-map: for every midi-event { for ever tempo until that midi-event {..} } This does not scale to 3.5M events and 24k tempo-changes.
This commit is contained in:
parent
ba7db8759b
commit
c6b87972b1
@ -552,7 +552,6 @@ SMF::instrument_names(vector<string>& names) const
|
||||
|
||||
SMF::Tempo::Tempo (smf_tempo_t* smft)
|
||||
: time_pulses (smft->time_pulses)
|
||||
, time_seconds (smft->time_seconds)
|
||||
, microseconds_per_quarter_note (smft->microseconds_per_quarter_note)
|
||||
, numerator (smft->numerator)
|
||||
, denominator (smft->denominator)
|
||||
@ -568,26 +567,6 @@ SMF::num_tempos () const
|
||||
return smf_get_tempo_count (_smf);
|
||||
}
|
||||
|
||||
SMF::Tempo*
|
||||
SMF::tempo_at_smf_pulse (size_t smf_pulse) const
|
||||
{
|
||||
smf_tempo_t* t = smf_get_tempo_by_seconds (_smf, smf_pulse);
|
||||
if (!t) {
|
||||
return 0;
|
||||
}
|
||||
return new Tempo (t);
|
||||
}
|
||||
|
||||
SMF::Tempo*
|
||||
SMF::tempo_at_seconds (double seconds) const
|
||||
{
|
||||
smf_tempo_t* t = smf_get_tempo_by_seconds (_smf, seconds);
|
||||
if (!t) {
|
||||
return 0;
|
||||
}
|
||||
return new Tempo (t);
|
||||
}
|
||||
|
||||
SMF::Tempo*
|
||||
SMF::nth_tempo (size_t n) const
|
||||
{
|
||||
|
@ -96,7 +96,6 @@ public:
|
||||
/* This is exactly modelled on smf_tempo_t */
|
||||
struct Tempo {
|
||||
size_t time_pulses;
|
||||
double time_seconds;
|
||||
int microseconds_per_quarter_note;
|
||||
int numerator;
|
||||
int denominator;
|
||||
@ -105,7 +104,6 @@ public:
|
||||
|
||||
Tempo ()
|
||||
: time_pulses (0)
|
||||
, time_seconds (0)
|
||||
, microseconds_per_quarter_note (-1)
|
||||
, numerator (-1)
|
||||
, denominator (-1)
|
||||
@ -118,8 +116,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
Tempo* tempo_at_smf_pulse (size_t smf_pulse) const;
|
||||
Tempo* tempo_at_seconds (double seconds) const;
|
||||
Tempo* nth_tempo (size_t n) const;
|
||||
|
||||
private:
|
||||
|
@ -247,7 +247,6 @@ smf_event_new(void)
|
||||
|
||||
event->delta_time_pulses = -1;
|
||||
event->time_pulses = -1;
|
||||
event->time_seconds = -1.0;
|
||||
event->track_number = -1;
|
||||
|
||||
return (event);
|
||||
@ -466,7 +465,6 @@ smf_track_add_event(smf_track_t *track, smf_event_t *event)
|
||||
assert(track->smf != NULL);
|
||||
assert(event->track == NULL);
|
||||
assert(event->delta_time_pulses == -1);
|
||||
assert(event->time_seconds >= 0.0);
|
||||
|
||||
remove_eot_if_before_pulses(track, event->time_pulses);
|
||||
|
||||
@ -574,26 +572,6 @@ smf_track_add_eot_pulses(smf_track_t *track, size_t pulses)
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
smf_track_add_eot_seconds(smf_track_t *track, double seconds)
|
||||
{
|
||||
smf_event_t *event, *last_event;
|
||||
|
||||
last_event = smf_track_get_last_event(track);
|
||||
if (last_event != NULL) {
|
||||
if (last_event->time_seconds > seconds)
|
||||
return (-2);
|
||||
}
|
||||
|
||||
event = smf_event_new_from_bytes(0xFF, 0x2F, 0x00);
|
||||
if (event == NULL)
|
||||
return (-1);
|
||||
|
||||
smf_track_add_event_seconds(track, event, seconds);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detaches event from its track.
|
||||
*/
|
||||
@ -642,7 +620,6 @@ smf_event_remove_from_track(smf_event_t *event)
|
||||
event->event_number = 0;
|
||||
event->delta_time_pulses = -1;
|
||||
event->time_pulses = 0;
|
||||
event->time_seconds = -1.0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -977,52 +954,6 @@ smf_seek_to_event(smf_t *smf, const smf_event_t *target)
|
||||
break;
|
||||
}
|
||||
|
||||
smf->last_seek_position = event->time_seconds;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Seeks the SMF to the given position. For example, after seeking to 1.0 seconds,
|
||||
* smf_get_next_event will return first event that happens after the first second of song.
|
||||
* \return 0 if everything went ok, nonzero otherwise.
|
||||
*/
|
||||
int
|
||||
smf_seek_to_seconds(smf_t *smf, double seconds)
|
||||
{
|
||||
smf_event_t *event;
|
||||
|
||||
assert(seconds >= 0.0);
|
||||
|
||||
if (seconds == smf->last_seek_position) {
|
||||
#if 0
|
||||
g_debug("Avoiding seek to %f seconds.", seconds);
|
||||
#endif
|
||||
return (0);
|
||||
}
|
||||
|
||||
smf_rewind(smf);
|
||||
|
||||
#if 0
|
||||
g_debug("Seeking to %f seconds.", seconds);
|
||||
#endif
|
||||
|
||||
for (;;) {
|
||||
event = smf_peek_next_event(smf);
|
||||
|
||||
if (event == NULL) {
|
||||
g_warning("Trying to seek past the end of song.");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (event->time_seconds < seconds)
|
||||
smf_skip_next_event(smf);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
smf->last_seek_position = seconds;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -1056,8 +987,6 @@ smf_seek_to_pulses(smf_t *smf, size_t pulses)
|
||||
break;
|
||||
}
|
||||
|
||||
smf->last_seek_position = event->time_seconds;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -1089,34 +1018,6 @@ smf_get_length_pulses(const smf_t *smf)
|
||||
return (pulses);
|
||||
}
|
||||
|
||||
/**
|
||||
* \return Length of SMF, in seconds.
|
||||
*/
|
||||
double
|
||||
smf_get_length_seconds(const smf_t *smf)
|
||||
{
|
||||
int i;
|
||||
double seconds = 0.0;
|
||||
|
||||
for (i = 1; i <= smf->number_of_tracks; i++) {
|
||||
smf_track_t *track;
|
||||
smf_event_t *event;
|
||||
|
||||
track = smf_get_track_by_number(smf, i);
|
||||
assert(track);
|
||||
|
||||
event = smf_track_get_last_event(track);
|
||||
/* Empty track? */
|
||||
if (event == NULL)
|
||||
continue;
|
||||
|
||||
if (event->time_seconds > seconds)
|
||||
seconds = event->time_seconds;
|
||||
}
|
||||
|
||||
return (seconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* \return Nonzero, if there are no events in the SMF after this one.
|
||||
* Note that may be more than one "last event", if they occur at the same time.
|
||||
|
@ -262,7 +262,6 @@ typedef struct smf_struct smf_t;
|
||||
/** Describes a single tempo or time signature change. */
|
||||
struct smf_tempo_struct {
|
||||
size_t time_pulses;
|
||||
double time_seconds;
|
||||
int microseconds_per_quarter_note;
|
||||
int numerator;
|
||||
int denominator;
|
||||
@ -313,9 +312,6 @@ struct smf_event_struct {
|
||||
/** Time, in pulses, since the start of the song. */
|
||||
size_t time_pulses;
|
||||
|
||||
/** Time, in seconds, since the start of the song. */
|
||||
double time_seconds;
|
||||
|
||||
/** Tracks are numbered consecutively, starting from 1. */
|
||||
int track_number;
|
||||
|
||||
@ -344,12 +340,10 @@ smf_event_t *smf_get_next_event(smf_t *smf) WARN_UNUSED_RESULT;
|
||||
void smf_skip_next_event(smf_t *smf);
|
||||
|
||||
void smf_rewind(smf_t *smf);
|
||||
int smf_seek_to_seconds(smf_t *smf, double seconds) WARN_UNUSED_RESULT;
|
||||
int smf_seek_to_pulses(smf_t *smf, size_t pulses) WARN_UNUSED_RESULT;
|
||||
int smf_seek_to_event(smf_t *smf, const smf_event_t *event) WARN_UNUSED_RESULT;
|
||||
|
||||
size_t smf_get_length_pulses(const smf_t *smf) WARN_UNUSED_RESULT;
|
||||
double smf_get_length_seconds(const smf_t *smf) WARN_UNUSED_RESULT;
|
||||
int smf_event_is_last(const smf_event_t *event) WARN_UNUSED_RESULT;
|
||||
|
||||
void smf_add_track(smf_t *smf, smf_track_t *track);
|
||||
@ -365,10 +359,8 @@ smf_event_t *smf_track_get_last_event(const smf_track_t *track) WARN_UNUSED_RESU
|
||||
|
||||
void smf_track_add_event_delta_pulses(smf_track_t *track, smf_event_t *event, uint32_t delta);
|
||||
void smf_track_add_event_pulses(smf_track_t *track, smf_event_t *event, size_t pulses);
|
||||
void smf_track_add_event_seconds(smf_track_t *track, smf_event_t *event, double seconds);
|
||||
int smf_track_add_eot_delta_pulses(smf_track_t *track, uint32_t delta) WARN_UNUSED_RESULT;
|
||||
int smf_track_add_eot_pulses(smf_track_t *track, size_t pulses) WARN_UNUSED_RESULT;
|
||||
int smf_track_add_eot_seconds(smf_track_t *track, double seconds) WARN_UNUSED_RESULT;
|
||||
void smf_event_remove_from_track(smf_event_t *event);
|
||||
|
||||
/* Routines for manipulating smf_event_t. */
|
||||
|
@ -576,7 +576,6 @@ check_smf_event_is_identical(const smf_event_t *a, const smf_event_t *b)
|
||||
CHECK(a->event_number == b->event_number);
|
||||
CHECK(a->delta_time_pulses == b->delta_time_pulses);
|
||||
CHECK(labs((long)(a->time_pulses - b->time_pulses)) <= 2);
|
||||
CHECK(fabs(a->time_seconds - b->time_seconds) <= 0.01);
|
||||
CHECK(a->track_number == b->track_number);
|
||||
CHECK(a->midi_buffer_length == b->midi_buffer_length);
|
||||
CHECK(memcmp(a->midi_buffer, b->midi_buffer, a->midi_buffer_length) == 0);
|
||||
|
@ -39,8 +39,6 @@
|
||||
#include "smf.h"
|
||||
#include "smf_private.h"
|
||||
|
||||
static double seconds_from_pulses(const smf_t *smf, size_t pulses);
|
||||
|
||||
/**
|
||||
* If there is tempo starting at "pulses" already, return it. Otherwise,
|
||||
* allocate new one, fill it with values from previous one (or default ones,
|
||||
@ -83,11 +81,6 @@ new_tempo(smf_t *smf, size_t pulses)
|
||||
|
||||
g_ptr_array_add(smf->tempo_array, tempo);
|
||||
|
||||
if (pulses == 0)
|
||||
tempo->time_seconds = 0.0;
|
||||
else
|
||||
tempo->time_seconds = seconds_from_pulses(smf, pulses);
|
||||
|
||||
return (tempo);
|
||||
}
|
||||
|
||||
@ -197,38 +190,6 @@ remove_last_tempo_with_pulses(smf_t *smf, size_t pulses)
|
||||
g_ptr_array_remove_index(smf->tempo_array, smf->tempo_array->len - 1);
|
||||
}
|
||||
|
||||
static double
|
||||
seconds_from_pulses(const smf_t *smf, size_t pulses)
|
||||
{
|
||||
double seconds;
|
||||
smf_tempo_t *tempo;
|
||||
|
||||
tempo = smf_get_tempo_by_pulses(smf, pulses);
|
||||
assert(tempo);
|
||||
assert(tempo->time_pulses <= pulses);
|
||||
|
||||
seconds = tempo->time_seconds + (double)(pulses - tempo->time_pulses) *
|
||||
(tempo->microseconds_per_quarter_note / ((double)smf->ppqn * 1000000.0));
|
||||
|
||||
return (seconds);
|
||||
}
|
||||
|
||||
static int
|
||||
pulses_from_seconds(const smf_t *smf, double seconds)
|
||||
{
|
||||
int pulses = 0;
|
||||
smf_tempo_t *tempo;
|
||||
|
||||
tempo = smf_get_tempo_by_seconds(smf, seconds);
|
||||
assert(tempo);
|
||||
assert(tempo->time_seconds <= seconds);
|
||||
|
||||
pulses = tempo->time_pulses + (seconds - tempo->time_seconds) *
|
||||
((double)smf->ppqn * 1000000.0 / tempo->microseconds_per_quarter_note);
|
||||
|
||||
return (pulses);
|
||||
}
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
@ -250,8 +211,6 @@ smf_create_tempo_map_and_compute_seconds(smf_t *smf)
|
||||
return;
|
||||
|
||||
maybe_add_to_tempo_map(event);
|
||||
|
||||
event->time_seconds = seconds_from_pulses(smf, event->time_pulses);
|
||||
}
|
||||
|
||||
/* Not reached. */
|
||||
@ -301,37 +260,9 @@ smf_get_tempo_by_pulses(const smf_t *smf, size_t pulses)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return last tempo (i.e. tempo with greatest time_seconds) that happens before "seconds".
|
||||
*/
|
||||
smf_tempo_t *
|
||||
smf_get_tempo_by_seconds(const smf_t *smf, double seconds)
|
||||
{
|
||||
size_t i;
|
||||
smf_tempo_t *tempo;
|
||||
|
||||
assert(seconds >= 0.0);
|
||||
|
||||
if (seconds == 0.0)
|
||||
return (smf_get_tempo_by_number(smf, 0));
|
||||
|
||||
assert(smf->tempo_array != NULL);
|
||||
|
||||
for (i = smf->tempo_array->len; i > 0; i--) {
|
||||
tempo = smf_get_tempo_by_number(smf, i - 1);
|
||||
|
||||
assert(tempo);
|
||||
if (tempo->time_seconds < seconds)
|
||||
return (tempo);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return last tempo.
|
||||
*/
|
||||
*/
|
||||
smf_tempo_t *
|
||||
smf_get_last_tempo(const smf_t *smf)
|
||||
{
|
||||
@ -413,7 +344,6 @@ last_event_pulses(const smf_track_t *track)
|
||||
void
|
||||
smf_track_add_event_delta_pulses(smf_track_t *track, smf_event_t *event, uint32_t delta)
|
||||
{
|
||||
assert(event->time_seconds == -1.0);
|
||||
assert(track->smf != NULL);
|
||||
|
||||
if (!smf_event_is_valid(event)) {
|
||||
@ -431,28 +361,8 @@ smf_track_add_event_delta_pulses(smf_track_t *track, smf_event_t *event, uint32_
|
||||
void
|
||||
smf_track_add_event_pulses(smf_track_t *track, smf_event_t *event, size_t pulses)
|
||||
{
|
||||
assert(event->time_seconds == -1.0);
|
||||
assert(track->smf != NULL);
|
||||
|
||||
event->time_pulses = pulses;
|
||||
event->time_seconds = seconds_from_pulses(track->smf, pulses);
|
||||
smf_track_add_event(track, event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds event to the track at the time "seconds" seconds from the start of song.
|
||||
* The remaining two time fields will be computed automatically based on the third argument
|
||||
* and current tempo map.
|
||||
*/
|
||||
void
|
||||
smf_track_add_event_seconds(smf_track_t *track, smf_event_t *event, double seconds)
|
||||
{
|
||||
assert(seconds >= 0.0);
|
||||
assert(event->time_seconds == -1.0);
|
||||
assert(track->smf != NULL);
|
||||
|
||||
event->time_seconds = seconds;
|
||||
event->time_pulses = pulses_from_seconds(track->smf, seconds);
|
||||
smf_track_add_event(track, event);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user