2007-05-30 21:56:52 +00:00
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers , whose names
* are too numerous to list here . Please refer to the COPYRIGHT
* file distributed with this source distribution .
2004-11-06 01:41:32 +00:00
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
2005-10-18 01:30:26 +00:00
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
2004-11-06 01:41:32 +00:00
*/
# include "common/scummsys.h"
2011-06-05 18:26:25 +02:00
# include "common/system.h"
2004-11-06 01:41:32 +00:00
# ifdef USE_MT32EMU
2011-02-09 01:09:01 +00:00
# include "audio/softsynth/mt32/mt32emu.h"
2012-12-26 21:17:53 +02:00
# include "audio/softsynth/mt32/ROMInfo.h"
2004-11-06 01:41:32 +00:00
2011-02-09 01:09:01 +00:00
# include "audio/softsynth/emumidi.h"
# include "audio/musicplugin.h"
# include "audio/mpu401.h"
2004-11-06 01:41:32 +00:00
# include "common/config-manager.h"
2009-01-30 05:25:17 +00:00
# include "common/debug.h"
2011-04-24 11:34:27 +03:00
# include "common/error.h"
2007-03-17 00:53:21 +00:00
# include "common/events.h"
# include "common/file.h"
2005-01-10 22:06:49 +00:00
# include "common/system.h"
2007-03-17 00:53:21 +00:00
# include "common/util.h"
2009-09-23 00:15:00 +00:00
# include "common/archive.h"
2011-04-24 11:34:27 +03:00
# include "common/textconsole.h"
2010-06-21 21:36:36 +00:00
# include "common/translation.h"
2004-11-06 01:41:32 +00:00
2005-01-06 21:15:52 +00:00
# include "graphics/fontman.h"
2004-11-28 05:35:07 +00:00
# include "graphics/surface.h"
2011-04-24 11:34:27 +03:00
# include "graphics/pixelformat.h"
# include "graphics/palette.h"
# include "graphics/font.h"
2004-11-28 05:35:07 +00:00
2012-12-26 21:17:53 +02:00
# include "gui/message.h"
namespace MT32Emu {
class ReportHandlerScummVM : public ReportHandler {
friend class Synth ;
public :
virtual ~ ReportHandlerScummVM ( ) { }
protected :
// Callback for debug messages, in vprintf() format
void printDebug ( const char * fmt , va_list list ) {
2013-07-04 14:44:41 +02:00
Common : : String out = Common : : String : : vformat ( fmt , list ) ;
2013-07-06 04:05:22 +01:00
debug ( 4 , " %s " , out . c_str ( ) ) ;
2012-12-26 21:17:53 +02:00
}
// Callbacks for reporting various errors and information
void onErrorControlROM ( ) {
GUI : : MessageDialog dialog ( " MT32emu: Init Error - Missing or invalid Control ROM image " , " OK " ) ;
dialog . runModal ( ) ;
error ( " MT32emu: Init Error - Missing or invalid Control ROM image " ) ;
}
void onErrorPCMROM ( ) {
GUI : : MessageDialog dialog ( " MT32emu: Init Error - Missing PCM ROM image " , " OK " ) ;
dialog . runModal ( ) ;
error ( " MT32emu: Init Error - Missing PCM ROM image " ) ;
}
void showLCDMessage ( const char * message ) {
g_system - > displayMessageOnOSD ( message ) ;
}
void onDeviceReset ( ) { }
void onDeviceReconfig ( ) { }
void onNewReverbMode ( Bit8u /* mode */ ) { }
void onNewReverbTime ( Bit8u /* time */ ) { }
void onNewReverbLevel ( Bit8u /* level */ ) { }
void onPartStateChanged ( int /* partNum */ , bool /* isActive */ ) { }
void onPolyStateChanged ( int /* partNum */ ) { }
void onPartialStateChanged ( int /* partialNum */ , int /* oldPartialPhase */ , int /* newPartialPhase */ ) { }
void onProgramChanged ( int /* partNum */ , char * /* patchName */ ) { }
} ;
} // end of namespace MT32Emu
2004-11-13 19:24:37 +00:00
class MidiChannel_MT32 : public MidiChannel_MPU401 {
void effectLevel ( byte value ) { }
void chorusLevel ( byte value ) { }
} ;
2004-11-06 01:41:32 +00:00
class MidiDriver_MT32 : public MidiDriver_Emulated {
private :
2004-11-13 19:24:37 +00:00
MidiChannel_MT32 _midiChannels [ 16 ] ;
2004-11-08 10:16:07 +00:00
uint16 _channelMask ;
2004-11-06 01:41:32 +00:00
MT32Emu : : Synth * _synth ;
2012-12-26 21:17:53 +02:00
MT32Emu : : ReportHandlerScummVM * _reportHandler ;
2012-12-27 16:34:23 +02:00
const MT32Emu : : ROMImage * _controlROM , * _pcmROM ;
Common : : File * _controlFile , * _pcmFile ;
void deleteMuntStructures ( ) ;
2004-11-06 01:41:32 +00:00
int _outputRate ;
protected :
2004-11-08 10:16:07 +00:00
void generateSamples ( int16 * buf , int len ) ;
2004-11-06 01:41:32 +00:00
public :
2011-05-25 11:17:11 -04:00
bool _initializing ;
2004-11-28 05:35:07 +00:00
2005-05-10 23:48:48 +00:00
MidiDriver_MT32 ( Audio : : Mixer * mixer ) ;
2004-11-06 01:41:32 +00:00
virtual ~ MidiDriver_MT32 ( ) ;
int open ( ) ;
void close ( ) ;
void send ( uint32 b ) ;
2004-11-13 19:24:37 +00:00
void setPitchBendRange ( byte channel , uint range ) ;
2006-02-27 01:59:07 +00:00
void sysEx ( const byte * msg , uint16 length ) ;
2004-11-06 01:41:32 +00:00
uint32 property ( int prop , uint32 param ) ;
MidiChannel * allocateChannel ( ) ;
MidiChannel * getPercussionChannel ( ) ;
// AudioStream API
bool isStereo ( ) const { return true ; }
int getRate ( ) const { return _outputRate ; }
} ;
2004-11-13 19:24:37 +00:00
////////////////////////////////////////
//
// MidiDriver_MT32
//
////////////////////////////////////////
2005-05-10 23:48:48 +00:00
MidiDriver_MT32 : : MidiDriver_MT32 ( Audio : : Mixer * mixer ) : MidiDriver_Emulated ( mixer ) {
2004-11-08 10:16:07 +00:00
_channelMask = 0xFFFF ; // Permit all 16 channels by default
2004-11-06 01:41:32 +00:00
uint i ;
2004-11-08 10:16:07 +00:00
for ( i = 0 ; i < ARRAYSIZE ( _midiChannels ) ; + + i ) {
_midiChannels [ i ] . init ( this , i ) ;
2004-11-06 01:41:32 +00:00
}
2012-12-26 21:17:53 +02:00
_reportHandler = NULL ;
2004-11-06 01:41:32 +00:00
_synth = NULL ;
2004-11-28 05:35:07 +00:00
// Unfortunately bugs in the emulator cause inaccurate tuning
// at rates other than 32KHz, thus we produce data at 32KHz and
2005-05-10 23:48:48 +00:00
// rely on Mixer to convert.
2004-11-13 19:24:37 +00:00
_outputRate = 32000 ; //_mixer->getOutputRate();
2011-05-25 11:17:11 -04:00
_initializing = false ;
2013-05-01 15:36:52 +03:00
// Initialized in open()
_controlROM = NULL ;
_pcmROM = NULL ;
_controlFile = NULL ;
_pcmFile = NULL ;
2004-11-06 01:41:32 +00:00
}
MidiDriver_MT32 : : ~ MidiDriver_MT32 ( ) {
2012-12-27 16:34:23 +02:00
deleteMuntStructures ( ) ;
}
void MidiDriver_MT32 : : deleteMuntStructures ( ) {
2010-01-03 19:37:43 +00:00
delete _synth ;
2012-12-27 16:34:23 +02:00
_synth = NULL ;
2012-12-26 21:17:53 +02:00
delete _reportHandler ;
2012-12-27 16:34:23 +02:00
_reportHandler = NULL ;
if ( _controlROM )
MT32Emu : : ROMImage : : freeROMImage ( _controlROM ) ;
_controlROM = NULL ;
if ( _pcmROM )
MT32Emu : : ROMImage : : freeROMImage ( _pcmROM ) ;
_pcmROM = NULL ;
delete _controlFile ;
_controlFile = NULL ;
delete _pcmFile ;
_pcmFile = NULL ;
2004-11-06 01:41:32 +00:00
}
int MidiDriver_MT32 : : open ( ) {
if ( _isOpen )
return MERR_ALREADY_OPEN ;
MidiDriver_Emulated : : open ( ) ;
2012-12-26 21:17:53 +02:00
_reportHandler = new MT32Emu : : ReportHandlerScummVM ( ) ;
_synth = new MT32Emu : : Synth ( _reportHandler ) ;
2010-04-20 18:29:53 +00:00
Graphics : : PixelFormat screenFormat = g_system - > getScreenFormat ( ) ;
if ( screenFormat . bytesPerPixel = = 1 ) {
const byte dummy_palette [ ] = {
2011-02-13 20:26:02 +01:00
0 , 0 , 0 , // background
0 , 171 , 0 , // border, font
171 , 0 , 0 // fill
2010-04-20 18:29:53 +00:00
} ;
2011-02-07 17:52:38 +00:00
g_system - > getPaletteManager ( ) - > setPalette ( dummy_palette , 0 , 3 ) ;
2010-04-20 18:29:53 +00:00
}
2011-05-25 11:17:11 -04:00
_initializing = true ;
2013-01-06 22:24:27 +02:00
debug ( 4 , _s ( " Initializing MT-32 Emulator " ) ) ;
2012-12-27 16:34:23 +02:00
_controlFile = new Common : : File ( ) ;
2013-02-04 23:13:15 +02:00
if ( ! _controlFile - > open ( " MT32_CONTROL.ROM " ) & & ! _controlFile - > open ( " CM32L_CONTROL.ROM " ) )
error ( " Error opening MT32_CONTROL.ROM / CM32L_CONTROL.ROM " ) ;
2012-12-27 16:34:23 +02:00
_pcmFile = new Common : : File ( ) ;
2013-02-04 23:13:15 +02:00
if ( ! _pcmFile - > open ( " MT32_PCM.ROM " ) & & ! _pcmFile - > open ( " CM32L_PCM.ROM " ) )
error ( " Error opening MT32_PCM.ROM / CM32L_PCM.ROM " ) ;
2012-12-27 16:34:23 +02:00
_controlROM = MT32Emu : : ROMImage : : makeROMImage ( _controlFile ) ;
_pcmROM = MT32Emu : : ROMImage : : makeROMImage ( _pcmFile ) ;
2012-12-26 21:17:53 +02:00
if ( ! _synth - > open ( * _controlROM , * _pcmROM ) )
2004-11-06 01:41:32 +00:00
return MERR_DEVICE_NOT_AVAILABLE ;
2012-02-09 11:29:57 +02:00
double gain = ( double ) ConfMan . getInt ( " midi_gain " ) / 100.0 ;
_synth - > setOutputGain ( 1.0f * gain ) ;
_synth - > setReverbOutputGain ( 0.68f * gain ) ;
2011-05-25 11:17:11 -04:00
_initializing = false ;
2010-04-20 18:29:53 +00:00
if ( screenFormat . bytesPerPixel > 1 )
g_system - > fillScreen ( screenFormat . RGBToColor ( 0 , 0 , 0 ) ) ;
else
g_system - > fillScreen ( 0 ) ;
2004-11-28 05:35:07 +00:00
g_system - > updateScreen ( ) ;
2010-04-20 18:29:53 +00:00
2011-03-21 22:50:21 +01:00
_mixer - > playStream ( Audio : : Mixer : : kSFXSoundType , & _mixerSoundHandle , this , - 1 , Audio : : Mixer : : kMaxChannelVolume , 0 , DisposeAfterUse : : NO , true ) ;
2010-04-20 18:29:53 +00:00
2004-11-06 01:41:32 +00:00
return 0 ;
}
void MidiDriver_MT32 : : send ( uint32 b ) {
_synth - > playMsg ( b ) ;
}
2004-11-13 19:24:37 +00:00
void MidiDriver_MT32 : : setPitchBendRange ( byte channel , uint range ) {
if ( range > 24 ) {
2011-05-02 14:42:08 +02:00
warning ( " setPitchBendRange() called with range > 24: %d " , range ) ;
2004-11-13 19:24:37 +00:00
}
byte benderRangeSysex [ 9 ] ;
benderRangeSysex [ 0 ] = 0x41 ; // Roland
benderRangeSysex [ 1 ] = channel ;
benderRangeSysex [ 2 ] = 0x16 ; // MT-32
benderRangeSysex [ 3 ] = 0x12 ; // Write
benderRangeSysex [ 4 ] = 0x00 ;
benderRangeSysex [ 5 ] = 0x00 ;
benderRangeSysex [ 6 ] = 0x04 ;
benderRangeSysex [ 7 ] = ( byte ) range ;
benderRangeSysex [ 8 ] = MT32Emu : : Synth : : calcSysexChecksum ( & benderRangeSysex [ 4 ] , 4 , 0 ) ;
sysEx ( benderRangeSysex , 9 ) ;
}
2006-02-27 01:59:07 +00:00
void MidiDriver_MT32 : : sysEx ( const byte * msg , uint16 length ) {
2004-11-06 01:41:32 +00:00
if ( msg [ 0 ] = = 0xf0 ) {
_synth - > playSysex ( msg , length ) ;
} else {
_synth - > playSysexWithoutFraming ( msg , length ) ;
}
}
void MidiDriver_MT32 : : close ( ) {
if ( ! _isOpen )
return ;
_isOpen = false ;
2004-11-28 05:35:07 +00:00
// Detach the player callback handler
setTimerCallback ( NULL , NULL ) ;
// Detach the mixer callback handler
2011-03-21 22:50:21 +01:00
_mixer - > stopHandle ( _mixerSoundHandle ) ;
2004-11-06 01:41:32 +00:00
_synth - > close ( ) ;
2012-12-27 16:34:23 +02:00
deleteMuntStructures ( ) ;
2004-11-06 01:41:32 +00:00
}
2004-11-08 10:16:07 +00:00
void MidiDriver_MT32 : : generateSamples ( int16 * data , int len ) {
2004-11-06 01:41:32 +00:00
_synth - > render ( data , len ) ;
}
2004-11-08 10:16:07 +00:00
uint32 MidiDriver_MT32 : : property ( int prop , uint32 param ) {
2004-11-06 01:41:32 +00:00
switch ( prop ) {
2004-11-08 10:16:07 +00:00
case PROP_CHANNEL_MASK :
_channelMask = param & 0xFFFF ;
return 1 ;
2004-11-06 01:41:32 +00:00
}
return 0 ;
}
MidiChannel * MidiDriver_MT32 : : allocateChannel ( ) {
2004-11-13 19:24:37 +00:00
MidiChannel_MT32 * chan ;
2004-11-06 01:41:32 +00:00
uint i ;
2004-11-08 10:16:07 +00:00
for ( i = 0 ; i < ARRAYSIZE ( _midiChannels ) ; + + i ) {
if ( i = = 9 | | ! ( _channelMask & ( 1 < < i ) ) )
2004-11-06 01:41:32 +00:00
continue ;
2004-11-08 10:16:07 +00:00
chan = & _midiChannels [ i ] ;
2004-11-06 01:41:32 +00:00
if ( chan - > allocate ( ) ) {
return chan ;
}
}
return NULL ;
}
MidiChannel * MidiDriver_MT32 : : getPercussionChannel ( ) {
2004-11-08 10:16:07 +00:00
return & _midiChannels [ 9 ] ;
2004-11-06 01:41:32 +00:00
}
2004-11-28 05:35:07 +00:00
// This code should be used when calling the timer callback from the mixer thread is undesirable.
// Note that it results in less accurate timing.
#if 0
class MidiEvent_MT32 {
public :
MidiEvent_MT32 * _next ;
uint32 _msg ; // 0xFFFFFFFF indicates a sysex message
byte * _data ;
uint32 _len ;
MidiEvent_MT32 ( uint32 msg , byte * data , uint32 len ) {
_msg = msg ;
if ( len > 0 ) {
_data = new byte [ len ] ;
memcpy ( _data , data , len ) ;
}
_len = len ;
_next = NULL ;
}
MidiEvent_MT32 ( ) {
if ( _len > 0 )
delete _data ;
}
} ;
class MidiDriver_ThreadedMT32 : public MidiDriver_MT32 {
private :
2005-01-28 22:05:51 +00:00
OSystem : : Mutex _eventMutex ;
2004-11-28 05:35:07 +00:00
MidiEvent_MT32 * _events ;
2006-06-24 09:34:49 +00:00
TimerManager : : TimerProc _timer_proc ;
2004-11-28 05:35:07 +00:00
void pushMidiEvent ( MidiEvent_MT32 * event ) ;
MidiEvent_MT32 * popMidiEvent ( ) ;
protected :
void send ( uint32 b ) ;
2006-02-27 01:59:07 +00:00
void sysEx ( const byte * msg , uint16 length ) ;
2004-11-28 05:35:07 +00:00
public :
2005-05-10 23:48:48 +00:00
MidiDriver_ThreadedMT32 ( Audio : : Mixer * mixer ) ;
2004-11-28 05:35:07 +00:00
void onTimer ( ) ;
void close ( ) ;
2006-06-24 09:34:49 +00:00
void setTimerCallback ( void * timer_param , TimerManager : : TimerProc timer_proc ) ;
2004-11-28 05:35:07 +00:00
} ;
2005-05-10 23:48:48 +00:00
MidiDriver_ThreadedMT32 : : MidiDriver_ThreadedMT32 ( Audio : : Mixer * mixer ) : MidiDriver_MT32 ( mixer ) {
2004-11-28 05:35:07 +00:00
_events = NULL ;
_timer_proc = NULL ;
}
void MidiDriver_ThreadedMT32 : : close ( ) {
MidiDriver_MT32 : : close ( ) ;
while ( ( popMidiEvent ( ) ! = NULL ) ) {
// Just eat any leftover events
}
}
2006-06-24 09:34:49 +00:00
void MidiDriver_ThreadedMT32 : : setTimerCallback ( void * timer_param , TimerManager : : TimerProc timer_proc ) {
2004-11-28 05:35:07 +00:00
if ( ! _timer_proc | | ! timer_proc ) {
if ( _timer_proc )
2006-10-22 15:42:29 +00:00
_vm - > _timer - > removeTimerProc ( _timer_proc ) ;
2004-11-28 05:35:07 +00:00
_timer_proc = timer_proc ;
if ( timer_proc )
2011-08-05 10:15:20 +01:00
_vm - > _timer - > installTimerProc ( timer_proc , getBaseTempo ( ) , timer_param , " MT32tempo " ) ;
2004-11-28 05:35:07 +00:00
}
}
void MidiDriver_ThreadedMT32 : : pushMidiEvent ( MidiEvent_MT32 * event ) {
2005-01-28 22:05:51 +00:00
Common : : StackLock lock ( _eventMutex ) ;
2004-11-28 05:35:07 +00:00
if ( _events = = NULL ) {
_events = event ;
} else {
MidiEvent_MT32 * last = _events ;
while ( last - > _next ! = NULL )
last = last - > _next ;
last - > _next = event ;
}
}
MidiEvent_MT32 * MidiDriver_ThreadedMT32 : : popMidiEvent ( ) {
2005-01-28 22:05:51 +00:00
Common : : StackLock lock ( _eventMutex ) ;
2004-11-28 05:35:07 +00:00
MidiEvent_MT32 * event ;
event = _events ;
if ( event ! = NULL )
_events = event - > _next ;
return event ;
}
void MidiDriver_ThreadedMT32 : : send ( uint32 b ) {
MidiEvent_MT32 * event = new MidiEvent_MT32 ( b , NULL , 0 ) ;
pushMidiEvent ( event ) ;
}
2006-02-27 01:59:07 +00:00
void MidiDriver_ThreadedMT32 : : sysEx ( const byte * msg , uint16 length ) {
2004-11-28 05:35:07 +00:00
MidiEvent_MT32 * event = new MidiEvent_MT32 ( 0xFFFFFFFF , msg , length ) ;
pushMidiEvent ( event ) ;
}
void MidiDriver_ThreadedMT32 : : onTimer ( ) {
MidiEvent_MT32 * event ;
while ( ( event = popMidiEvent ( ) ) ! = NULL ) {
if ( event - > _msg = = 0xFFFFFFFF ) {
MidiDriver_MT32 : : sysEx ( event - > _data , event - > _len ) ;
} else {
MidiDriver_MT32 : : send ( event - > _msg ) ;
}
delete event ;
}
}
# endif
2008-05-14 14:56:29 +00:00
// Plugin interface
2008-06-13 16:04:43 +00:00
class MT32EmuMusicPlugin : public MusicPluginObject {
2008-05-14 14:56:29 +00:00
public :
2008-06-13 16:04:43 +00:00
const char * getName ( ) const {
2010-06-21 21:36:36 +00:00
return _s ( " MT-32 Emulator " ) ;
2008-05-14 14:56:29 +00:00
}
2008-06-13 16:04:43 +00:00
const char * getId ( ) const {
2008-05-14 14:56:29 +00:00
return " mt32 " ;
}
2008-06-13 16:04:43 +00:00
MusicDevices getDevices ( ) const ;
2011-06-05 18:26:25 +02:00
bool checkDevice ( MidiDriver : : DeviceHandle ) const ;
2010-06-21 21:36:36 +00:00
Common : : Error createInstance ( MidiDriver * * mididriver , MidiDriver : : DeviceHandle = 0 ) const ;
2008-05-14 14:56:29 +00:00
} ;
2008-06-13 16:04:43 +00:00
MusicDevices MT32EmuMusicPlugin : : getDevices ( ) const {
MusicDevices devices ;
devices . push_back ( MusicDevice ( this , " " , MT_MT32 ) ) ;
return devices ;
}
2011-06-05 18:26:25 +02:00
bool MT32EmuMusicPlugin : : checkDevice ( MidiDriver : : DeviceHandle ) const {
if ( ! ( ( Common : : File : : exists ( " MT32_CONTROL.ROM " ) & & Common : : File : : exists ( " MT32_PCM.ROM " ) ) | |
( Common : : File : : exists ( " CM32L_CONTROL.ROM " ) & & Common : : File : : exists ( " CM32L_PCM.ROM " ) ) ) ) {
2011-06-06 16:05:55 +02:00
warning ( " The MT-32 emulator requires one of the two following file sets (not bundled with ScummVM): \n Either 'MT32_CONTROL.ROM' and 'MT32_PCM.ROM' or 'CM32L_CONTROL.ROM' and 'CM32L_PCM.ROM' " ) ;
2011-06-05 18:26:25 +02:00
return false ;
}
2011-06-20 00:59:48 +02:00
return true ;
2011-06-05 18:26:25 +02:00
}
2010-06-21 21:36:36 +00:00
Common : : Error MT32EmuMusicPlugin : : createInstance ( MidiDriver * * mididriver , MidiDriver : : DeviceHandle ) const {
2005-07-30 21:11:48 +00:00
if ( ConfMan . hasKey ( " extrapath " ) )
2009-09-23 00:15:00 +00:00
SearchMan . addDirectory ( " extrapath " , ConfMan . get ( " extrapath " ) ) ;
2008-05-14 14:56:29 +00:00
2010-06-21 21:36:36 +00:00
* mididriver = new MidiDriver_MT32 ( g_system - > getMixer ( ) ) ;
2008-05-14 14:56:29 +00:00
2010-06-21 21:36:36 +00:00
return Common : : kNoError ;
2004-11-06 01:41:32 +00:00
}
2008-05-14 14:56:29 +00:00
//#if PLUGIN_ENABLED_DYNAMIC(MT32)
2008-06-13 16:04:43 +00:00
//REGISTER_PLUGIN_DYNAMIC(MT32, PLUGIN_TYPE_MUSIC, MT32EmuMusicPlugin);
2008-05-14 14:56:29 +00:00
//#else
2008-06-13 16:04:43 +00:00
REGISTER_PLUGIN_STATIC ( MT32 , PLUGIN_TYPE_MUSIC , MT32EmuMusicPlugin ) ;
2008-05-14 14:56:29 +00:00
//#endif
2004-11-06 01:41:32 +00:00
# endif