From 65332e603b444240878fb6a2377942b0b111edd3 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 17 Nov 2025 14:37:27 -0700 Subject: [PATCH] libsmf: speed up ridiculous design of smf_save() This would realloc a buffer for every event, making it absurdly slow for large MIDI files (say, 10k events). Use the somewhat standard heuristic of doubling the requested allocation every time we need to increase the size. This results in a speedup of 40-100x when saving SMF to disk --- libs/evoral/libsmf/smf.h | 1 + libs/evoral/libsmf/smf_save.c | 41 ++++++++++++++++++++++------------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/libs/evoral/libsmf/smf.h b/libs/evoral/libsmf/smf.h index 70206e70aa..9a915915f6 100644 --- a/libs/evoral/libsmf/smf.h +++ b/libs/evoral/libsmf/smf.h @@ -244,6 +244,7 @@ struct smf_struct { /** These are private fields using only by loading and saving routines. */ FILE *stream; void *file_buffer; + size_t file_buffer_capacity; size_t file_buffer_length; size_t next_chunk_offset; int expected_number_of_tracks; diff --git a/libs/evoral/libsmf/smf_save.c b/libs/evoral/libsmf/smf_save.c index 6614fc257d..988ecc71d5 100644 --- a/libs/evoral/libsmf/smf_save.c +++ b/libs/evoral/libsmf/smf_save.c @@ -58,21 +58,32 @@ smf_extend(smf_t *smf, const int length) int i, previous_file_buffer_length = smf->file_buffer_length; char *previous_file_buffer = (char*)smf->file_buffer; - /* XXX: Not terribly efficient. */ - smf->file_buffer_length += length; - smf->file_buffer = realloc(smf->file_buffer, smf->file_buffer_length); - if (smf->file_buffer == NULL) { - g_warning("realloc(3) failed: %s", strerror(errno)); - smf->file_buffer_length = 0; - return (NULL); - } + if (smf->file_buffer_capacity >= smf->file_buffer_length + length) { + smf->file_buffer_length += length; + } else { - /* Fix up pointers. XXX: omgwtf. */ - for (i = 1; i <= smf->number_of_tracks; i++) { - smf_track_t *track; - track = smf_get_track_by_number(smf, i); - if (track->file_buffer != NULL) - track->file_buffer = (char *)track->file_buffer + ((char *)smf->file_buffer - previous_file_buffer); + if (smf->file_buffer_capacity == 0) { + smf->file_buffer_capacity = length * 2; + } else { + smf->file_buffer_capacity *= 2; + } + smf->file_buffer = realloc(smf->file_buffer, smf->file_buffer_capacity); + if (smf->file_buffer == NULL) { + g_warning("realloc(3) failed: %s", strerror(errno)); + smf->file_buffer_length = 0; + smf->file_buffer_capacity = 0; + return (NULL); + } + + smf->file_buffer_length += length; + + /* Fix up pointers. XXX: omgwtf. */ + for (i = 1; i <= smf->number_of_tracks; i++) { + smf_track_t *track; + track = smf_get_track_by_number(smf, i); + if (track->file_buffer != NULL) + track->file_buffer = (char *)track->file_buffer + ((char *)smf->file_buffer - previous_file_buffer); + } } return ((char *)smf->file_buffer + previous_file_buffer_length); @@ -441,6 +452,7 @@ free_buffer(smf_t *smf) free(smf->file_buffer); smf->file_buffer = NULL; smf->file_buffer_length = 0; + smf->file_buffer_capacity = 0; for (i = 1; i <= smf->number_of_tracks; i++) { track = smf_get_track_by_number(smf, i); @@ -681,4 +693,3 @@ smf_save(smf_t *smf, FILE* file) return (0); } -