Added a SoundFont handle cache, since BASSMIDI doesn't appear to employ reference counting on its SoundFont handles

CQTexperiment
Chris Moeller 2013-10-15 11:34:55 -07:00
parent 7d600e1911
commit 99c1942eb3
1 changed files with 120 additions and 6 deletions

View File

@ -6,6 +6,11 @@
#include <dlfcn.h> #include <dlfcn.h>
#include <map>
#include <thread>
#include <time.h>
#include <unistd.h>
#define SF2PACK #define SF2PACK
#define _countof(arr) (sizeof(arr) / sizeof((arr)[0])) #define _countof(arr) (sizeof(arr) / sizeof((arr)[0]))
@ -27,6 +32,113 @@ static bool is_gs_reset(const unsigned char * data, unsigned long size)
return true; return true;
} }
struct Cached_SoundFont
{
unsigned long ref_count;
time_t time_released;
HSOUNDFONT handle;
Cached_SoundFont() : handle( 0 ) { }
};
pthread_mutex_t Cache_Lock;
static std::map<std::string, Cached_SoundFont> Cache_List;
bool Cache_Running = false;
std::thread * Cache_Thread = NULL;
void cache_run();
void cache_init()
{
pthread_mutex_init( &Cache_Lock, NULL );
Cache_Thread = new std::thread( cache_run );
}
void cache_deinit()
{
Cache_Running = false;
Cache_Thread->join();
delete Cache_Thread;
for ( auto it = Cache_List.begin(); it != Cache_List.end(); ++it )
{
BASS_MIDI_FontFree( it->second.handle );
}
}
HSOUNDFONT cache_open( const char * path )
{
HSOUNDFONT font = NULL;
pthread_mutex_lock( &Cache_Lock );
Cached_SoundFont & entry = Cache_List[ path ];
if ( !entry.handle )
{
font = BASS_MIDI_FontInit( path, 0 );
if ( font )
{
entry.handle = font;
entry.ref_count = 1;
}
}
else
font = entry.handle;
pthread_mutex_unlock( &Cache_Lock );
return font;
}
void cache_close( HSOUNDFONT handle )
{
pthread_mutex_lock( &Cache_Lock );
for ( auto it = Cache_List.begin(); it != Cache_List.end(); ++it )
{
if ( it->second.handle == handle )
{
if ( --it->second.ref_count == 0 )
time( &it->second.time_released );
break;
}
}
pthread_mutex_unlock( &Cache_Lock );
}
void cache_run()
{
Cache_Running = true;
while ( Cache_Running )
{
time_t now;
time( &now );
pthread_mutex_lock( &Cache_Lock );
for ( auto it = Cache_List.begin(); it != Cache_List.end(); ++it )
{
if ( it->second.ref_count == 0 )
{
if ( difftime( it->second.time_released, now ) >= 10.0 )
{
BASS_MIDI_FontFree( it->second.handle );
Cache_List.erase( it );
}
}
}
pthread_mutex_unlock( &Cache_Lock );
usleep( 250000 );
}
}
class Bass_Initializer class Bass_Initializer
{ {
pthread_mutex_t lock; pthread_mutex_t lock;
@ -45,6 +157,7 @@ public:
{ {
if ( initialized ) if ( initialized )
{ {
cache_deinit();
BASS_Free(); BASS_Free();
} }
pthread_mutex_destroy( &lock ); pthread_mutex_destroy( &lock );
@ -93,6 +206,7 @@ public:
{ {
BASS_SetConfigPtr( BASS_CONFIG_MIDI_DEFFONT, NULL ); BASS_SetConfigPtr( BASS_CONFIG_MIDI_DEFFONT, NULL );
BASS_SetConfig( BASS_CONFIG_MIDI_VOICES, 256 ); BASS_SetConfig( BASS_CONFIG_MIDI_VOICES, 256 );
cache_init();
this->initialized = initialized; this->initialized = initialized;
} }
} }
@ -159,12 +273,12 @@ void BMPlayer::send_event(uint32_t b)
} }
else else
{ {
unsigned long n = b & 0xffffff; uint32_t n = b & 0xffffff;
const uint8_t * data; const uint8_t * data;
std::size_t size, port; std::size_t size, port;
mSysexMap.get_entry( n, data, size, port ); mSysexMap.get_entry( n, data, size, port );
if ( port > 2 ) port = 2; if ( port > 2 ) port = 2;
BASS_MIDI_StreamEvents( _stream, BASS_MIDI_EVENTS_RAW, data, size ); BASS_MIDI_StreamEvents( _stream, BASS_MIDI_EVENTS_RAW, data, (unsigned int) size );
if ( ( size == _countof( sysex_gm_reset ) && !memcmp( data, sysex_gm_reset, _countof( sysex_gm_reset ) ) ) || 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 ) ) ) || ( size == _countof( sysex_gm2_reset ) && !memcmp( data, sysex_gm2_reset, _countof( sysex_gm2_reset ) ) ) ||
is_gs_reset( data, size ) || is_gs_reset( data, size ) ||
@ -223,7 +337,7 @@ void BMPlayer::shutdown()
_stream = NULL; _stream = NULL;
for ( unsigned long i = 0; i < _soundFonts.size(); ++i ) for ( unsigned long i = 0; i < _soundFonts.size(); ++i )
{ {
BASS_MIDI_FontFree( _soundFonts[i] ); cache_close( _soundFonts[i] );
} }
_soundFonts.resize( 0 ); _soundFonts.resize( 0 );
} }
@ -248,7 +362,7 @@ bool BMPlayer::startup()
#endif #endif
) )
{ {
HSOUNDFONT font = BASS_MIDI_FontInit( sSoundFontName.c_str(), 0 ); HSOUNDFONT font = cache_open( sSoundFontName.c_str() );
if ( !font ) if ( !font )
{ {
shutdown(); shutdown();
@ -282,7 +396,7 @@ bool BMPlayer::startup()
temp = path; temp = path;
temp += name; temp += name;
} }
HSOUNDFONT font = BASS_MIDI_FontInit( temp.c_str(), 0 ); HSOUNDFONT font = cache_open( temp.c_str() );
if ( !font ) if ( !font )
{ {
fclose( fl ); fclose( fl );
@ -302,7 +416,7 @@ bool BMPlayer::startup()
if ( sFileSoundFontName.length() ) if ( sFileSoundFontName.length() )
{ {
HSOUNDFONT font = BASS_MIDI_FontInit( sFileSoundFontName.c_str(), 0 ); HSOUNDFONT font = cache_open( sFileSoundFontName.c_str() );
if ( !font ) if ( !font )
{ {
shutdown(); shutdown();