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)
{