shithub: sf2mid

Download patch

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