From 2e07cf29a050025e7af106cd31721e413509d166 Mon Sep 17 00:00:00 2001 From: Chris Moeller Date: Fri, 18 Oct 2013 21:01:19 -0700 Subject: [PATCH] Added sflist channel and preset redirection control, just like foo_midi --- Plugins/MIDI/MIDI/BMPlayer.cpp | 219 ++++++++++++++++++++++++++++++--- Plugins/MIDI/MIDI/BMPlayer.h | 3 +- 2 files changed, 204 insertions(+), 18 deletions(-) diff --git a/Plugins/MIDI/MIDI/BMPlayer.cpp b/Plugins/MIDI/MIDI/BMPlayer.cpp index 43cdef4f8..ab04adc66 100644 --- a/Plugins/MIDI/MIDI/BMPlayer.cpp +++ b/Plugins/MIDI/MIDI/BMPlayer.cpp @@ -1,5 +1,7 @@ #include "BMPlayer.h" +#include + #include #include @@ -244,6 +246,8 @@ void BMPlayer::send_event(uint32_t b) unsigned command = b & 0xF0; unsigned event_length = ( command == 0xC0 || command == 0xD0 ) ? 2 : 3; channel += 16 * port; + channel %= 48; + if ( command == 0xB0 && event[ 1 ] == 0x20 ) return; BASS_MIDI_StreamEvents( _stream, BASS_MIDI_EVENTS_RAW + 1 + channel, event, event_length ); if ( command == 0xB0 && event[ 1 ] == 0 ) { @@ -280,7 +284,7 @@ void BMPlayer::send_event(uint32_t b) is_gs_reset( data, size ) || ( size == _countof( sysex_xg_reset ) && !memcmp( data, sysex_xg_reset, _countof( sysex_xg_reset ) ) ) ) { - reset_drum_channels(); + reset_parameters(); synth_mode = ( size == _countof( sysex_xg_reset ) ) ? mode_xg : ( size == _countof( sysex_gs_reset ) ) ? mode_gs : ( data [4] == 0x01 ) ? mode_gm : @@ -347,6 +351,8 @@ bool BMPlayer::startup() { return false; } + memset( bank_lsb_override, 0, sizeof( bank_lsb_override ) ); + std::vector presetList; if (sSoundFontName.length()) { std::string ext; @@ -364,7 +370,8 @@ bool BMPlayer::startup() shutdown(); return false; } - _soundFonts.push_back( font ); + _soundFonts.push_back( font ); + presetList.push_back( {font, -1, -1, -1, 0, 0} ); } else if ( !strcasecmp( ext.c_str(), "sflist" ) ) { @@ -373,24 +380,197 @@ bool BMPlayer::startup() { std::string path, temp; char name[32768]; + char *nameptr; size_t slash = sSoundFontName.find_last_of('/'); if ( slash != std::string::npos ) path.assign( sSoundFontName.begin(), sSoundFontName.begin() + slash + 1 ); while ( !feof( fl ) ) { + std::vector presets; + if ( !fgets( name, 32767, fl ) ) break; name[32767] = 0; char * cr = strchr( name, '\n' ); if ( cr ) *cr = 0; cr = strchr( name, '\r' ); if ( cr ) *cr = 0; - if ( name[0] == '/' ) + cr = strchr( name, '|' ); + if ( cr ) + { + long dbank = 0, dpreset = -1, sbank = -1, spreset = -1; + std::vector channels; + bool valid = true; + bool pushed_back = true; + char *endchr; + nameptr = cr + 1; + *cr = 0; + cr = name; + while ( *cr && valid ) + { + switch ( *cr++ ) + { + case 'p': + { + // patch override - "p[db#,]dp#=[sb#,]sp#" ex. "p0,5=0,1" + // may be used once per preset group + pushed_back = false; + dbank = 0; + dpreset = strtol( cr, &endchr, 10 ); + if ( endchr == cr ) + { + valid = false; + break; + } + if ( *endchr == ',' ) + { + dbank = dpreset; + cr = endchr + 1; + dpreset = strtol( cr, &endchr, 10 ); + if ( endchr == cr ) + { + valid = false; + break; + } + } + if ( *endchr != '=' ) + { + valid = false; + break; + } + cr = endchr + 1; + sbank = -1; + spreset = strtol( cr, &endchr, 10 ); + if ( endchr == cr ) + { + valid = false; + break; + } + if ( *endchr == ',' ) + { + sbank = spreset; + cr = endchr + 1; + spreset = strtol( cr, &endchr, 10 ); + if ( endchr == cr ) + { + cr = nameptr - 1; + break; + } + } + if ( *endchr && *endchr != ';' && *endchr != '&' ) + { + cr = nameptr - 1; + break; + } + cr = endchr; + } + break; + + case 'c': + { + // channel override - implemented using bank LSB, which is disabled from + // actual use. - format "c#" ex. "c16" (range is 1-48) + // may be used multiple times per preset group + pushed_back = false; + long channel = strtol(cr, &endchr, 10); + if ( endchr == cr ) + { + valid = false; + break; + } + if ( channel < 1 || channel > 48 ) + { + valid = false; + break; + } + for ( auto it = channels.begin(); it != channels.end(); ++it ) + { + if ( *it == channel ) + { + valid = false; + break; + } + } + if ( *endchr && *endchr != ';' ) + { + valid = false; + break; + } + cr = endchr; + channels.push_back( channel ); + } + break; + + case '&': + { + // separates preset groups per SoundFont bank + if ( !pushed_back ) + { + if ( channels.size() ) + { + for ( auto it = channels.begin(); it != channels.end(); ++it ) + { + bank_lsb_override[ *it - 1 ] = *it; + + int dbanklsb = (int) *it; + presets.push_back( { 0, (int) spreset, (int) sbank, (int) dpreset, (int) dbank, dbanklsb } ); + } + } + else + { + presets.push_back( { 0, (int) spreset, (int) sbank, (int) dpreset, (int) dbank, 0 } ); + } + sbank = -1; spreset = -1; dpreset = -1; dbank = 0; channels.clear(); + pushed_back = true; + } + } + break; + + case ';': + // separates preset items + break; + + default: + // invalid command character + valid = false; + break; + } + } + if ( !pushed_back && valid ) + { + if ( channels.size() ) + { + for ( auto it = channels.begin(); it != channels.end(); ++it ) + { + bank_lsb_override[ *it - 1 ] = *it; + + int dbanklsb = (int) *it; + presets.push_back( { 0, (int) spreset, (int) sbank, (int) dpreset, (int) dbank, dbanklsb } ); + } + } + else + { + presets.push_back( { 0, (int) spreset, (int) sbank, (int) dpreset, (int) dbank, 0 } ); + } + } + if ( !valid ) + { + presets.clear(); + presets.push_back( { 0, -1, -1, -1, 0, 0 } ); + memset( bank_lsb_override, 0, sizeof(bank_lsb_override) ); + } + } + else + { + presets.push_back( { 0, -1, -1, -1, 0, 0 } ); + nameptr = name; + } + if ( nameptr[0] == '/' ) { - temp = name; + temp = nameptr; } else { temp = path; - temp += name; + temp += nameptr; } HSOUNDFONT font = cache_open( temp.c_str() ); if ( !font ) @@ -399,7 +579,12 @@ bool BMPlayer::startup() shutdown(); return false; } - _soundFonts.push_back( font ); + for ( auto it = presets.begin(); it != presets.end(); ++it ) + { + it->font = font; + presetList.push_back( *it ); + } + _soundFonts.push_back( font ); } fclose( fl ); } @@ -418,28 +603,25 @@ bool BMPlayer::startup() shutdown(); return false; } - _soundFonts.push_back( font ); + _soundFonts.push_back( font ); + presetList.push_back( { font, -1, -1, -1, 0, 0 } ); } - std::vector< BASS_MIDI_FONT > fonts; - for ( unsigned long i = 0, j = _soundFonts.size(); i < j; ++i ) + std::vector< BASS_MIDI_FONTEX > fonts; + for ( unsigned long i = 0, j = presetList.size(); i < j; ++i ) { - BASS_MIDI_FONT sf; - sf.font = _soundFonts[ j - i - 1 ]; - sf.preset = -1; - sf.bank = 0; - fonts.push_back( sf ); + fonts.push_back( presetList[j - i - 1] ); } - BASS_MIDI_StreamSetFonts( _stream, &fonts[0], (unsigned int) fonts.size() ); + BASS_MIDI_StreamSetFonts( _stream, &fonts[0], (unsigned int) fonts.size() | BASS_MIDI_FONT_EX ); - reset_drum_channels(); + reset_parameters(); synth_mode = mode_gm; return true; } -void BMPlayer::reset_drum_channels() +void BMPlayer::reset_parameters() { static const uint8_t part_to_ch[16] = { 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15 }; @@ -458,4 +640,7 @@ void BMPlayer::reset_drum_channels() BASS_MIDI_StreamEvent( _stream, i, MIDI_EVENT_DRUMS, drum_channels[ i ] ); } } + + for ( unsigned int i = 0; i < 48; ++i ) + BASS_MIDI_StreamEvent( _stream, i, MIDI_EVENT_BANK_LSB, bank_lsb_override[i] ); } diff --git a/Plugins/MIDI/MIDI/BMPlayer.h b/Plugins/MIDI/MIDI/BMPlayer.h index 7f450003e..5c4868cc5 100644 --- a/Plugins/MIDI/MIDI/BMPlayer.h +++ b/Plugins/MIDI/MIDI/BMPlayer.h @@ -26,7 +26,7 @@ private: virtual void shutdown(); virtual bool startup(); - void reset_drum_channels(); + void reset_parameters(); std::vector _soundFonts; std::string sSoundFontName; @@ -47,6 +47,7 @@ private: uint8_t gs_part_to_ch[3][16]; uint8_t drum_channels[48]; + uint8_t bank_lsb_override[48]; }; #endif