shithub: sf2mid

Download patch

ref: ff0b418b1fb585c17fb0b45b126ba2977c0a7fa0
parent: bf574519e601202c3a9d27a74f345921277eed39
author: Ellie <el@horse64.org>
date: Sat Nov 6 20:02:56 EDT 2021

Add "tsf_copy" function for linked copies

Originally written by @paladin-t (github.com/paladin-t), GitHub wouldn't
let me rebase the actual original commit to retain this info.

--- a/tsf.h
+++ b/tsf.h
@@ -89,6 +89,12 @@
 // Generic SoundFont loading method using the stream structure above
 TSFDEF tsf* tsf_load(struct tsf_stream* stream);
 
+// Copy a tsf instance from an existing one, use tsf_close to close it as well.
+// All copied tsf instances and their original instance are linked, and share the underlying soundfont.
+// This allows loading a soundfont only once, but using it for multiple independent playbacks.
+// (This function isn't thread-safe without locking.)
+TSFDEF tsf* tsf_copy(tsf* f);
+
 // Free the memory related to this tsf instance
 TSFDEF void tsf_close(tsf* f);
 
@@ -302,17 +308,18 @@
 	float* fontSamples;
 	struct tsf_voice* voices;
 	struct tsf_channels* channels;
-	float* outputSamples;
+	float** outputSamples;
 
 	int presetNum;
 	int voiceNum;
 	int maxVoiceNum;
-	int outputSampleSize;
+	int *outputSampleSize;
 	unsigned int voicePlayIndex;
 
 	enum TSFOutputMode outputmode;
 	float outSampleRate;
 	float globalGainDB;
+	int* refCount;
 };
 
 #ifndef TSF_NO_STDIO
@@ -1265,6 +1272,12 @@
 		res->presets = (struct tsf_preset*)TSF_MALLOC(res->presetNum * sizeof(struct tsf_preset));
 		res->fontSamples = fontSamples;
 		res->outSampleRate = 44100.0f;
+		res->outputSamples = (float**)TSF_MALLOC(sizeof(float*));
+		*res->outputSamples = TSF_NULL;
+		res->outputSampleSize = (int*)TSF_MALLOC(sizeof(int));
+		*res->outputSampleSize = 0;
+		res->refCount = (int*)TSF_MALLOC(sizeof(int));
+		*res->refCount = 1;
 		fontSamples = TSF_NULL; //don't free below
 		tsf_load_presets(res, &hydra, fontSampleCount);
 	}
@@ -1275,17 +1288,40 @@
 	return res;
 }
 
+TSFDEF tsf* tsf_copy(tsf* f)
+{
+	if (!f)
+		return TSF_NULL;
+
+	tsf* res = TSF_NULL;
+
+	res = (tsf*)TSF_MALLOC(sizeof(tsf));
+	memcpy(res, f, sizeof(tsf));
+	res->voices = TSF_NULL;
+	res->voiceNum = 0;
+	res->channels = TSF_NULL;
+	++(*res->refCount);
+
+	return res;
+}
+
 TSFDEF void tsf_close(tsf* f)
 {
 	struct tsf_preset *preset, *presetEnd;
 	if (!f) return;
-	for (preset = f->presets, presetEnd = preset + f->presetNum; preset != presetEnd; preset++)
-		TSF_FREE(preset->regions);
-	TSF_FREE(f->presets);
-	TSF_FREE(f->fontSamples);
+	if (--(*f->refCount) == 0)
+	{
+		for (preset = f->presets, presetEnd = preset + f->presetNum; preset != presetEnd; preset++)
+			TSF_FREE(preset->regions);
+		TSF_FREE(f->presets);
+		TSF_FREE(f->fontSamples);
+		TSF_FREE(*f->outputSamples);
+		TSF_FREE(f->outputSamples);
+		TSF_FREE(f->outputSampleSize);
+		TSF_FREE(f->refCount);
+	}
 	TSF_FREE(f->voices);
 	if (f->channels) { TSF_FREE(f->channels->channels); TSF_FREE(f->channels); }
-	TSF_FREE(f->outputSamples);
 	TSF_FREE(f);
 }
 
@@ -1482,16 +1518,16 @@
 	float *floatSamples;
 	int channelSamples = (f->outputmode == TSF_MONO ? 1 : 2) * samples, floatBufferSize = channelSamples * sizeof(float);
 	short* bufferEnd = buffer + channelSamples;
-	if (floatBufferSize > f->outputSampleSize)
+	if (floatBufferSize > *f->outputSampleSize)
 	{
-		TSF_FREE(f->outputSamples);
-		f->outputSamples = (float*)TSF_MALLOC(floatBufferSize);
-		f->outputSampleSize = floatBufferSize;
+		TSF_FREE(*f->outputSamples);
+		*f->outputSamples = (float*)TSF_MALLOC(floatBufferSize);
+		*f->outputSampleSize = floatBufferSize;
 	}
 
-	tsf_render_float(f, f->outputSamples, samples, TSF_FALSE);
+	tsf_render_float(f, *f->outputSamples, samples, TSF_FALSE);
 
-	floatSamples = f->outputSamples;
+	floatSamples = *f->outputSamples;
 	if (flag_mixing) 
 		while (buffer != bufferEnd)
 		{