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 .
2003-10-02 22:52:57 +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 .
2014-02-18 02:34:17 +01:00
*
2003-10-02 22:52:57 +00:00
* 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 .
2014-02-18 02:34:17 +01:00
*
2003-10-02 22:52:57 +00:00
* 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 .
2003-10-02 22:52:57 +00:00
*
*/
2004-12-02 00:33:42 +00:00
# include "common/config-manager.h"
2011-04-24 11:34:27 +03:00
# include "common/error.h"
2012-02-22 15:33:29 +01:00
# include "common/gui_options.h"
2004-12-02 00:33:42 +00:00
# include "common/str.h"
2006-10-21 12:44:10 +00:00
# include "common/system.h"
2011-04-24 11:34:27 +03:00
# include "common/textconsole.h"
2011-06-06 12:44:28 +02:00
# include "common/translation.h"
2005-01-10 22:35:43 +00:00
# include "common/util.h"
2020-02-19 19:51:53 +02:00
# include "common/file.h"
2011-06-05 22:04:42 +02:00
# include "gui/message.h"
2011-02-09 01:09:01 +00:00
# include "audio/mididrv.h"
# include "audio/musicplugin.h"
2003-10-02 22:52:57 +00:00
2005-04-03 22:01:38 +00:00
const byte MidiDriver : : _mt32ToGm [ 128 ] = {
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
0 , 1 , 0 , 2 , 4 , 4 , 5 , 3 , 16 , 17 , 18 , 16 , 16 , 19 , 20 , 21 , // 0x
6 , 6 , 6 , 7 , 7 , 7 , 8 , 112 , 62 , 62 , 63 , 63 , 38 , 38 , 39 , 39 , // 1x
88 , 95 , 52 , 98 , 97 , 99 , 14 , 54 , 102 , 96 , 53 , 102 , 81 , 100 , 14 , 80 , // 2x
48 , 48 , 49 , 45 , 41 , 40 , 42 , 42 , 43 , 46 , 45 , 24 , 25 , 28 , 27 , 104 , // 3x
32 , 32 , 34 , 33 , 36 , 37 , 35 , 35 , 79 , 73 , 72 , 72 , 74 , 75 , 64 , 65 , // 4x
66 , 67 , 71 , 71 , 68 , 69 , 70 , 22 , 56 , 59 , 57 , 57 , 60 , 60 , 58 , 61 , // 5x
61 , 11 , 11 , 98 , 14 , 9 , 14 , 13 , 12 , 107 , 107 , 77 , 78 , 78 , 76 , 76 , // 6x
47 , 117 , 127 , 118 , 118 , 116 , 115 , 119 , 115 , 112 , 55 , 124 , 123 , 0 , 14 , 117 // 7x
} ;
const byte MidiDriver : : _gmToMt32 [ 128 ] = {
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
5 , 1 , 2 , 7 , 3 , 5 , 16 , 21 , 22 , 101 , 101 , 97 , 104 , 103 , 102 , 20 , // 0x
8 , 9 , 11 , 12 , 14 , 15 , 87 , 15 , 59 , 60 , 61 , 62 , 67 , 44 , 79 , 23 , // 1x
64 , 67 , 66 , 70 , 68 , 69 , 28 , 31 , 52 , 54 , 55 , 56 , 49 , 51 , 57 , 112 , // 2x
48 , 50 , 45 , 26 , 34 , 35 , 45 , 122 , 89 , 90 , 94 , 81 , 92 , 95 , 24 , 25 , // 3x
80 , 78 , 79 , 78 , 84 , 85 , 86 , 82 , 74 , 72 , 76 , 77 , 110 , 107 , 108 , 76 , // 4x
47 , 44 , 111 , 45 , 44 , 34 , 44 , 30 , 32 , 33 , 88 , 34 , 35 , 35 , 38 , 33 , // 5x
41 , 36 , 100 , 37 , 40 , 34 , 43 , 40 , 63 , 21 , 99 , 105 , 103 , 86 , 55 , 84 , // 6x
101 , 103 , 100 , 120 , 117 , 113 , 99 , 128 , 128 , 128 , 128 , 124 , 123 , 128 , 128 , 128 , // 7x
} ;
2003-10-02 22:52:57 +00:00
2020-02-04 16:46:34 +01:00
// This is the drum map for the Roland Sound Canvas SC-55 v1.xx. It had a fallback mechanism
// to correct invalid drumkit selections. Some games rely on this mechanism to select the
// correct Roland GS drumkit. Use this map to emulate this mechanism.
// E.g. correct invalid drumkit 50: _gsDrumkitFallbackMap[50] == 48
const uint8 MidiDriver : : _gsDrumkitFallbackMap [ 128 ] = {
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // STANDARD
8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , // ROOM
16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , // POWER
24 , 25 , 24 , 24 , 24 , 24 , 24 , 24 , // ELECTRONIC; TR-808 (25)
32 , 32 , 32 , 32 , 32 , 32 , 32 , 32 , // JAZZ
40 , 40 , 40 , 40 , 40 , 40 , 40 , 40 , // BRUSH
48 , 48 , 48 , 48 , 48 , 48 , 48 , 48 , // ORCHESTRA
56 , 56 , 56 , 56 , 56 , 56 , 56 , 56 , // SFX
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // No drumkit defined (fall back to STANDARD)
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // No drumkit defined
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // No drumkit defined
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // No drumkit defined
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // No drumkit defined
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // No drumkit defined
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // No drumkit defined
0 , 0 , 0 , 0 , 0 , 0 , 0 , 127 // No drumkit defined; CM-64/32L (127)
} ;
2011-10-23 15:14:41 +01:00
static const struct {
uint32 type ;
const char * guio ;
} GUIOMapping [ ] = {
2012-01-21 15:31:03 +01:00
{ MT_PCSPK , GUIO_MIDIPCSPK } ,
{ MT_CMS , GUIO_MIDICMS } ,
{ MT_PCJR , GUIO_MIDIPCJR } ,
{ MT_ADLIB , GUIO_MIDIADLIB } ,
{ MT_C64 , GUIO_MIDIC64 } ,
{ MT_AMIGA , GUIO_MIDIAMIGA } ,
{ MT_APPLEIIGS , GUIO_MIDIAPPLEIIGS } ,
{ MT_TOWNS , GUIO_MIDITOWNS } ,
{ MT_PC98 , GUIO_MIDIPC98 } ,
{ MT_GM , GUIO_MIDIGM } ,
{ MT_MT32 , GUIO_MIDIMT32 } ,
2011-10-23 15:14:41 +01:00
{ 0 , 0 } ,
2010-06-21 21:36:36 +00:00
} ;
2011-10-23 15:14:41 +01:00
Common : : String MidiDriver : : musicType2GUIO ( uint32 musicType ) {
2011-10-23 20:02:35 +02:00
Common : : String res ;
2003-10-18 00:22:46 +00:00
2011-10-23 15:14:41 +01:00
for ( int i = 0 ; GUIOMapping [ i ] . guio ; i + + ) {
if ( musicType = = GUIOMapping [ i ] . type | | musicType = = ( uint32 ) - 1 )
res + = GUIOMapping [ i ] . guio ;
2010-06-21 21:36:36 +00:00
}
2003-10-18 00:22:46 +00:00
2010-06-21 21:36:36 +00:00
return res ;
}
2007-09-19 08:40:12 +00:00
2010-06-21 21:36:36 +00:00
bool MidiDriver : : _forceTypeMT32 = false ;
2003-10-18 00:22:46 +00:00
2010-06-21 21:36:36 +00:00
MusicType MidiDriver : : getMusicType ( MidiDriver : : DeviceHandle handle ) {
if ( _forceTypeMT32 )
return MT_MT32 ;
if ( handle ) {
2017-11-10 23:06:42 -06:00
const PluginList p = MusicMan . getPlugins ( ) ;
for ( PluginList : : const_iterator m = p . begin ( ) ; m ! = p . end ( ) ; m + + ) {
MusicDevices i = ( * m ) - > get < MusicPluginObject > ( ) . getDevices ( ) ;
2010-06-21 21:36:36 +00:00
for ( MusicDevices : : iterator d = i . begin ( ) ; d ! = i . end ( ) ; d + + ) {
if ( handle = = d - > getHandle ( ) )
return d - > getMusicType ( ) ;
}
2003-10-18 00:22:46 +00:00
}
}
2010-07-21 18:17:51 +00:00
2010-06-29 00:29:35 +00:00
return MT_INVALID ;
2003-10-18 00:22:46 +00:00
}
2004-12-02 00:33:42 +00:00
2010-06-21 21:36:36 +00:00
Common : : String MidiDriver : : getDeviceString ( DeviceHandle handle , DeviceStringType type ) {
if ( handle ) {
2017-11-10 23:06:42 -06:00
const PluginList p = MusicMan . getPlugins ( ) ;
for ( PluginList : : const_iterator m = p . begin ( ) ; m ! = p . end ( ) ; m + + ) {
MusicDevices i = ( * m ) - > get < MusicPluginObject > ( ) . getDevices ( ) ;
2010-06-21 21:36:36 +00:00
for ( MusicDevices : : iterator d = i . begin ( ) ; d ! = i . end ( ) ; d + + ) {
if ( handle = = d - > getHandle ( ) ) {
if ( type = = kDriverName )
return d - > getMusicDriverName ( ) ;
else if ( type = = kDriverId )
return d - > getMusicDriverId ( ) ;
2011-06-06 00:17:24 +02:00
else if ( type = = kDeviceName )
return d - > getCompleteName ( ) ;
2010-06-21 21:36:36 +00:00
else if ( type = = kDeviceId )
return d - > getCompleteId ( ) ;
else
return Common : : String ( " auto " ) ;
}
}
}
}
2005-12-30 14:18:21 +00:00
2010-06-21 21:36:36 +00:00
return Common : : String ( " auto " ) ;
2009-03-26 13:52:43 +00:00
}
2010-06-21 21:36:36 +00:00
MidiDriver : : DeviceHandle MidiDriver : : detectDevice ( int flags ) {
// Query the selected music device (defaults to MT_AUTO device).
2011-07-04 08:32:20 +02:00
Common : : String selDevStr = ConfMan . hasKey ( " music_driver " ) ? ConfMan . get ( " music_driver " ) : Common : : String ( " auto " ) ;
DeviceHandle hdl = getDeviceHandle ( selDevStr . empty ( ) ? Common : : String ( " auto " ) : selDevStr ) ;
2011-06-06 01:15:04 +02:00
DeviceHandle reslt = 0 ;
2009-03-26 13:52:43 +00:00
2010-06-21 21:36:36 +00:00
_forceTypeMT32 = false ;
2005-12-30 14:18:21 +00:00
// Check whether the selected music driver is compatible with the
// given flags.
2010-06-21 21:36:36 +00:00
switch ( getMusicType ( hdl ) ) {
case MT_PCSPK :
if ( flags & MDT_PCSPK )
2011-06-05 18:26:25 +02:00
reslt = hdl ;
2010-06-21 21:36:36 +00:00
break ;
2010-06-22 16:42:49 +00:00
case MT_PCJR :
2010-06-22 15:30:41 +00:00
if ( flags & MDT_PCJR )
2011-06-05 18:26:25 +02:00
reslt = hdl ;
2010-06-22 15:30:41 +00:00
break ;
2010-07-21 18:17:51 +00:00
2010-06-25 18:47:52 +00:00
case MT_CMS :
if ( flags & MDT_CMS )
2011-06-05 18:26:25 +02:00
reslt = hdl ;
2010-06-25 18:47:52 +00:00
break ;
2010-06-22 15:30:41 +00:00
2010-06-21 21:36:36 +00:00
case MT_ADLIB :
if ( flags & MDT_ADLIB )
2011-06-05 18:26:25 +02:00
reslt = hdl ;
2010-06-21 21:36:36 +00:00
break ;
2010-07-21 18:17:51 +00:00
2010-08-11 19:32:07 +00:00
case MT_C64 :
2010-08-11 18:54:56 +00:00
if ( flags & MDT_C64 )
2011-06-05 18:26:25 +02:00
reslt = hdl ;
2010-08-11 18:54:56 +00:00
break ;
2010-08-11 19:32:07 +00:00
case MT_AMIGA :
2010-08-11 18:54:56 +00:00
if ( flags & MDT_AMIGA )
2011-06-05 18:26:25 +02:00
reslt = hdl ;
2010-10-12 02:18:11 +00:00
break ;
2010-08-11 18:54:56 +00:00
2010-08-11 19:32:07 +00:00
case MT_APPLEIIGS :
2010-08-11 18:54:56 +00:00
if ( flags & MDT_APPLEIIGS )
2011-06-05 18:26:25 +02:00
reslt = hdl ;
2010-08-11 18:54:56 +00:00
break ;
2010-06-21 21:36:36 +00:00
case MT_TOWNS :
if ( flags & MDT_TOWNS )
2011-06-05 18:26:25 +02:00
reslt = hdl ;
2010-06-21 21:36:36 +00:00
break ;
2010-06-25 18:47:52 +00:00
case MT_PC98 :
if ( flags & MDT_PC98 )
2011-06-05 18:26:25 +02:00
reslt = hdl ;
2010-06-25 18:47:52 +00:00
break ;
2010-06-21 21:36:36 +00:00
case MT_GM :
case MT_GS :
case MT_MT32 :
if ( flags & MDT_MIDI )
2011-06-05 18:26:25 +02:00
reslt = hdl ;
2010-06-25 18:47:52 +00:00
break ;
2010-06-21 21:36:36 +00:00
case MT_NULL :
2011-06-05 18:26:25 +02:00
reslt = hdl ;
2011-06-07 18:27:13 +02:00
break ;
2005-12-30 14:18:21 +00:00
2010-06-21 21:36:36 +00:00
default :
break ;
}
2005-12-30 14:18:21 +00:00
2011-06-05 18:26:25 +02:00
Common : : String failedDevStr ;
2011-06-07 18:27:13 +02:00
if ( getMusicType ( hdl ) = = MT_INVALID ) {
// If the expressly selected driver or device cannot be found (no longer compiled in, turned off, etc.)
// we display a warning and continue.
2011-07-04 08:32:20 +02:00
failedDevStr = selDevStr ;
2011-08-18 11:08:00 +02:00
Common : : String warningMsg = Common : : String : : format ( _ ( " The selected audio device '%s' was not found (e.g. might be turned off or disconnected). " ) , failedDevStr . c_str ( ) ) + " " + _ ( " Attempting to fall back to the next available device... " ) ;
2011-06-07 18:27:13 +02:00
GUI : : MessageDialog dialog ( warningMsg ) ;
dialog . runModal ( ) ;
}
2011-06-05 18:26:25 +02:00
MusicType tp = getMusicType ( reslt ) ;
if ( tp ! = MT_INVALID & & tp ! = MT_AUTO ) {
if ( checkDevice ( reslt ) ) {
return reslt ;
} else {
2011-06-07 18:27:13 +02:00
// If the expressly selected device cannot be used we display a warning and continue.
2011-06-06 00:17:24 +02:00
failedDevStr = getDeviceString ( hdl , MidiDriver : : kDeviceName ) ;
2011-08-18 11:08:00 +02:00
Common : : String warningMsg = Common : : String : : format ( _ ( " The selected audio device '%s' cannot be used. See log file for more information. " ) , failedDevStr . c_str ( ) ) + " " + _ ( " Attempting to fall back to the next available device... " ) ;
2011-06-05 22:04:42 +02:00
GUI : : MessageDialog dialog ( warningMsg ) ;
dialog . runModal ( ) ;
2011-06-05 18:26:25 +02:00
}
}
2010-06-21 21:36:36 +00:00
// If the selected driver did not match the flags setting,
// we try to determine a suitable and "optimal" music driver.
2017-11-10 23:06:42 -06:00
const PluginList p = MusicMan . getPlugins ( ) ;
2010-06-25 20:51:57 +00:00
// If only MDT_MIDI but not MDT_PREFER_MT32 or MDT_PREFER_GM is set we prefer the other devices (which will always be
2011-06-06 16:05:55 +02:00
// detected since they are hard coded and cannot be disabled).
2011-06-05 18:26:25 +02:00
bool skipMidi = ! ( flags & ( MDT_PREFER_GM | MDT_PREFER_MT32 ) ) ;
while ( flags ! = MDT_NONE ) {
if ( ( flags & MDT_MIDI ) & & ! skipMidi ) {
// If a preferred MT32 or GM device has been selected that device gets returned if available.
2011-06-07 18:27:13 +02:00
Common : : String devStr ;
2011-06-20 00:59:48 +02:00
if ( flags & MDT_PREFER_MT32 )
2011-07-04 08:32:20 +02:00
devStr = ConfMan . hasKey ( " mt32_device " ) ? ConfMan . get ( " mt32_device " ) : Common : : String ( " null " ) ;
2010-06-29 00:30:16 +00:00
else if ( flags & MDT_PREFER_GM )
2011-07-04 08:32:20 +02:00
devStr = ConfMan . hasKey ( " gm_device " ) ? ConfMan . get ( " gm_device " ) : Common : : String ( " null " ) ;
2010-06-29 00:30:16 +00:00
else
2011-06-07 18:27:13 +02:00
devStr = " auto " ;
2012-09-26 04:17:31 +02:00
2011-07-04 08:32:20 +02:00
// Default to Null device here, since we also register a default null setting for
// the MT32 or GM device in the config manager.
hdl = getDeviceHandle ( devStr . empty ( ) ? Common : : String ( " null " ) : devStr ) ;
2010-06-29 00:29:57 +00:00
const MusicType type = getMusicType ( hdl ) ;
2010-06-21 21:36:36 +00:00
2011-05-30 18:34:27 +02:00
// If we have a "Don't use GM/MT-32" setting we skip this part and jump
2010-10-24 19:15:17 +00:00
// to AdLib, PC Speaker etc. detection right away.
if ( type ! = MT_NULL ) {
2011-06-07 18:27:13 +02:00
if ( type = = MT_INVALID ) {
// If the preferred (expressly requested) selected driver or device cannot be found (no longer compiled in, turned off, etc.)
// we display a warning and continue. Don't warn about the missing device if we did already (this becomes relevant if the
// missing device is selected as preferred device and also as GM or MT-32 device).
if ( failedDevStr ! = devStr ) {
2011-08-18 11:08:00 +02:00
Common : : String warningMsg = Common : : String : : format ( _ ( " The preferred audio device '%s' was not found (e.g. might be turned off or disconnected). " ) , devStr . c_str ( ) ) + " " + _ ( " Attempting to fall back to the next available device... " ) ;
2011-06-07 18:27:13 +02:00
GUI : : MessageDialog dialog ( warningMsg ) ;
dialog . runModal ( ) ;
}
} else if ( type ! = MT_AUTO ) {
2011-06-05 18:26:25 +02:00
if ( checkDevice ( hdl ) ) {
if ( flags & MDT_PREFER_MT32 )
// If we have a preferred MT32 device we disable the gm/mt32 mapping (more about this in mididrv.h).
_forceTypeMT32 = true ;
return hdl ;
} else {
2011-06-07 18:27:13 +02:00
// If the preferred (expressly requested) device cannot be used we display a warning and continue.
// Don't warn about the failing device if we did already (this becomes relevant if the failing
2011-06-05 18:26:25 +02:00
// device is selected as preferred device and also as GM or MT-32 device).
2011-06-20 00:59:48 +02:00
if ( failedDevStr ! = getDeviceString ( hdl , MidiDriver : : kDeviceName ) ) {
2011-08-18 11:08:00 +02:00
Common : : String warningMsg = Common : : String : : format ( _ ( " The preferred audio device '%s' cannot be used. See log file for more information. " ) , getDeviceString ( hdl , MidiDriver : : kDeviceName ) . c_str ( ) ) + " " + _ ( " Attempting to fall back to the next available device... " ) ;
2011-06-05 22:04:42 +02:00
GUI : : MessageDialog dialog ( warningMsg ) ;
dialog . runModal ( ) ;
2011-06-05 18:26:25 +02:00
}
}
2010-10-24 19:15:17 +00:00
}
2010-06-22 16:42:49 +00:00
2011-05-30 18:34:27 +02:00
// If no specific device is selected (neither in the scummvm nor in the game domain)
2011-06-05 18:26:25 +02:00
// and there is no preferred MT32 or GM device selected either or if the detected device is unavailable we arrive here.
2011-05-30 18:34:27 +02:00
// If MT32 is preferred we try for the first available device with music type 'MT_MT32' (usually the mt32 emulator).
2010-10-24 19:15:17 +00:00
if ( flags & MDT_PREFER_MT32 ) {
2017-11-10 23:06:42 -06:00
for ( PluginList : : const_iterator m = p . begin ( ) ; m ! = p . end ( ) ; + + m ) {
MusicDevices i = ( * m ) - > get < MusicPluginObject > ( ) . getDevices ( ) ;
2010-10-24 19:15:17 +00:00
for ( MusicDevices : : iterator d = i . begin ( ) ; d ! = i . end ( ) ; + + d ) {
2011-06-05 18:26:25 +02:00
if ( d - > getMusicType ( ) = = MT_MT32 ) {
hdl = d - > getHandle ( ) ;
if ( checkDevice ( hdl ) )
return hdl ;
}
2010-10-24 19:15:17 +00:00
}
}
}
2011-06-20 00:59:48 +02:00
// Now we default to the first available device with music type 'MT_GM' if not
2011-06-05 18:26:25 +02:00
// MT-32 is preferred or if MT-32 is preferred but all other devices have failed.
if ( ! ( flags & MDT_PREFER_MT32 ) | | flags = = ( MDT_PREFER_MT32 | MDT_MIDI ) ) {
2017-11-10 23:06:42 -06:00
for ( PluginList : : const_iterator m = p . begin ( ) ; m ! = p . end ( ) ; + + m ) {
MusicDevices i = ( * m ) - > get < MusicPluginObject > ( ) . getDevices ( ) ;
2011-06-05 18:26:25 +02:00
for ( MusicDevices : : iterator d = i . begin ( ) ; d ! = i . end ( ) ; + + d ) {
if ( d - > getMusicType ( ) = = MT_GM | | d - > getMusicType ( ) = = MT_GS ) {
hdl = d - > getHandle ( ) ;
if ( checkDevice ( hdl ) )
return hdl ;
}
}
2010-06-21 21:36:36 +00:00
}
2011-06-05 18:26:25 +02:00
// Detection flags get removed after final detection attempt to avoid further attempts.
flags & = ~ ( MDT_MIDI | MDT_PREFER_GM | MDT_PREFER_MT32 ) ;
2010-06-21 21:36:36 +00:00
}
}
2010-06-29 00:29:57 +00:00
}
2010-06-22 16:42:49 +00:00
2011-06-05 18:26:25 +02:00
// The order in this list is important, since this is the order of preference
2011-06-06 16:05:55 +02:00
// (e.g. MT_ADLIB is checked before MT_PCJR and MT_PCSPK for a good reason).
2011-06-05 18:26:25 +02:00
// Detection flags get removed after detection attempt to avoid further attempts.
if ( flags & MDT_TOWNS ) {
2010-06-21 21:36:36 +00:00
tp = MT_TOWNS ;
2011-06-05 18:26:25 +02:00
flags & = ~ MDT_TOWNS ;
} else if ( flags & MDT_PC98 ) {
2010-08-11 18:54:56 +00:00
tp = MT_PC98 ;
2011-06-05 18:26:25 +02:00
flags & = ~ MDT_PC98 ;
} else if ( flags & MDT_ADLIB ) {
2010-06-21 21:36:36 +00:00
tp = MT_ADLIB ;
2011-06-05 18:26:25 +02:00
flags & = ~ MDT_ADLIB ;
} else if ( flags & MDT_PCJR ) {
2010-08-11 18:54:56 +00:00
tp = MT_PCJR ;
2011-06-05 18:26:25 +02:00
flags & = ~ MDT_PCJR ;
} else if ( flags & MDT_PCSPK ) {
2010-10-10 07:43:12 +00:00
tp = MT_PCSPK ;
2011-06-05 18:26:25 +02:00
flags & = ~ MDT_PCSPK ;
} else if ( flags & MDT_C64 ) {
2010-08-11 18:54:56 +00:00
tp = MT_C64 ;
2011-06-05 18:26:25 +02:00
flags & = ~ MDT_C64 ;
} else if ( flags & MDT_AMIGA ) {
2010-08-11 18:54:56 +00:00
tp = MT_AMIGA ;
2011-06-05 18:26:25 +02:00
flags & = ~ MDT_AMIGA ;
} else if ( flags & MDT_APPLEIIGS ) {
2010-08-11 18:54:56 +00:00
tp = MT_APPLEIIGS ;
2011-06-05 18:26:25 +02:00
flags & = ~ MDT_APPLEIIGS ;
} else if ( flags & MDT_MIDI ) {
2011-05-30 18:34:27 +02:00
// If we haven't tried to find a MIDI device yet we do this now.
2011-06-05 18:26:25 +02:00
skipMidi = false ;
2010-06-29 21:56:04 +00:00
continue ;
2011-06-05 18:26:25 +02:00
} else if ( flags ) {
// Invalid flags. Set them to MDT_NONE to leave detection loop.
flags = MDT_NONE ;
2010-06-25 18:47:52 +00:00
tp = MT_AUTO ;
2011-06-05 18:26:25 +02:00
}
2010-06-21 21:36:36 +00:00
2017-11-10 23:06:42 -06:00
for ( PluginList : : const_iterator m = p . begin ( ) ; m ! = p . end ( ) ; + + m ) {
MusicDevices i = ( * m ) - > get < MusicPluginObject > ( ) . getDevices ( ) ;
2010-06-29 00:29:57 +00:00
for ( MusicDevices : : iterator d = i . begin ( ) ; d ! = i . end ( ) ; + + d ) {
2011-06-05 18:26:25 +02:00
if ( d - > getMusicType ( ) = = tp ) {
hdl = d - > getHandle ( ) ;
if ( checkDevice ( hdl ) )
return hdl ;
}
2010-06-21 21:36:36 +00:00
}
2005-12-30 14:18:21 +00:00
}
2004-12-02 00:33:42 +00:00
}
2011-06-09 18:15:55 +02:00
return 0 ;
2004-12-02 00:33:42 +00:00
}
2004-12-25 18:34:44 +00:00
2010-06-21 21:36:36 +00:00
MidiDriver * MidiDriver : : createMidi ( MidiDriver : : DeviceHandle handle ) {
MidiDriver * driver = 0 ;
2017-11-10 23:06:42 -06:00
const PluginList p = MusicMan . getPlugins ( ) ;
for ( PluginList : : const_iterator m = p . begin ( ) ; m ! = p . end ( ) ; m + + ) {
const MusicPluginObject & musicPlugin = ( * m ) - > get < MusicPluginObject > ( ) ;
if ( getDeviceString ( handle , MidiDriver : : kDriverId ) . equals ( musicPlugin . getId ( ) ) )
musicPlugin . createInstance ( & driver , handle ) ;
2004-12-25 18:34:44 +00:00
}
2010-06-22 16:42:49 +00:00
2010-06-21 21:36:36 +00:00
return driver ;
}
2011-06-05 18:26:25 +02:00
bool MidiDriver : : checkDevice ( MidiDriver : : DeviceHandle handle ) {
2017-11-10 23:06:42 -06:00
const PluginList p = MusicMan . getPlugins ( ) ;
for ( PluginList : : const_iterator m = p . begin ( ) ; m ! = p . end ( ) ; m + + ) {
const MusicPluginObject & musicPlugin = ( * m ) - > get < MusicPluginObject > ( ) ;
if ( getDeviceString ( handle , MidiDriver : : kDriverId ) . equals ( musicPlugin . getId ( ) ) )
return musicPlugin . checkDevice ( handle ) ;
2011-06-05 18:26:25 +02:00
}
return false ;
}
2010-06-21 21:36:36 +00:00
MidiDriver : : DeviceHandle MidiDriver : : getDeviceHandle ( const Common : : String & identifier ) {
2017-11-10 23:06:42 -06:00
const PluginList p = MusicMan . getPlugins ( ) ;
2010-06-22 18:27:00 +00:00
if ( p . begin ( ) = = p . end ( ) )
2011-05-30 18:34:27 +02:00
error ( " MidiDriver::getDeviceHandle: Music plugins must be loaded prior to calling this method " ) ;
2010-06-22 18:27:00 +00:00
2017-11-10 23:06:42 -06:00
for ( PluginList : : const_iterator m = p . begin ( ) ; m ! = p . end ( ) ; m + + ) {
MusicDevices i = ( * m ) - > get < MusicPluginObject > ( ) . getDevices ( ) ;
2010-06-21 21:36:36 +00:00
for ( MusicDevices : : iterator d = i . begin ( ) ; d ! = i . end ( ) ; d + + ) {
2010-07-26 06:19:57 +00:00
// The music driver id isn't unique, but it will match
// driver's first device. This is useful when selecting
// the driver from the command line.
if ( identifier . equals ( d - > getMusicDriverId ( ) ) | | identifier . equals ( d - > getCompleteId ( ) ) | | identifier . equals ( d - > getCompleteName ( ) ) ) {
2010-06-21 21:36:36 +00:00
return d - > getHandle ( ) ;
2010-06-29 00:29:35 +00:00
}
2010-06-21 21:36:36 +00:00
}
2010-06-22 16:42:49 +00:00
}
2004-12-25 18:34:44 +00:00
2010-06-29 00:29:35 +00:00
return 0 ;
2004-12-25 18:34:44 +00:00
}
MIDI: Send a reset MIDI device signal on startup.
This is currently done in the engine code. I adapted AGI, AGOS, DRACI,
GROOVIE, LURE, MADE, QUEEN, SAGA, SKY, TINSEL and TOUCHE to send a reset
device on startup. The sound output still works fine (started up a game
from every engine), so this should hopefully not introduce any regressions.
As far as I can tell it seems that SCUMM does send a proper device reset, so
I did not touch it. KYRA only sends a proper reset for MT-32 currently. I am
not sure about SCI though.
This fixes bug #3066826 "SIMON: MIDI notes off when using RTL after SCI".
svn-id: r52736
2010-09-15 22:00:20 +00:00
void MidiDriver : : sendMT32Reset ( ) {
static const byte resetSysEx [ ] = { 0x41 , 0x10 , 0x16 , 0x12 , 0x7F , 0x00 , 0x00 , 0x01 , 0x00 } ;
sysEx ( resetSysEx , sizeof ( resetSysEx ) ) ;
g_system - > delayMillis ( 100 ) ;
}
void MidiDriver : : sendGMReset ( ) {
static const byte resetSysEx [ ] = { 0x7E , 0x7F , 0x09 , 0x01 } ;
sysEx ( resetSysEx , sizeof ( resetSysEx ) ) ;
g_system - > delayMillis ( 100 ) ;
}
2020-02-19 19:51:53 +02:00
void MidiDriver_BASE : : midiDumpInit ( ) {
g_system - > displayMessageOnOSD ( _ ( " Starting MIDI dump " ) ) ;
_midiDumpCache . clear ( ) ;
_prevMillis = g_system - > getMillis ( true ) ;
}
int MidiDriver_BASE : : midiDumpVarLength ( const uint32 & delta ) {
// MIDI file format has a very strange representation - "Variable Length Values"
// we're using only *7* bits of each byte for the data
// the MSB bit is 1 for all bytes, except the last one
if ( delta < = 127 ) {
// "Variable Length Values" of 1 byte
debugN ( " 0x%02x " , delta ) ;
_midiDumpCache . push_back ( delta ) ;
return 1 ;
} else {
// "Variable Length Values" of 2 bytes
// theoretically, "Variable Length Values" can have more than 2 bytes, but it won't happen in our use case
byte msb = delta / 128 ;
msb | = 0x80 ;
byte lsb = delta % 128 ;
debugN ( " 0x%02x,0x%02x " , msb , lsb ) ;
_midiDumpCache . push_back ( msb ) ;
_midiDumpCache . push_back ( lsb ) ;
return 2 ;
}
}
void MidiDriver_BASE : : midiDumpDelta ( ) {
uint32 millis = g_system - > getMillis ( true ) ;
uint32 delta = millis - _prevMillis ;
_prevMillis = millis ;
debugN ( " MIDI : delta( " ) ;
int varLength = midiDumpVarLength ( delta ) ;
if ( varLength = = 1 )
debugN ( " ), \t " ) ;
else
debugN ( " ), " ) ;
}
void MidiDriver_BASE : : midiDumpDo ( uint32 b ) {
const byte status = b & 0xff ;
const byte firstOp = ( b > > 8 ) & 0xff ;
const byte secondOp = ( b > > 16 ) & 0xff ;
midiDumpDelta ( ) ;
debugN ( " message(0x%02x 0x%02x " , status , firstOp ) ;
_midiDumpCache . push_back ( status ) ;
_midiDumpCache . push_back ( firstOp ) ;
if ( status < 0xc0 | | status > 0xdf ) {
_midiDumpCache . push_back ( secondOp ) ;
debug ( " 0x%02x) " , secondOp ) ;
} else
debug ( " ) " ) ;
}
void MidiDriver_BASE : : midiDumpSysEx ( const byte * msg , uint16 length ) {
midiDumpDelta ( ) ;
_midiDumpCache . push_back ( 0xf0 ) ;
debugN ( " 0xf0, length( " ) ;
midiDumpVarLength ( length + 1 ) ; // +1 because of closing 0xf7
debugN ( " ), sysex[ " ) ;
for ( int i = 0 ; i < length ; i + + ) {
debugN ( " 0x%x, " , msg [ i ] ) ;
_midiDumpCache . push_back ( msg [ i ] ) ;
}
debug ( " 0xf7] \t \t " ) ;
_midiDumpCache . push_back ( 0xf7 ) ;
}
void MidiDriver_BASE : : midiDumpFinish ( ) {
Common : : DumpFile * midiDumpFile = new Common : : DumpFile ( ) ;
midiDumpFile - > open ( " dump.mid " ) ;
midiDumpFile - > write ( " MThd \0 \0 \0 \ x6 \0 \ x1 \0 \ x2 " , 12 ) ; // standard MIDI file header, with two tracks
midiDumpFile - > write ( " \ x1 \xf4 " , 2 ) ; // division - 500 ticks per beat, i.e. a quarter note. Each tick is 1ms
midiDumpFile - > write ( " MTrk " , 4 ) ; // start of first track - doesn't contain real data, it's just common practice to use two tracks
midiDumpFile - > writeUint32BE ( 4 ) ; // first track size
midiDumpFile - > write ( " \0 \xff \x2f \0 " , 4 ) ; // meta event - end of track
midiDumpFile - > write ( " MTrk " , 4 ) ; // start of second track
midiDumpFile - > writeUint32BE ( _midiDumpCache . size ( ) + 4 ) ; // track size (+4 because of the 'end of track' event)
midiDumpFile - > write ( _midiDumpCache . data ( ) , _midiDumpCache . size ( ) ) ;
midiDumpFile - > write ( " \0 \xff \x2f \0 " , 4 ) ; // meta event - end of track
midiDumpFile - > finalize ( ) ;
midiDumpFile - > close ( ) ;
const char msg [ ] = " Ending MIDI dump, created 'dump.mid' " ;
g_system - > displayMessageOnOSD ( _ ( msg ) ) ; //TODO: why it doesn't appear?
debug ( _ ( msg ) ) ;
}
MidiDriver_BASE : : MidiDriver_BASE ( ) {
_midiDumpEnable = ConfMan . getBool ( " dump_midi " ) ;
if ( _midiDumpEnable ) {
midiDumpInit ( ) ;
}
}
MidiDriver_BASE : : ~ MidiDriver_BASE ( ) {
if ( _midiDumpEnable & & ! _midiDumpCache . empty ( ) ) {
midiDumpFinish ( ) ;
}
}
void MidiDriver_BASE : : send ( byte status , byte firstOp , byte secondOp ) {
send ( status | ( ( uint32 ) firstOp < < 8 ) | ( ( uint32 ) secondOp < < 16 ) ) ;
}
void MidiDriver : : midiDriverCommonSend ( uint32 b ) {
if ( _midiDumpEnable ) {
midiDumpDo ( b ) ;
}
}
void MidiDriver : : midiDriverCommonSysEx ( const byte * msg , uint16 length ) {
if ( _midiDumpEnable ) {
midiDumpSysEx ( msg , length ) ;
}
}