shithub: sf2mid

Download patch

ref: 8d5e0448baaa1cb6de7fc45d2d74289f207b8db4
parent: 92ad83700763106cadfdfafd24090160710bcae2
author: Bernhard Schelling <schellingb@gmail.com>
date: Thu Mar 22 14:38:55 EDT 2018

MIDI controls update
- Correct bank selection when using bank selection with just one control message (MSB without LSB)
- Better volume curve for MIDI controlled volume/expression
- Able to handle special rules of MIDI drum channel directly in tsf_channel_set_presetnumber

--- a/examples/example3.c
+++ b/examples/example3.c
@@ -28,15 +28,8 @@
 		{
 			switch (g_MidiMessage->type)
 			{
-				case TML_PROGRAM_CHANGE: //channel program (preset) change
-					if (g_MidiMessage->channel == 9)
-					{
-						//10th MIDI channel uses percussion sound bank (128)
-						if (!tsf_channel_set_bank_preset(g_TinySoundFont, 9, 128, g_MidiMessage->program))
-							if (!tsf_channel_set_bank_preset(g_TinySoundFont, 9, 128, 0))
-								tsf_channel_set_presetnumber(g_TinySoundFont, 9, g_MidiMessage->program);
-					}
-					else tsf_channel_set_presetnumber(g_TinySoundFont, g_MidiMessage->channel, g_MidiMessage->program);
+				case TML_PROGRAM_CHANGE: //channel program (preset) change (special handling for 10th MIDI channel with drums)
+					tsf_channel_set_presetnumber(g_TinySoundFont, g_MidiMessage->channel, g_MidiMessage->program, (g_MidiMessage->channel == 9));
 					break;
 				case TML_NOTE_ON: //play a note
 					tsf_channel_note_on(g_TinySoundFont, g_MidiMessage->channel, g_MidiMessage->key, g_MidiMessage->velocity / 127.0f);
--- a/tsf.h
+++ b/tsf.h
@@ -158,10 +158,11 @@
 TSFDEF void tsf_render_float(tsf* f, float* buffer, int samples, int flag_mixing CPP_DEFAULT0);
 
 // Higher level channel based functions, set up channel parameters
+//   channel: channel number
 //   preset_index: preset index >= 0 and < tsf_get_presetcount()
-//   bank: instrument bank number (alternative to preset_index)
 //   preset_number: preset number (alternative to preset_index)
-//   channel: channel number
+//   flag_mididrums: 0 for normal channels, otherwise apply MIDI drum channel rules
+//   bank: instrument bank number (alternative to preset_index)
 //   pan: stereo panning value from 0.0 (left) to 1.0 (right) (default 0.5 center)
 //   volume: linear volume scale factor (default 1.0 full)
 //   pitch_wheel: pitch wheel position 0 to 16383 (default 8192 unpitched)
@@ -169,7 +170,7 @@
 //   tuning: tuning of all playing voices in semitones (default 0.0 standard (A440) tuning)
 //   (set_preset_number and set_bank_preset return 0 if preset does not exist, otherwise 1)
 TSFDEF void tsf_channel_set_presetindex(tsf* f, int channel, int preset_index);
-TSFDEF int  tsf_channel_set_presetnumber(tsf* f, int channel, int preset_number);
+TSFDEF int  tsf_channel_set_presetnumber(tsf* f, int channel, int preset_number, int flag_mididrums CPP_DEFAULT0);
 TSFDEF void tsf_channel_set_bank(tsf* f, int channel, int bank);
 TSFDEF int  tsf_channel_set_bank_preset(tsf* f, int channel, int bank, int preset_number);
 TSFDEF void tsf_channel_set_pan(tsf* f, int channel, float pan);
@@ -1434,10 +1435,18 @@
 	tsf_channel_init(f, channel)->presetIndex = (unsigned short)preset_index;
 }
 
-TSFDEF int tsf_channel_set_presetnumber(tsf* f, int channel, int preset_number)
+TSFDEF int tsf_channel_set_presetnumber(tsf* f, int channel, int preset_number, int flag_mididrums)
 {
 	struct tsf_channel *c = tsf_channel_init(f, channel);
-	int preset_index = tsf_get_presetindex(f, c->bank, preset_number);
+	int preset_index;
+	if (flag_mididrums)
+	{
+		preset_index = tsf_get_presetindex(f, 128 | (c->bank & 0x7FFF), preset_number);
+		if (preset_index == -1) preset_index = tsf_get_presetindex(f, 128, preset_number);
+		if (preset_index == -1) preset_index = tsf_get_presetindex(f, 128, 0);
+		if (preset_index == -1) preset_index = tsf_get_presetindex(f, (c->bank & 0x7FFF), preset_number);
+	}
+	else preset_index = tsf_get_presetindex(f, (c->bank & 0x7FFF), preset_number);
 	if (preset_index == -1) preset_index = tsf_get_presetindex(f, 0, preset_number);
 	if (preset_index != -1) { c->presetIndex = preset_index; return 1; }
 	return 0;
@@ -1561,10 +1570,10 @@
 		case  43 /*EXPRESSION_LSB*/  : c->midiExpression = (c->midiExpression & 0x3F80) |  control_value;       goto TCMC_SET_VOLUME;
 		case  10 /*PAN_MSB*/         : c->midiPan        = (c->midiPan        & 0x7F  ) | (control_value << 7); goto TCMC_SET_PAN;
 		case  42 /*PAN_LSB*/         : c->midiPan        = (c->midiPan        & 0x3F80) |  control_value;       goto TCMC_SET_PAN;
-		case   0 /*BANK_SELECT_MSB*/ : c->bank           = (c->bank           & 0x7F  ) | (control_value << 7); return;
-		case  32 /*BANK_SELECT_LSB*/ : c->bank           = (c->bank           & 0x3F80) |  control_value;       return;
 		case   6 /*DATA_ENTRY_MSB*/  : c->midiData       = (c->midiData       & 0x7F)   | (control_value << 7); goto TCMC_SET_DATA;
 		case  38 /*DATA_ENTRY_LSB*/  : c->midiData       = (c->midiData       & 0x3F80) |  control_value;       goto TCMC_SET_DATA;
+		case   0 /*BANK_SELECT_MSB*/ : c->bank = 0x8000 | control_value; return; //bank select MSB alone acts like LSB
+		case  32 /*BANK_SELECT_LSB*/ : c->bank = (c->bank & 0x8000 ? ((c->bank & 0x7F) << 7) : 0) | control_value; return;
 		case 101 /*RPN_MSB*/         : c->midiRPN = ((c->midiRPN == 0xFFFF ? 0 : c->midiRPN) & 0x7F  ) | (control_value << 7); return;
 		case 100 /*RPN_LSB*/         : c->midiRPN = ((c->midiRPN == 0xFFFF ? 0 : c->midiRPN) & 0x3F80) |  control_value;       return;
 		case  98 /*NRPN_LSB*/        : c->midiRPN = 0xFFFF; return;
@@ -1582,7 +1591,8 @@
 	}
 	return;
 TCMC_SET_VOLUME:
-	tsf_channel_set_volume(f, channel, c->midiVolume / 16383.0f * c->midiExpression / 16383.0f);
+	//Raising to the power of 3 seems to result in a decent sounding volume curve for MIDI
+	tsf_channel_set_volume(f, channel, TSF_POWF((c->midiVolume / 16383.0f) * (c->midiExpression / 16383.0f), 3.0f));
 	return;
 TCMC_SET_PAN:
 	tsf_channel_set_pan(f, channel, c->midiPan / 16383.0f);
@@ -1601,7 +1611,7 @@
 
 TSFDEF int tsf_channel_get_preset_bank(tsf* f, int channel)
 {
-	return (f->channels && channel < f->channels->channelNum ? f->channels->channels[channel].bank : 0);
+	return (f->channels && channel < f->channels->channelNum ? (f->channels->channels[channel].bank & 0x7FFF) : 0);
 }
 
 TSFDEF int tsf_channel_get_preset_number(tsf* f, int channel)