From cd53301d069da291fa87a1a40b3726eb02279460 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Sat, 5 Feb 2022 17:03:42 +0100 Subject: [PATCH] Significantly speed up loading SMF tempo-maps Files that have many tracks, each with tempo information were near impossible to load (30+ mins on modern 4.2Ghz CPU!), because tempo is parsed incrementally: ``` For each new track: for each new tempo-event: rewind() for each loaded track so far: for each event on this track so far ``` This reduces the complexity from O(tracks^2 * tempos^2) to O(tracks * tempos). "Come Thou Fount Tempo Map.mid" has 238 Tracks and 56168 total Tempo Changes (236 per track). This now requires only 56168 iterations in smf_create_tempo_map_and_compute_seconds, rather than 1.64e+9 iterations --- libs/evoral/libsmf/smf.c | 3 ++- libs/evoral/libsmf/smf.h | 1 + libs/evoral/libsmf/smf_load.c | 5 +++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/libs/evoral/libsmf/smf.c b/libs/evoral/libsmf/smf.c index 49223f9800..8697252d48 100644 --- a/libs/evoral/libsmf/smf.c +++ b/libs/evoral/libsmf/smf.c @@ -525,7 +525,7 @@ smf_track_add_event(smf_track_t *track, smf_event_t *event) if (smf_event_is_last(event)) maybe_add_to_tempo_map(event); else - smf_create_tempo_map_and_compute_seconds(event->track->smf); + event->track->smf->need_tempo_map_compute = 1; } } @@ -709,6 +709,7 @@ smf_track_get_next_event(smf_track_t *track) if (track->next_event_number < track->number_of_events) { next_event = smf_track_get_event_by_number(track, track->next_event_number + 1); assert(next_event); + assert(next_event->time_pulses >= event->time_pulses); track->time_of_next_event = next_event->time_pulses; track->next_event_number++; diff --git a/libs/evoral/libsmf/smf.h b/libs/evoral/libsmf/smf.h index edcac580d3..5a4809121b 100644 --- a/libs/evoral/libsmf/smf.h +++ b/libs/evoral/libsmf/smf.h @@ -251,6 +251,7 @@ struct smf_struct { /** Private, used by smf.c. */ GPtrArray *tracks_array; double last_seek_position; + int need_tempo_map_compute; /** Private, used by smf_tempo.c. */ /** Array of pointers to smf_tempo_struct. */ diff --git a/libs/evoral/libsmf/smf_load.c b/libs/evoral/libsmf/smf_load.c index 6a6223de0c..dee880968b 100644 --- a/libs/evoral/libsmf/smf_load.c +++ b/libs/evoral/libsmf/smf_load.c @@ -972,6 +972,11 @@ smf_load_from_memory(void *buffer, const size_t buffer_length) smf->expected_number_of_tracks = smf->number_of_tracks; } + /* process tempo-map */ + if (smf->need_tempo_map_compute) { + smf_create_tempo_map_and_compute_seconds(smf); + } + smf->file_buffer = NULL; smf->file_buffer_length = 0; smf->next_chunk_offset = 0;