ref: 7f29067b40e7069910f1259fefee30f333af2ba4
parent: 2aa076933897c693f2b6c977c521f7b7f21c121d
author: Bernhard Schelling <schellingb@gmail.com>
date: Sun Oct 22 00:59:58 EDT 2017
Added global output panning
--- a/tsf.h
+++ b/tsf.h
@@ -125,9 +125,14 @@
// Setup the parameters for the voice render methods
// outputmode: if mono or stereo and how stereo channel data is ordered
// samplerate: the number of samples per second (output frequency)
-// globalgaindb: volume gain in decibels (>0 means higher, <0 means lower)
-TSFDEF void tsf_set_output(tsf* f, enum TSFOutputMode outputmode, int samplerate, float globalgaindb CPP_DEFAULT0);
+// global_gain_db: volume gain in decibels (>0 means higher, <0 means lower)
+TSFDEF void tsf_set_output(tsf* f, enum TSFOutputMode outputmode, int samplerate, float global_gain_db CPP_DEFAULT0);
+// Adjust global panning values. Mono output will apply the average of both.
+// pan_factor_left: volume gain factor for the left channel
+// pan_factor_right: volume gain factor for the right channel
+TSFDEF void tsf_set_panning(tsf* f, float pan_factor_left, float pan_factor_right);
+
// Start playing a note
// preset_index: preset index >= 0 and < tsf_get_presetcount()
// key: note value between 0 and 127 (60 being middle C)
@@ -236,7 +241,7 @@
float outSampleRate;
enum TSFOutputMode outputmode;
- float globalGainDB;
+ float globalGainDB, globalPanFactorLeft, globalPanFactorRight;
float* outputSamples;
int outputSampleSize;
@@ -899,7 +904,7 @@
if (dynamicPitchRatio) pitchRatio = 0, tmpModLfoToPitch = (float)region->modLfoToPitch, tmpVibLfoToPitch = (float)region->vibLfoToPitch, tmpModEnvToPitch = (float)region->modEnvToPitch;
else pitchRatio = tsf_timecents2Secsd(v->pitchInputTimecents) * v->pitchOutputFactor, tmpModLfoToPitch = 0, tmpVibLfoToPitch = 0, tmpModEnvToPitch = 0;
- if (dynamicGain) noteGain = 0, tmpModLfoToVolume = (float)region->modLfoToVolume * 0.1f;
+ if (dynamicGain) tmpModLfoToVolume = (float)region->modLfoToVolume * 0.1f;
else noteGain = tsf_decibelsToGain(v->noteGainDB), tmpModLfoToVolume = 0;
while (numSamples)
@@ -934,7 +939,7 @@
switch (f->outputmode)
{
case TSF_STEREO_INTERLEAVED:
- gainLeft = gainMono * v->panFactorLeft, gainRight = gainMono * v->panFactorRight;
+ gainLeft = gainMono * f->globalPanFactorLeft * v->panFactorLeft, gainRight = gainMono * f->globalPanFactorRight * v->panFactorRight;
while (blockSamples-- && tmpSourceSamplePosition < tmpSampleEndDbl)
{
unsigned int pos = (unsigned int)tmpSourceSamplePosition, nextPos = (pos >= tmpLoopEnd && isLooping ? tmpLoopStart : pos + 1);
@@ -955,7 +960,7 @@
break;
case TSF_STEREO_UNWEAVED:
- gainLeft = gainMono * v->panFactorLeft, gainRight = gainMono * v->panFactorRight;
+ gainLeft = gainMono * f->globalPanFactorLeft * v->panFactorLeft, gainRight = gainMono * f->globalPanFactorRight * v->panFactorRight;
while (blockSamples-- && tmpSourceSamplePosition < tmpSampleEndDbl)
{
unsigned int pos = (unsigned int)tmpSourceSamplePosition, nextPos = (pos >= tmpLoopEnd && isLooping ? tmpLoopStart : pos + 1);
@@ -976,6 +981,7 @@
break;
case TSF_MONO:
+ gainMono *= (f->globalPanFactorLeft + f->globalPanFactorRight) * .5f;
while (blockSamples-- && tmpSourceSamplePosition < tmpSampleEndDbl)
{
unsigned int pos = (unsigned int)tmpSourceSamplePosition, nextPos = (pos >= tmpLoopEnd && isLooping ? tmpLoopStart : pos + 1);
@@ -1080,6 +1086,7 @@
res->fontSamples = fontSamples;
res->fontSampleCount = fontSampleCount;
res->outSampleRate = 44100.0f;
+ res->globalPanFactorLeft = res->globalPanFactorRight = 1.0f;
fontSamples = TSF_NULL; //don't free below
tsf_load_presets(res, &hydra);
}
@@ -1128,13 +1135,19 @@
return tsf_get_presetname(f, tsf_get_presetindex(f, bank, preset_number));
}
-TSFDEF void tsf_set_output(tsf* f, enum TSFOutputMode outputmode, int samplerate, float globalgaindb)
+TSFDEF void tsf_set_output(tsf* f, enum TSFOutputMode outputmode, int samplerate, float global_gain_db)
{
f->outSampleRate = (float)(samplerate >= 1 ? samplerate : 44100.0f);
f->outputmode = outputmode;
- f->globalGainDB = globalgaindb;
+ f->globalGainDB = global_gain_db;
}
+TSFDEF void tsf_set_panning(tsf* f, float pan_factor_left, float pan_factor_right)
+{
+ f->globalPanFactorLeft = pan_factor_left;
+ f->globalPanFactorRight = pan_factor_right;
+}
+
TSFDEF void tsf_note_on(tsf* f, int preset_index, int key, float vel)
{
int midiVelocity = (int)(vel * 127);
@@ -1141,7 +1154,7 @@
TSF_BOOL haveGroupedNotesPlaying = TSF_FALSE;
struct tsf_voice *v, *vEnd; struct tsf_region *region, *regionEnd;
- if (preset_index < 0 || preset_index >= f->presetNum) return;
+ if (preset_index < 0 || preset_index >= f->presetNum || midiVelocity <= 0) return;
// Are any grouped notes playing? (Needed for group stopping) Also stop any voices still playing this note.
for (v = f->voices, vEnd = v + f->voiceNum; v != vEnd; v++)