Looping and Loop Points
I have some sf2 soundfonts that loop fine normally, but using TinySoundFont come to an abrupt end rather than looping.
Can you think of any reason this would happen? I assume something this basic should have been tried and tested. Modifying tsf_voice_ender as follows keeps the sound looping, but not sure this is the correct way to go about things?
if (tmpSourceSamplePosition >= tmpSampleEndDbl || v->ampenv.segment == TSF_SEGMENT_DONE) { if (isLooping) tmpSourceSamplePosition -= (tmpLoopEnd - tmpLoopStart + 1.0); // Added line else { tsf_voice_kill(v); return; } }
Also in the following function the highlighted line is problematic as it forces the play position to jump abruptly to the end of the loop.
static void tsf_voice_end(tsf* f, struct tsf_voice* v) { // if maxVoiceNum is set, assume that voice rendering and note queuing are on separate threads // so to minimize the chance that voice rendering would advance the segment at the same time // we just do it twice here and hope that it sticks int repeats = (f->maxVoiceNum ? 2 : 1); while (repeats--) { tsf_voice_envelope_nextsegment(&v->ampenv, TSF_SEGMENT_SUSTAIN, f->outSampleRate); tsf_voice_envelope_nextsegment(&v->modenv, TSF_SEGMENT_SUSTAIN, f->outSampleRate); if (v->region->loop_mode == TSF_LOOPMODE_SUSTAIN) { // Continue playing, but stop looping. v->loopEnd = v->loopStart; < ---- PROBLEMATIC LINE } } }
Paul
I don't think your "fix" makes much sense.
if (tmpSourceSamplePosition >= tmpSampleEndDbl || v->ampenv.segment == TSF_SEGMENT_DONE)
The part tmpSourceSamplePosition >= tmpSampleEndDbl means the sample hasn't looped and has played to its end. The second part v->ampenv.segment == TSF_SEGMENT_DONE means the voice has been stopped and the amplitude envelope has finished all its segments (decay, sustain and release). Both cases where you don't want the voice to play anything further (thus its getting killed).
The line you annotated with "PROBLEMATIC LINE" is not problematic. It just stops repeating another loop done the next time the voice is processed in tsf_voice_render. Check this line from that function:
TSF_BOOL isLooping = (v->loopStart < v->loopEnd);
So after the "problematic line" this will result in isLooping being false and the voice ending its amplitude envelope like it should.
If you have a problematic soundfont, use a tool like Viena SoundFont editor to create a small culled version, ideally with a single instrument, and replace any samples that might be under copyright then share it here so others can reproduce the bug (and find the correct fix).