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"
2002-08-21 16:53:11 +00:00
# include "scumm/scumm.h"
# include "sound/fmopl.h"
# include "sound/mididrv.h"
# include "scumm/imuse.h"
2002-12-18 13:22:40 +00:00
# include "scumm/instrument.h"
2002-08-21 16:53:11 +00:00
# include "scumm/saveload.h"
2002-08-29 23:45:15 +00:00
# include "scumm/sound.h"
2002-09-08 01:08:12 +00:00
# include "common/util.h"
2001-12-01 17:23:50 +00:00
2003-05-07 19:24:14 +00:00
// Unremark this statement to activate some of
// the most common iMuse diagnostic messages.
2003-05-15 19:40:10 +00:00
// #define IMUSE_DEBUG
2003-05-07 19:24:14 +00:00
2002-12-15 01:55:27 +00:00
//
// Some constants
//
2001-12-01 17:23:50 +00:00
# define TICKS_PER_BEAT 480
2002-11-06 21:34:38 +00:00
# define IMUSE_SYSEX_ID 0x7D
# define ROLAND_SYSEX_ID 0x41
2002-07-23 10:29:11 +00:00
# define PERCUSSION_CHANNEL 9
2001-12-01 17:23:50 +00:00
# define TRIGGER_ID 0
# define COMMAND_ID 1
2002-03-11 04:37:06 +00:00
# define MDPG_TAG "MDpg"
# define MDHD_TAG "MDhd"
2002-04-18 06:22:18 +00:00
2002-12-15 01:55:27 +00:00
// Put IMUSE specific classes here, instead of in a .h file
// they will only be used from this file, so it will reduce
// compile time.
2002-04-14 18:13:08 +00:00
struct Part ;
struct HookDatas {
2003-05-05 16:07:10 +00:00
byte _jump [ 2 ] ;
byte _transpose ;
2002-04-14 18:13:08 +00:00
byte _part_onoff [ 16 ] ;
byte _part_volume [ 16 ] ;
byte _part_program [ 16 ] ;
byte _part_transpose [ 16 ] ;
int query_param ( int param , byte chan ) ;
int set ( byte cls , byte value , byte chan ) ;
} ;
struct Player {
2002-04-29 11:48:33 +00:00
IMuseInternal * _se ;
2003-05-16 01:52:45 +00:00
MidiDriver * _midi ;
2002-04-14 18:13:08 +00:00
Part * _parts ;
bool _active ;
bool _scanning ;
int _id ;
byte _priority ;
byte _volume ;
int8 _pan ;
int8 _transpose ;
int8 _detune ;
uint _vol_chan ;
byte _vol_eff ;
2002-07-07 18:04:03 +00:00
2002-04-14 18:13:08 +00:00
uint _song_index ;
uint _track_index ;
uint _timer_counter ;
uint _loop_to_beat ;
uint _loop_from_beat ;
uint _loop_counter ;
uint _loop_to_tick ;
uint _loop_from_tick ;
uint32 _tempo ;
2002-12-15 01:55:27 +00:00
uint32 _tempo_eff ; // No Save
2002-04-14 18:13:08 +00:00
uint32 _cur_pos ;
uint32 _next_pos ;
uint32 _song_offset ;
2002-12-15 01:55:27 +00:00
uint32 _timer_speed ; // No Save
2002-04-14 18:13:08 +00:00
uint _tick_index ;
uint _beat_index ;
uint _ticks_per_beat ;
2002-12-15 01:55:27 +00:00
byte _speed ; // No Save
2002-04-14 18:13:08 +00:00
bool _abort ;
HookDatas _hook ;
2002-05-04 00:20:39 +00:00
bool _mt32emulate ;
2002-09-29 11:11:42 +00:00
bool _isGM ;
2002-05-04 00:20:39 +00:00
2002-12-15 01:55:27 +00:00
// Player part
2002-04-14 18:13:08 +00:00
void hook_clear ( ) ;
void clear ( ) ;
2003-05-16 01:52:45 +00:00
bool startSound ( int sound , MidiDriver * midi ) ;
2002-04-14 18:13:08 +00:00
void uninit_parts ( ) ;
byte * parse_midi ( byte * s ) ;
void key_off ( uint8 chan , byte data ) ;
void key_on ( uint8 chan , byte data , byte velocity ) ;
void part_set_transpose ( uint8 chan , byte relative , int8 b ) ;
void parse_sysex ( byte * p , uint len ) ;
2002-10-10 15:06:02 +00:00
void maybe_jump ( byte cmd , uint track , uint beat , uint tick ) ;
2002-04-14 18:13:08 +00:00
void maybe_set_transpose ( byte * data ) ;
void maybe_part_onoff ( byte * data ) ;
void maybe_set_volume ( byte * data ) ;
void maybe_set_program ( byte * data ) ;
void maybe_set_transpose_part ( byte * data ) ;
uint update_actives ( ) ;
Part * get_part ( uint8 part ) ;
void turn_off_pedals ( ) ;
int set_vol ( byte vol ) ;
int get_param ( int param , byte chan ) ;
int query_part_param ( int param , byte chan ) ;
int set_transpose ( byte relative , int b ) ;
void set_priority ( int pri ) ;
void set_pan ( int pan ) ;
void set_detune ( int detune ) ;
void turn_off_parts ( ) ;
void play_active_notes ( ) ;
void cancel_volume_fade ( ) ;
static void decode_sysex_bytes ( byte * src , byte * dst , int len ) ;
void clear_active_note ( int chan , byte note ) ;
void set_active_note ( int chan , byte note ) ;
void clear_active_notes ( ) ;
2002-12-15 01:55:27 +00:00
// Sequencer part
2002-04-14 18:13:08 +00:00
bool set_loop ( uint count , uint tobeat , uint totick , uint frombeat , uint fromtick ) ;
void clear_loop ( ) ;
void set_speed ( byte speed ) ;
bool jump ( uint track , uint beat , uint tick ) ;
void uninit_seq ( ) ;
void set_tempo ( uint32 data ) ;
int start_seq_sound ( int sound ) ;
void find_sustaining_notes ( byte * a , byte * b , uint32 l ) ;
int scan ( uint totrack , uint tobeat , uint totick ) ;
int query_param ( int param ) ;
int fade_vol ( byte vol , int time ) ;
2002-09-11 13:28:34 +00:00
bool is_fading_out ( ) ;
2002-04-14 18:13:08 +00:00
void sequencer_timer ( ) ;
2003-04-30 13:23:31 +00:00
Player ( ) {
memset ( this , 0 , sizeof ( Player ) ) ; // palmos
}
2002-04-14 18:13:08 +00:00
} ;
struct VolumeFader {
Player * player ;
bool active ;
byte curvol ;
2002-07-07 18:04:03 +00:00
uint16 speed_lo_max , num_steps ;
2002-04-14 18:13:08 +00:00
int8 speed_hi ;
int8 direction ;
int8 speed_lo ;
uint16 speed_lo_counter ;
2002-07-07 18:04:03 +00:00
void initialize ( ) {
active = false ;
2002-09-11 13:28:34 +00:00
}
void on_timer ( bool probe ) ;
byte fading_to ( ) ;
2003-04-30 13:23:31 +00:00
VolumeFader ( ) {
memset ( this , 0 , sizeof ( VolumeFader ) ) ; //palmos
}
2002-04-14 18:13:08 +00:00
} ;
struct SustainingNotes {
SustainingNotes * next ;
SustainingNotes * prev ;
Player * player ;
2002-07-07 18:04:03 +00:00
byte note , chan ;
2002-04-14 18:13:08 +00:00
uint32 off_pos ;
uint32 pos ;
uint16 counter ;
} ;
struct CommandQueue {
uint16 array [ 8 ] ;
} ;
struct IsNoteCmdData {
byte chan ;
byte note ;
byte vel ;
} ;
struct Part {
int _slot ;
Part * _next , * _prev ;
MidiChannel * _mc ;
Player * _player ;
int16 _pitchbend ;
byte _pitchbend_factor ;
2002-07-07 18:04:03 +00:00
int8 _transpose , _transpose_eff ;
byte _vol , _vol_eff ;
int8 _detune , _detune_eff ;
int8 _pan , _pan_eff ;
2002-04-14 18:13:08 +00:00
bool _on ;
byte _modwheel ;
bool _pedal ;
int8 _pri ;
byte _pri_eff ;
byte _chan ;
byte _effect_level ;
byte _chorus ;
byte _percussion ;
byte _bank ;
2002-12-18 13:22:40 +00:00
// New abstract instrument definition
Instrument _instrument ;
2003-05-07 19:24:14 +00:00
bool _unassigned_instrument ; // For diagnostic reporting purposes only
2002-12-18 13:22:40 +00:00
// Used to be in MidiDriver
2002-11-26 16:54:58 +00:00
uint16 _actives [ 8 ] ;
2002-04-14 18:13:08 +00:00
void key_on ( byte note , byte velocity ) ;
void key_off ( byte note ) ;
2003-05-15 22:31:56 +00:00
void set_param ( byte param , int value ) { }
2003-05-16 01:52:45 +00:00
void init ( ) ;
2002-04-14 18:13:08 +00:00
void setup ( Player * player ) ;
void uninit ( ) ;
void off ( ) ;
void silence ( ) ;
void set_instrument ( uint b ) ;
2003-03-06 17:58:13 +00:00
void set_instrument ( byte * data ) ;
2002-12-20 13:09:01 +00:00
void load_global_instrument ( byte b ) ;
2002-04-14 18:13:08 +00:00
void set_transpose ( int8 transpose ) ;
void set_vol ( uint8 volume ) ;
void set_detune ( int8 detune ) ;
void set_pri ( int8 pri ) ;
void set_pan ( int8 pan ) ;
void set_modwheel ( uint value ) ;
void set_pedal ( bool value ) ;
void set_pitchbend ( int value ) ;
void release_pedal ( ) ;
void set_program ( byte program ) ;
void set_chorus ( uint chorus ) ;
void set_effect_level ( uint level ) ;
2002-07-07 18:04:03 +00:00
2002-04-14 18:13:08 +00:00
int update_actives ( uint16 * active ) ;
void set_pitchbend_factor ( uint8 value ) ;
void set_onoff ( bool on ) ;
void fix_after_load ( ) ;
2003-05-15 19:39:10 +00:00
void sendAll ( ) ;
bool clearToTransmit ( ) ;
2003-04-30 13:23:31 +00:00
Part ( ) {
memset ( this , 0 , sizeof ( Part ) ) ;
}
2002-04-14 18:13:08 +00:00
} ;
2002-10-14 16:42:57 +00:00
struct ImTrigger {
int sound ;
byte id ;
2002-11-23 16:15:33 +00:00
uint16 expire ;
2002-10-14 16:42:57 +00:00
byte command [ 4 ] ;
} ;
2002-04-14 18:13:08 +00:00
// WARNING: This is the internal variant of the IMUSE class.
// imuse.h contains a public version of the same class.
// the public version, only contains a set of methods.
2002-12-21 21:09:36 +00:00
class IMuseInternal {
2002-07-07 18:04:03 +00:00
friend struct Player ;
2002-12-21 21:09:36 +00:00
2002-04-14 18:13:08 +00:00
private :
2003-05-16 01:52:45 +00:00
MidiDriver * _midi_adlib ;
MidiDriver * _midi_native ;
2002-04-14 18:13:08 +00:00
byte * * _base_sounds ;
private :
2002-08-21 16:07:07 +00:00
bool _paused ;
2002-04-14 18:13:08 +00:00
bool _active_volume_faders ;
2002-07-07 18:04:03 +00:00
bool _initialized ;
2002-04-14 18:13:08 +00:00
byte _volume_fader_counter ;
int _game_tempo ;
uint _queue_end , _queue_pos , _queue_sound ;
byte _queue_adding ;
SustainingNotes * _sustain_notes_used ;
SustainingNotes * _sustain_notes_free ;
SustainingNotes * _sustain_notes_head ;
byte _queue_marker ;
byte _queue_cleared ;
2002-12-21 21:09:36 +00:00
byte _master_volume ; // Master volume. 0-255
byte _music_volume ; // Global music volume. 0-255
2002-04-14 18:13:08 +00:00
uint16 _trigger_count ;
2002-12-21 21:09:36 +00:00
ImTrigger _snm_triggers [ 16 ] ; // Sam & Max triggers
2002-11-23 16:15:33 +00:00
uint16 _snm_trigger_index ;
2002-07-07 18:04:03 +00:00
2002-04-14 18:13:08 +00:00
uint16 _channel_volume [ 8 ] ;
2002-12-15 01:55:27 +00:00
uint16 _channel_volume_eff [ 8 ] ; // No Save
2002-04-14 18:13:08 +00:00
uint16 _volchan_table [ 8 ] ;
2002-07-07 18:04:03 +00:00
2002-04-14 18:13:08 +00:00
Player _players [ 8 ] ;
SustainingNotes _sustaining_notes [ 24 ] ;
VolumeFader _volume_fader [ 8 ] ;
Part _parts [ 32 ] ;
2002-07-07 18:04:03 +00:00
2002-04-14 18:13:08 +00:00
uint16 _active_notes [ 128 ] ;
2003-05-16 01:52:45 +00:00
Instrument _global_adlib_instruments [ 32 ] ;
2002-04-14 18:13:08 +00:00
CommandQueue _cmd_queue [ 64 ] ;
byte * findTag ( int sound , char * tag , int index ) ;
2002-05-04 00:20:39 +00:00
bool isMT32 ( int sound ) ;
2002-09-29 11:11:42 +00:00
bool isGM ( int sound ) ;
2002-04-14 18:13:08 +00:00
int get_queue_sound_status ( int sound ) ;
Player * allocate_player ( byte priority ) ;
void handle_marker ( uint id , byte data ) ;
int get_channel_volume ( uint a ) ;
2003-05-16 01:52:45 +00:00
void initMidiDriver ( MidiDriver * midi ) ;
2002-04-14 18:13:08 +00:00
void init_players ( ) ;
void init_parts ( ) ;
void init_volume_fader ( ) ;
void init_sustaining_notes ( ) ;
void init_queue ( ) ;
2003-05-16 01:52:45 +00:00
void sequencer_timers ( MidiDriver * midi ) ;
void expire_sustain_notes ( MidiDriver * midi ) ;
void expire_volume_faders ( MidiDriver * midi ) ;
2002-04-14 18:13:08 +00:00
2003-05-16 01:52:45 +00:00
Part * allocate_part ( byte pri , MidiDriver * midi ) ;
2002-04-14 18:13:08 +00:00
2002-11-23 16:15:33 +00:00
int32 ImSetTrigger ( int sound , int id , int a , int b , int c , int d ) ;
int32 ImClearTrigger ( int sound , int id ) ;
2003-05-15 18:24:59 +00:00
int32 ImFireAllTriggers ( int sound ) ;
2002-11-23 16:15:33 +00:00
2002-04-14 18:13:08 +00:00
int enqueue_command ( int a , int b , int c , int d , int e , int f , int g ) ;
int enqueue_trigger ( int sound , int marker ) ;
int query_queue ( int param ) ;
Player * get_player_byid ( int id ) ;
2002-07-07 18:04:03 +00:00
2002-04-14 18:13:08 +00:00
int get_volchan_entry ( uint a ) ;
int set_volchan_entry ( uint a , uint b ) ;
int set_channel_volume ( uint chan , uint vol ) ;
void update_volumes ( ) ;
void reset_tick ( ) ;
VolumeFader * allocate_volume_fader ( ) ;
int set_volchan ( int sound , int volchan ) ;
void fix_parts_after_load ( ) ;
void fix_players_after_load ( Scumm * scumm ) ;
2002-12-08 16:14:29 +00:00
static int saveReference ( void * me_ref , byte type , void * ref ) ;
static void * loadReference ( void * me_ref , byte type , int ref ) ;
2002-04-14 18:13:08 +00:00
2003-05-16 01:52:45 +00:00
static void midiTimerCallback ( void * data ) ;
2002-04-14 18:13:08 +00:00
public :
2003-04-30 13:23:31 +00:00
IMuseInternal ( ) {
memset ( this , 0 , sizeof ( IMuseInternal ) ) ; // palmos
}
2002-10-21 07:31:51 +00:00
~ IMuseInternal ( ) ;
2002-04-14 18:13:08 +00:00
int initialize ( OSystem * syst , MidiDriver * midi , SoundMixer * mixer ) ;
2003-05-16 01:52:45 +00:00
void reallocateMidiChannels ( MidiDriver * midi ) ;
void setGlobalAdlibInstrument ( byte slot , byte * data ) ;
void copyGlobalAdlibInstrument ( byte slot , Instrument * dest ) ;
2002-04-14 18:13:08 +00:00
2003-05-15 22:31:56 +00:00
// IMuse interface
2002-07-07 18:04:03 +00:00
2003-05-16 01:52:45 +00:00
void on_timer ( MidiDriver * midi ) ;
2002-04-14 18:13:08 +00:00
void pause ( bool paused ) ;
int terminate ( ) ;
int save_or_load ( Serializer * ser , Scumm * scumm ) ;
int set_music_volume ( uint vol ) ;
int get_music_volume ( ) ;
int set_master_volume ( uint vol ) ;
int get_master_volume ( ) ;
2003-03-18 16:13:52 +00:00
bool startSound ( int sound ) ;
int stopSound ( int sound ) ;
2002-04-14 18:13:08 +00:00
int stop_all_sounds ( ) ;
2003-03-23 13:14:54 +00:00
int getSoundStatus ( int sound ) ;
2002-12-05 21:45:55 +00:00
bool get_sound_active ( int sound ) ;
2003-03-18 16:13:52 +00:00
int32 doCommand ( int a , int b , int c , int d , int e , int f , int g , int h ) ;
2002-04-14 18:13:08 +00:00
int clear_queue ( ) ;
void setBase ( byte * * base ) ;
uint32 property ( int prop , uint32 value ) ;
2002-07-07 18:04:03 +00:00
2002-04-29 11:48:33 +00:00
static IMuseInternal * create ( OSystem * syst , MidiDriver * midi , SoundMixer * mixer ) ;
2002-04-14 18:13:08 +00:00
} ;
2002-12-15 01:55:27 +00:00
////////////////////////////////////////
//
// IMUSE helper functions
//
////////////////////////////////////////
2002-04-14 18:13:08 +00:00
2003-03-06 17:58:13 +00:00
static int clamp ( int val , int min , int max ) {
2002-04-11 17:19:16 +00:00
if ( val < min )
2001-12-01 17:23:50 +00:00
return min ;
2002-04-11 17:19:16 +00:00
if ( val > max )
2001-12-01 17:23:50 +00:00
return max ;
return val ;
}
2003-03-06 17:58:13 +00:00
static int transpose_clamp ( int a , int b , int c ) {
2002-04-11 17:19:16 +00:00
if ( b > a )
a + = ( b - a + 11 ) / 12 * 12 ;
if ( c < a )
a - = ( a - c + 11 ) / 12 * 12 ;
2001-12-01 17:23:50 +00:00
return a ;
}
2003-03-06 17:58:13 +00:00
static uint32 get_delta_time ( byte * * s ) {
2002-04-11 17:19:16 +00:00
byte * d = * s , b ;
2001-12-01 17:23:50 +00:00
uint32 time = 0 ;
do {
b = * d + + ;
2002-04-11 17:19:16 +00:00
time = ( time < < 7 ) | ( b & 0x7F ) ;
} while ( b & 0x80 ) ;
2001-12-01 17:23:50 +00:00
* s = d ;
return time ;
}
2003-03-06 17:58:13 +00:00
static uint read_word ( byte * a ) {
2002-04-11 17:19:16 +00:00
return ( a [ 0 ] < < 8 ) + a [ 1 ] ;
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
static void skip_midi_cmd ( byte * * song_ptr ) {
2001-12-01 17:23:50 +00:00
byte * s , code ;
const byte num_skip [ ] = {
2002-04-11 17:19:16 +00:00
2 , 2 , 2 , 2 , 1 , 1 , 2
2001-12-01 17:23:50 +00:00
} ;
s = * song_ptr ;
code = * s + + ;
2002-04-11 17:19:16 +00:00
if ( code < 0x80 ) {
2001-12-01 17:23:50 +00:00
s = NULL ;
2002-04-11 17:19:16 +00:00
} else if ( code < 0xF0 ) {
s + = num_skip [ ( code & 0x70 ) > > 4 ] ;
2001-12-01 17:23:50 +00:00
} else {
2002-04-11 17:19:16 +00:00
if ( code = = 0xF0 | | code = = 0xF7 | | code = = 0xFF & & * s + + ! = 0x2F ) {
2001-12-01 17:23:50 +00:00
s + = get_delta_time ( & s ) ;
} else {
s = NULL ;
}
}
* song_ptr = s ;
}
2003-03-06 17:58:13 +00:00
static int is_note_cmd ( byte * * a , IsNoteCmdData * isnote ) {
2001-12-01 17:23:50 +00:00
byte * s = * a ;
byte code ;
code = * s + + ;
2002-04-11 17:19:16 +00:00
switch ( code > > 4 ) {
2002-12-15 01:55:27 +00:00
case 8 : // Key Off
2002-04-11 17:19:16 +00:00
isnote - > chan = code & 0xF ;
2001-12-01 17:23:50 +00:00
isnote - > note = * s + + ;
isnote - > vel = * s + + ;
* a = s ;
return 1 ;
2002-12-15 01:55:27 +00:00
case 9 : // Key On
2002-04-11 17:19:16 +00:00
isnote - > chan = code & 0xF ;
2001-12-01 17:23:50 +00:00
isnote - > note = * s + + ;
isnote - > vel = * s + + ;
* a = s ;
if ( isnote - > vel )
return 2 ;
return 1 ;
case 0xA :
case 0xB :
case 0xE :
s + + ;
case 0xC :
case 0xD :
s + + ;
break ;
case 0xF :
2002-04-11 17:19:16 +00:00
if ( code = = 0xF0 | | code = = 0xF7 | | code = = 0xFF & & * s + + ! = 0x2F ) {
2001-12-01 17:23:50 +00:00
s + = get_delta_time ( & s ) ;
break ;
}
return - 1 ;
default :
return - 1 ;
}
* a = s ;
return 0 ;
}
2002-12-15 01:55:27 +00:00
////////////////////////////////////////
//
// IMuseInternal implementation
//
////////////////////////////////////////
2001-12-01 17:23:50 +00:00
2002-10-21 07:31:51 +00:00
IMuseInternal : : ~ IMuseInternal ( ) {
terminate ( ) ;
}
2003-03-06 17:58:13 +00:00
byte * IMuseInternal : : findTag ( int sound , char * tag , int index ) {
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 ) {
2002-08-25 15:06:53 +00:00
debug ( 1 , " IMuseInternal::findTag completely failed finding sound %d " , sound ) ;
2002-04-24 14:13:09 +00:00
return NULL ;
2002-04-25 03:37:56 +00:00
2001-12-01 17:23:50 +00:00
}
ptr + = 8 ;
size = READ_BE_UINT32_UNALIGNED ( ptr ) ;
ptr + = 4 ;
pos = 0 ;
2002-07-07 18:04:03 +00:00
2001-12-01 17:23:50 +00:00
while ( pos < size ) {
if ( ! memcmp ( ptr + pos , tag , 4 ) & & ! index - - )
return ptr + pos + 8 ;
pos + = READ_BE_UINT32_UNALIGNED ( ptr + pos + 4 ) + 8 ;
}
2002-07-07 18:04:03 +00:00
2002-10-10 15:06:02 +00:00
debug ( 3 , " IMuseInternal::findTag failed finding sound %d " , sound ) ;
2001-12-01 17:23:50 +00:00
return NULL ;
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 ;
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 ;
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-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 ;
}
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
}
2002-04-11 17:19:16 +00:00
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).
2002-10-14 16:42:57 +00:00
for ( i = ARRAYSIZE ( _players ) , player = _players ; i ! = 0 ; i - - , player + + ) {
if ( player - > _active & & player - > _id = = sound )
2002-10-21 08:17:18 +00:00
break ;
2002-10-14 16:42:57 +00:00
}
if ( ! i )
player = allocate_player ( 128 ) ;
if ( ! player )
return false ;
2001-12-01 17:23:50 +00:00
player - > clear ( ) ;
2003-05-16 01:52:45 +00:00
return player - > startSound ( sound , _midi_native ) ;
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 ;
2002-04-11 17:19:16 +00:00
for ( i = ARRAYSIZE ( _players ) ; i ! = 0 ; i - - , player + + ) {
2001-12-01 17:23:50 +00:00
if ( ! player - > _active )
return player ;
if ( player - > _priority < bestpri ) {
best = player ;
bestpri = player - > _priority ;
}
}
if ( bestpri < priority )
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 + + ) {
2001-12-01 17:23:50 +00:00
player - > _active = 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_sustaining_notes ( ) {
2001-12-01 17:23:50 +00:00
SustainingNotes * next = NULL , * sn = _sustaining_notes ;
int i ;
_sustain_notes_used = NULL ;
_sustain_notes_head = NULL ;
2002-04-11 17:19:16 +00:00
for ( i = ARRAYSIZE ( _sustaining_notes ) ; i ! = 0 ; i - - , sn + + ) {
2001-12-01 17:23:50 +00:00
sn - > next = next ;
next = sn ;
}
_sustain_notes_free = next ;
}
2003-03-06 17:58:13 +00:00
void IMuseInternal : : init_volume_fader ( ) {
2001-12-01 17:23:50 +00:00
VolumeFader * vf = _volume_fader ;
int i ;
2002-04-11 17:19:16 +00:00
for ( i = ARRAYSIZE ( _volume_fader ) ; i ! = 0 ; i - - , vf + + )
2001-12-01 17:23:50 +00:00
vf - > initialize ( ) ;
_active_volume_faders = false ;
}
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
Player * player = _players ;
int i ;
int r = - 1 ;
2002-04-11 17:19:16 +00:00
for ( i = ARRAYSIZE ( _players ) ; i ! = 0 ; i - - , player + + ) {
if ( player - > _active & & player - > _id = = sound ) {
2001-12-01 17:23:50 +00:00
player - > clear ( ) ;
r = 0 ;
}
}
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 + + ) {
2001-12-01 17:23:50 +00:00
if ( player - > _active )
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-16 01:52:45 +00:00
sequencer_timers ( midi ) ;
expire_sustain_notes ( midi ) ;
expire_volume_faders ( 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-16 01:52:45 +00:00
if ( player - > _active & & player - > _midi = = midi ) {
2001-12-01 17:23:50 +00:00
player - > sequencer_timer ( ) ;
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-16 01:52:45 +00:00
void IMuseInternal : : expire_sustain_notes ( MidiDriver * midi ) {
2002-04-11 17:19:16 +00:00
SustainingNotes * sn , * next ;
2001-12-01 17:23:50 +00:00
Player * player ;
uint32 counter ;
2002-04-11 17:19:16 +00:00
for ( sn = _sustain_notes_head ; sn ; sn = next ) {
2001-12-01 17:23:50 +00:00
next = sn - > next ;
player = sn - > player ;
2003-05-16 01:52:45 +00:00
if ( player - > _midi ! = midi ) continue ;
2001-12-01 17:23:50 +00:00
counter = sn - > counter + player - > _timer_speed ;
2002-04-11 17:19:16 +00:00
sn - > pos + = counter > > 16 ;
2002-02-24 17:25:03 +00:00
sn - > counter = ( unsigned short ) counter & 0xFFFF ;
2001-12-01 17:23:50 +00:00
if ( sn - > pos > = sn - > off_pos ) {
player - > key_off ( sn - > chan , sn - > note ) ;
2002-12-15 01:55:27 +00:00
// Unlink the node
2001-12-01 17:23:50 +00:00
if ( next )
next - > prev = sn - > prev ;
if ( sn - > prev )
sn - > prev - > next = next ;
else
_sustain_notes_head = next ;
2002-12-15 01:55:27 +00:00
// And put it in the free list
2001-12-01 17:23:50 +00:00
sn - > next = _sustain_notes_free ;
_sustain_notes_free = sn ;
}
}
}
2003-05-16 01:52:45 +00:00
void IMuseInternal : : expire_volume_faders ( MidiDriver * midi ) {
2001-12-01 17:23:50 +00:00
VolumeFader * vf ;
int i ;
if ( + + _volume_fader_counter & 7 )
return ;
if ( ! _active_volume_faders )
return ;
_active_volume_faders = false ;
vf = _volume_fader ;
2002-04-11 17:19:16 +00:00
for ( i = ARRAYSIZE ( _volume_fader ) ; i ! = 0 ; i - - , vf + + ) {
2003-05-16 01:52:45 +00:00
if ( vf - > active & & vf - > player - > _midi = = midi ) {
2001-12-01 17:23:50 +00:00
_active_volume_faders = true ;
2002-09-11 13:28:34 +00:00
vf - > on_timer ( false ) ;
2001-12-01 17:23:50 +00:00
}
}
}
2003-03-06 17:58:13 +00:00
void VolumeFader : : on_timer ( bool probe ) {
2001-12-01 17:23:50 +00:00
byte newvol ;
2002-04-11 17:19:16 +00:00
2001-12-01 17:23:50 +00:00
newvol = curvol + speed_hi ;
speed_lo_counter + = speed_lo ;
if ( speed_lo_counter > = speed_lo_max ) {
speed_lo_counter - = speed_lo_max ;
newvol + = direction ;
}
2002-04-11 17:19:16 +00:00
if ( curvol ! = newvol ) {
2002-09-11 13:28:34 +00:00
curvol = newvol ;
2001-12-01 17:23:50 +00:00
if ( ! newvol ) {
2002-09-11 13:28:34 +00:00
if ( ! probe )
player - > clear ( ) ;
2001-12-01 17:23:50 +00:00
active = false ;
return ;
}
2002-09-11 13:28:34 +00:00
if ( ! probe )
player - > set_vol ( newvol ) ;
2001-12-01 17:23:50 +00:00
}
2002-04-11 17:19:16 +00:00
2001-12-01 17:23:50 +00:00
if ( ! - - num_steps ) {
active = false ;
}
}
2003-03-06 17:58:13 +00:00
byte VolumeFader : : fading_to ( ) {
2002-09-11 13:28:34 +00:00
byte newvol ;
byte orig_curvol ;
uint16 orig_speed_lo_counter , orig_num_steps ;
if ( ! active )
return 127 ;
// It would be so much easier to just store the fade-to volume in a
// variable, but then we'd have to break savegame compatibility. So
// instead we do a "dry run" fade.
orig_speed_lo_counter = speed_lo_counter ;
orig_num_steps = num_steps ;
orig_curvol = curvol ;
while ( active )
on_timer ( true ) ;
active = true ;
newvol = curvol ;
speed_lo_counter = orig_speed_lo_counter ;
num_steps = orig_num_steps ;
curvol = orig_curvol ;
return newvol ;
}
2003-03-23 13:14:54 +00:00
int IMuseInternal : : getSoundStatus ( int sound ) {
2001-12-01 17:23:50 +00:00
int i ;
Player * player ;
2002-04-11 17:19:16 +00:00
for ( i = ARRAYSIZE ( _players ) , player = _players ; i ! = 0 ; i - - , player + + ) {
2002-09-11 13:28:34 +00:00
if ( player - > _active & & player - > _id = = ( uint16 ) sound ) {
// Assume that anyone asking for the sound status is
// really asking "is it ok if I start playing this
// sound now?" So if the sound is about to fade out,
2002-10-21 08:17:18 +00:00
// pretend it's not playing.
if ( player - > is_fading_out ( ) )
2002-09-11 13:28:34 +00:00
continue ;
2001-12-01 17:23:50 +00:00
return 1 ;
2002-09-11 13:28:34 +00:00
}
2001-12-01 17:23:50 +00:00
}
return get_queue_sound_status ( sound ) ;
}
2003-03-23 13:14:54 +00:00
// This is exactly the same as getSoundStatus except that
2002-12-05 21:45:55 +00:00
// it treats sounds that are fading out just the same as
// other sounds. This is the method to use when determining
// what resources to expire from memory.
2003-03-06 17:58:13 +00:00
bool IMuseInternal : : get_sound_active ( int sound ) {
2002-12-05 21:45:55 +00:00
int i ;
Player * player ;
for ( i = ARRAYSIZE ( _players ) , player = _players ; i ! = 0 ; i - - , player + + ) {
if ( player - > _active & & player - > _id = = ( uint16 ) sound )
return 1 ;
}
return ( get_queue_sound_status ( sound ) ! = 0 ) ;
}
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 ) {
2002-04-11 17:19:16 +00:00
for ( i = ARRAYSIZE ( _players ) , player = _players ; i ! = 0 ; i - - , player + + ) {
2002-07-07 18:04:03 +00:00
if ( player - > _active & & player - > _id = = ( uint16 ) sound & & player - > _vol_chan ! = ( uint16 ) volchan ) {
2001-12-01 17:23:50 +00:00
player - > _vol_chan = volchan ;
player - > set_vol ( player - > _volume ) ;
return 0 ;
}
}
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 + + ) {
2001-12-01 17:23:50 +00:00
if ( player - > _active ) {
2002-04-11 17:19:16 +00:00
if ( player - > _vol_chan = = ( uint16 ) volchan ) {
2001-12-01 17:23:50 +00:00
num + + ;
if ( ! best | | player - > _priority < = best - > _priority )
best = player ;
} else if ( player - > _id = = ( uint16 ) sound ) {
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 ;
player - > set_vol ( player - > _volume ) ;
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 ;
2002-07-28 15:03:45 +00:00
else if ( vol < 0 )
vol = 0 ;
2002-07-26 00:41:07 +00:00
2002-11-17 17:59:00 +00:00
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 ;
else if ( vol < 0 )
vol = 0 ;
if ( _master_volume = = vol )
return 0 ;
2002-03-05 23:37:31 +00:00
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-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
for ( i = ARRAYSIZE ( _players ) , player = _players ; i ! = 0 ; i - - , player + + ) {
if ( player - > _active & & player - > _id = = ( uint16 ) b )
break ;
}
if ( ! i )
return - 1 ;
switch ( d ) {
case 6 :
// Set player volume.
return player - > set_vol ( e ) ;
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 :
// Sam and Max: Volume Fader?
2002-10-14 16:42:57 +00:00
// Prevent instantaneous volume fades.
// Fixes a Ball of Twine issue, but might not be the right long-term solution.
2002-10-13 05:39:26 +00:00
if ( f ! = 0 ) {
for ( i = ARRAYSIZE ( _players ) , player = _players ; i ! = 0 ; i - - , player + + ) {
if ( player - > _active & & player - > _id = = ( uint16 ) b ) {
player - > fade_vol ( e , f ) ;
return 0 ;
}
2002-10-12 04:57:49 +00:00
}
}
return - 1 ;
case 15 :
2002-12-14 02:51:37 +00:00
// Sam & Max: Set hook for a "maybe" jump
2002-10-12 04:57:49 +00:00
for ( i = ARRAYSIZE ( _players ) , player = _players ; i ! = 0 ; i - - , player + + ) {
if ( player - > _active & & player - > _id = = ( uint16 ) b ) {
2003-05-05 16:07:10 +00:00
player - > _hook . set ( 0 , d , 0 ) ;
2002-10-12 04:57:49 +00:00
return 0 ;
2002-05-10 20:21:12 +00:00
}
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
// FIXME: Right now this acts as an immediate command.
// The significance of parameter b is unknown.
2003-03-18 16:13:52 +00:00
warning ( " Incomplete support for iMuse::doCommand(20) " ) ;
return doCommand ( c , d , e , f , g , h , 0 , 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 ) ) {
2001-12-01 17:23:50 +00:00
player = get_player_byid ( b ) ;
if ( ! player )
return - 1 ;
2002-04-11 17:19:16 +00:00
if ( ( 1 < < cmd ) & ( 1 < < 11 | 1 < < 22 ) ) {
assert ( c > = 0 & & c < = 15 ) ;
player = ( Player * ) player - > get_part ( c ) ;
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
return ( ( player - > _beat_index - 1 ) > > 2 ) + 1 ;
else if ( d = = 2 ) // Beat number
2002-11-10 18:34:57 +00:00
return player - > _beat_index ;
return - 1 ;
} else {
2002-10-13 05:39:26 +00:00
return player - > get_param ( 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 )
2002-10-12 04:57:49 +00:00
player - > jump ( d - 1 , ( e - 1 ) * 4 + f , ( ( g * player - > _ticks_per_beat ) > > 2 ) + h ) ;
else
player - > set_priority ( c ) ;
2001-12-01 17:23:50 +00:00
return 0 ;
case 2 :
return player - > set_vol ( c ) ;
case 3 :
player - > set_pan ( c ) ;
return 0 ;
case 4 :
return player - > set_transpose ( c , d ) ;
case 5 :
player - > set_detune ( c ) ;
return 0 ;
case 6 :
player - > set_speed ( c ) ;
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 :
2002-04-11 17:19:16 +00:00
return player - > set_loop ( c , d , e , f , g ) ? 0 : - 1 ;
2001-12-01 17:23:50 +00:00
case 10 :
player - > clear_loop ( ) ;
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 :
return player - > _hook . set ( c , d , e ) ;
case 13 :
2002-04-11 17:19:16 +00:00
return player - > fade_vol ( 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 :
2002-04-11 17:19:16 +00:00
return player - > get_param ( c , d ) ;
2001-12-01 17:23:50 +00:00
case 20 :
2002-04-11 17:19:16 +00:00
return player - > _hook . set ( c , d , e ) ;
2001-12-01 17:23:50 +00:00
case 21 :
return - 1 ;
case 22 :
2002-04-11 17:19:16 +00:00
( ( Part * ) player ) - > set_vol ( 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 + + ) {
2001-12-01 17:23:50 +00:00
if ( player - > _active )
player - > set_vol ( player - > _volume ) ;
}
}
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-05 16:07:10 +00:00
_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-03-06 17:58:13 +00:00
VolumeFader * IMuseInternal : : allocate_volume_fader ( ) {
2001-12-01 17:23:50 +00:00
VolumeFader * vf ;
int i ;
vf = _volume_fader ;
2002-04-11 17:19:16 +00:00
for ( i = ARRAYSIZE ( _volume_fader ) ; vf - > active ; ) {
2001-12-01 17:23:50 +00:00
vf + + ;
if ( ! - - i )
return NULL ;
}
vf - > active = true ;
_active_volume_faders = true ;
return vf ;
}
2003-03-06 17:58:13 +00:00
Player * IMuseInternal : : get_player_byid ( int id ) {
2001-12-01 17:23:50 +00:00
int i ;
2002-04-11 17:19:16 +00:00
Player * player , * found = NULL ;
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 + + ) {
if ( player - > _active & & player - > _id = = ( uint16 ) id ) {
if ( found )
2001-12-01 17:23:50 +00:00
return NULL ;
found = player ;
}
}
return found ;
}
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 :
2002-04-14 18:13:08 +00:00
_game_tempo = value ;
break ;
}
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-03-06 17:58:13 +00:00
IMuseInternal * IMuseInternal : : create ( OSystem * syst , MidiDriver * midi , SoundMixer * mixer ) {
2002-04-29 11:48:33 +00:00
IMuseInternal * i = new IMuseInternal ;
2002-04-14 18:13:08 +00:00
i - > initialize ( syst , midi , mixer ) ;
return i ;
}
2003-03-06 17:58:13 +00:00
int IMuseInternal : : initialize ( OSystem * syst , MidiDriver * midi , SoundMixer * mixer ) {
2001-12-01 17:23:50 +00:00
int i ;
2002-12-18 13:22:40 +00:00
if ( midi = = NULL )
2003-05-16 01:52:45 +00:00
error ( " IMuse was initialized without a MIDI driver (even the NULL driver) " ) ;
2001-12-01 17:23:50 +00:00
2003-05-16 01:52:45 +00:00
_midi_native = midi ;
_game_tempo = _midi_native - > getBaseTempo ( ) ;
initMidiDriver ( _midi_native ) ;
2002-04-11 17:19:16 +00:00
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_sustaining_notes ( ) ;
init_volume_fader ( ) ;
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
int result = midi - > open ( ) ;
if ( result )
error ( " IMuse initialization - " , MidiDriver : : getErrorName ( result ) ) ;
// Connect to the driver's timer
midi - > setTimerCallback ( midi , & IMuseInternal : : midiTimerCallback ) ;
}
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 ;
}
2002-12-15 01:55:27 +00:00
////////////////////////////////////////
//
// Player implementation
//
////////////////////////////////////////
2001-12-01 17:23:50 +00:00
2003-03-06 17:58:13 +00:00
int Player : : fade_vol ( byte vol , int time ) {
2001-12-01 17:23:50 +00:00
VolumeFader * vf ;
int i ;
cancel_volume_fade ( ) ;
2002-04-11 17:19:16 +00:00
if ( time = = 0 ) {
2001-12-01 17:23:50 +00:00
set_vol ( vol ) ;
return 0 ;
}
2002-04-11 17:19:16 +00:00
2001-12-01 17:23:50 +00:00
vf = _se - > allocate_volume_fader ( ) ;
2002-04-11 17:19:16 +00:00
if ( vf = = NULL )
2001-12-01 17:23:50 +00:00
return - 1 ;
vf - > player = this ;
vf - > num_steps = vf - > speed_lo_max = time ;
vf - > curvol = _volume ;
i = ( vol - vf - > curvol ) ;
vf - > speed_hi = i / time ;
2002-04-11 17:19:16 +00:00
if ( i < 0 ) {
2001-12-01 17:23:50 +00:00
i = - i ;
vf - > direction = - 1 ;
} else {
vf - > direction = 1 ;
}
vf - > speed_lo = i % time ;
vf - > speed_lo_counter = 0 ;
return 0 ;
}
2003-03-06 17:58:13 +00:00
bool Player : : is_fading_out ( ) {
2002-09-11 13:28:34 +00:00
VolumeFader * vf = _se - > _volume_fader ;
int i ;
for ( i = 0 ; i < 8 ; i + + , vf + + ) {
if ( vf - > active & & vf - > direction < 0 & & vf - > player = = this & & vf - > fading_to ( ) = = 0 )
return true ;
}
return false ;
}
2003-03-06 17:58:13 +00:00
void Player : : clear ( ) {
2001-12-01 17:23:50 +00:00
uninit_seq ( ) ;
cancel_volume_fade ( ) ;
uninit_parts ( ) ;
2003-05-15 18:24:59 +00:00
_se - > ImFireAllTriggers ( _id ) ;
2001-12-01 17:23:50 +00:00
_active = false ;
_ticks_per_beat = TICKS_PER_BEAT ;
2003-05-16 01:52:45 +00:00
_midi = NULL ;
2001-12-01 17:23:50 +00:00
}
2003-05-16 01:52:45 +00:00
bool Player : : startSound ( int sound , MidiDriver * midi ) {
2001-12-01 17:23:50 +00:00
void * mdhd ;
2002-04-11 17:19:16 +00:00
2001-12-01 17:23:50 +00:00
mdhd = _se - > findTag ( sound , MDHD_TAG , 0 ) ;
2002-04-11 17:19:16 +00:00
if ( mdhd = = NULL ) {
2002-03-11 04:37:06 +00:00
mdhd = _se - > findTag ( sound , MDPG_TAG , 0 ) ;
2002-04-11 17:19:16 +00:00
if ( mdhd = = NULL ) {
2003-03-18 16:13:52 +00:00
warning ( " P::startSound failed: Couldn't find %s " , MDHD_TAG ) ;
2002-08-25 15:06:53 +00:00
return false ;
2002-03-11 04:37:06 +00:00
}
2002-03-05 16:13:09 +00:00
}
2002-07-22 12:44:57 +00:00
2002-05-04 00:20:39 +00:00
_mt32emulate = _se - > isMT32 ( sound ) ;
2002-09-29 11:11:42 +00:00
_isGM = _se - > isGM ( sound ) ;
2001-12-01 17:23:50 +00:00
_parts = NULL ;
_active = true ;
_id = sound ;
_priority = 0x80 ;
_volume = 0x7F ;
_vol_chan = 0xFFFF ;
2002-04-11 17:19:16 +00:00
_vol_eff = ( _se - > get_channel_volume ( 0xFFFF ) < < 7 ) > > 7 ;
2001-12-01 17:23:50 +00:00
_pan = 0 ;
_transpose = 0 ;
_detune = 0 ;
hook_clear ( ) ;
if ( start_seq_sound ( sound ) ! = 0 ) {
_active = false ;
return false ;
}
2003-05-16 01:52:45 +00:00
_midi = midi ;
2001-12-01 17:23:50 +00:00
return true ;
}
2003-03-06 17:58:13 +00:00
void Player : : hook_clear ( ) {
2001-12-01 17:23:50 +00:00
memset ( & _hook , 0 , sizeof ( _hook ) ) ;
}
2003-03-06 17:58:13 +00:00
int Player : : start_seq_sound ( int sound ) {
2001-12-01 17:23:50 +00:00
byte * ptr , * track_ptr ;
_song_index = sound ;
_timer_counter = 0 ;
_loop_to_beat = 1 ;
_loop_from_beat = 1 ;
_track_index = 0 ;
_loop_counter = 0 ;
_loop_to_tick = 0 ;
_loop_from_tick = 0 ;
set_tempo ( 500000 ) ;
set_speed ( 128 ) ;
ptr = _se - > findTag ( sound , " MTrk " , _track_index ) ;
2002-04-11 17:19:16 +00:00
if ( ptr = = NULL )
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
track_ptr = ptr ;
_cur_pos = _next_pos = get_delta_time ( & track_ptr ) ;
_song_offset = track_ptr - ptr ;
2002-04-11 17:19:16 +00:00
2001-12-01 17:23:50 +00:00
_tick_index = _cur_pos ;
_beat_index = 1 ;
if ( _tick_index > = _ticks_per_beat ) {
2002-04-11 17:19:16 +00:00
_beat_index + = _tick_index / _ticks_per_beat ;
2001-12-01 17:23:50 +00:00
_tick_index % = _ticks_per_beat ;
}
return 0 ;
}
2003-03-06 17:58:13 +00:00
void Player : : set_tempo ( uint32 b ) {
2002-04-11 17:19:16 +00:00
uint32 i , j ;
2002-03-05 15:50:11 +00:00
2002-04-14 18:13:08 +00:00
i = _se - > _game_tempo ;
2002-07-07 18:04:03 +00:00
2001-12-01 17:23:50 +00:00
j = _tempo = b ;
2002-04-11 17:19:16 +00:00
while ( i & 0xFFFF0000 | | j & 0xFFFF0000 ) {
i > > = 1 ;
j > > = 1 ;
}
2001-12-01 17:23:50 +00:00
2002-04-11 17:19:16 +00:00
_tempo_eff = ( i < < 16 ) / j ;
2001-12-01 17:23:50 +00:00
set_speed ( _speed ) ;
}
2003-03-06 17:58:13 +00:00
void Player : : cancel_volume_fade ( ) {
2001-12-01 17:23:50 +00:00
VolumeFader * vf = _se - > _volume_fader ;
int i ;
2002-04-11 17:19:16 +00:00
for ( i = 0 ; i < 8 ; i + + , vf + + ) {
if ( vf - > active & & vf - > player = = this )
2001-12-01 17:23:50 +00:00
vf - > active = false ;
}
}
2003-03-06 17:58:13 +00:00
void Player : : uninit_parts ( ) {
2001-12-01 17:23:50 +00:00
if ( _parts & & _parts - > _player ! = this )
error ( " asd " ) ;
2002-04-11 17:19:16 +00:00
while ( _parts )
2001-12-01 17:23:50 +00:00
_parts - > uninit ( ) ;
2003-05-16 01:52:45 +00:00
_se - > reallocateMidiChannels ( _midi ) ; // In case another player couldn't allocate all its parts
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
void Player : : uninit_seq ( ) {
2001-12-01 17:23:50 +00:00
_abort = true ;
}
2003-03-06 17:58:13 +00:00
void Player : : set_speed ( byte speed ) {
2001-12-01 17:23:50 +00:00
_speed = speed ;
_timer_speed = ( _tempo_eff * speed > > 7 ) ;
}
2003-03-06 17:58:13 +00:00
byte * Player : : parse_midi ( byte * s ) {
2002-04-11 17:19:16 +00:00
byte cmd , chan , note , velocity , control ;
2001-12-01 17:23:50 +00:00
uint value ;
Part * part ;
2002-04-11 17:19:16 +00:00
2001-12-01 17:23:50 +00:00
cmd = * s + + ;
2002-04-11 17:19:16 +00:00
chan = cmd & 0xF ;
2001-12-01 17:23:50 +00:00
2002-04-11 17:19:16 +00:00
switch ( cmd > > 4 ) {
2002-12-15 01:55:27 +00:00
case 0x8 : // Key Off
2001-12-01 17:23:50 +00:00
note = * s + + ;
if ( ! _scanning ) {
key_off ( chan , note ) ;
} else {
clear_active_note ( chan , note ) ;
}
2002-12-15 01:55:27 +00:00
s + + ; // Skip velocity
2001-12-01 17:23:50 +00:00
break ;
2002-12-15 01:55:27 +00:00
case 0x9 : // Key On
2001-12-01 17:23:50 +00:00
note = * s + + ;
velocity = * s + + ;
if ( velocity ) {
if ( ! _scanning )
2002-04-11 17:19:16 +00:00
key_on ( chan , note , velocity ) ;
2001-12-01 17:23:50 +00:00
else
2002-04-11 17:19:16 +00:00
set_active_note ( chan , note ) ;
2001-12-01 17:23:50 +00:00
} else {
if ( ! _scanning )
key_off ( chan , note ) ;
else
2002-04-11 17:19:16 +00:00
clear_active_note ( chan , note ) ;
2001-12-01 17:23:50 +00:00
}
break ;
2002-12-15 01:55:27 +00:00
case 0xA : // Aftertouch
2001-12-01 17:23:50 +00:00
s + = 2 ;
break ;
2002-12-15 01:55:27 +00:00
case 0xB : // Control Change
2001-12-01 17:23:50 +00:00
control = * s + + ;
value = * s + + ;
part = get_part ( chan ) ;
if ( ! part )
break ;
2002-04-11 17:19:16 +00:00
switch ( control ) {
2002-12-15 01:55:27 +00:00
case 1 : // Modulation Wheel
2001-12-01 17:23:50 +00:00
part - > set_modwheel ( value ) ;
break ;
2002-12-15 01:55:27 +00:00
case 7 : // Volume
2001-12-01 17:23:50 +00:00
part - > set_vol ( value ) ;
break ;
2002-12-15 01:55:27 +00:00
case 10 : // Pan Position
2001-12-01 17:23:50 +00:00
part - > set_pan ( value - 0x40 ) ;
break ;
2002-12-15 01:55:27 +00:00
case 16 : // Pitchbend Factor (non-standard)
2001-12-01 17:23:50 +00:00
part - > set_pitchbend_factor ( value ) ;
break ;
2002-12-15 01:55:27 +00:00
case 17 : // GP Slider 2
2001-12-01 17:23:50 +00:00
part - > set_detune ( value - 0x40 ) ;
break ;
2002-12-15 01:55:27 +00:00
case 18 : // GP Slider 3
2001-12-01 17:23:50 +00:00
part - > set_pri ( value - 0x40 ) ;
2003-05-16 01:52:45 +00:00
_se - > reallocateMidiChannels ( _midi ) ;
2001-12-01 17:23:50 +00:00
break ;
2002-12-15 01:55:27 +00:00
case 64 : // Sustain Pedal
2002-04-11 17:19:16 +00:00
part - > set_pedal ( value ! = 0 ) ;
2001-12-01 17:23:50 +00:00
break ;
2002-12-15 01:55:27 +00:00
case 91 : // Effects Level
2001-12-01 17:23:50 +00:00
part - > set_effect_level ( value ) ;
break ;
2002-12-15 01:55:27 +00:00
case 93 : // Chorus Level
2001-12-01 17:23:50 +00:00
part - > set_chorus ( value ) ;
break ;
default :
warning ( " parse_midi: invalid control %d " , control ) ;
}
break ;
2002-12-15 01:55:27 +00:00
case 0xC : // Program Change
2001-12-01 17:23:50 +00:00
value = * s + + ;
part = get_part ( chan ) ;
2002-12-20 13:09:01 +00:00
if ( part ) {
2003-03-25 00:28:09 +00:00
if ( _isGM ) {
if ( value < 128 )
part - > set_program ( value ) ;
} else {
if ( value < 32 )
part - > load_global_instrument ( value ) ;
}
2002-12-20 13:09:01 +00:00
}
2001-12-01 17:23:50 +00:00
break ;
2002-12-15 01:55:27 +00:00
case 0xD : // Channel Pressure
2001-12-01 17:23:50 +00:00
s + + ;
break ;
2002-12-15 01:55:27 +00:00
case 0xE : // Pitch Bend
2001-12-01 17:23:50 +00:00
part = get_part ( chan ) ;
if ( part )
2002-10-13 06:07:39 +00:00
part - > set_pitchbend ( ( ( s [ 1 ] < < 7 ) | s [ 0 ] ) - 0x2000 ) ;
2002-04-11 17:19:16 +00:00
s + = 2 ;
2001-12-01 17:23:50 +00:00
break ;
case 0xF :
2002-04-11 17:19:16 +00:00
if ( chan = = 0 ) {
2001-12-01 17:23:50 +00:00
uint size = get_delta_time ( & s ) ;
2002-11-06 21:34:38 +00:00
parse_sysex ( s , size ) ;
2001-12-01 17:23:50 +00:00
s + = size ;
2002-04-11 17:19:16 +00:00
} else if ( chan = = 0xF ) {
2001-12-01 17:23:50 +00:00
cmd = * s + + ;
2002-04-11 17:19:16 +00:00
if ( cmd = = 47 )
2002-12-15 01:55:27 +00:00
goto Error ; // End of song
2002-04-11 17:19:16 +00:00
if ( cmd = = 81 ) {
set_tempo ( ( s [ 1 ] < < 16 ) | ( s [ 2 ] < < 8 ) | s [ 3 ] ) ;
s + = 4 ;
2001-12-01 17:23:50 +00:00
break ;
}
s + = get_delta_time ( & s ) ;
2002-04-11 17:19:16 +00:00
} else if ( chan = = 0x7 ) {
2001-12-01 17:23:50 +00:00
s + = get_delta_time ( & s ) ;
} else {
goto Error ;
}
break ;
default :
2002-04-11 17:19:16 +00:00
Error : ;
if ( ! _scanning )
2001-12-01 17:23:50 +00:00
clear ( ) ;
return NULL ;
}
return s ;
}
2003-03-06 17:58:13 +00:00
void Player : : parse_sysex ( byte * p , uint len ) {
2001-12-01 17:23:50 +00:00
byte code ;
byte a ;
uint b ;
byte buf [ 128 ] ;
Part * part ;
2002-11-06 21:34:38 +00:00
// Check SysEx manufacturer.
// Roland is 0x41
a = * p + + ;
- - len ;
if ( a ! = IMUSE_SYSEX_ID ) {
if ( a = = ROLAND_SYSEX_ID ) {
// Roland custom instrument definition.
part = get_part ( p [ 0 ] & 0x0F ) ;
if ( part ) {
2002-12-18 13:22:40 +00:00
part - > _instrument . roland ( p - 1 ) ;
2003-05-15 19:39:10 +00:00
if ( part - > clearToTransmit ( ) ) part - > _instrument . send ( part - > _mc ) ;
2002-11-06 21:34:38 +00:00
}
} else {
warning ( " Unknown SysEx manufacturer 0x%02X " , ( int ) a ) ;
}
2002-12-18 09:27:46 +00:00
return ;
2002-11-06 21:34:38 +00:00
}
- - len ;
// Too big?
2002-04-11 17:19:16 +00:00
if ( len > = sizeof ( buf ) * 2 )
2001-12-01 17:23:50 +00:00
return ;
2003-05-07 19:24:14 +00:00
# ifdef IMUSE_DEBUG
for ( a = 0 ; a < len + 1 & & a < 20 ; + + a ) {
sprintf ( ( char * ) & buf [ a * 3 ] , " %02X " , p [ a ] ) ;
} // next for
if ( a < len + 1 ) {
buf [ a * 3 ] = buf [ a * 3 + 1 ] = buf [ a * 3 + 2 ] = ' . ' ;
+ + a ;
} // end if
buf [ a * 3 ] = ' \0 ' ;
debug ( 0 , " SysEx:%s " , buf ) ;
# endif
2002-04-11 17:19:16 +00:00
switch ( code = * p + + ) {
2002-10-10 15:06:02 +00:00
case 0 :
2002-10-14 16:42:57 +00:00
if ( g_scumm - > _gameId ! = GID_SAMNMAX ) {
2002-11-06 21:34:38 +00:00
// There are 17 bytes of useful information beyond
// what we've read so far. All we know about them is
// as follows:
// BYTE 00: Channel #
// BYTE 02: BIT 01 (0x01): Part on? (1 = yes)
// BYTE 05: Volume (upper 4 bits) [guessing]
// BYTE 06: Volume (lower 4 bits) [guessing]
// BYTE 09: BIT 04 (0x08): Percussion? (1 = yes)
part = get_part ( p [ 0 ] & 0x0F ) ;
2002-10-10 15:06:02 +00:00
if ( part ) {
2002-11-06 21:34:38 +00:00
part - > set_onoff ( p [ 2 ] & 0x01 ) ;
part - > set_vol ( ( p [ 5 ] & 0x0F ) < < 4 | ( p [ 6 ] & 0x0F ) ) ;
2002-11-21 19:06:42 +00:00
part - > _percussion = _isGM ? ( ( p [ 9 ] & 0x08 ) > 0 ) : false ;
2002-11-06 21:34:38 +00:00
if ( part - > _percussion ) {
2002-12-18 17:14:05 +00:00
if ( part - > _mc ) {
2002-11-06 21:34:38 +00:00
part - > off ( ) ;
2003-05-16 01:52:45 +00:00
_se - > reallocateMidiChannels ( _midi ) ;
2002-12-18 17:14:05 +00:00
}
2002-11-06 21:34:38 +00:00
} else {
2003-05-15 19:39:10 +00:00
part - > sendAll ( ) ;
2002-11-06 21:34:38 +00:00
}
2002-10-10 15:06:02 +00:00
}
2002-10-12 04:57:49 +00:00
} else {
2002-12-15 01:55:27 +00:00
// Sam & Max: Trigger Event
2003-03-18 16:13:52 +00:00
// Triggers are set by doCommand (ImSetTrigger).
2002-12-15 01:55:27 +00:00
// When a SysEx marker is encountered whose sound
// ID and marker ID match what was set by ImSetTrigger,
// something magical is supposed to happen....
2002-10-14 16:42:57 +00:00
for ( a = 0 ; a < 16 ; + + a ) {
if ( _se - > _snm_triggers [ a ] . sound = = _id & &
_se - > _snm_triggers [ a ] . id = = * p )
{
_se - > _snm_triggers [ a ] . sound = _se - > _snm_triggers [ a ] . id = 0 ;
2003-03-18 16:13:52 +00:00
_se - > doCommand ( _se - > _snm_triggers [ a ] . command [ 0 ] ,
2002-10-14 16:42:57 +00:00
_se - > _snm_triggers [ a ] . command [ 1 ] ,
_se - > _snm_triggers [ a ] . command [ 2 ] ,
_se - > _snm_triggers [ a ] . command [ 3 ] ,
0 , 0 , 0 , 0 ) ;
break ;
}
}
2002-10-10 15:06:02 +00:00
} // end if
break ;
case 1 :
2002-10-14 16:42:57 +00:00
// This SysEx is used in Sam & Max for maybe_jump.
2002-10-10 15:06:02 +00:00
if ( _scanning )
break ;
maybe_jump ( p [ 0 ] , p [ 1 ] - 1 , ( read_word ( p + 2 ) - 1 ) * 4 + p [ 4 ] , ( ( p [ 5 ] * _ticks_per_beat ) > > 2 ) + p [ 6 ] ) ;
2002-09-09 05:03:55 +00:00
break ;
2002-12-05 21:45:55 +00:00
case 2 : // Start of song. Ignore for now.
break ;
2002-12-15 01:55:27 +00:00
case 16 : // Adlib instrument definition (Part)
2001-12-01 17:23:50 +00:00
a = * p + + & 0x0F ;
part = get_part ( a ) ;
2003-05-07 19:24:14 +00:00
if ( part ) {
if ( len = = 63 ) {
decode_sysex_bytes ( p , buf , len - 3 ) ;
part - > set_instrument ( ( byte * ) buf ) ;
} else {
// SPK tracks have len == 49 here, and are not supported
part - > set_program ( 254 ) ; // Must be invalid, but not 255 (which is reserved)
}
}
2001-12-01 17:23:50 +00:00
break ;
2002-12-15 01:55:27 +00:00
case 17 : // Adlib instrument definition (Global)
2001-12-01 17:23:50 +00:00
p + + ;
2002-04-11 17:19:16 +00:00
a = * p + + ;
2001-12-01 17:23:50 +00:00
decode_sysex_bytes ( p , buf , len - 4 ) ;
2003-05-16 01:52:45 +00:00
_se - > setGlobalAdlibInstrument ( a , buf ) ;
2001-12-01 17:23:50 +00:00
break ;
2002-12-15 01:55:27 +00:00
case 33 : // Parameter adjust
2001-12-01 17:23:50 +00:00
a = * p + + & 0x0F ;
decode_sysex_bytes ( p , buf , len - 3 ) ;
part = get_part ( a ) ;
if ( part )
2002-04-11 17:19:16 +00:00
part - > set_param ( read_word ( buf ) , read_word ( buf + 2 ) ) ;
2001-12-01 17:23:50 +00:00
break ;
2002-12-15 01:55:27 +00:00
case 48 : // Hook - jump
2001-12-01 17:23:50 +00:00
if ( _scanning )
break ;
2002-04-11 17:19:16 +00:00
decode_sysex_bytes ( p + 1 , buf , len - 2 ) ;
2002-10-10 15:06:02 +00:00
maybe_jump ( buf [ 0 ] , read_word ( buf + 1 ) , read_word ( buf + 3 ) , read_word ( buf + 5 ) ) ;
2001-12-01 17:23:50 +00:00
break ;
2002-12-15 01:55:27 +00:00
case 49 : // Hook - global transpose
2002-04-11 17:19:16 +00:00
decode_sysex_bytes ( p + 1 , buf , len - 2 ) ;
2001-12-01 17:23:50 +00:00
maybe_set_transpose ( buf ) ;
break ;
2002-12-15 01:55:27 +00:00
case 50 : // Hook - part on/off
2001-12-01 17:23:50 +00:00
buf [ 0 ] = * p + + & 0x0F ;
2002-04-11 17:19:16 +00:00
decode_sysex_bytes ( p , buf + 1 , len - 2 ) ;
2001-12-01 17:23:50 +00:00
maybe_part_onoff ( buf ) ;
break ;
2002-12-15 01:55:27 +00:00
case 51 : // Hook - set volume
2001-12-01 17:23:50 +00:00
buf [ 0 ] = * p + + & 0x0F ;
2002-04-11 17:19:16 +00:00
decode_sysex_bytes ( p , buf + 1 , len - 2 ) ;
2001-12-01 17:23:50 +00:00
maybe_set_volume ( buf ) ;
break ;
2002-12-15 01:55:27 +00:00
case 52 : // Hook - set program
2001-12-01 17:23:50 +00:00
buf [ 0 ] = * p + + & 0x0F ;
2002-04-11 17:19:16 +00:00
decode_sysex_bytes ( p , buf + 1 , len - 2 ) ;
2001-12-01 17:23:50 +00:00
maybe_set_program ( buf ) ;
break ;
2002-04-11 17:19:16 +00:00
2002-12-15 01:55:27 +00:00
case 53 : // Hook - set transpose
2001-12-01 17:23:50 +00:00
buf [ 0 ] = * p + + & 0x0F ;
2002-04-11 17:19:16 +00:00
decode_sysex_bytes ( p , buf + 1 , len - 2 ) ;
2001-12-01 17:23:50 +00:00
maybe_set_transpose_part ( buf ) ;
break ;
2002-12-15 01:55:27 +00:00
case 64 : // Marker
2001-12-01 17:23:50 +00:00
p + + ;
len - = 2 ;
while ( len - - ) {
_se - > handle_marker ( _id , * p + + ) ;
}
break ;
2002-12-15 01:55:27 +00:00
case 80 : // Loop
2002-04-11 17:19:16 +00:00
decode_sysex_bytes ( p + 1 , buf , len - 2 ) ;
set_loop ( read_word ( buf ) ,
2002-07-07 18:04:03 +00:00
read_word ( buf + 2 ) , read_word ( buf + 4 ) , read_word ( buf + 6 ) , read_word ( buf + 8 )
2002-04-11 17:19:16 +00:00
) ;
2001-12-01 17:23:50 +00:00
break ;
2002-12-15 01:55:27 +00:00
case 81 : // End loop
2001-12-01 17:23:50 +00:00
clear_loop ( ) ;
break ;
2002-12-15 01:55:27 +00:00
case 96 : // Set instrument
2001-12-01 17:23:50 +00:00
part = get_part ( p [ 0 ] & 0x0F ) ;
2002-07-07 18:04:03 +00:00
b = ( p [ 1 ] & 0x0F ) < < 12 | ( p [ 2 ] & 0x0F ) < < 8 | ( p [ 4 ] & 0x0F ) < < 4 | ( p [ 4 ] & 0x0F ) ;
2002-04-11 17:19:16 +00:00
if ( part )
2001-12-01 17:23:50 +00:00
part - > set_instrument ( b ) ;
break ;
default :
2002-12-01 15:51:29 +00:00
warning ( " Unknown SysEx command %d " , ( int ) code ) ;
2001-12-01 17:23:50 +00:00
}
}
2003-03-06 17:58:13 +00:00
void Player : : decode_sysex_bytes ( byte * src , byte * dst , int len ) {
2002-04-11 17:19:16 +00:00
while ( len > = 0 ) {
* dst + + = ( src [ 0 ] < < 4 ) | ( src [ 1 ] & 0xF ) ;
2001-12-01 17:23:50 +00:00
src + = 2 ;
len - = 2 ;
}
}
2003-03-06 17:58:13 +00:00
void Player : : maybe_jump ( byte cmd , uint track , uint beat , uint tick ) {
2002-12-15 01:55:27 +00:00
// Is this the hook I'm waiting for?
2003-05-05 16:07:10 +00:00
if ( cmd & & _hook . _jump [ 0 ] ! = cmd )
2001-12-01 17:23:50 +00:00
return ;
2002-12-15 01:55:27 +00:00
// Reset hook?
2003-05-05 16:07:10 +00:00
if ( cmd ! = 0 & & cmd < 0x80 ) {
_hook . _jump [ 0 ] = _hook . _jump [ 1 ] ;
_hook . _jump [ 1 ] = 0 ;
}
2001-12-01 17:23:50 +00:00
2002-10-10 15:06:02 +00:00
jump ( track , beat , tick ) ;
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
void Player : : maybe_set_transpose ( byte * data ) {
2001-12-01 17:23:50 +00:00
byte cmd ;
cmd = data [ 0 ] ;
2002-12-15 01:55:27 +00:00
// Is this the hook I'm waiting for?
2002-04-11 17:19:16 +00:00
if ( cmd & & _hook . _transpose ! = cmd )
2001-12-01 17:23:50 +00:00
return ;
2002-12-15 01:55:27 +00:00
// Reset hook?
2002-04-11 17:19:16 +00:00
if ( cmd ! = 0 & & cmd < 0x80 )
2001-12-01 17:23:50 +00:00
_hook . _transpose = 0 ;
2002-07-07 18:04:03 +00:00
set_transpose ( data [ 1 ] , ( int8 ) data [ 2 ] ) ;
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
void Player : : maybe_part_onoff ( byte * data ) {
2002-04-11 17:19:16 +00:00
byte cmd , * p ;
2001-12-01 17:23:50 +00:00
uint chan ;
Part * part ;
cmd = data [ 1 ] ;
chan = data [ 0 ] ;
p = & _hook . _part_onoff [ chan ] ;
2002-12-15 01:55:27 +00:00
// Is this the hook I'm waiting for?
2002-04-11 17:19:16 +00:00
if ( cmd & & * p ! = cmd )
2001-12-01 17:23:50 +00:00
return ;
2002-04-11 17:19:16 +00:00
if ( cmd ! = 0 & & cmd < 0x80 )
2001-12-01 17:23:50 +00:00
* p = 0 ;
part = get_part ( chan ) ;
if ( part )
2002-04-11 17:19:16 +00:00
part - > set_onoff ( data [ 2 ] ! = 0 ) ;
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
void Player : : maybe_set_volume ( byte * data ) {
2001-12-01 17:23:50 +00:00
byte cmd ;
byte * p ;
uint chan ;
Part * part ;
cmd = data [ 1 ] ;
chan = data [ 0 ] ;
p = & _hook . _part_volume [ chan ] ;
2002-12-15 01:55:27 +00:00
// Is this the hook I'm waiting for?
2002-04-11 17:19:16 +00:00
if ( cmd & & * p ! = cmd )
2001-12-01 17:23:50 +00:00
return ;
2002-12-15 01:55:27 +00:00
// Reset hook?
2002-04-11 17:19:16 +00:00
if ( cmd ! = 0 & & cmd < 0x80 )
2001-12-01 17:23:50 +00:00
* p = 0 ;
part = get_part ( chan ) ;
if ( part )
part - > set_vol ( data [ 2 ] ) ;
}
2003-03-06 17:58:13 +00:00
void Player : : maybe_set_program ( byte * data ) {
2001-12-01 17:23:50 +00:00
byte cmd ;
byte * p ;
uint chan ;
Part * part ;
cmd = data [ 1 ] ;
chan = data [ 0 ] ;
2002-12-15 01:55:27 +00:00
// Is this the hook I'm waiting for?
2001-12-01 17:23:50 +00:00
p = & _hook . _part_program [ chan ] ;
2002-04-11 17:19:16 +00:00
if ( cmd & & * p ! = cmd )
2001-12-01 17:23:50 +00:00
return ;
2002-04-11 17:19:16 +00:00
if ( cmd ! = 0 & & cmd < 0x80 )
2001-12-01 17:23:50 +00:00
* p = 0 ;
part = get_part ( chan ) ;
if ( part )
part - > set_program ( data [ 2 ] ) ;
}
2003-03-06 17:58:13 +00:00
void Player : : maybe_set_transpose_part ( byte * data ) {
2001-12-01 17:23:50 +00:00
byte cmd ;
byte * p ;
uint chan ;
cmd = data [ 1 ] ;
chan = data [ 0 ] ;
2002-12-15 01:55:27 +00:00
// Is this the hook I'm waiting for?
2001-12-01 17:23:50 +00:00
p = & _hook . _part_transpose [ chan ] ;
2002-04-11 17:19:16 +00:00
if ( cmd & & * p ! = cmd )
2001-12-01 17:23:50 +00:00
return ;
2002-12-15 01:55:27 +00:00
// Reset hook?
2002-04-11 17:19:16 +00:00
if ( cmd ! = 0 & & cmd < 0x80 )
2001-12-01 17:23:50 +00:00
* p = 0 ;
2002-07-07 18:04:03 +00:00
part_set_transpose ( chan , data [ 2 ] , ( int8 ) data [ 3 ] ) ;
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
int Player : : set_transpose ( byte relative , int b ) {
2001-12-01 17:23:50 +00:00
Part * part ;
2002-04-11 17:19:16 +00:00
if ( b > 24 | | b < - 24 | | relative > 1 )
2001-12-01 17:23:50 +00:00
return - 1 ;
if ( relative )
b = transpose_clamp ( _transpose + b , - 7 , 7 ) ;
_transpose = b ;
2002-04-11 17:19:16 +00:00
for ( part = _parts ; part ; part = part - > _next ) {
2001-12-01 17:23:50 +00:00
part - > set_transpose ( part - > _transpose ) ;
}
return 0 ;
}
2003-03-06 17:58:13 +00:00
void Player : : clear_active_notes ( ) {
2001-12-01 17:23:50 +00:00
memset ( _se - > _active_notes , 0 , sizeof ( _se - > _active_notes ) ) ;
}
2003-03-06 17:58:13 +00:00
void Player : : clear_active_note ( int chan , byte note ) {
2002-04-11 17:19:16 +00:00
_se - > _active_notes [ note ] & = ~ ( 1 < < chan ) ;
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
void Player : : set_active_note ( int chan , byte note ) {
2002-04-11 17:19:16 +00:00
_se - > _active_notes [ note ] | = ( 1 < < chan ) ;
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
void Player : : part_set_transpose ( uint8 chan , byte relative , int8 b ) {
2001-12-01 17:23:50 +00:00
Part * part ;
2002-04-11 17:19:16 +00:00
if ( b > 24 | | b < - 24 )
2001-12-01 17:23:50 +00:00
return ;
part = get_part ( chan ) ;
if ( ! part )
return ;
if ( relative )
b = transpose_clamp ( b + part - > _transpose , - 7 , 7 ) ;
part - > set_transpose ( b ) ;
}
2003-03-06 17:58:13 +00:00
void Player : : key_on ( uint8 chan , uint8 note , uint8 velocity ) {
2001-12-01 17:23:50 +00:00
Part * part ;
part = get_part ( chan ) ;
if ( ! part | | ! part - > _on )
return ;
part - > key_on ( note , velocity ) ;
}
2003-03-06 17:58:13 +00:00
void Player : : key_off ( uint8 chan , uint8 note ) {
2001-12-01 17:23:50 +00:00
Part * part ;
2002-04-11 17:19:16 +00:00
for ( part = _parts ; part ; part = part - > _next ) {
if ( part - > _chan = = ( byte ) chan & & part - > _on )
2001-12-01 17:23:50 +00:00
part - > key_off ( note ) ;
}
}
2003-03-06 17:58:13 +00:00
bool Player : : jump ( uint track , uint beat , uint tick ) {
2001-12-01 17:23:50 +00:00
byte * mtrk , * cur_mtrk , * scanpos ;
2002-04-11 17:19:16 +00:00
uint32 topos , curpos , track_offs ;
2001-12-01 17:23:50 +00:00
if ( ! _active )
return false ;
mtrk = _se - > findTag ( _song_index , " MTrk " , track ) ;
if ( ! mtrk )
return false ;
2002-04-11 17:19:16 +00:00
cur_mtrk = _se - > findTag ( _song_index , " MTrk " , _track_index ) ;
2001-12-01 17:23:50 +00:00
if ( ! cur_mtrk )
return false ;
2002-04-11 17:19:16 +00:00
if ( beat = = 0 )
beat = 1 ;
2001-12-01 17:23:50 +00:00
2002-04-11 17:19:16 +00:00
topos = ( beat - 1 ) * _ticks_per_beat + tick ;
2001-12-01 17:23:50 +00:00
2003-04-19 14:23:40 +00:00
if ( track = = _track_index & & topos > = _next_pos ) {
2001-12-01 17:23:50 +00:00
scanpos = _song_offset + mtrk ;
curpos = _next_pos ;
} else {
scanpos = mtrk ;
curpos = get_delta_time ( & scanpos ) ;
}
while ( curpos < topos ) {
skip_midi_cmd ( & scanpos ) ;
2003-05-15 18:24:59 +00:00
if ( ! scanpos )
2001-12-01 17:23:50 +00:00
return false ;
curpos + = get_delta_time ( & scanpos ) ;
}
track_offs = scanpos - mtrk ;
turn_off_pedals ( ) ;
2002-07-07 18:04:03 +00:00
find_sustaining_notes ( cur_mtrk + _song_offset , mtrk + track_offs , curpos - topos ) ;
2001-12-01 17:23:50 +00:00
_beat_index = beat ;
_tick_index = tick ;
2003-04-19 14:23:40 +00:00
_cur_pos = topos ;
2001-12-01 17:23:50 +00:00
_next_pos = curpos ;
_timer_counter = 0 ;
_song_offset = track_offs ;
if ( track ! = _track_index ) {
_track_index = track ;
_loop_counter = 0 ;
}
_abort = true ;
return true ;
}
2003-03-06 17:58:13 +00:00
bool Player : : set_loop ( uint count , uint tobeat , uint totick , uint frombeat , uint fromtick ) {
2002-04-11 17:19:16 +00:00
if ( tobeat + 1 > = frombeat )
2001-12-01 17:23:50 +00:00
return false ;
2002-04-11 17:19:16 +00:00
if ( tobeat = = 0 )
tobeat = 1 ;
2001-12-01 17:23:50 +00:00
2002-12-15 01:55:27 +00:00
_loop_counter = 0 ; // Because of possible interrupts
2001-12-01 17:23:50 +00:00
_loop_to_beat = tobeat ;
_loop_to_tick = totick ;
_loop_from_beat = frombeat ;
_loop_from_tick = fromtick ;
_loop_counter = count ;
return true ;
}
2003-03-06 17:58:13 +00:00
void Player : : clear_loop ( ) {
2001-12-01 17:23:50 +00:00
_loop_counter = 0 ;
}
2003-03-06 17:58:13 +00:00
void Player : : turn_off_pedals ( ) {
2001-12-01 17:23:50 +00:00
Part * part ;
2002-04-11 17:19:16 +00:00
for ( part = _parts ; part ; part = part - > _next ) {
2001-12-01 17:23:50 +00:00
if ( part - > _pedal )
part - > set_pedal ( false ) ;
}
}
2003-03-06 17:58:13 +00:00
void Player : : find_sustaining_notes ( byte * a , byte * b , uint32 l ) {
2001-12-01 17:23:50 +00:00
uint32 pos ;
uint16 mask ;
uint16 * bitlist_ptr ;
2002-04-11 17:19:16 +00:00
SustainingNotes * sn , * next ;
2001-12-01 17:23:50 +00:00
IsNoteCmdData isnote ;
int j ;
uint num_active ;
uint max_off_pos ;
num_active = update_actives ( ) ;
2002-12-15 01:55:27 +00:00
// pos contains number of ticks since current position
2001-12-01 17:23:50 +00:00
pos = _next_pos - _cur_pos ;
2002-07-07 18:04:03 +00:00
if ( ( int32 ) pos < 0 )
2001-12-01 17:23:50 +00:00
pos = 0 ;
2002-12-15 01:55:27 +00:00
// Locate the positions where the notes are turned off.
// Remember each note that was turned off.
2001-12-01 17:23:50 +00:00
while ( num_active ! = 0 ) {
2002-12-15 01:55:27 +00:00
// Is note off?
2002-04-11 17:19:16 +00:00
j = is_note_cmd ( & a , & isnote ) ;
if ( j = = - 1 )
2001-12-01 17:23:50 +00:00
break ;
if ( j = = 1 ) {
2002-04-11 17:19:16 +00:00
mask = 1 < < isnote . chan ;
2001-12-01 17:23:50 +00:00
bitlist_ptr = _se - > _active_notes + isnote . note ;
if ( * bitlist_ptr & mask ) {
* bitlist_ptr & = ~ mask ;
num_active - - ;
2002-12-15 01:55:27 +00:00
// Get a node from the free list
2002-04-11 17:19:16 +00:00
if ( ( sn = _se - > _sustain_notes_free ) = = NULL )
2001-12-01 17:23:50 +00:00
return ;
_se - > _sustain_notes_free = sn - > next ;
2002-04-11 17:19:16 +00:00
2002-12-15 01:55:27 +00:00
// Insert it in the beginning of the used list
2001-12-01 17:23:50 +00:00
sn - > next = _se - > _sustain_notes_used ;
_se - > _sustain_notes_used = sn ;
sn - > prev = NULL ;
if ( sn - > next )
sn - > next - > prev = sn ;
sn - > note = isnote . note ;
sn - > chan = isnote . chan ;
sn - > player = this ;
sn - > off_pos = pos ;
sn - > pos = 0 ;
sn - > counter = 0 ;
}
}
pos + = get_delta_time ( & a ) ;
}
2002-12-15 01:55:27 +00:00
// Find the maximum position where a note was turned off
2001-12-01 17:23:50 +00:00
max_off_pos = 0 ;
2002-04-11 17:19:16 +00:00
for ( sn = _se - > _sustain_notes_used ; sn ; sn = sn - > next ) {
_se - > _active_notes [ sn - > note ] | = ( 1 < < sn - > chan ) ;
2001-12-01 17:23:50 +00:00
if ( sn - > off_pos > max_off_pos ) {
max_off_pos = sn - > off_pos ;
}
}
2002-12-15 01:55:27 +00:00
// locate positions where notes are turned on
2001-12-01 17:23:50 +00:00
pos = l ;
while ( pos < max_off_pos ) {
2002-04-11 17:19:16 +00:00
j = is_note_cmd ( & b , & isnote ) ;
if ( j = = - 1 )
2001-12-01 17:23:50 +00:00
break ;
if ( j = = 2 ) {
2002-04-11 17:19:16 +00:00
mask = 1 < < isnote . chan ;
2001-12-01 17:23:50 +00:00
bitlist_ptr = _se - > _active_notes + isnote . note ;
2002-04-11 17:19:16 +00:00
if ( * bitlist_ptr & mask ) {
2001-12-01 17:23:50 +00:00
sn = _se - > _sustain_notes_used ;
while ( sn ) {
next = sn - > next ;
2002-07-07 18:04:03 +00:00
if ( sn - > note = = isnote . note & & sn - > chan = = isnote . chan & & pos < sn - > off_pos ) {
2001-12-01 17:23:50 +00:00
* bitlist_ptr & = ~ mask ;
2002-12-15 01:55:27 +00:00
// Unlink from the sustain list
2001-12-01 17:23:50 +00:00
if ( next )
next - > prev = sn - > prev ;
if ( sn - > prev )
sn - > prev - > next = next ;
else
_se - > _sustain_notes_used = next ;
2002-12-15 01:55:27 +00:00
// Insert into the free list
2001-12-01 17:23:50 +00:00
sn - > next = _se - > _sustain_notes_free ;
_se - > _sustain_notes_free = sn ;
}
sn = next ;
}
}
}
pos + = get_delta_time ( & b ) ;
}
2002-12-15 01:55:27 +00:00
// Concatenate head and used list
2001-12-01 17:23:50 +00:00
if ( ! _se - > _sustain_notes_head ) {
_se - > _sustain_notes_head = _se - > _sustain_notes_used ;
_se - > _sustain_notes_used = NULL ;
return ;
}
sn = _se - > _sustain_notes_head ;
2002-04-11 17:19:16 +00:00
while ( sn - > next )
sn = sn - > next ;
2001-12-01 17:23:50 +00:00
sn - > next = _se - > _sustain_notes_used ;
_se - > _sustain_notes_used = NULL ;
if ( sn - > next )
sn - > next - > prev = sn ;
}
2003-03-06 17:58:13 +00:00
Part * Player : : get_part ( uint8 chan ) {
2001-12-01 17:23:50 +00:00
Part * part ;
part = _parts ;
while ( part ) {
if ( part - > _chan = = chan )
return part ;
part = part - > _next ;
}
2003-05-16 01:52:45 +00:00
part = _se - > allocate_part ( _priority , _midi ) ;
2001-12-01 17:23:50 +00:00
if ( ! part ) {
warning ( " no parts available " ) ;
return NULL ;
}
2002-04-11 17:19:16 +00:00
2001-12-01 17:23:50 +00:00
part - > _chan = chan ;
part - > setup ( this ) ;
return part ;
}
2003-03-06 17:58:13 +00:00
uint Player : : update_actives ( ) {
2001-12-01 17:23:50 +00:00
Part * part ;
uint16 * active ;
int count = 0 ;
2002-04-11 17:19:16 +00:00
clear_active_notes ( ) ;
2001-12-01 17:23:50 +00:00
active = _se - > _active_notes ;
2002-04-11 17:19:16 +00:00
for ( part = _parts ; part ; part = part - > _next ) {
2001-12-01 17:23:50 +00:00
if ( part - > _mc )
count + = part - > update_actives ( active ) ;
}
return count ;
}
2003-03-06 17:58:13 +00:00
void Player : : set_priority ( int pri ) {
2001-12-01 17:23:50 +00:00
Part * part ;
_priority = pri ;
2002-04-11 17:19:16 +00:00
for ( part = _parts ; part ; part = part - > _next ) {
2001-12-01 17:23:50 +00:00
part - > set_pri ( part - > _pri ) ;
}
2003-05-16 01:52:45 +00:00
_se - > reallocateMidiChannels ( _midi ) ;
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
void Player : : set_pan ( int pan ) {
2001-12-01 17:23:50 +00:00
Part * part ;
_pan = pan ;
2002-04-11 17:19:16 +00:00
for ( part = _parts ; part ; part = part - > _next ) {
2001-12-01 17:23:50 +00:00
part - > set_pan ( part - > _pan ) ;
}
}
2003-03-06 17:58:13 +00:00
void Player : : set_detune ( int detune ) {
2001-12-01 17:23:50 +00:00
Part * part ;
_detune = detune ;
2002-04-11 17:19:16 +00:00
for ( part = _parts ; part ; part = part - > _next ) {
2001-12-01 17:23:50 +00:00
part - > set_detune ( part - > _detune ) ;
}
}
2003-03-06 17:58:13 +00:00
int Player : : scan ( uint totrack , uint tobeat , uint totick ) {
2002-04-11 17:19:16 +00:00
byte * mtrk , * scanptr ;
uint32 curpos , topos ;
2001-12-01 17:23:50 +00:00
uint32 pos ;
2002-04-11 17:19:16 +00:00
assert ( totrack > = 0 & & tobeat > = 0 & & totick > = 0 ) ;
2001-12-01 17:23:50 +00:00
if ( ! _active )
return - 1 ;
mtrk = _se - > findTag ( _song_index , " MTrk " , totrack ) ;
if ( ! mtrk )
return - 1 ;
2002-04-11 17:19:16 +00:00
if ( tobeat = = 0 )
2001-12-01 17:23:50 +00:00
tobeat + + ;
turn_off_parts ( ) ;
clear_active_notes ( ) ;
scanptr = mtrk ;
curpos = get_delta_time ( & scanptr ) ;
2002-04-11 17:19:16 +00:00
_scanning = true ;
2001-12-01 17:23:50 +00:00
2002-04-11 17:19:16 +00:00
topos = ( tobeat - 1 ) * _ticks_per_beat + totick ;
2001-12-01 17:23:50 +00:00
while ( curpos < topos ) {
scanptr = parse_midi ( scanptr ) ;
if ( ! scanptr ) {
2002-04-11 17:19:16 +00:00
_scanning = false ;
2001-12-01 17:23:50 +00:00
return - 1 ;
}
curpos + = get_delta_time ( & scanptr ) ;
}
pos = scanptr - mtrk ;
2002-04-11 17:19:16 +00:00
_scanning = false ;
2003-05-16 01:52:45 +00:00
_se - > reallocateMidiChannels ( _midi ) ;
2001-12-01 17:23:50 +00:00
play_active_notes ( ) ;
_beat_index = tobeat ;
_tick_index = totick ;
_cur_pos = topos ;
_next_pos = curpos ;
_timer_counter = 0 ;
_song_offset = pos ;
if ( _track_index ! = totrack ) {
_track_index = totrack ;
_loop_counter = 0 ;
}
return 0 ;
}
2003-03-06 17:58:13 +00:00
void Player : : turn_off_parts ( ) {
2001-12-01 17:23:50 +00:00
Part * part ;
2002-04-11 17:19:16 +00:00
for ( part = _parts ; part ; part = part - > _next )
2001-12-01 17:23:50 +00:00
part - > off ( ) ;
2003-05-16 01:52:45 +00:00
_se - > reallocateMidiChannels ( _midi ) ;
2001-12-01 17:23:50 +00:00
}
2003-03-06 17:58:13 +00:00
void Player : : play_active_notes ( ) {
2002-04-11 17:19:16 +00:00
int i , j ;
2001-12-01 17:23:50 +00:00
uint mask ;
2002-04-11 17:19:16 +00:00
for ( i = 0 ; i ! = 128 ; i + + ) {
2001-12-01 17:23:50 +00:00
mask = _se - > _active_notes [ i ] ;
2002-04-11 17:19:16 +00:00
for ( j = 0 ; j ! = 16 ; j + + , mask > > = 1 ) {
if ( mask & 1 ) {
2001-12-01 17:23:50 +00:00
key_on ( j , i , 80 ) ;
}
}
}
}
2003-03-06 17:58:13 +00:00
int Player : : set_vol ( byte vol ) {
2001-12-01 17:23:50 +00:00
Part * part ;
if ( vol > 127 )
return - 1 ;
_volume = vol ;
_vol_eff = _se - > get_channel_volume ( _vol_chan ) * ( vol + 1 ) > > 7 ;
2002-04-11 17:19:16 +00:00
for ( part = _parts ; part ; part = part - > _next ) {
2001-12-01 17:23:50 +00:00
part - > set_vol ( part - > _vol ) ;
}
return 0 ;
}
2003-03-06 17:58:13 +00:00
int Player : : get_param ( int param , byte chan ) {
2002-04-11 17:19:16 +00:00
switch ( param ) {
2001-12-01 17:23:50 +00:00
case 0 :
return ( byte ) _priority ;
case 1 :
return ( byte ) _volume ;
case 2 :
return ( byte ) _pan ;
case 3 :
return ( byte ) _transpose ;
case 4 :
return ( byte ) _detune ;
case 5 :
return _speed ;
case 6 :
return _track_index ;
case 7 :
return _beat_index ;
case 8 :
return _tick_index ;
case 9 :
return _loop_counter ;
case 10 :
return _loop_to_beat ;
case 11 :
return _loop_to_tick ;
case 12 :
return _loop_from_beat ;
case 13 :
return _loop_from_tick ;
2002-04-11 17:19:16 +00:00
case 14 :
case 15 :
case 16 :
case 17 :
2001-12-01 17:23:50 +00:00
return query_part_param ( param , chan ) ;
2002-04-11 17:19:16 +00:00
case 18 :
case 19 :
case 20 :
case 21 :
case 22 :
case 23 :
2001-12-01 17:23:50 +00:00
return _hook . query_param ( param , chan ) ;
default :
return - 1 ;
}
}
2003-03-06 17:58:13 +00:00
int Player : : query_part_param ( int param , byte chan ) {
2001-12-01 17:23:50 +00:00
Part * part ;
part = _parts ;
while ( part ) {
2002-04-11 17:19:16 +00:00
if ( part - > _chan = = chan ) {
switch ( param ) {
2001-12-01 17:23:50 +00:00
case 14 :
return part - > _on ;
case 15 :
return part - > _vol ;
case 16 :
2003-05-15 23:08:03 +00:00
return ( int ) part - > _instrument ;
2001-12-01 17:23:50 +00:00
case 17 :
return part - > _transpose ;
default :
return - 1 ;
}
}
part = part - > _next ;
}
return 129 ;
}
2003-03-06 17:58:13 +00:00
void Player : : sequencer_timer ( ) {
2002-05-04 00:20:39 +00:00
byte * mtrk ;
uint32 counter ;
byte * song_ptr ;
counter = _timer_counter + _timer_speed ;
_timer_counter = counter & 0xFFFF ;
_cur_pos + = counter > > 16 ;
_tick_index + = counter > > 16 ;
if ( _tick_index > = _ticks_per_beat ) {
_beat_index + = _tick_index / _ticks_per_beat ;
_tick_index % = _ticks_per_beat ;
}
2002-07-07 18:04:03 +00:00
if ( _loop_counter & & _beat_index > = _loop_from_beat & & _tick_index > = _loop_from_tick ) {
2002-05-04 00:20:39 +00:00
_loop_counter - - ;
jump ( _track_index , _loop_to_beat , _loop_to_tick ) ;
}
if ( _next_pos < = _cur_pos ) {
mtrk = _se - > findTag ( _song_index , " MTrk " , _track_index ) ;
if ( ! mtrk ) {
warning ( " Sound %d was unloaded while active " , _song_index ) ;
clear ( ) ;
} else {
song_ptr = mtrk + _song_offset ;
_abort = false ;
while ( _next_pos < = _cur_pos ) {
song_ptr = parse_midi ( song_ptr ) ;
if ( ! song_ptr | | _abort )
return ;
_next_pos + = get_delta_time ( & song_ptr ) ;
2003-04-19 14:23:40 +00:00
_song_offset = song_ptr - mtrk ;
2002-05-04 00:20:39 +00:00
}
}
}
}
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
2001-12-01 17:23:50 +00:00
const SaveLoadEntry playerEntries [ ] = {
2002-12-08 16:14:29 +00:00
MKREF ( Player , _parts , TYPE_PART , VER_V8 ) ,
MKLINE ( Player , _active , sleByte , VER_V8 ) ,
MKLINE ( Player , _id , sleUint16 , VER_V8 ) ,
MKLINE ( Player , _priority , sleByte , VER_V8 ) ,
MKLINE ( Player , _volume , sleByte , VER_V8 ) ,
MKLINE ( Player , _pan , sleInt8 , VER_V8 ) ,
MKLINE ( Player , _transpose , sleByte , VER_V8 ) ,
MKLINE ( Player , _detune , sleInt8 , VER_V8 ) ,
MKLINE ( Player , _vol_chan , sleUint16 , VER_V8 ) ,
MKLINE ( Player , _vol_eff , sleByte , VER_V8 ) ,
MKLINE ( Player , _speed , sleByte , VER_V8 ) ,
MKLINE ( Player , _song_index , sleUint16 , VER_V8 ) ,
MKLINE ( Player , _track_index , sleUint16 , VER_V8 ) ,
MKLINE ( Player , _timer_counter , sleUint16 , VER_V8 ) ,
MKLINE ( Player , _loop_to_beat , sleUint16 , VER_V8 ) ,
MKLINE ( Player , _loop_from_beat , sleUint16 , VER_V8 ) ,
MKLINE ( Player , _loop_counter , sleUint16 , VER_V8 ) ,
MKLINE ( Player , _loop_to_tick , sleUint16 , VER_V8 ) ,
MKLINE ( Player , _loop_from_tick , sleUint16 , VER_V8 ) ,
MKLINE ( Player , _tempo , sleUint32 , VER_V8 ) ,
MKLINE ( Player , _cur_pos , sleUint32 , VER_V8 ) ,
MKLINE ( Player , _next_pos , sleUint32 , VER_V8 ) ,
MKLINE ( Player , _song_offset , sleUint32 , VER_V8 ) ,
MKLINE ( Player , _tick_index , sleUint16 , VER_V8 ) ,
MKLINE ( Player , _beat_index , sleUint16 , VER_V8 ) ,
MKLINE ( Player , _ticks_per_beat , sleUint16 , VER_V8 ) ,
2003-05-05 16:07:10 +00:00
MKLINE ( Player , _hook . _jump [ 0 ] , sleByte , VER_V8 ) ,
2002-12-08 16:14:29 +00:00
MKLINE ( Player , _hook . _transpose , sleByte , VER_V8 ) ,
MKARRAY ( Player , _hook . _part_onoff [ 0 ] , sleByte , 16 , VER_V8 ) ,
MKARRAY ( Player , _hook . _part_volume [ 0 ] , sleByte , 16 , VER_V8 ) ,
MKARRAY ( Player , _hook . _part_program [ 0 ] , sleByte , 16 , VER_V8 ) ,
MKARRAY ( Player , _hook . _part_transpose [ 0 ] , sleByte , 16 , VER_V8 ) ,
2001-12-01 17:23:50 +00:00
MKEND ( )
} ;
const SaveLoadEntry volumeFaderEntries [ ] = {
2002-12-08 16:14:29 +00:00
MKREF ( VolumeFader , player , TYPE_PLAYER , VER_V8 ) ,
MKLINE ( VolumeFader , active , sleUint8 , VER_V8 ) ,
MKLINE ( VolumeFader , curvol , sleUint8 , VER_V8 ) ,
MKLINE ( VolumeFader , speed_lo_max , sleUint16 , VER_V8 ) ,
MKLINE ( VolumeFader , num_steps , sleUint16 , VER_V8 ) ,
MKLINE ( VolumeFader , speed_hi , sleInt8 , VER_V8 ) ,
MKLINE ( VolumeFader , direction , sleInt8 , VER_V8 ) ,
MKLINE ( VolumeFader , speed_lo , sleInt8 , VER_V8 ) ,
MKLINE ( VolumeFader , speed_lo_counter , sleUint16 , VER_V8 ) ,
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
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 ) ;
2002-07-07 18:04:03 +00:00
ser - > saveLoadArrayOf ( _players , ARRAYSIZE ( _players ) , sizeof ( _players [ 0 ] ) , playerEntries ) ;
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
int i ;
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
}
}
2002-04-11 17:19:16 +00:00
ser - > saveLoadArrayOf ( _volume_fader , ARRAYSIZE ( _volume_fader ) ,
2002-12-15 01:55:27 +00:00
sizeof ( _volume_fader [ 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
init_sustaining_notes ( ) ;
_active_volume_faders = true ;
fix_parts_after_load ( ) ;
2003-05-16 01:52:45 +00:00
reallocateMidiChannels ( _midi_native ) ;
2002-12-07 18:03:10 +00:00
set_master_volume ( _master_volume ) ;
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 + + ) {
2001-12-01 17:23:50 +00:00
if ( player - > _active ) {
player - > set_tempo ( player - > _tempo ) ;
2002-04-14 18:13:08 +00:00
scumm - > getResourceAddress ( rtSound , player - > _id ) ;
2002-05-04 00:20:39 +00:00
player - > _mt32emulate = isMT32 ( player - > _id ) ;
2002-09-29 11:11:42 +00:00
player - > _isGM = isGM ( player - > _id ) ;
2003-05-16 02:13:21 +00:00
player - > _midi = _midi_native ;
2001-12-01 17:23:50 +00:00
}
}
}
2003-03-06 17:58:13 +00:00
void Part : : set_detune ( int8 detune ) {
2002-04-11 17:19:16 +00:00
_detune_eff = clamp ( ( _detune = detune ) + _player - > _detune , - 128 , 127 ) ;
2003-05-15 19:39:10 +00:00
if ( clearToTransmit ( ) ) {
_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-15 19:39:10 +00:00
if ( clearToTransmit ( ) ) {
_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_vol ( uint8 vol ) {
2002-04-11 17:19:16 +00:00
_vol_eff = ( ( _vol = vol ) + 1 ) * _player - > _vol_eff > > 7 ;
2003-05-15 19:39:10 +00:00
if ( clearToTransmit ( ) ) _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 ) {
2002-04-11 17:19:16 +00:00
_pri_eff = clamp ( ( _pri = pri ) + _player - > _priority , 0 , 255 ) ;
2003-05-15 19:39:10 +00:00
if ( clearToTransmit ( ) ) _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 ) {
2002-04-11 17:19:16 +00:00
_pan_eff = clamp ( ( _pan = pan ) + _player - > _pan , - 64 , 63 ) ;
2003-05-15 19:39:10 +00:00
if ( clearToTransmit ( ) ) _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 ) {
2002-07-07 18:04:03 +00:00
_transpose_eff = transpose_clamp ( ( _transpose = transpose ) + _player - > _transpose , - 12 , 12 ) ;
2003-05-15 19:39:10 +00:00
if ( clearToTransmit ( ) ) {
_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-15 19:39:10 +00:00
if ( clearToTransmit ( ) ) _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-15 19:39:10 +00:00
if ( clearToTransmit ( ) ) _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-15 19:39:10 +00:00
if ( clearToTransmit ( ) ) _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-15 19:39:10 +00:00
if ( clearToTransmit ( ) ) _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 ) ;
set_vol ( _vol ) ;
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-15 19:39:10 +00:00
if ( clearToTransmit ( ) ) _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-16 01:52:45 +00:00
_player - > _se - > reallocateMidiChannels ( _player - > _midi ) ;
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-15 19:39:10 +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 ) ;
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-16 01:52:45 +00:00
mc = _player - > _midi - > 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-16 01:52:45 +00:00
mc = _player - > _midi - > 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
2002-12-15 01:55:27 +00:00
// Insert first into player's list
2001-12-01 17:23:50 +00:00
_prev = NULL ;
2002-04-11 17:19:16 +00:00
_next = player - > _parts ;
2001-12-01 17:23:50 +00:00
if ( player - > _parts )
player - > _parts - > _prev = this ;
player - > _parts = this ;
2002-11-06 21:34:38 +00:00
_percussion = ( player - > _isGM & & _chan = = 9 ) ; // true;
2001-12-01 17:23:50 +00:00
_on = true ;
_pri_eff = player - > _priority ;
_pri = 0 ;
_vol = 127 ;
_vol_eff = player - > _vol_eff ;
_pan = clamp ( player - > _pan , - 64 , 63 ) ;
_transpose_eff = player - > _transpose ;
_transpose = 0 ;
_detune = 0 ;
_detune_eff = player - > _detune ;
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 ;
2002-11-06 21:34:38 +00:00
2003-05-07 19:24:14 +00:00
if ( _instrument . isValid ( ) )
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 : : uninit ( ) {
2001-12-01 17:23:50 +00:00
if ( ! _player )
return ;
off ( ) ;
2002-04-11 17:19:16 +00:00
2002-12-15 01:55:27 +00:00
// Unlink
2001-12-01 17:23:50 +00:00
if ( _next )
_next - > _prev = _prev ;
if ( _prev )
_prev - > _next = _next ;
else
_player - > _parts = _next ;
_player = NULL ;
_next = NULL ;
_prev = 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-16 01:52:45 +00:00
_player - > _se - > reallocateMidiChannels ( _player - > _midi ) ;
if ( _mc ) sendAll ( ) ;
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 ) ;
if ( _instrument . isValid ( ) ) {
_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 ;
_instrument . program ( program , _player - > _mt32emulate ) ;
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-15 23:08:03 +00:00
_instrument . program ( ( byte ) b , _player - > _mt32emulate ) ;
2003-05-15 19:39:10 +00:00
if ( clearToTransmit ( ) ) _instrument . send ( _mc ) ;
2002-04-14 18:13:08 +00:00
}
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-16 01:52:45 +00:00
if ( part - > _player & & part - > _player - > _midi = = midi & &
! 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-03-23 13:14:54 +00:00
int IMuse : : getSoundStatus ( int sound ) { in ( ) ; int ret = _target - > getSoundStatus ( sound ) ; out ( ) ; return ret ; }
2002-12-21 21:09:36 +00:00
bool IMuse : : get_sound_active ( int sound ) { in ( ) ; bool ret = _target - > get_sound_active ( sound ) ; 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 ; }
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-03-06 17:58:13 +00:00
IMuse * IMuse : : create ( OSystem * syst , MidiDriver * midi , SoundMixer * mixer ) {
2002-12-21 21:09:36 +00:00
IMuseInternal * engine = IMuseInternal : : create ( syst , midi , mixer ) ;
2002-12-01 15:51:29 +00:00
if ( midi )
midi - > property ( MidiDriver : : PROP_SMALLHEADER , ( g_scumm - > _features & GF_SMALL_HEADER ) ? 1 : 0 ) ;
2002-12-21 21:09:36 +00:00
return new IMuse ( syst , engine ) ;
2002-04-29 11:48:33 +00:00
}