2001-12-01 17:23:50 +00:00
/* ScummVM - Scumm Interpreter
2002-03-20 17:51:07 +00:00
* Copyright ( C ) 2001 Ludvig Strigeus
2003-03-06 21:46:56 +00:00
* Copyright ( C ) 2001 - 2003 The ScummVM project
2001-12-01 17:23:50 +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
* Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*
* $ Header $
*/
# include "stdafx.h"
2003-06-15 01:42:19 +00:00
# include "imuse.h"
2003-05-22 16:15:48 +00:00
# include "imuse_internal.h"
2003-06-15 01:42:19 +00:00
# include "instrument.h"
# include "saveload.h"
# include "scumm.h"
# include "common/util.h"
# include "sound/mididrv.h"
# include "common/gameDetector.h" // For kDefaultMasterVolume etc.
2001-12-01 17:23:50 +00:00
2002-12-15 01:55:27 +00:00
////////////////////////////////////////
//
// IMuseInternal implementation
//
////////////////////////////////////////
2001-12-01 17:23:50 +00:00
2003-05-23 04:19:47 +00:00
IMuseInternal : : IMuseInternal ( ) :
_old_adlib_instruments ( false ) ,
_enable_multi_midi ( false ) ,
_midi_adlib ( 0 ) ,
_midi_native ( 0 ) ,
_base_sounds ( 0 ) ,
_paused ( false ) ,
_initialized ( false ) ,
_tempoFactor ( 0 ) ,
2003-05-23 18:35:53 +00:00
_player_limit ( ARRAYSIZE ( _players ) ) ,
_recycle_players ( false ) ,
2003-05-23 04:19:47 +00:00
_queue_end ( 0 ) ,
_queue_pos ( 0 ) ,
_queue_sound ( 0 ) ,
_queue_adding ( 0 ) ,
_queue_marker ( 0 ) ,
_queue_cleared ( 0 ) ,
_master_volume ( 0 ) ,
_music_volume ( 0 ) ,
_trigger_count ( 0 ) ,
_snm_trigger_index ( 0 )
{
memset ( _channel_volume , 0 , sizeof ( _channel_volume ) ) ;
memset ( _channel_volume_eff , 0 , sizeof ( _channel_volume_eff ) ) ;
memset ( _volchan_table , 0 , sizeof ( _volchan_table ) ) ;
memset ( _active_notes , 0 , sizeof ( _active_notes ) ) ;
}
2002-10-21 07:31:51 +00:00
IMuseInternal : : ~ IMuseInternal ( ) {
terminate ( ) ;
}
2003-05-19 05:04:38 +00:00
MidiDriver * IMuseInternal : : getMidiDriver ( ) {
MidiDriver * driver = NULL ;
if ( _midi_native ) {
driver = _midi_native ;
} else {
// Route it through Adlib anyway.
if ( ! _midi_adlib ) {
_midi_adlib = MidiDriver_ADLIB_create ( ) ;
initMidiDriver ( _midi_adlib ) ;
}
driver = _midi_adlib ;
}
return driver ;
}
2003-05-23 18:35:53 +00:00
byte * IMuseInternal : : findStartOfSound ( int sound ) {
2002-03-14 08:04:21 +00:00
byte * ptr = NULL ;
2002-04-11 17:19:16 +00:00
int32 size , pos ;
2001-12-01 17:23:50 +00:00
2002-12-18 13:22:40 +00:00
if ( _base_sounds )
2002-04-11 17:19:16 +00:00
ptr = _base_sounds [ sound ] ;
2002-03-14 08:04:21 +00:00
2002-04-11 17:19:16 +00:00
if ( ptr = = NULL ) {
2003-05-23 18:35:53 +00:00
debug ( 1 , " IMuseInternal::findStartOfSound(): Sound %d doesn't exist! " , sound ) ;
2002-04-24 14:13:09 +00:00
return NULL ;
2001-12-01 17:23:50 +00:00
}
ptr + = 8 ;
2003-06-14 18:52:30 +00:00
size = READ_BE_UINT32 ( ptr ) ;
2001-12-01 17:23:50 +00:00
ptr + = 4 ;
2003-05-23 18:35:53 +00:00
// Okay, we're looking for one of those things: either
// an 'MThd' tag (for SMF), or a 'FORM' tag (for XMIDI).
size = 48 ; // Arbitrary; we should find our tag within the first 48 bytes of the resource
2001-12-01 17:23:50 +00:00
pos = 0 ;
while ( pos < size ) {
2003-05-23 18:35:53 +00:00
if ( ! memcmp ( ptr + pos , " MThd " , 4 ) | | ! memcmp ( ptr + pos , " FORM " , 4 ) )
return ptr + pos ;
+ + pos ; // We could probably iterate more intelligently
2001-12-01 17:23:50 +00:00
}
2002-07-07 18:04:03 +00:00
2003-05-23 18:35:53 +00:00
debug ( 3 , " IMuseInternal::findStartOfSound(): Failed to align on sound %d! " , sound ) ;
return 0 ;
2002-05-04 00:20:39 +00:00
}
2003-03-06 17:58:13 +00:00
bool IMuseInternal : : isMT32 ( int sound ) {
2002-05-04 00:20:39 +00:00
byte * ptr = NULL ;
uint32 tag ;
if ( _base_sounds )
ptr = _base_sounds [ sound ] ;
if ( ptr = = NULL )
return false ;
2001-12-01 17:23:50 +00:00
2002-07-07 18:04:03 +00:00
tag = * ( ( ( uint32 * ) ptr ) + 1 ) ;
2002-05-04 00:20:39 +00:00
switch ( tag ) {
case MKID ( ' ADL ' ) :
return false ;
2003-05-28 11:56:50 +00:00
case MKID ( ' AMI ' ) :
return true ;
2002-05-04 00:20:39 +00:00
case MKID ( ' ROL ' ) :
return true ;
case MKID ( ' GMD ' ) :
return false ;
case MKID ( ' MAC ' ) :
return true ;
case MKID ( ' SPK ' ) :
return false ;
}
2002-07-07 18:04:03 +00:00
2002-05-04 00:20:39 +00:00
return false ;
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
bool IMuseInternal : : isGM ( int sound ) {
2002-09-29 11:11:42 +00:00
byte * ptr = NULL ;
uint32 tag ;
if ( _base_sounds )
ptr = _base_sounds [ sound ] ;
if ( ptr = = NULL )
return false ;
tag = * ( ( ( uint32 * ) ptr ) + 1 ) ;
switch ( tag ) {
case MKID ( ' ADL ' ) :
return false ;
2003-05-28 11:56:50 +00:00
case MKID ( ' AMI ' ) :
return true ; // Yeah... for our purposes, this is GM
2002-09-29 11:11:42 +00:00
case MKID ( ' ROL ' ) :
return true ; // Yeah... for our purposes, this is GM
case MKID ( ' GMD ' ) :
return true ;
case MKID ( ' MIDI ' ) :
return true ;
case MKID ( ' MAC ' ) :
return true ; // I guess this one too, since it qualifies under isMT32()
case MKID ( ' SPK ' ) :
return false ;
}
return false ;
}
2003-05-16 22:00:33 +00:00
MidiDriver * IMuseInternal : : getBestMidiDriver ( int sound ) {
MidiDriver * driver = NULL ;
if ( isGM ( sound ) ) {
if ( _midi_native ) {
driver = _midi_native ;
} else {
// Route it through Adlib anyway.
if ( ! _midi_adlib ) {
_midi_adlib = MidiDriver_ADLIB_create ( ) ;
initMidiDriver ( _midi_adlib ) ;
}
driver = _midi_adlib ;
}
} else {
2003-05-17 03:06:16 +00:00
if ( ! _midi_adlib & & ( _enable_multi_midi | | ! _midi_native ) ) {
2003-05-16 22:00:33 +00:00
_midi_adlib = MidiDriver_ADLIB_create ( ) ;
initMidiDriver ( _midi_adlib ) ;
}
driver = _midi_adlib ;
}
return driver ;
}
2003-03-18 16:13:52 +00:00
bool IMuseInternal : : startSound ( int sound ) {
2001-12-01 17:23:50 +00:00
Player * player ;
void * mdhd ;
2002-12-14 02:51:37 +00:00
// Do not start a sound if it is already set to
// start on an ImTrigger event. This fixes carnival
// music problems where a sound has been set to trigger
// at the right time, but then is started up immediately
// anyway, only to be restarted later when the trigger
// occurs.
int i ;
ImTrigger * trigger = _snm_triggers ;
for ( i = ARRAYSIZE ( _snm_triggers ) ; i ; - - i , + + trigger ) {
if ( trigger - > sound & & trigger - > id & & trigger - > command [ 0 ] = = 8 & & trigger - > command [ 1 ] = = sound )
return false ;
}
2003-05-23 18:35:53 +00:00
// Not sure exactly what the old code was doing,
// but we'll go ahead and do a similar check.
mdhd = findStartOfSound ( sound ) ;
if ( ! mdhd ) {
debug ( 2 , " IMuseInternal::startSound(): Couldn't find sound %d! " , sound ) ;
return false ;
}
/*
2002-04-11 17:19:16 +00:00
mdhd = findTag ( sound , MDHD_TAG , 0 ) ;
if ( ! mdhd ) {
2002-03-11 04:37:06 +00:00
mdhd = findTag ( sound , MDPG_TAG , 0 ) ;
if ( ! mdhd ) {
2003-05-07 19:24:14 +00:00
debug ( 2 , " SE::startSound failed: Couldn't find sound %d " , sound ) ;
2002-09-30 06:04:50 +00:00
return false ;
2002-03-11 04:37:06 +00:00
}
2002-03-05 16:13:09 +00:00
}
2003-05-23 18:35:53 +00:00
*/
2002-04-11 17:19:16 +00:00
2003-05-16 22:00:33 +00:00
// Check which MIDI driver this track should use.
// If it's NULL, it ain't something we can play.
MidiDriver * driver = getBestMidiDriver ( sound ) ;
if ( ! driver )
return false ;
2002-10-21 08:17:18 +00:00
// If the requested sound is already playing, start it over
// from scratch. This was originally a hack to prevent Sam & Max
// iMuse messiness while upgrading the iMuse engine, but it
// is apparently necessary to deal with fade-and-restart
// race conditions that were observed in MI2. Reference
// Bug #590511 and Patch #607175 (which was reversed to fix
// an FOA regression: Bug #622606).
2003-05-23 04:19:47 +00:00
player = findActivePlayer ( sound ) ;
if ( ! player )
2002-10-14 16:42:57 +00:00
player = allocate_player ( 128 ) ;
if ( ! player )
return false ;
2001-12-01 17:23:50 +00:00
player - > clear ( ) ;
2003-05-16 22:00:33 +00:00
return player - > startSound ( sound , driver ) ;
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
Player * IMuseInternal : : allocate_player ( byte priority ) {
2001-12-01 17:23:50 +00:00
Player * player = _players , * best = NULL ;
int i ;
byte bestpri = 255 ;
2003-05-23 18:35:53 +00:00
for ( i = _player_limit ; i ! = 0 ; i - - , player + + ) {
2003-05-23 04:19:47 +00:00
if ( ! player - > isActive ( ) )
2001-12-01 17:23:50 +00:00
return player ;
2003-05-23 04:19:47 +00:00
if ( player - > getPriority ( ) < bestpri ) {
2001-12-01 17:23:50 +00:00
best = player ;
2003-05-23 04:19:47 +00:00
bestpri = player - > getPriority ( ) ;
2001-12-01 17:23:50 +00:00
}
}
2003-05-23 18:35:53 +00:00
if ( bestpri < priority | | _recycle_players )
2001-12-01 17:23:50 +00:00
return best ;
debug ( 1 , " Denying player request " ) ;
return NULL ;
}
2003-03-06 17:58:13 +00:00
void IMuseInternal : : init_players ( ) {
2001-12-01 17:23:50 +00:00
Player * player = _players ;
int i ;
2002-04-11 17:19:16 +00:00
for ( i = ARRAYSIZE ( _players ) ; i ! = 0 ; i - - , player + + ) {
2003-05-23 04:19:47 +00:00
player - > clear ( ) ; // Used to just set _active to false
2002-04-11 17:19:16 +00:00
player - > _se = this ;
2001-12-01 17:23:50 +00:00
}
}
2003-03-06 17:58:13 +00:00
void IMuseInternal : : init_parts ( ) {
2001-12-01 17:23:50 +00:00
Part * part ;
int i ;
2002-04-11 17:19:16 +00:00
for ( i = 0 , part = _parts ; i ! = ARRAYSIZE ( _parts ) ; i + + , part + + ) {
2003-05-16 01:52:45 +00:00
part - > init ( ) ;
2001-12-01 17:23:50 +00:00
part - > _slot = i ;
}
}
2003-03-18 16:13:52 +00:00
int IMuseInternal : : stopSound ( int sound ) {
2001-12-01 17:23:50 +00:00
int r = - 1 ;
2003-05-23 04:19:47 +00:00
Player * player = findActivePlayer ( sound ) ;
if ( player ) {
player - > clear ( ) ;
r = 0 ;
2001-12-01 17:23:50 +00:00
}
return r ;
}
2003-03-06 17:58:13 +00:00
int IMuseInternal : : stop_all_sounds ( ) {
2001-12-01 17:23:50 +00:00
Player * player = _players ;
int i ;
2002-04-11 17:19:16 +00:00
for ( i = ARRAYSIZE ( _players ) ; i ! = 0 ; i - - , player + + ) {
2003-05-23 04:19:47 +00:00
if ( player - > isActive ( ) )
2001-12-01 17:23:50 +00:00
player - > clear ( ) ;
}
return 0 ;
}
2003-05-16 01:52:45 +00:00
void IMuseInternal : : on_timer ( MidiDriver * midi ) {
2003-05-15 18:24:59 +00:00
if ( _paused )
2001-12-01 17:23:50 +00:00
return ;
2002-04-11 17:19:16 +00:00
2003-05-20 01:12:40 +00:00
if ( midi = = _midi_native | | ! _midi_native )
handleDeferredCommands ( midi ) ;
2003-05-16 01:52:45 +00:00
sequencer_timers ( midi ) ;
2001-12-01 17:23:50 +00:00
}
2003-05-16 01:52:45 +00:00
void IMuseInternal : : sequencer_timers ( MidiDriver * midi ) {
2001-12-01 17:23:50 +00:00
Player * player = _players ;
int i ;
2002-04-11 17:19:16 +00:00
for ( i = ARRAYSIZE ( _players ) ; i ! = 0 ; i - - , player + + ) {
2003-05-23 04:19:47 +00:00
if ( player - > isActive ( ) & & player - > getMidiDriver ( ) = = midi ) {
player - > onTimer ( ) ;
2003-05-15 18:24:59 +00:00
}
2001-12-01 17:23:50 +00:00
}
}
2003-03-06 17:58:13 +00:00
void IMuseInternal : : handle_marker ( uint id , byte data ) {
2003-05-07 22:50:15 +00:00
uint16 * p = 0 ;
2002-04-11 17:19:16 +00:00
uint pos ;
if ( _queue_adding & & _queue_sound = = id & & data = = _queue_marker )
2001-12-01 17:23:50 +00:00
return ;
2003-05-07 19:24:14 +00:00
// Fix for bug #733401: It would seem that sometimes the
// queue read position gets out of sync (possibly just
// reset to zero). Therefore, the read position should
// skip over any empty (i.e. all zeros) queue entries
// until it finds a legit entry to review.
pos = _queue_end ;
while ( pos ! = _queue_pos ) {
p = _cmd_queue [ pos ] . array ;
if ( ( p [ 0 ] | p [ 1 ] | p [ 2 ] | p [ 3 ] | p [ 4 ] | p [ 5 ] | p [ 6 ] | p [ 7 ] ) ! = 0 )
break ;
warning ( " Skipping empty command queue entry at position %d " , pos ) ;
pos = ( pos + 1 ) & ( ARRAYSIZE ( _cmd_queue ) - 1 ) ;
}
if ( pos = = _queue_pos )
return ;
2001-12-01 17:23:50 +00:00
if ( p [ 0 ] ! = TRIGGER_ID | | p [ 1 ] ! = id | | p [ 2 ] ! = data )
return ;
_trigger_count - - ;
_queue_cleared = false ;
do {
2002-04-11 17:19:16 +00:00
pos = ( pos + 1 ) & ( ARRAYSIZE ( _cmd_queue ) - 1 ) ;
2001-12-01 17:23:50 +00:00
if ( _queue_pos = = pos )
break ;
p = _cmd_queue [ pos ] . array ;
if ( * p + + ! = COMMAND_ID )
break ;
_queue_end = pos ;
2003-03-18 16:13:52 +00:00
doCommand ( p [ 0 ] , p [ 1 ] , p [ 2 ] , p [ 3 ] , p [ 4 ] , p [ 5 ] , p [ 6 ] , 0 ) ;
2001-12-01 17:23:50 +00:00
if ( _queue_cleared )
return ;
pos = _queue_end ;
} while ( 1 ) ;
_queue_end = pos ;
}
2003-03-06 17:58:13 +00:00
int IMuseInternal : : get_channel_volume ( uint a ) {
2002-04-11 17:19:16 +00:00
if ( a < 8 )
2001-12-01 17:23:50 +00:00
return _channel_volume_eff [ a ] ;
2002-11-17 17:59:00 +00:00
return ( _master_volume * _music_volume / 255 ) > > 1 ;
2001-12-01 17:23:50 +00:00
}
2003-05-16 01:52:45 +00:00
Part * IMuseInternal : : allocate_part ( byte pri , MidiDriver * midi ) {
2002-04-11 17:19:16 +00:00
Part * part , * best = NULL ;
2001-12-01 17:23:50 +00:00
int i ;
2002-04-11 17:19:16 +00:00
for ( i = ARRAYSIZE ( _parts ) , part = _parts ; i ! = 0 ; i - - , part + + ) {
2001-12-01 17:23:50 +00:00
if ( ! part - > _player )
return part ;
if ( pri > = part - > _pri_eff ) {
pri = part - > _pri_eff ;
best = part ;
}
}
2002-12-18 17:14:05 +00:00
if ( best ) {
2001-12-01 17:23:50 +00:00
best - > uninit ( ) ;
2003-05-16 01:52:45 +00:00
reallocateMidiChannels ( midi ) ;
2002-12-18 17:14:05 +00:00
} else {
2001-12-01 17:23:50 +00:00
debug ( 1 , " Denying part request " ) ;
2002-12-18 17:14:05 +00:00
}
2001-12-01 17:23:50 +00:00
return best ;
}
2003-05-23 18:35:53 +00:00
int IMuseInternal : : getSoundStatus ( int sound , bool ignoreFadeouts ) {
Player * player ;
if ( sound = = - 1 ) {
player = _players ;
for ( int i = ARRAYSIZE ( _players ) ; i ; - - i , + + player ) {
if ( player - > isActive ( ) & & ( ! ignoreFadeouts | | ! player - > isFadingOut ( ) ) )
2003-05-24 23:21:08 +00:00
return player - > getID ( ) ;
2003-05-23 18:35:53 +00:00
}
return 0 ;
}
2001-12-01 17:23:50 +00:00
2003-05-23 18:35:53 +00:00
player = findActivePlayer ( sound ) ;
if ( player & & ( ! ignoreFadeouts | | ! player - > isFadingOut ( ) ) )
2003-05-23 04:19:47 +00:00
return 1 ;
2003-05-23 18:35:53 +00:00
return get_queue_sound_status ( sound ) ;
2002-12-05 21:45:55 +00:00
}
2003-03-06 17:58:13 +00:00
int IMuseInternal : : get_queue_sound_status ( int sound ) {
2001-12-01 17:23:50 +00:00
uint16 * a ;
2002-04-11 17:19:16 +00:00
int i , j ;
2001-12-01 17:23:50 +00:00
j = _queue_pos ;
i = _queue_end ;
2002-04-11 17:19:16 +00:00
while ( i ! = j ) {
2001-12-01 17:23:50 +00:00
a = _cmd_queue [ i ] . array ;
if ( a [ 0 ] = = COMMAND_ID & & a [ 1 ] = = 8 & & a [ 2 ] = = ( uint16 ) sound )
return 2 ;
2002-04-11 17:19:16 +00:00
i = ( i + 1 ) & ( ARRAYSIZE ( _cmd_queue ) - 1 ) ;
2001-12-01 17:23:50 +00:00
}
return 0 ;
}
2003-03-06 17:58:13 +00:00
int IMuseInternal : : set_volchan ( int sound , int volchan ) {
2001-12-01 17:23:50 +00:00
int r ;
int i ;
int num ;
2002-04-11 17:19:16 +00:00
Player * player , * best , * sameid ;
2001-12-01 17:23:50 +00:00
r = get_volchan_entry ( volchan ) ;
2002-04-11 17:19:16 +00:00
if ( r = = - 1 )
2001-12-01 17:23:50 +00:00
return - 1 ;
if ( r > = 8 ) {
2003-05-23 04:19:47 +00:00
player = findActivePlayer ( sound ) ;
if ( player & & player - > _vol_chan ! = ( uint16 ) volchan ) {
player - > _vol_chan = volchan ;
player - > setVolume ( player - > getVolume ( ) ) ;
return 0 ;
2001-12-01 17:23:50 +00:00
}
return - 1 ;
} else {
best = NULL ;
num = 0 ;
sameid = NULL ;
2002-04-11 17:19:16 +00:00
for ( i = ARRAYSIZE ( _players ) , player = _players ; i ! = 0 ; i - - , player + + ) {
2003-05-23 04:19:47 +00:00
if ( player - > isActive ( ) ) {
2002-04-11 17:19:16 +00:00
if ( player - > _vol_chan = = ( uint16 ) volchan ) {
2001-12-01 17:23:50 +00:00
num + + ;
2003-05-23 04:19:47 +00:00
if ( ! best | | player - > getPriority ( ) < = best - > getPriority ( ) )
2001-12-01 17:23:50 +00:00
best = player ;
2003-05-23 04:19:47 +00:00
} else if ( player - > getID ( ) = = ( uint16 ) sound ) {
2001-12-01 17:23:50 +00:00
sameid = player ;
}
}
}
2002-04-11 17:19:16 +00:00
if ( sameid = = NULL )
2001-12-01 17:23:50 +00:00
return - 1 ;
if ( num > = r )
best - > clear ( ) ;
player - > _vol_chan = volchan ;
2003-05-23 04:19:47 +00:00
player - > setVolume ( player - > getVolume ( ) ) ;
2001-12-01 17:23:50 +00:00
return 0 ;
}
}
2003-03-06 17:58:13 +00:00
int IMuseInternal : : clear_queue ( ) {
2001-12-01 17:23:50 +00:00
_queue_adding = false ;
_queue_cleared = true ;
_queue_pos = 0 ;
_queue_end = 0 ;
_trigger_count = 0 ;
return 0 ;
}
2003-03-06 17:58:13 +00:00
int IMuseInternal : : enqueue_command ( int a , int b , int c , int d , int e , int f , int g ) {
2001-12-01 17:23:50 +00:00
uint16 * p ;
uint i ;
i = _queue_pos ;
if ( i = = _queue_end )
return - 1 ;
2002-04-11 17:19:16 +00:00
if ( a = = - 1 ) {
2001-12-01 17:23:50 +00:00
_queue_adding = false ;
_trigger_count + + ;
return 0 ;
}
p = _cmd_queue [ _queue_pos ] . array ;
p [ 0 ] = COMMAND_ID ;
p [ 1 ] = a ;
p [ 2 ] = b ;
p [ 3 ] = c ;
p [ 4 ] = d ;
p [ 5 ] = e ;
p [ 6 ] = f ;
p [ 7 ] = g ;
2002-04-11 17:19:16 +00:00
i = ( i + 1 ) & ( ARRAYSIZE ( _cmd_queue ) - 1 ) ;
2001-12-01 17:23:50 +00:00
2002-04-11 17:19:16 +00:00
if ( _queue_end ! = i ) {
2001-12-01 17:23:50 +00:00
_queue_pos = i ;
return 0 ;
} else {
2002-04-11 17:19:16 +00:00
_queue_pos = ( i - 1 ) & ( ARRAYSIZE ( _cmd_queue ) - 1 ) ;
2001-12-01 17:23:50 +00:00
return - 1 ;
}
}
2003-03-06 17:58:13 +00:00
int IMuseInternal : : query_queue ( int param ) {
2002-04-11 17:19:16 +00:00
switch ( param ) {
2002-12-15 01:55:27 +00:00
case 0 : // Get trigger count
2001-12-01 17:23:50 +00:00
return _trigger_count ;
2002-12-15 01:55:27 +00:00
case 1 : // Get trigger type
2002-04-11 17:19:16 +00:00
if ( _queue_end = = _queue_pos )
2001-12-01 17:23:50 +00:00
return - 1 ;
return _cmd_queue [ _queue_end ] . array [ 1 ] ;
2002-12-15 01:55:27 +00:00
case 2 : // Get trigger sound
2002-04-11 17:19:16 +00:00
if ( _queue_end = = _queue_pos )
2001-12-01 17:23:50 +00:00
return 0xFF ;
return _cmd_queue [ _queue_end ] . array [ 2 ] ;
default :
return - 1 ;
}
}
2003-03-06 17:58:13 +00:00
int IMuseInternal : : get_music_volume ( ) {
2002-11-17 17:59:00 +00:00
return _music_volume ;
2002-03-05 23:37:31 +00:00
}
2003-03-06 17:58:13 +00:00
int IMuseInternal : : set_music_volume ( uint vol ) {
2002-11-17 17:59:00 +00:00
if ( vol > 255 )
vol = 255 ;
if ( _music_volume = = vol )
return 0 ;
_music_volume = vol ;
vol = vol * _master_volume / 255 ;
2002-11-18 20:05:25 +00:00
for ( uint i = 0 ; i < ARRAYSIZE ( _channel_volume ) ; i + + ) {
2002-11-17 17:59:00 +00:00
_channel_volume_eff [ i ] = _channel_volume [ i ] * vol / 255 ;
}
if ( ! _paused )
update_volumes ( ) ;
2002-03-05 23:37:31 +00:00
return 0 ;
}
2003-03-06 17:58:13 +00:00
int IMuseInternal : : set_master_volume ( uint vol ) {
2002-11-17 17:59:00 +00:00
if ( vol > 255 )
vol = 255 ;
if ( _master_volume = = vol )
return 0 ;
2002-04-11 17:19:16 +00:00
_master_volume = vol ;
2002-11-17 17:59:00 +00:00
vol = vol * _music_volume / 255 ;
2002-11-18 20:05:25 +00:00
for ( uint i = 0 ; i < ARRAYSIZE ( _channel_volume ) ; i + + ) {
2002-11-17 17:59:00 +00:00
_channel_volume_eff [ i ] = _channel_volume [ i ] * vol / 255 ;
}
2002-11-16 14:23:22 +00:00
if ( ! _paused )
update_volumes ( ) ;
2001-12-01 17:23:50 +00:00
return 0 ;
}
2003-03-06 17:58:13 +00:00
int IMuseInternal : : get_master_volume ( ) {
2002-11-17 17:59:00 +00:00
return _master_volume ;
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
int IMuseInternal : : terminate ( ) {
2003-06-18 22:46:17 +00:00
stop_all_sounds ( ) ;
2003-05-26 14:51:13 +00:00
2003-05-16 01:52:45 +00:00
if ( _midi_adlib ) {
_midi_adlib - > close ( ) ;
delete _midi_adlib ;
_midi_adlib = 0 ;
}
if ( _midi_native ) {
_midi_native - > close ( ) ;
delete _midi_native ;
_midi_native = 0 ;
2002-08-22 12:09:06 +00:00
}
2003-05-16 01:52:45 +00:00
2001-12-01 17:23:50 +00:00
return 0 ;
}
2003-03-06 17:58:13 +00:00
int IMuseInternal : : enqueue_trigger ( int sound , int marker ) {
2001-12-01 17:23:50 +00:00
uint16 * p ;
uint pos ;
pos = _queue_pos ;
p = _cmd_queue [ pos ] . array ;
p [ 0 ] = TRIGGER_ID ;
p [ 1 ] = sound ;
p [ 2 ] = marker ;
2002-04-11 17:19:16 +00:00
pos = ( pos + 1 ) & ( ARRAYSIZE ( _cmd_queue ) - 1 ) ;
if ( _queue_end = = pos ) {
_queue_pos = ( pos - 1 ) & ( ARRAYSIZE ( _cmd_queue ) - 1 ) ;
2001-12-01 17:23:50 +00:00
return - 1 ;
}
2002-04-11 17:19:16 +00:00
2001-12-01 17:23:50 +00:00
_queue_pos = pos ;
_queue_adding = true ;
_queue_sound = sound ;
_queue_marker = marker ;
return 0 ;
}
2003-03-18 16:13:52 +00:00
int32 IMuseInternal : : doCommand ( int a , int b , int c , int d , int e , int f , int g , int h ) {
2002-10-12 04:57:49 +00:00
int i ;
2002-04-11 17:19:16 +00:00
byte cmd = a & 0xFF ;
byte param = a > > 8 ;
Player * player = NULL ;
2001-12-01 17:23:50 +00:00
if ( ! _initialized & & ( cmd | | param ) )
return - 1 ;
2003-05-07 19:24:14 +00:00
# ifdef IMUSE_DEBUG
debug ( 0 , " doCommand - %d (%d/%d), %d, %d, %d, %d, %d, %d, %d " , a , ( int ) param , ( int ) cmd , b , c , d , e , f , g , h ) ;
# endif
2002-04-11 17:19:16 +00:00
if ( param = = 0 ) {
switch ( cmd ) {
2001-12-01 17:23:50 +00:00
case 6 :
2002-11-17 17:59:00 +00:00
if ( b > 127 )
return - 1 ;
else
return set_master_volume ( ( b < < 1 ) | ( b ? 0 : 1 ) ) ; // Convert b from 0-127 to 0-255
2001-12-01 17:23:50 +00:00
case 7 :
2002-11-17 17:59:00 +00:00
return _master_volume > > 1 ; // Convert from 0-255 to 0-127
2001-12-01 17:23:50 +00:00
case 8 :
2003-03-18 16:13:52 +00:00
return startSound ( b ) ? 0 : - 1 ;
2001-12-01 17:23:50 +00:00
case 9 :
2003-03-18 16:13:52 +00:00
return stopSound ( b ) ;
2002-10-10 15:16:58 +00:00
case 10 : // FIXME: Sam and Max - Not sure if this is correct
return stop_all_sounds ( ) ;
2001-12-01 17:23:50 +00:00
case 11 :
return stop_all_sounds ( ) ;
2002-10-14 16:42:57 +00:00
case 12 :
// Sam & Max: Player-scope commands
2003-05-23 04:19:47 +00:00
player = findActivePlayer ( b ) ;
if ( ! player )
2002-10-14 16:42:57 +00:00
return - 1 ;
switch ( d ) {
case 6 :
// Set player volume.
2003-05-23 04:19:47 +00:00
return player - > setVolume ( e ) ;
2002-10-14 16:42:57 +00:00
default :
2003-03-18 16:13:52 +00:00
warning ( " IMuseInternal::doCommand (6) unsupported sub-command %d " , d ) ;
2002-10-14 16:42:57 +00:00
}
return - 1 ;
2001-12-01 17:23:50 +00:00
case 13 :
2003-03-23 13:14:54 +00:00
return getSoundStatus ( b ) ;
2002-10-12 04:57:49 +00:00
case 14 :
2003-05-23 04:19:47 +00:00
// Sam and Max: Parameter fade
player = this - > findActivePlayer ( b ) ;
2003-05-20 01:12:40 +00:00
if ( player )
2003-05-21 20:23:01 +00:00
return player - > addParameterFader ( d , e , f ) ;
return - 1 ;
2003-05-19 22:29:35 +00:00
2002-10-12 04:57:49 +00:00
case 15 :
2002-12-14 02:51:37 +00:00
// Sam & Max: Set hook for a "maybe" jump
2003-05-23 04:19:47 +00:00
player = findActivePlayer ( b ) ;
if ( player ) {
player - > setHook ( 0 , d , 0 ) ;
return 0 ;
2002-07-07 18:04:03 +00:00
}
2002-10-12 04:57:49 +00:00
return - 1 ;
case 16 :
return set_volchan ( b , c ) ;
case 17 :
2002-10-14 16:42:57 +00:00
if ( g_scumm - > _gameId ! = GID_SAMNMAX ) {
return set_channel_volume ( b , c ) ;
} else {
2002-11-23 16:15:33 +00:00
if ( e | | f | | g | | h )
return ImSetTrigger ( b , d , e , f , g , h ) ;
else
return ImClearTrigger ( b , d ) ;
2002-07-07 18:04:03 +00:00
}
2001-12-01 17:23:50 +00:00
case 18 :
2002-10-14 16:42:57 +00:00
if ( g_scumm - > _gameId ! = GID_SAMNMAX ) {
return set_volchan_entry ( b , c ) ;
} else {
// Sam & Max: ImCheckTrigger.
// According to Mike's notes to Ender,
// this function returns the number of triggers
// associated with a particular player ID and
// trigger ID.
a = 0 ;
for ( i = 0 ; i < 16 ; + + i ) {
if ( _snm_triggers [ i ] . sound = = b & & _snm_triggers [ i ] . id & &
( d = = - 1 | | _snm_triggers [ i ] . id = = d ) )
{
+ + a ;
}
}
return a ;
}
2002-04-21 17:54:59 +00:00
case 19 :
2002-10-14 16:42:57 +00:00
// Sam & Max: ImClearTrigger
// This should clear a trigger that's been set up
// with ImSetTrigger (cmd == 17). Seems to work....
2002-11-23 16:15:33 +00:00
return ImClearTrigger ( b , d ) ;
2002-12-13 15:49:30 +00:00
case 20 :
// Sam & Max: Deferred Command
2003-05-20 01:12:40 +00:00
// warning ("[--] doCommand (20): %3d %3d %3d %3d %3d %3d (%d)", c, d, e, f, g, h, b);
addDeferredCommand ( b , c , d , e , f , g , h ) ;
return 0 ;
2002-04-14 18:13:08 +00:00
case 2 :
case 3 :
return 0 ;
2001-12-01 17:23:50 +00:00
default :
2003-03-18 16:13:52 +00:00
warning ( " doCommand (%d [%d/%d], %d, %d, %d, %d, %d, %d, %d) unsupported " , a , param , cmd , b , c , d , e , f , g , h ) ;
2001-12-01 17:23:50 +00:00
}
2002-04-11 17:19:16 +00:00
} else if ( param = = 1 ) {
if ( ( 1 < < cmd ) & ( 0x783FFF ) ) {
2003-05-23 04:19:47 +00:00
player = findActivePlayer ( b ) ;
2001-12-01 17:23:50 +00:00
if ( ! player )
return - 1 ;
2002-04-11 17:19:16 +00:00
if ( ( 1 < < cmd ) & ( 1 < < 11 | 1 < < 22 ) ) {
assert ( c > = 0 & & c < = 15 ) ;
2003-05-23 04:19:47 +00:00
player = ( Player * ) player - > getPart ( c ) ;
2002-04-11 17:19:16 +00:00
if ( ! player )
2001-12-01 17:23:50 +00:00
return - 1 ;
}
}
2002-04-11 17:19:16 +00:00
switch ( cmd ) {
2001-12-01 17:23:50 +00:00
case 0 :
2002-11-10 18:34:57 +00:00
if ( g_scumm - > _gameId = = GID_SAMNMAX ) {
2002-12-13 15:16:40 +00:00
if ( d = = 1 ) // Measure number
2003-05-23 04:19:47 +00:00
return ( ( player - > getBeatIndex ( ) - 1 ) > > 2 ) + 1 ;
2002-12-13 15:16:40 +00:00
else if ( d = = 2 ) // Beat number
2003-05-23 04:19:47 +00:00
return player - > getBeatIndex ( ) ;
2002-11-10 18:34:57 +00:00
return - 1 ;
} else {
2003-05-23 04:19:47 +00:00
return player - > getParam ( c , d ) ;
2002-11-10 18:34:57 +00:00
}
2001-12-01 17:23:50 +00:00
case 1 :
2002-10-14 16:42:57 +00:00
if ( g_scumm - > _gameId = = GID_SAMNMAX )
2003-05-23 04:19:47 +00:00
player - > jump ( d - 1 , ( e - 1 ) * 4 + f , ( ( g * player - > getTicksPerBeat ( ) ) > > 2 ) + h ) ;
2002-10-12 04:57:49 +00:00
else
2003-05-23 04:19:47 +00:00
player - > setPriority ( c ) ;
2001-12-01 17:23:50 +00:00
return 0 ;
case 2 :
2003-05-23 04:19:47 +00:00
return player - > setVolume ( c ) ;
2001-12-01 17:23:50 +00:00
case 3 :
2003-05-23 04:19:47 +00:00
player - > setPan ( c ) ;
2001-12-01 17:23:50 +00:00
return 0 ;
case 4 :
2003-05-23 04:19:47 +00:00
return player - > setTranspose ( c , d ) ;
2001-12-01 17:23:50 +00:00
case 5 :
2003-05-23 04:19:47 +00:00
player - > setDetune ( c ) ;
2001-12-01 17:23:50 +00:00
return 0 ;
case 6 :
2003-05-23 04:19:47 +00:00
player - > setSpeed ( c ) ;
2001-12-01 17:23:50 +00:00
return 0 ;
case 7 :
2002-04-11 17:19:16 +00:00
return player - > jump ( c , d , e ) ? 0 : - 1 ;
2001-12-01 17:23:50 +00:00
case 8 :
2002-04-11 17:19:16 +00:00
return player - > scan ( c , d , e ) ;
2001-12-01 17:23:50 +00:00
case 9 :
2003-05-23 04:19:47 +00:00
return player - > setLoop ( c , d , e , f , g ) ? 0 : - 1 ;
2001-12-01 17:23:50 +00:00
case 10 :
2003-05-23 04:19:47 +00:00
player - > clearLoop ( ) ;
2001-12-01 17:23:50 +00:00
return 0 ;
case 11 :
2002-04-11 17:19:16 +00:00
( ( Part * ) player ) - > set_onoff ( d ! = 0 ) ;
2001-12-01 17:23:50 +00:00
return 0 ;
case 12 :
2003-05-23 04:19:47 +00:00
return player - > setHook ( c , d , e ) ;
2001-12-01 17:23:50 +00:00
case 13 :
2003-05-21 20:23:01 +00:00
return player - > addParameterFader ( ParameterFader : : pfVolume , c , d ) ;
2001-12-01 17:23:50 +00:00
case 14 :
2002-04-11 17:19:16 +00:00
return enqueue_trigger ( b , c ) ;
2001-12-01 17:23:50 +00:00
case 15 :
2002-04-11 17:19:16 +00:00
return enqueue_command ( b , c , d , e , f , g , h ) ;
2001-12-01 17:23:50 +00:00
case 16 :
return clear_queue ( ) ;
case 19 :
2003-05-23 04:19:47 +00:00
return player - > getParam ( c , d ) ;
2001-12-01 17:23:50 +00:00
case 20 :
2003-05-23 04:19:47 +00:00
return player - > setHook ( c , d , e ) ;
2001-12-01 17:23:50 +00:00
case 21 :
return - 1 ;
case 22 :
2003-05-23 04:19:47 +00:00
( ( Part * ) player ) - > setVolume ( d ) ;
2001-12-01 17:23:50 +00:00
return 0 ;
case 23 :
return query_queue ( b ) ;
case 24 :
return 0 ;
default :
2003-03-18 16:13:52 +00:00
warning ( " doCommand (%d [%d/%d], %d, %d, %d, %d, %d, %d, %d) unsupported " , a , param , cmd , b , c , d , e , f , g , h ) ;
2001-12-01 17:23:50 +00:00
return - 1 ;
}
}
return - 1 ;
}
2002-11-23 16:15:33 +00:00
int32 IMuseInternal : : ImSetTrigger ( int sound , int id , int a , int b , int c , int d ) {
// Sam & Max: ImSetTrigger.
// Sets a trigger for a particular player and
2003-03-18 16:13:52 +00:00
// marker ID, along with doCommand parameters
2002-11-23 16:15:33 +00:00
// to invoke at the marker. The marker is
// represented by MIDI SysEx block 00 xx (F7)
// where "xx" is the marker ID.
uint16 oldest_trigger = 0 ;
2002-12-14 02:51:37 +00:00
ImTrigger * oldest_ptr = NULL ;
2002-11-23 16:15:33 +00:00
int i ;
2002-12-14 02:51:37 +00:00
ImTrigger * trig = _snm_triggers ;
for ( i = ARRAYSIZE ( _snm_triggers ) ; i ; - - i , + + trig ) {
2002-11-23 16:15:33 +00:00
if ( ! trig - > id )
break ;
if ( trig - > id = = id & & trig - > sound = = sound )
break ;
uint16 diff ;
if ( trig - > expire < = _snm_trigger_index )
diff = _snm_trigger_index - trig - > expire ;
else
diff = 0x10000 - trig - > expire + _snm_trigger_index ;
2002-12-14 02:51:37 +00:00
if ( ! oldest_ptr | | oldest_trigger < diff ) {
oldest_ptr = trig ;
2002-11-23 16:15:33 +00:00
oldest_trigger = diff ;
}
}
// If we didn't find a trigger, see if we can expire one.
2002-12-14 02:51:37 +00:00
if ( ! i ) {
if ( ! oldest_ptr )
2002-11-23 16:15:33 +00:00
return - 1 ;
2002-12-14 02:51:37 +00:00
trig = oldest_ptr ;
2002-11-23 16:15:33 +00:00
}
2002-12-14 02:51:37 +00:00
trig - > id = id ;
trig - > sound = sound ;
trig - > expire = ( + + _snm_trigger_index & 0xFFFF ) ;
trig - > command [ 0 ] = a ;
trig - > command [ 1 ] = b ;
trig - > command [ 2 ] = c ;
trig - > command [ 3 ] = d ;
// If the command is to start a sound, stop that sound if it's already playing.
// This fixes some carnival music problems.
2003-03-23 13:14:54 +00:00
if ( trig - > command [ 0 ] = = 8 & & getSoundStatus ( trig - > command [ 1 ] ) )
2003-03-18 16:13:52 +00:00
stopSound ( trig - > command [ 1 ] ) ;
2002-11-23 16:15:33 +00:00
return 0 ;
}
int32 IMuseInternal : : ImClearTrigger ( int sound , int id ) {
int count = 0 ;
int i ;
for ( i = 0 ; i < 16 ; + + i ) {
if ( _snm_triggers [ i ] . sound = = sound & & _snm_triggers [ i ] . id & &
( id = = - 1 | | _snm_triggers [ i ] . id = = id ) )
{
_snm_triggers [ i ] . sound = _snm_triggers [ i ] . id = 0 ;
+ + count ;
}
}
return ( count > 0 ) ? 0 : - 1 ;
}
2003-05-15 18:24:59 +00:00
int32 IMuseInternal : : ImFireAllTriggers ( int sound ) {
if ( ! sound ) return 0 ;
int count = 0 ;
int i ;
for ( i = 0 ; i < 16 ; + + i ) {
if ( _snm_triggers [ i ] . sound = = sound )
{
_snm_triggers [ i ] . sound = _snm_triggers [ i ] . id = 0 ;
doCommand ( _snm_triggers [ i ] . command [ 0 ] ,
_snm_triggers [ i ] . command [ 1 ] ,
_snm_triggers [ i ] . command [ 2 ] ,
_snm_triggers [ i ] . command [ 3 ] ,
0 , 0 , 0 , 0 ) ;
+ + count ;
}
}
return ( count > 0 ) ? 0 : - 1 ;
}
2002-04-29 11:48:33 +00:00
int IMuseInternal : : set_channel_volume ( uint chan , uint vol )
2002-04-11 17:19:16 +00:00
{
if ( chan > = 8 | | vol > 127 )
2001-12-01 17:23:50 +00:00
return - 1 ;
_channel_volume [ chan ] = vol ;
2002-11-17 17:59:00 +00:00
_channel_volume_eff [ chan ] = _master_volume * _music_volume * vol / 255 / 255 ;
2001-12-01 17:23:50 +00:00
update_volumes ( ) ;
return 0 ;
}
2003-03-06 17:58:13 +00:00
void IMuseInternal : : update_volumes ( ) {
2001-12-01 17:23:50 +00:00
Player * player ;
int i ;
2002-04-11 17:19:16 +00:00
for ( i = ARRAYSIZE ( _players ) , player = _players ; i ! = 0 ; i - - , player + + ) {
2003-05-23 04:19:47 +00:00
if ( player - > isActive ( ) )
player - > setVolume ( player - > getVolume ( ) ) ;
2001-12-01 17:23:50 +00:00
}
}
2003-03-06 17:58:13 +00:00
int IMuseInternal : : set_volchan_entry ( uint a , uint b ) {
2001-12-01 17:23:50 +00:00
if ( a > = 8 )
return - 1 ;
_volchan_table [ a ] = b ;
return 0 ;
}
2003-03-06 17:58:13 +00:00
int HookDatas : : query_param ( int param , byte chan ) {
2002-04-11 17:19:16 +00:00
switch ( param ) {
2001-12-01 17:23:50 +00:00
case 18 :
2003-05-05 16:07:10 +00:00
return _jump [ 0 ] ;
2001-12-01 17:23:50 +00:00
case 19 :
return _transpose ;
case 20 :
return _part_onoff [ chan ] ;
case 21 :
return _part_volume [ chan ] ;
case 22 :
return _part_program [ chan ] ;
case 23 :
return _part_transpose [ chan ] ;
default :
return - 1 ;
}
}
2003-03-06 17:58:13 +00:00
int HookDatas : : set ( byte cls , byte value , byte chan ) {
2002-04-11 17:19:16 +00:00
switch ( cls ) {
2001-12-01 17:23:50 +00:00
case 0 :
2003-05-19 22:29:35 +00:00
if ( value ! = _jump [ 0 ] ) {
_jump [ 1 ] = _jump [ 0 ] ;
_jump [ 0 ] = value ;
}
2001-12-01 17:23:50 +00:00
break ;
case 1 :
_transpose = value ;
break ;
case 2 :
2002-04-11 17:19:16 +00:00
if ( chan < 16 )
2001-12-01 17:23:50 +00:00
_part_onoff [ chan ] = value ;
2002-04-11 17:19:16 +00:00
else if ( chan = = 16 )
2001-12-01 17:23:50 +00:00
memset ( _part_onoff , value , 16 ) ;
break ;
case 3 :
2002-04-11 17:19:16 +00:00
if ( chan < 16 )
2001-12-01 17:23:50 +00:00
_part_volume [ chan ] = value ;
2002-04-11 17:19:16 +00:00
else if ( chan = = 16 )
2001-12-01 17:23:50 +00:00
memset ( _part_volume , value , 16 ) ;
break ;
case 4 :
2002-04-11 17:19:16 +00:00
if ( chan < 16 )
2001-12-01 17:23:50 +00:00
_part_program [ chan ] = value ;
2002-04-11 17:19:16 +00:00
else if ( chan = = 16 )
2001-12-01 17:23:50 +00:00
memset ( _part_program , value , 16 ) ;
break ;
case 5 :
2002-04-11 17:19:16 +00:00
if ( chan < 16 )
2001-12-01 17:23:50 +00:00
_part_transpose [ chan ] = value ;
2002-04-11 17:19:16 +00:00
else if ( chan = = 16 )
2001-12-01 17:23:50 +00:00
memset ( _part_transpose , value , 16 ) ;
break ;
default :
return - 1 ;
}
return 0 ;
}
2003-05-23 04:19:47 +00:00
Player * IMuseInternal : : findActivePlayer ( int id ) {
2001-12-01 17:23:50 +00:00
int i ;
2003-05-23 04:19:47 +00:00
Player * player ;
2001-12-01 17:23:50 +00:00
2002-04-11 17:19:16 +00:00
for ( i = ARRAYSIZE ( _players ) , player = _players ; i ! = 0 ; i - - , player + + ) {
2003-05-23 04:19:47 +00:00
if ( player - > isActive ( ) & & player - > getID ( ) = = ( uint16 ) id )
return player ;
2001-12-01 17:23:50 +00:00
}
2003-05-23 04:19:47 +00:00
return NULL ;
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
int IMuseInternal : : get_volchan_entry ( uint a ) {
2002-04-11 17:19:16 +00:00
if ( a < 8 )
2001-12-01 17:23:50 +00:00
return _volchan_table [ a ] ;
return - 1 ;
}
2003-03-06 17:58:13 +00:00
uint32 IMuseInternal : : property ( int prop , uint32 value ) {
2002-07-07 18:04:03 +00:00
switch ( prop ) {
2002-04-29 11:48:33 +00:00
case IMuse : : PROP_TEMPO_BASE :
2003-05-16 22:28:33 +00:00
// This is a specified as a percentage of normal
// music speed. The number must be an integer
// ranging from 50 to 200 (for 50% to 200% normal speed).
if ( value > = 50 & & value < = 200 )
_tempoFactor = value ;
2002-04-14 18:13:08 +00:00
break ;
2003-05-17 03:06:16 +00:00
case IMuse : : PROP_NATIVE_MT32 :
Instrument : : nativeMT32 ( value > 0 ) ;
break ;
case IMuse : : PROP_MULTI_MIDI :
_enable_multi_midi = ( value > 0 ) ;
2003-05-17 19:03:25 +00:00
if ( ! _enable_multi_midi & & _midi_native & & _midi_adlib ) {
MidiDriver * driver = _midi_adlib ;
_midi_adlib = NULL ;
int i ;
for ( i = 0 ; i < ARRAYSIZE ( _players ) ; + + i ) {
2003-05-23 04:19:47 +00:00
if ( _players [ i ] . isActive ( ) & & _players [ i ] . getMidiDriver ( ) = = driver )
2003-05-17 19:03:25 +00:00
_players [ i ] . clear ( ) ;
}
driver - > close ( ) ;
}
2003-05-17 03:06:16 +00:00
break ;
2003-05-17 17:20:27 +00:00
case IMuse : : PROP_OLD_ADLIB_INSTRUMENTS :
_old_adlib_instruments = ( value > 0 ) ;
2003-05-23 18:35:53 +00:00
break ;
case IMuse : : PROP_LIMIT_PLAYERS :
if ( value > 0 & & value < = ARRAYSIZE ( _players ) )
_player_limit = ( int ) value ;
break ;
case IMuse : : PROP_RECYCLE_PLAYERS :
if ( value > 0 & & value < = ARRAYSIZE ( _players ) )
_recycle_players = ( value ! = 0 ) ;
break ;
2002-04-14 18:13:08 +00:00
}
return 0 ;
}
2003-03-06 17:58:13 +00:00
void IMuseInternal : : setBase ( byte * * base ) {
2002-04-14 18:13:08 +00:00
_base_sounds = base ;
}
2003-05-16 22:00:33 +00:00
IMuseInternal * IMuseInternal : : create ( OSystem * syst , MidiDriver * native_midi ) {
2002-04-29 11:48:33 +00:00
IMuseInternal * i = new IMuseInternal ;
2003-05-16 22:00:33 +00:00
i - > initialize ( syst , native_midi ) ;
2002-04-14 18:13:08 +00:00
return i ;
}
2003-05-16 22:00:33 +00:00
int IMuseInternal : : initialize ( OSystem * syst , MidiDriver * native_midi ) {
2001-12-01 17:23:50 +00:00
int i ;
2003-05-16 22:00:33 +00:00
_midi_native = native_midi ;
_midi_adlib = NULL ;
if ( native_midi )
initMidiDriver ( _midi_native ) ;
2002-04-11 17:19:16 +00:00
2003-05-16 22:28:33 +00:00
if ( ! _tempoFactor ) _tempoFactor = 100 ;
2002-11-17 17:59:00 +00:00
_master_volume = 255 ;
2002-04-11 17:19:16 +00:00
if ( _music_volume < 1 )
2002-07-28 15:03:45 +00:00
_music_volume = kDefaultMusicVolume ;
2002-03-05 23:37:31 +00:00
2002-04-11 17:19:16 +00:00
for ( i = 0 ; i ! = 8 ; i + + )
2001-12-01 17:23:50 +00:00
_channel_volume [ i ] = _channel_volume_eff [ i ] = _volchan_table [ i ] = 127 ;
init_players ( ) ;
init_queue ( ) ;
init_parts ( ) ;
_initialized = true ;
2002-04-11 17:19:16 +00:00
2001-12-01 17:23:50 +00:00
return 0 ;
}
2003-05-16 01:52:45 +00:00
void IMuseInternal : : initMidiDriver ( MidiDriver * midi ) {
// Open MIDI driver
2003-05-17 17:20:27 +00:00
midi - > property ( MidiDriver : : PROP_OLD_ADLIB , _old_adlib_instruments ? 1 : 0 ) ;
2003-05-16 01:52:45 +00:00
int result = midi - > open ( ) ;
if ( result )
2003-06-12 07:46:48 +00:00
error ( " IMuse initialization - %s " , MidiDriver : : getErrorName ( result ) ) ;
2003-05-16 01:52:45 +00:00
2003-06-01 04:05:13 +00:00
// In case we have an MT-32 attached.
initMT32 ( midi ) ;
2003-06-01 00:42:01 +00:00
2003-05-16 01:52:45 +00:00
// Connect to the driver's timer
midi - > setTimerCallback ( midi , & IMuseInternal : : midiTimerCallback ) ;
}
2003-06-01 04:05:13 +00:00
void IMuseInternal : : initMT32 ( MidiDriver * midi ) {
byte buffer [ 32 ] = " \x41 \x10 \x16 \x12 \x00 \x00 \x00 " ;
// Reset the MT-32
memcpy ( & buffer [ 4 ] , " \x7f \x00 \x00 \x01 \x00 " , 5 ) ;
midi - > sysEx ( buffer , 9 ) ;
// Display a welcome message on MT-32 displays.
memcpy ( & buffer [ 4 ] , " \x20 \x00 \x00 " , 3 ) ;
memcpy ( & buffer [ 7 ] , " " , 20 ) ;
2003-06-01 04:15:10 +00:00
memcpy ( buffer + 7 + ( 20 - strlen ( " ScummVM " SCUMMVM_VERSION ) ) / 2 ,
2003-06-01 04:05:13 +00:00
" ScummVM " SCUMMVM_VERSION ,
strlen ( " ScummVM " SCUMMVM_VERSION ) ) ;
byte checksum = 0 ;
for ( int i = 4 ; i < 27 ; + + i )
checksum - = buffer [ i ] ;
buffer [ 27 ] = checksum ;
midi - > sysEx ( buffer , 28 ) ;
}
2003-03-06 17:58:13 +00:00
void IMuseInternal : : init_queue ( ) {
2001-12-01 17:23:50 +00:00
_queue_adding = false ;
_queue_pos = 0 ;
_queue_end = 0 ;
_trigger_count = 0 ;
}
2003-03-06 17:58:13 +00:00
void IMuseInternal : : pause ( bool paused ) {
2002-11-17 17:59:00 +00:00
int vol = _music_volume ;
if ( paused )
_music_volume = 0 ;
update_volumes ( ) ;
_music_volume = vol ;
2001-12-01 17:23:50 +00:00
_paused = paused ;
}
2003-05-20 01:12:40 +00:00
void IMuseInternal : : handleDeferredCommands ( MidiDriver * midi ) {
2003-05-23 04:19:47 +00:00
uint32 advance = midi - > getBaseTempo ( ) ;
2003-05-20 01:12:40 +00:00
DeferredCommand * ptr = & _deferredCommands [ 0 ] ;
int i ;
for ( i = ARRAYSIZE ( _deferredCommands ) ; i ; - - i , + + ptr ) {
if ( ! ptr - > time_left )
continue ;
if ( ptr - > time_left < = advance ) {
doCommand ( ptr - > a , ptr - > b , ptr - > c , ptr - > d , ptr - > e , ptr - > f , 0 , 0 ) ;
ptr - > time_left = advance ;
}
ptr - > time_left - = advance ;
}
}
2003-05-23 04:19:47 +00:00
// "time" is interpreted as hundredths of a second.
// FIXME: Is that correct?
2003-05-20 01:12:40 +00:00
// We convert it to microseconds before prceeding
void IMuseInternal : : addDeferredCommand ( int time , int a , int b , int c , int d , int e , int f ) {
DeferredCommand * ptr = & _deferredCommands [ 0 ] ;
int i ;
for ( i = ARRAYSIZE ( _deferredCommands ) ; i ; - - i , + + ptr ) {
if ( ! ptr - > time_left )
break ;
}
2003-05-26 20:42:25 +00:00
if ( i ) {
2003-05-20 01:12:40 +00:00
ptr - > time_left = time * 10000 ;
ptr - > a = a ;
ptr - > b = b ;
ptr - > c = c ;
ptr - > d = d ;
ptr - > e = e ;
ptr - > f = f ;
}
}
2003-05-22 16:15:48 +00:00
////////////////////////////////////////////////////////////
//
// IMuseInternal load/save implementation
//
2002-12-15 01:55:27 +00:00
////////////////////////////////////////////////////////////
2001-12-01 17:23:50 +00:00
enum {
TYPE_PART = 1 ,
2002-12-25 00:38:53 +00:00
TYPE_PLAYER = 2
2001-12-01 17:23:50 +00:00
} ;
2003-03-06 17:58:13 +00:00
int IMuseInternal : : saveReference ( void * me_ref , byte type , void * ref ) {
2002-12-08 16:14:29 +00:00
IMuseInternal * me = ( IMuseInternal * ) me_ref ;
2002-04-11 17:19:16 +00:00
switch ( type ) {
case TYPE_PART :
return ( Part * ) ref - me - > _parts ;
case TYPE_PLAYER :
return ( Player * ) ref - me - > _players ;
2001-12-01 17:23:50 +00:00
default :
error ( " saveReference: invalid type " ) ;
}
}
2003-03-06 17:58:13 +00:00
void * IMuseInternal : : loadReference ( void * me_ref , byte type , int ref ) {
2002-12-08 16:14:29 +00:00
IMuseInternal * me = ( IMuseInternal * ) me_ref ;
2002-04-11 17:19:16 +00:00
switch ( type ) {
case TYPE_PART :
return & me - > _parts [ ref ] ;
case TYPE_PLAYER :
return & me - > _players [ ref ] ;
2001-12-01 17:23:50 +00:00
default :
error ( " loadReference: invalid type " ) ;
}
}
2003-03-06 17:58:13 +00:00
int IMuseInternal : : save_or_load ( Serializer * ser , Scumm * scumm ) {
2001-12-01 17:23:50 +00:00
const SaveLoadEntry mainEntries [ ] = {
2002-12-08 16:14:29 +00:00
MKLINE ( IMuseInternal , _queue_end , sleUint8 , VER_V8 ) ,
MKLINE ( IMuseInternal , _queue_pos , sleUint8 , VER_V8 ) ,
MKLINE ( IMuseInternal , _queue_sound , sleUint16 , VER_V8 ) ,
MKLINE ( IMuseInternal , _queue_adding , sleByte , VER_V8 ) ,
MKLINE ( IMuseInternal , _queue_marker , sleByte , VER_V8 ) ,
MKLINE ( IMuseInternal , _queue_cleared , sleByte , VER_V8 ) ,
MKLINE ( IMuseInternal , _master_volume , sleByte , VER_V8 ) ,
MKLINE ( IMuseInternal , _trigger_count , sleUint16 , VER_V8 ) ,
MKARRAY ( IMuseInternal , _channel_volume [ 0 ] , sleUint16 , 8 , VER_V8 ) ,
MKARRAY ( IMuseInternal , _volchan_table [ 0 ] , sleUint16 , 8 , VER_V8 ) ,
2003-05-07 19:24:14 +00:00
// TODO: Add _cmd_queue in here
2001-12-01 17:23:50 +00:00
MKEND ( )
} ;
2002-04-11 17:19:16 +00:00
2003-05-21 21:38:03 +00:00
// VolumeFader is obsolete.
2001-12-01 17:23:50 +00:00
const SaveLoadEntry volumeFaderEntries [ ] = {
2003-05-21 20:23:01 +00:00
MK_OBSOLETE_REF ( VolumeFader , player , TYPE_PLAYER , VER_V8 , VER_V16 ) ,
MK_OBSOLETE ( VolumeFader , active , sleUint8 , VER_V8 , VER_V16 ) ,
MK_OBSOLETE ( VolumeFader , curvol , sleUint8 , VER_V8 , VER_V16 ) ,
MK_OBSOLETE ( VolumeFader , speed_lo_max , sleUint16 , VER_V8 , VER_V16 ) ,
MK_OBSOLETE ( VolumeFader , num_steps , sleUint16 , VER_V8 , VER_V16 ) ,
MK_OBSOLETE ( VolumeFader , speed_hi , sleInt8 , VER_V8 , VER_V16 ) ,
MK_OBSOLETE ( VolumeFader , direction , sleInt8 , VER_V8 , VER_V16 ) ,
MK_OBSOLETE ( VolumeFader , speed_lo , sleInt8 , VER_V8 , VER_V16 ) ,
MK_OBSOLETE ( VolumeFader , speed_lo_counter , sleUint16 , VER_V8 , VER_V16 ) ,
2001-12-01 17:23:50 +00:00
MKEND ( )
} ;
const SaveLoadEntry partEntries [ ] = {
2002-12-08 16:14:29 +00:00
MKREF ( Part , _next , TYPE_PART , VER_V8 ) ,
MKREF ( Part , _prev , TYPE_PART , VER_V8 ) ,
MKREF ( Part , _player , TYPE_PLAYER , VER_V8 ) ,
MKLINE ( Part , _pitchbend , sleInt16 , VER_V8 ) ,
MKLINE ( Part , _pitchbend_factor , sleUint8 , VER_V8 ) ,
MKLINE ( Part , _transpose , sleInt8 , VER_V8 ) ,
MKLINE ( Part , _vol , sleUint8 , VER_V8 ) ,
MKLINE ( Part , _detune , sleInt8 , VER_V8 ) ,
MKLINE ( Part , _pan , sleInt8 , VER_V8 ) ,
MKLINE ( Part , _on , sleUint8 , VER_V8 ) ,
MKLINE ( Part , _modwheel , sleUint8 , VER_V8 ) ,
MKLINE ( Part , _pedal , sleUint8 , VER_V8 ) ,
2003-05-15 23:08:03 +00:00
MK_OBSOLETE ( Part , _program , sleUint8 , VER_V8 , VER_V16 ) ,
2002-12-08 16:14:29 +00:00
MKLINE ( Part , _pri , sleUint8 , VER_V8 ) ,
MKLINE ( Part , _chan , sleUint8 , VER_V8 ) ,
MKLINE ( Part , _effect_level , sleUint8 , VER_V8 ) ,
MKLINE ( Part , _chorus , sleUint8 , VER_V8 ) ,
MKLINE ( Part , _percussion , sleUint8 , VER_V8 ) ,
MKLINE ( Part , _bank , sleUint8 , VER_V8 ) ,
2001-12-01 17:23:50 +00:00
MKEND ( )
} ;
2002-12-15 01:55:27 +00:00
# ifdef _WIN32_WCE // Don't break savegames made with andys' build
2002-04-11 17:19:16 +00:00
if ( ! ser - > isSaving ( ) & & ser - > checkEOFLoadStream ( ) )
return 0 ;
2003-04-30 13:23:31 +00:00
# elif defined(__PALM_OS__) // previous PalmOS ver. without imuse implementation or not saved(Oopps...forgot it !), is this really working ? will we have sound with old saved game ?
if ( ! ser - > isSaving ( ) & & ser - > checkEOFLoadStream ( ) )
return 0 ; //palmfixme
2002-04-11 17:19:16 +00:00
# endif
2002-03-14 14:45:04 +00:00
2003-05-21 21:38:03 +00:00
int i ;
2001-12-01 17:23:50 +00:00
ser - > _ref_me = this ;
2002-12-08 16:14:29 +00:00
ser - > _save_ref = saveReference ;
ser - > _load_ref = loadReference ;
2001-12-01 17:23:50 +00:00
ser - > saveLoadEntries ( this , mainEntries ) ;
2003-05-23 04:19:47 +00:00
for ( i = 0 ; i < ARRAYSIZE ( _players ) ; + + i )
_players [ i ] . save_or_load ( ser ) ;
2002-07-07 18:04:03 +00:00
ser - > saveLoadArrayOf ( _parts , ARRAYSIZE ( _parts ) , sizeof ( _parts [ 0 ] ) , partEntries ) ;
2002-12-21 20:10:47 +00:00
2002-12-21 23:19:42 +00:00
{ // Load/save the instrument definitions, which were revamped with V11.
2002-12-21 20:10:47 +00:00
Part * part = & _parts [ 0 ] ;
2002-12-21 23:19:42 +00:00
if ( ser - > getVersion ( ) > = VER_V11 ) {
for ( i = ARRAYSIZE ( _parts ) ; i ; - - i , + + part ) {
part - > _instrument . saveOrLoad ( ser ) ;
}
} else {
for ( i = ARRAYSIZE ( _parts ) ; i ; - - i , + + part )
part - > _instrument . clear ( ) ;
2002-12-21 20:10:47 +00:00
}
}
2003-05-21 20:23:01 +00:00
// VolumeFader has been replaced with the more generic ParameterFader.
2003-05-21 21:38:03 +00:00
for ( i = 0 ; i < 8 ; + + i )
ser - > saveLoadEntries ( 0 , volumeFaderEntries ) ;
2001-12-01 17:23:50 +00:00
if ( ! ser - > isSaving ( ) ) {
2002-12-15 01:55:27 +00:00
// Load all sounds that we need
2002-04-14 18:13:08 +00:00
fix_players_after_load ( scumm ) ;
2001-12-01 17:23:50 +00:00
fix_parts_after_load ( ) ;
2002-12-07 18:03:10 +00:00
set_master_volume ( _master_volume ) ;
2003-05-16 22:00:33 +00:00
if ( _midi_native )
reallocateMidiChannels ( _midi_native ) ;
if ( _midi_adlib )
reallocateMidiChannels ( _midi_adlib ) ;
2001-12-01 17:23:50 +00:00
}
return 0 ;
}
# undef MKLINE
# undef MKEND
2003-03-06 17:58:13 +00:00
void IMuseInternal : : fix_parts_after_load ( ) {
2001-12-01 17:23:50 +00:00
Part * part ;
int i ;
2002-04-11 17:19:16 +00:00
for ( i = ARRAYSIZE ( _parts ) , part = _parts ; i ! = 0 ; i - - , part + + ) {
2001-12-01 17:23:50 +00:00
if ( part - > _player )
part - > fix_after_load ( ) ;
}
}
2002-12-15 01:55:27 +00:00
// Only call this routine from the main thread,
// since it uses getResourceAddress
2003-03-06 17:58:13 +00:00
void IMuseInternal : : fix_players_after_load ( Scumm * scumm ) {
2001-12-01 17:23:50 +00:00
Player * player = _players ;
int i ;
2002-04-11 17:19:16 +00:00
for ( i = ARRAYSIZE ( _players ) ; i ! = 0 ; i - - , player + + ) {
2003-05-23 04:19:47 +00:00
if ( player - > isActive ( ) ) {
scumm - > getResourceAddress ( rtSound , player - > getID ( ) ) ;
player - > fixAfterLoad ( ) ;
2001-12-01 17:23:50 +00:00
}
}
}
2003-03-06 17:58:13 +00:00
void Part : : set_detune ( int8 detune ) {
2003-05-23 04:19:47 +00:00
_detune_eff = clamp ( ( _detune = detune ) + _player - > getDetune ( ) , - 128 , 127 ) ;
2003-05-16 15:48:01 +00:00
if ( _mc ) {
2003-05-15 19:39:10 +00:00
_mc - > pitchBend ( clamp ( _pitchbend +
( _detune_eff * 64 / 12 ) +
( _transpose_eff * 8192 / 12 ) , - 8192 , 8191 ) ) ;
}
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
void Part : : set_pitchbend ( int value ) {
2002-09-24 23:45:25 +00:00
_pitchbend = value ;
2003-05-16 15:48:01 +00:00
if ( _mc ) {
2003-05-15 19:39:10 +00:00
_mc - > pitchBend ( clamp ( _pitchbend +
( _detune_eff * 64 / 12 ) +
( _transpose_eff * 8192 / 12 ) , - 8192 , 8191 ) ) ;
}
2001-12-01 17:23:50 +00:00
}
2003-05-23 04:19:47 +00:00
void Part : : setVolume ( uint8 vol ) {
_vol_eff = ( ( _vol = vol ) + 1 ) * _player - > getEffectiveVolume ( ) > > 7 ;
2003-05-16 15:48:01 +00:00
if ( _mc )
_mc - > volume ( _vol_eff ) ;
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
void Part : : set_pri ( int8 pri ) {
2003-05-23 04:19:47 +00:00
_pri_eff = clamp ( ( _pri = pri ) + _player - > getPriority ( ) , 0 , 255 ) ;
2003-05-16 15:48:01 +00:00
if ( _mc )
_mc - > priority ( _pri_eff ) ;
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
void Part : : set_pan ( int8 pan ) {
2003-05-23 04:19:47 +00:00
_pan_eff = clamp ( ( _pan = pan ) + _player - > getPan ( ) , - 64 , 63 ) ;
2003-05-16 15:48:01 +00:00
if ( _mc )
_mc - > panPosition ( _pan_eff + 0x40 ) ;
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
void Part : : set_transpose ( int8 transpose ) {
2003-05-23 04:19:47 +00:00
_transpose_eff = transpose_clamp ( ( _transpose = transpose ) + _player - > getTranspose ( ) , - 12 , 12 ) ;
2003-05-16 15:48:01 +00:00
if ( _mc ) {
2003-05-15 19:39:10 +00:00
_mc - > pitchBend ( clamp ( _pitchbend +
( _detune_eff * 64 / 12 ) +
( _transpose_eff * 8192 / 12 ) , - 8192 , 8191 ) ) ;
}
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
void Part : : set_pedal ( bool value ) {
2001-12-01 17:23:50 +00:00
_pedal = value ;
2003-05-16 15:48:01 +00:00
if ( _mc )
_mc - > sustain ( _pedal ) ;
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
void Part : : set_modwheel ( uint value ) {
2001-12-01 17:23:50 +00:00
_modwheel = value ;
2003-05-16 15:48:01 +00:00
if ( _mc )
_mc - > modulationWheel ( _modwheel ) ;
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
void Part : : set_chorus ( uint chorus ) {
2001-12-01 17:23:50 +00:00
_chorus = chorus ;
2003-05-16 15:48:01 +00:00
if ( _mc )
_mc - > chorusLevel ( _effect_level ) ;
2001-12-01 17:23:50 +00:00
}
2002-04-11 17:19:16 +00:00
void Part : : set_effect_level ( uint level )
{
2001-12-01 17:23:50 +00:00
_effect_level = level ;
2003-05-16 15:48:01 +00:00
if ( _mc )
_mc - > effectLevel ( _effect_level ) ;
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
void Part : : fix_after_load ( ) {
2001-12-01 17:23:50 +00:00
set_transpose ( _transpose ) ;
2003-05-23 04:19:47 +00:00
setVolume ( _vol ) ;
2001-12-01 17:23:50 +00:00
set_detune ( _detune ) ;
set_pri ( _pri ) ;
set_pan ( _pan ) ;
2003-05-15 19:39:10 +00:00
sendAll ( ) ;
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
void Part : : set_pitchbend_factor ( uint8 value ) {
2001-12-01 17:23:50 +00:00
if ( value > 12 )
return ;
set_pitchbend ( 0 ) ;
_pitchbend_factor = value ;
2003-05-16 15:48:01 +00:00
if ( _mc )
_mc - > pitchBendFactor ( _pitchbend_factor ) ;
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
void Part : : set_onoff ( bool on ) {
2001-12-01 17:23:50 +00:00
if ( _on ! = on ) {
_on = on ;
if ( ! on )
off ( ) ;
if ( ! _percussion )
2003-05-23 04:19:47 +00:00
_player - > _se - > reallocateMidiChannels ( _player - > getMidiDriver ( ) ) ;
2001-12-01 17:23:50 +00:00
}
}
2003-03-06 17:58:13 +00:00
void Part : : set_instrument ( byte * data ) {
2002-12-18 13:22:40 +00:00
_instrument . adlib ( data ) ;
2003-05-16 15:48:01 +00:00
if ( clearToTransmit ( ) )
_instrument . send ( _mc ) ;
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
void Part : : load_global_instrument ( byte slot ) {
2003-05-16 01:52:45 +00:00
_player - > _se - > copyGlobalAdlibInstrument ( slot , & _instrument ) ;
2003-05-16 15:48:01 +00:00
if ( clearToTransmit ( ) )
_instrument . send ( _mc ) ;
2002-12-20 13:09:01 +00:00
}
2003-03-06 17:58:13 +00:00
void Part : : key_on ( byte note , byte velocity ) {
2003-05-07 19:24:14 +00:00
MidiChannel * mc = _mc ;
_actives [ note > > 4 ] | = ( 1 < < ( note & 0xF ) ) ;
// DEBUG
if ( _unassigned_instrument & & ! _percussion ) {
_unassigned_instrument = false ;
2003-05-15 19:39:10 +00:00
if ( ! _instrument . isValid ( ) ) {
warning ( " [%02d] No instrument specified " , ( int ) _chan ) ;
return ;
}
2003-05-07 19:24:14 +00:00
}
if ( mc & & _instrument . isValid ( ) ) {
mc - > noteOn ( note , velocity ) ;
} else if ( _percussion ) {
2003-05-23 04:19:47 +00:00
mc = _player - > getMidiDriver ( ) - > getPercussionChannel ( ) ;
2003-05-07 19:24:14 +00:00
if ( ! mc )
return ;
mc - > volume ( _vol_eff ) ;
mc - > programChange ( _bank ) ;
mc - > noteOn ( note , velocity ) ;
}
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
void Part : : key_off ( byte note ) {
2003-05-07 19:24:14 +00:00
MidiChannel * mc = _mc ;
_actives [ note > > 4 ] & = ~ ( 1 < < ( note & 0xF ) ) ;
if ( mc ) {
mc - > noteOff ( note ) ;
} else if ( _percussion ) {
2003-05-23 04:19:47 +00:00
mc = _player - > getMidiDriver ( ) - > getPercussionChannel ( ) ;
2003-05-07 19:24:14 +00:00
if ( mc )
mc - > noteOff ( note ) ;
}
2001-12-01 17:23:50 +00:00
}
2003-05-16 01:52:45 +00:00
void Part : : init ( ) {
2001-12-01 17:23:50 +00:00
_player = NULL ;
_next = NULL ;
_prev = NULL ;
_mc = NULL ;
2002-11-26 16:54:58 +00:00
memset ( _actives , 0 , sizeof ( _actives ) ) ;
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
void Part : : setup ( Player * player ) {
2001-12-01 17:23:50 +00:00
_player = player ;
2002-04-11 17:19:16 +00:00
2003-05-23 04:19:47 +00:00
_percussion = ( player - > isGM ( ) & & _chan = = 9 ) ; // true;
2001-12-01 17:23:50 +00:00
_on = true ;
2003-05-23 04:19:47 +00:00
_pri_eff = player - > getPriority ( ) ;
2001-12-01 17:23:50 +00:00
_pri = 0 ;
_vol = 127 ;
2003-05-23 04:19:47 +00:00
_vol_eff = player - > getEffectiveVolume ( ) ;
_pan = clamp ( player - > getPan ( ) , - 64 , 63 ) ;
_transpose_eff = player - > getTranspose ( ) ;
2001-12-01 17:23:50 +00:00
_transpose = 0 ;
_detune = 0 ;
2003-05-23 04:19:47 +00:00
_detune_eff = player - > getDetune ( ) ;
2002-10-14 16:42:57 +00:00
_pitchbend_factor = 2 ;
2001-12-01 17:23:50 +00:00
_pitchbend = 0 ;
_effect_level = 64 ;
2002-12-18 17:14:05 +00:00
_instrument . clear ( ) ;
2003-05-07 19:24:14 +00:00
_unassigned_instrument = true ;
2001-12-01 17:23:50 +00:00
_chorus = 0 ;
_modwheel = 0 ;
_bank = 0 ;
_pedal = false ;
_mc = NULL ;
}
2003-03-06 17:58:13 +00:00
void Part : : uninit ( ) {
2001-12-01 17:23:50 +00:00
if ( ! _player )
return ;
off ( ) ;
2003-05-23 04:19:47 +00:00
_player - > removePart ( this ) ;
2001-12-01 17:23:50 +00:00
_player = NULL ;
}
2003-03-06 17:58:13 +00:00
void Part : : off ( ) {
2003-05-15 22:31:56 +00:00
if ( _mc ) {
_mc - > allNotesOff ( ) ;
_mc - > release ( ) ;
_mc = NULL ;
}
2003-05-16 01:52:45 +00:00
memset ( _actives , 0 , sizeof ( _actives ) ) ;
2001-12-01 17:23:50 +00:00
}
2003-05-15 19:39:10 +00:00
bool Part : : clearToTransmit ( ) {
if ( _mc ) return true ;
2003-05-23 04:19:47 +00:00
if ( _instrument . isValid ( ) ) _player - > _se - > reallocateMidiChannels ( _player - > getMidiDriver ( ) ) ;
2003-05-15 19:39:10 +00:00
return false ;
2001-12-01 17:23:50 +00:00
}
2003-05-15 19:39:10 +00:00
void Part : : sendAll ( ) {
if ( ! clearToTransmit ( ) ) return ;
_mc - > pitchBendFactor ( _pitchbend_factor ) ;
_mc - > pitchBend ( clamp ( _pitchbend +
( _detune_eff * 64 / 12 ) +
( _transpose_eff * 8192 / 12 ) , - 8192 , 8191 ) ) ;
_mc - > volume ( _vol_eff ) ;
_mc - > sustain ( _pedal ) ;
_mc - > modulationWheel ( _modwheel ) ;
_mc - > panPosition ( _pan_eff + 0x40 ) ;
_mc - > effectLevel ( _effect_level ) ;
2003-05-16 04:02:33 +00:00
if ( _instrument . isValid ( ) )
2003-05-15 19:39:10 +00:00
_instrument . send ( _mc ) ;
_mc - > chorusLevel ( _effect_level ) ;
_mc - > priority ( _pri_eff ) ;
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
int Part : : update_actives ( uint16 * active ) {
2003-05-15 19:39:10 +00:00
int i , j ;
uint16 * act , mask , bits ;
int count = 0 ;
bits = 1 < < _chan ;
act = _actives ;
for ( i = 8 ; i ; i - - ) {
mask = * act + + ;
if ( mask ) {
for ( j = 16 ; j ; j - - , mask > > = 1 , active + + ) {
if ( mask & 1 & & ! ( * active & bits ) ) {
* active | = bits ;
count + + ;
}
}
} else {
active + = 16 ;
}
}
return count ;
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
void Part : : set_program ( byte program ) {
2003-05-15 23:08:03 +00:00
_bank = 0 ;
2003-05-23 04:19:47 +00:00
_instrument . program ( program , _player - > isMT32 ( ) ) ;
2003-05-16 15:48:01 +00:00
if ( clearToTransmit ( ) )
_instrument . send ( _mc ) ;
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
void Part : : set_instrument ( uint b ) {
2002-04-11 17:19:16 +00:00
_bank = ( byte ) ( b > > 8 ) ;
2003-05-23 04:19:47 +00:00
_instrument . program ( ( byte ) b , _player - > isMT32 ( ) ) ;
2003-05-16 15:48:01 +00:00
if ( clearToTransmit ( ) )
_instrument . send ( _mc ) ;
2002-04-14 18:13:08 +00:00
}
2003-05-23 04:19:47 +00:00
void Part : : silence ( ) {
if ( ! _mc )
return ;
_mc - > allNotesOff ( ) ;
memset ( _actives , 0 , sizeof ( _actives ) ) ;
}
2002-12-15 01:55:27 +00:00
////////////////////////////////////////
//
2003-05-16 01:52:45 +00:00
// Some more IMuseInternal stuff
2002-12-15 01:55:27 +00:00
//
////////////////////////////////////////
2002-04-14 18:13:08 +00:00
2003-05-16 01:52:45 +00:00
void IMuseInternal : : midiTimerCallback ( void * data ) {
MidiDriver * driver = ( MidiDriver * ) data ;
2002-12-03 17:54:25 +00:00
if ( g_scumm - > _imuse )
2003-05-16 01:52:45 +00:00
g_scumm - > _imuse - > on_timer ( driver ) ;
2002-08-22 12:09:06 +00:00
}
2003-05-16 01:52:45 +00:00
void IMuseInternal : : reallocateMidiChannels ( MidiDriver * midi ) {
2002-04-14 18:13:08 +00:00
Part * part , * hipart ;
int i ;
byte hipri , lopri ;
2002-11-26 16:54:58 +00:00
Part * lopart ;
2002-04-14 18:13:08 +00:00
while ( true ) {
hipri = 0 ;
hipart = NULL ;
2003-05-15 22:31:56 +00:00
for ( i = 32 , part = _parts ; i ; i - - , part + + ) {
2003-05-23 04:19:47 +00:00
if ( part - > _player & & part - > _player - > getMidiDriver ( ) = = midi & &
2003-05-16 01:52:45 +00:00
! part - > _percussion & & part - > _on & &
! part - > _mc & & part - > _pri_eff > = hipri )
{
2002-04-14 18:13:08 +00:00
hipri = part - > _pri_eff ;
hipart = part ;
}
}
if ( ! hipart )
return ;
2003-05-16 01:52:45 +00:00
if ( ( hipart - > _mc = midi - > allocateChannel ( ) ) = = NULL ) {
2002-12-18 17:14:05 +00:00
lopri = 255 ;
lopart = NULL ;
2003-05-15 22:31:56 +00:00
for ( i = 32 , part = _parts ; i ; i - - , part + + ) {
2003-05-16 01:52:45 +00:00
if ( part - > _mc & & part - > _mc - > device ( ) = = midi & & part - > _pri_eff < = lopri ) {
2002-12-18 17:14:05 +00:00
lopri = part - > _pri_eff ;
lopart = part ;
}
2002-04-14 18:13:08 +00:00
}
2002-12-18 17:14:05 +00:00
if ( lopart = = NULL | | lopri > = hipri )
return ;
lopart - > off ( ) ;
2002-11-26 16:54:58 +00:00
2003-05-16 01:52:45 +00:00
if ( ( hipart - > _mc = midi - > allocateChannel ( ) ) = = NULL )
2002-12-18 17:14:05 +00:00
return ;
}
2003-05-15 19:39:10 +00:00
hipart - > sendAll ( ) ;
2002-04-14 18:13:08 +00:00
}
}
2003-05-16 01:52:45 +00:00
void IMuseInternal : : setGlobalAdlibInstrument ( byte slot , byte * data ) {
2002-12-18 13:22:40 +00:00
if ( slot < 32 ) {
2003-05-16 01:52:45 +00:00
_global_adlib_instruments [ slot ] . adlib ( data ) ;
2002-12-18 13:22:40 +00:00
}
2002-11-21 19:06:42 +00:00
}
2003-05-16 01:52:45 +00:00
void IMuseInternal : : copyGlobalAdlibInstrument ( byte slot , Instrument * dest ) {
2002-12-20 13:09:01 +00:00
if ( slot > = 32 )
return ;
2003-05-16 01:52:45 +00:00
_global_adlib_instruments [ slot ] . copy_to ( dest ) ;
2002-12-20 13:09:01 +00:00
}
2002-12-21 21:09:36 +00:00
////////////////////////////////////////////////////////////
//
// IMuse implementation
//
// IMuse actually serves as a concurency monitor front-end
// to IMuseInternal and ensures that only one thread
// accesses the object at a time. This is necessary to
// prevent scripts and the MIDI parser from yanking objects
// out from underneath each other.
//
////////////////////////////////////////////////////////////
IMuse : : IMuse ( OSystem * system , IMuseInternal * target ) : _system ( system ) , _target ( target ) { _mutex = system - > create_mutex ( ) ; }
IMuse : : ~ IMuse ( ) { if ( _mutex ) _system - > delete_mutex ( _mutex ) ; if ( _target ) delete _target ; }
inline void IMuse : : in ( ) { _system - > lock_mutex ( _mutex ) ; }
inline void IMuse : : out ( ) { _system - > unlock_mutex ( _mutex ) ; }
2003-05-16 01:52:45 +00:00
void IMuse : : on_timer ( MidiDriver * midi ) { in ( ) ; _target - > on_timer ( midi ) ; out ( ) ; }
2002-12-21 21:09:36 +00:00
void IMuse : : pause ( bool paused ) { in ( ) ; _target - > pause ( paused ) ; out ( ) ; }
int IMuse : : save_or_load ( Serializer * ser , Scumm * scumm ) { in ( ) ; int ret = _target - > save_or_load ( ser , scumm ) ; out ( ) ; return ret ; }
int IMuse : : set_music_volume ( uint vol ) { in ( ) ; int ret = _target - > set_music_volume ( vol ) ; out ( ) ; return ret ; }
int IMuse : : get_music_volume ( ) { in ( ) ; int ret = _target - > get_music_volume ( ) ; out ( ) ; return ret ; }
int IMuse : : set_master_volume ( uint vol ) { in ( ) ; int ret = _target - > set_master_volume ( vol ) ; out ( ) ; return ret ; }
int IMuse : : get_master_volume ( ) { in ( ) ; int ret = _target - > get_master_volume ( ) ; out ( ) ; return ret ; }
2003-03-18 16:13:52 +00:00
bool IMuse : : startSound ( int sound ) { in ( ) ; bool ret = _target - > startSound ( sound ) ; out ( ) ; return ret ; }
int IMuse : : stopSound ( int sound ) { in ( ) ; int ret = _target - > stopSound ( sound ) ; out ( ) ; return ret ; }
2002-12-21 21:09:36 +00:00
int IMuse : : stop_all_sounds ( ) { in ( ) ; int ret = _target - > stop_all_sounds ( ) ; out ( ) ; return ret ; }
2003-05-23 18:35:53 +00:00
int IMuse : : getSoundStatus ( int sound ) { in ( ) ; int ret = _target - > getSoundStatus ( sound , true ) ; out ( ) ; return ret ; }
bool IMuse : : get_sound_active ( int sound ) { in ( ) ; bool ret = _target - > getSoundStatus ( sound , false ) ? 1 : 0 ; out ( ) ; return ret ; }
2003-03-18 16:13:52 +00:00
int32 IMuse : : doCommand ( int a , int b , int c , int d , int e , int f , int g , int h ) { in ( ) ; int32 ret = _target - > doCommand ( a , b , c , d , e , f , g , h ) ; out ( ) ; return ret ; }
2002-12-21 21:09:36 +00:00
int IMuse : : clear_queue ( ) { in ( ) ; int ret = _target - > clear_queue ( ) ; out ( ) ; return ret ; }
void IMuse : : setBase ( byte * * base ) { in ( ) ; _target - > setBase ( base ) ; out ( ) ; }
uint32 IMuse : : property ( int prop , uint32 value ) { in ( ) ; uint32 ret = _target - > property ( prop , value ) ; out ( ) ; return ret ; }
2003-05-19 05:04:38 +00:00
MidiDriver * IMuse : : getMidiDriver ( ) { in ( ) ; MidiDriver * ret = _target - > getMidiDriver ( ) ; out ( ) ; return ret ; }
2002-12-21 21:09:36 +00:00
2002-10-21 07:31:51 +00:00
// The IMuse::create method provides a front-end factory
// for creating IMuseInternal without exposing that class
// to the client.
2003-05-16 20:38:04 +00:00
IMuse * IMuse : : create ( OSystem * syst , MidiDriver * midi ) {
IMuseInternal * engine = IMuseInternal : : create ( syst , midi ) ;
2002-12-21 21:09:36 +00:00
return new IMuse ( syst , engine ) ;
2002-04-29 11:48:33 +00:00
}