Update FluidSynth code, changing default gain, and letting it handle SysEx messages on its own

CQTexperiment
Christopher Snowhill 2021-05-06 13:35:24 -07:00
parent 9c58f67c48
commit 1a95c234b2
2 changed files with 73 additions and 153 deletions

View File

@ -12,42 +12,24 @@
#define _countof(x) (sizeof((x))/sizeof(((x)[0])))
static const uint8_t sysex_gm_reset[] = { 0xF0, 0x7E, 0x7F, 0x09, 0x01, 0xF7 };
static const uint8_t sysex_gm2_reset[]= { 0xF0, 0x7E, 0x7F, 0x09, 0x03, 0xF7 };
static const uint8_t sysex_gs_reset[] = { 0xF0, 0x41, 0x10, 0x42, 0x12, 0x40, 0x00, 0x7F, 0x00, 0x41, 0xF7 };
static const uint8_t sysex_xg_reset[] = { 0xF0, 0x43, 0x10, 0x4C, 0x00, 0x00, 0x7E, 0x00, 0xF7 };
static bool is_gs_reset(const unsigned char * data, unsigned long size)
{
if ( size != _countof( sysex_gs_reset ) ) return false;
if ( memcmp( data, sysex_gs_reset, 5 ) != 0 ) return false;
if ( memcmp( data + 7, sysex_gs_reset + 7, 2 ) != 0 ) return false;
if ( ( ( data[ 5 ] + data[ 6 ] + 1 ) & 127 ) != data[ 9 ] ) return false;
if ( data[ 10 ] != sysex_gs_reset[ 10 ] ) return false;
return true;
}
SFPlayer::SFPlayer() : MIDIPlayer()
{
_synth = 0;
_synth[0] = 0;
_synth[1] = 0;
_synth[2] = 0;
uInterpolationMethod = FLUID_INTERP_DEFAULT;
reset_drums();
synth_mode = mode_gm;
_settings = new_fluid_settings();
fluid_settings_setnum(_settings, "synth.gain", 1.0);
fluid_settings_setnum(_settings, "synth.gain", 0.2);
fluid_settings_setnum(_settings, "synth.sample-rate", 44100);
fluid_settings_setint(_settings, "synth.midi-channels", 48);
fluid_settings_setint(_settings, "synth.midi-channels", 16);
}
SFPlayer::~SFPlayer()
{
if (_synth) delete_fluid_synth(_synth);
for (unsigned int i = 0; i < 3; ++i)
if (_synth[i]) delete_fluid_synth(_synth[i]);
if (_settings) delete_fluid_settings(_settings);
}
@ -55,7 +37,8 @@ void SFPlayer::setInterpolationMethod(unsigned method)
{
shutdown();
uInterpolationMethod = method;
if ( _synth ) fluid_synth_set_interp_method( _synth, -1, method );
for (unsigned int i = 0; i < 3; ++i)
if ( _synth[i] ) fluid_synth_set_interp_method( _synth[i], -1, method );
}
void SFPlayer::send_event(uint32_t b)
@ -67,9 +50,10 @@ void SFPlayer::send_event(uint32_t b)
int cmd = b & 0xF0;
int chan = b & 0x0F;
int port = (b >> 24) & 0x7F;
fluid_synth_t* _synth = this->_synth[0];
if ( port && port < 3 )
chan += port * 16;
_synth = this->_synth[port];
switch (cmd)
{
@ -83,28 +67,8 @@ void SFPlayer::send_event(uint32_t b)
break;
case 0xB0:
fluid_synth_cc(_synth, chan, param1, param2);
if ( param1 == 0 || param1 == 0x20 )
{
unsigned bank = channel_banks[ chan ];
if ( param1 == 0x20 ) bank = ( bank & 0x3F80 ) | ( param2 & 0x7F );
else bank = ( bank & 0x007F ) | ( ( param2 & 0x7F ) << 7 );
channel_banks[ chan ] = bank;
if ( synth_mode == mode_xg )
{
if ( bank == 16256 ) drum_channels [chan] = 1;
else drum_channels [chan] = 0;
}
else if ( synth_mode == mode_gm2 )
{
if ( bank == 15360 )
drum_channels [chan] = 1;
else if ( bank == 15488 )
drum_channels [chan] = 0;
}
}
break;
case 0xC0:
if ( drum_channels [chan] ) fluid_synth_bank_select(_synth, chan, 16256 /*DRUM_INST_BANK*/);
fluid_synth_program_change(_synth, chan, param1);
break;
case 0xD0:
@ -123,49 +87,33 @@ void SFPlayer::send_event(uint32_t b)
mSysexMap.get_entry( n, data, size, port );
if (port >= 3)
port = 0;
if ( ( size == _countof( sysex_gm_reset ) && !memcmp( data, sysex_gm_reset, _countof( sysex_gm_reset ) ) ) ||
( size == _countof( sysex_gm2_reset ) && !memcmp( data, sysex_gm2_reset, _countof( sysex_gm2_reset ) ) ) ||
is_gs_reset( data, size ) ||
( size == _countof( sysex_xg_reset ) && !memcmp( data, sysex_xg_reset, _countof( sysex_xg_reset ) ) ) )
{
fluid_synth_system_reset( _synth );
reset_drums();
synth_mode = ( size == _countof( sysex_xg_reset ) ) ? mode_xg :
( size == _countof( sysex_gs_reset ) ) ? mode_gs :
( data [4] == 0x01 ) ? mode_gm :
mode_gm2;
}
else if ( synth_mode == mode_gs && size == 11 &&
data [0] == 0xF0 && data [1] == 0x41 && data [3] == 0x42 &&
data [4] == 0x12 && data [5] == 0x40 && (data [6] & 0xF0) == 0x10 &&
data [10] == 0xF7)
{
if (data [7] == 2)
{
// GS MIDI channel to part assign
gs_part_to_ch [ ( port * 16 ) + ( data [6] & 15 ) ] = data [8];
}
else if ( data [7] == 0x15 )
{
// GS part to rhythm allocation
unsigned int drum_channel = gs_part_to_ch [ ( port * 16 ) + ( data [6] & 15 ) ];
if ( drum_channel < 16 )
{
drum_channels [ ( port * 16 ) + drum_channel ] = data [8];
if ( port == 0 )
{
drum_channels [ 16 + drum_channel ] = data [8];
drum_channels [ 32 + drum_channel ] = data [8];
}
}
}
}
fluid_synth_sysex(_synth[port], (const char *)data, size, NULL, NULL, NULL, 0);
}
}
void SFPlayer::render(float * out, unsigned long count)
{
fluid_synth_write_float(_synth, count, out, 0, 2, out, 1, 2);
unsigned long done = 0;
memset(out, 0, sizeof(float) * 2 * count);
while (done < count)
{
float buffer[512 * 2];
unsigned long todo = count - done;
unsigned long i;
if (todo > 512) todo = 512;
for (unsigned long j = 0; j < 3; ++j)
{
memset(buffer, 0, sizeof(buffer));
fluid_synth_write_float(_synth[j], todo, buffer, 0, 2, buffer, 1, 2);
for (i = 0; i < todo; ++i)
{
out[i * 2 + 0] += buffer[i * 2 + 0];
out[i * 2 + 1] += buffer[i * 2 + 1];
}
}
out += todo * 2;
done += todo;
}
}
void SFPlayer::setSoundFont( const char * in )
@ -182,25 +130,29 @@ void SFPlayer::setFileSoundFont( const char * in )
void SFPlayer::shutdown()
{
if (_synth) delete_fluid_synth(_synth);
_synth = 0;
for (unsigned int i = 0; i < 3; ++i)
{
if (_synth[i]) delete_fluid_synth(_synth[i]);
_synth[i] = 0;
}
}
bool SFPlayer::startup()
{
if ( _synth ) return true;
if ( _synth[0] && _synth[1] && _synth[2] ) return true;
fluid_settings_setnum(_settings, "synth.sample-rate", uSampleRate);
_synth = new_fluid_synth(_settings);
if (!_synth)
for (unsigned int i = 0; i < 3; ++i)
{
_last_error = "Out of memory";
return false;
_synth[i] = new_fluid_synth(_settings);
if (!_synth[i])
{
_last_error = "Out of memory";
return false;
}
fluid_synth_set_interp_method( _synth[i], -1, uInterpolationMethod );
}
fluid_synth_set_interp_method( _synth, -1, uInterpolationMethod );
reset_drums();
synth_mode = mode_gm;
if (sSoundFontName.length())
{
std::string ext;
@ -209,12 +161,15 @@ bool SFPlayer::startup()
ext.assign( sSoundFontName.begin() + dot + 1, sSoundFontName.end() );
if ( !strcasecmp( ext.c_str(), "sf2" ) || !strcasecmp( ext.c_str(), "sf3" ) )
{
if ( FLUID_FAILED == fluid_synth_sfload( _synth, sSoundFontName.c_str(), 1) )
for (unsigned i = 0; i < 3; ++i)
{
shutdown();
_last_error = "Failed to load SoundFont bank: ";
_last_error += sSoundFontName;
return false;
if ( FLUID_FAILED == fluid_synth_sfload( _synth[i], sSoundFontName.c_str(), 1) )
{
shutdown();
_last_error = "Failed to load SoundFont bank: ";
_last_error += sSoundFontName;
return false;
}
}
}
else if ( !strcasecmp( ext.c_str(), "sflist" ) )
@ -244,13 +199,16 @@ bool SFPlayer::startup()
temp = path;
temp += name;
}
if ( FLUID_FAILED == fluid_synth_sfload( _synth, temp.c_str(), 1 ) )
for (unsigned i = 0; i < 3; ++i)
{
fclose( fl );
shutdown();
_last_error = "Failed to load SoundFont bank: ";
_last_error += temp;
return false;
if ( FLUID_FAILED == fluid_synth_sfload( _synth[i], temp.c_str(), 1 ) )
{
fclose( fl );
shutdown();
_last_error = "Failed to load SoundFont bank: ";
_last_error += temp;
return false;
}
}
}
fclose( fl );
@ -266,12 +224,15 @@ bool SFPlayer::startup()
if ( sFileSoundFontName.length() )
{
if ( FLUID_FAILED == fluid_synth_sfload(_synth, sFileSoundFontName.c_str(), 1) )
for (unsigned i = 0; i < 3; ++i)
{
shutdown();
_last_error = "Failed to load SoundFont bank: ";
_last_error += sFileSoundFontName;
return false;
if ( FLUID_FAILED == fluid_synth_sfload(_synth[i], sFileSoundFontName.c_str(), 1) )
{
shutdown();
_last_error = "Failed to load SoundFont bank: ";
_last_error += sFileSoundFontName;
return false;
}
}
}
@ -280,33 +241,6 @@ bool SFPlayer::startup()
return true;
}
void SFPlayer::reset_drums()
{
static const uint8_t part_to_ch[16] = { 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15 };
memset( drum_channels, 0, sizeof( drum_channels ) );
drum_channels [9] = 1;
drum_channels [9+16] = 1;
drum_channels [9+32] = 1;
memcpy( gs_part_to_ch, part_to_ch, sizeof( gs_part_to_ch ) );
memcpy( gs_part_to_ch+16, part_to_ch, sizeof( gs_part_to_ch ) );
memcpy( gs_part_to_ch+32, part_to_ch, sizeof( gs_part_to_ch ) );
memset( channel_banks, 0, sizeof( channel_banks ) );
if ( _synth )
{
for ( unsigned i = 0; i < 48; ++i )
{
if ( drum_channels [i] )
{
fluid_synth_bank_select( _synth, i, 16256 /*DRUM_INST_BANK*/);
}
}
}
}
const char * SFPlayer::GetLastError() const
{
if ( _last_error.length() ) return _last_error.c_str();

View File

@ -39,25 +39,11 @@ private:
std::string _last_error;
fluid_settings_t * _settings;
fluid_synth_t * _synth;
fluid_synth_t * _synth[3];
std::string sSoundFontName;
std::string sFileSoundFontName;
unsigned uInterpolationMethod;
enum
{
mode_gm = 0,
mode_gm2,
mode_gs,
mode_xg
}
synth_mode;
void reset_drums();
uint8_t drum_channels[48];
uint8_t gs_part_to_ch[48];
unsigned short channel_banks[48];
};
#endif /* SFPlayer_h */