2003-05-22 16:15:48 +00:00
|
|
|
/* ScummVM - Scumm Interpreter
|
|
|
|
* Copyright (C) 2001 Ludvig Strigeus
|
|
|
|
* Copyright (C) 2001-2003 The ScummVM project
|
|
|
|
*
|
|
|
|
* 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$
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef DEFINED_IMUSE_INTERNAL
|
|
|
|
#define DEFINED_IMUSE_INTERNAL
|
|
|
|
|
2003-05-23 04:19:47 +00:00
|
|
|
#include "sound/mididrv.h"
|
2003-05-22 16:15:48 +00:00
|
|
|
#include "common/scummsys.h"
|
2003-05-23 04:19:47 +00:00
|
|
|
#include "scumm/instrument.h"
|
2003-05-22 16:15:48 +00:00
|
|
|
|
2003-05-24 19:20:52 +00:00
|
|
|
// Unremark this statement to activate some of
|
|
|
|
// the most common iMuse diagnostic messages.
|
2003-05-24 19:43:20 +00:00
|
|
|
#define IMUSE_DEBUG
|
2003-05-24 19:20:52 +00:00
|
|
|
|
2003-05-22 16:15:48 +00:00
|
|
|
struct HookDatas;
|
|
|
|
struct ParameterFader;
|
|
|
|
struct DeferredCommand;
|
|
|
|
struct ImTrigger;
|
|
|
|
struct SustainingNotes;
|
|
|
|
struct CommandQueue;
|
|
|
|
struct IsNoteCmdData;
|
2003-05-23 04:19:47 +00:00
|
|
|
class Player;
|
2003-05-22 16:15:48 +00:00
|
|
|
struct Part;
|
2003-05-23 04:19:47 +00:00
|
|
|
class IMuseInternal;
|
2003-05-22 16:15:48 +00:00
|
|
|
|
|
|
|
// Some entities also referenced
|
2003-05-23 04:19:47 +00:00
|
|
|
class MidiParser;
|
2003-05-22 16:15:48 +00:00
|
|
|
class Scumm;
|
|
|
|
class OSystem;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Some constants
|
|
|
|
//
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
|
|
|
|
#define TICKS_PER_BEAT 480
|
|
|
|
|
|
|
|
#define IMUSE_SYSEX_ID 0x7D
|
|
|
|
#define ROLAND_SYSEX_ID 0x41
|
|
|
|
#define PERCUSSION_CHANNEL 9
|
|
|
|
|
|
|
|
#define TRIGGER_ID 0
|
|
|
|
#define COMMAND_ID 1
|
|
|
|
|
|
|
|
#define MDPG_TAG "MDpg"
|
|
|
|
#define MDHD_TAG "MDhd"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Helper functions
|
|
|
|
//
|
|
|
|
////////////////////////////////////////
|
|
|
|
|
2003-05-23 04:19:47 +00:00
|
|
|
inline int clamp(int val, int min, int max) {
|
2003-05-22 16:15:48 +00:00
|
|
|
if (val < min)
|
|
|
|
return min;
|
|
|
|
if (val > max)
|
|
|
|
return max;
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2003-05-23 04:19:47 +00:00
|
|
|
inline int transpose_clamp(int a, int b, int c) {
|
2003-05-22 16:15:48 +00:00
|
|
|
if (b > a)
|
|
|
|
a += (b - a + 11) / 12 * 12;
|
|
|
|
if (c < a)
|
|
|
|
a -= (a - c + 11) / 12 * 12;
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Entity declarations
|
|
|
|
//
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
|
|
|
|
struct HookDatas {
|
|
|
|
byte _jump[2];
|
|
|
|
byte _transpose;
|
|
|
|
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);
|
2003-05-23 04:19:47 +00:00
|
|
|
HookDatas() { memset (this, 0, sizeof (HookDatas)); }
|
2003-05-22 16:15:48 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct ParameterFader {
|
|
|
|
enum {
|
|
|
|
pfVolume = 1,
|
|
|
|
pfTranspose = 3,
|
|
|
|
pfSpeed = 4
|
|
|
|
};
|
|
|
|
|
|
|
|
int param;
|
|
|
|
int start;
|
|
|
|
int end;
|
|
|
|
uint32 total_time;
|
|
|
|
uint32 current_time;
|
|
|
|
|
|
|
|
ParameterFader() { param = 0; }
|
|
|
|
void init() { param = 0; }
|
|
|
|
};
|
|
|
|
|
|
|
|
struct DeferredCommand {
|
|
|
|
MidiDriver *midi;
|
|
|
|
uint32 time_left;
|
|
|
|
int a, b, c, d, e, f;
|
2003-05-23 04:19:47 +00:00
|
|
|
DeferredCommand() { memset (this, 0, sizeof (DeferredCommand)); }
|
2003-05-22 16:15:48 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct ImTrigger {
|
|
|
|
int sound;
|
|
|
|
byte id;
|
|
|
|
uint16 expire;
|
|
|
|
byte command [4];
|
2003-05-23 04:19:47 +00:00
|
|
|
ImTrigger() { memset (this, 0, sizeof (ImTrigger)); }
|
2003-05-22 16:15:48 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct CommandQueue {
|
|
|
|
uint16 array[8];
|
2003-05-23 04:19:47 +00:00
|
|
|
CommandQueue() { memset (this, 0, sizeof (CommandQueue)); }
|
2003-05-22 16:15:48 +00:00
|
|
|
};
|
|
|
|
|
2003-05-23 04:19:47 +00:00
|
|
|
class Player : public MidiDriver {
|
|
|
|
protected:
|
2003-05-22 16:15:48 +00:00
|
|
|
MidiDriver *_midi;
|
2003-05-23 04:19:47 +00:00
|
|
|
MidiParser *_parser;
|
2003-05-22 16:15:48 +00:00
|
|
|
|
|
|
|
Part *_parts;
|
|
|
|
bool _active;
|
|
|
|
bool _scanning;
|
|
|
|
int _id;
|
|
|
|
byte _priority;
|
|
|
|
byte _volume;
|
|
|
|
int8 _pan;
|
|
|
|
int8 _transpose;
|
|
|
|
int8 _detune;
|
|
|
|
byte _vol_eff;
|
|
|
|
|
|
|
|
uint _song_index;
|
|
|
|
uint _track_index;
|
|
|
|
uint _loop_to_beat;
|
|
|
|
uint _loop_from_beat;
|
|
|
|
uint _loop_counter;
|
|
|
|
uint _loop_to_tick;
|
|
|
|
uint _loop_from_tick;
|
|
|
|
uint32 _tempo;
|
|
|
|
uint32 _tempo_eff; // No Save
|
2003-05-23 04:19:47 +00:00
|
|
|
byte _speed;
|
2003-05-22 16:15:48 +00:00
|
|
|
bool _abort;
|
|
|
|
|
2003-05-23 04:19:47 +00:00
|
|
|
// This does not get used by us! It is only
|
|
|
|
// here for save/load purposes, and gets
|
|
|
|
// passed on to the MidiParser during
|
|
|
|
// fixAfterLoad().
|
|
|
|
uint32 _music_tick;
|
|
|
|
|
2003-05-22 16:15:48 +00:00
|
|
|
HookDatas _hook;
|
|
|
|
ParameterFader _parameterFaders[4];
|
|
|
|
|
2003-05-23 04:19:47 +00:00
|
|
|
bool _isMT32;
|
2003-05-22 16:15:48 +00:00
|
|
|
bool _isGM;
|
|
|
|
|
2003-05-23 04:19:47 +00:00
|
|
|
protected:
|
2003-05-22 16:15:48 +00:00
|
|
|
// Player part
|
|
|
|
void hook_clear();
|
|
|
|
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);
|
|
|
|
void maybe_jump (byte cmd, uint track, uint beat, uint tick);
|
|
|
|
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();
|
|
|
|
void turn_off_pedals();
|
2003-05-23 04:19:47 +00:00
|
|
|
int query_part_param(int param, byte chan);
|
2003-05-22 16:15:48 +00:00
|
|
|
void turn_off_parts();
|
|
|
|
void play_active_notes();
|
|
|
|
|
|
|
|
void transitionParameters();
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
|
|
|
// Sequencer part
|
2003-05-23 04:19:47 +00:00
|
|
|
void setTempo(uint32 data);
|
2003-05-22 16:15:48 +00:00
|
|
|
int start_seq_sound(int sound);
|
|
|
|
int query_param(int param);
|
|
|
|
|
2003-05-23 04:19:47 +00:00
|
|
|
public:
|
|
|
|
IMuseInternal *_se;
|
|
|
|
uint _vol_chan;
|
2003-05-22 16:15:48 +00:00
|
|
|
|
2003-05-23 04:19:47 +00:00
|
|
|
public:
|
|
|
|
Player();
|
|
|
|
virtual ~Player();
|
|
|
|
|
|
|
|
int addParameterFader (int param, int target, int time);
|
|
|
|
void clear();
|
|
|
|
void clearLoop();
|
|
|
|
void fixAfterLoad();
|
|
|
|
Part * getActivePart (uint8 part);
|
|
|
|
uint getBeatIndex();
|
|
|
|
int8 getDetune() { return _detune; }
|
|
|
|
byte getEffectiveVolume() { return _vol_eff; }
|
|
|
|
int getID() { return _id; }
|
|
|
|
MidiDriver *getMidiDriver() { return _midi; }
|
|
|
|
int getParam (int param, byte chan);
|
|
|
|
int8 getPan() { return _pan; }
|
|
|
|
Part * getPart (uint8 part);
|
|
|
|
byte getPriority() { return _priority; }
|
|
|
|
uint32 getTempo() { return _tempo; }
|
|
|
|
uint getTicksPerBeat() { return TICKS_PER_BEAT; }
|
|
|
|
int8 getTranspose() { return _transpose; }
|
|
|
|
byte getVolume() { return _volume; }
|
|
|
|
bool isActive() { return _active; }
|
|
|
|
bool isFadingOut();
|
|
|
|
bool isGM() { return _isGM; }
|
|
|
|
bool isMT32() { return _isMT32; }
|
|
|
|
bool jump (uint track, uint beat, uint tick);
|
|
|
|
void onTimer();
|
|
|
|
void removePart (Part *part);
|
|
|
|
int scan (uint totrack, uint tobeat, uint totick);
|
|
|
|
int save_or_load (Serializer *ser);
|
|
|
|
int setHook (byte cls, byte value, byte chan) { return _hook.set (cls, value, chan); }
|
|
|
|
void setDetune (int detune);
|
|
|
|
bool setLoop (uint count, uint tobeat, uint totick, uint frombeat, uint fromtick);
|
|
|
|
void setPan (int pan);
|
|
|
|
void setPriority (int pri);
|
|
|
|
void setSpeed (byte speed);
|
|
|
|
int setTranspose(byte relative, int b);
|
|
|
|
int setVolume (byte vol);
|
|
|
|
bool startSound (int sound, MidiDriver *midi);
|
2003-05-22 16:15:48 +00:00
|
|
|
|
2003-05-23 04:19:47 +00:00
|
|
|
public:
|
|
|
|
// MidiDriver interface
|
|
|
|
int open() { return 0; }
|
|
|
|
void close() { }
|
|
|
|
void send (uint32 b);
|
|
|
|
const char *getErrorName (int error_code) { return "Unknown"; }
|
|
|
|
void sysEx (byte *msg, uint16 length);
|
|
|
|
void metaEvent (byte type, byte *data, uint16 length);
|
|
|
|
void setTimerCallback (void *timer_param, void (*timer_proc) (void *)) { }
|
|
|
|
uint32 getBaseTempo();
|
|
|
|
MidiChannel *allocateChannel() { return 0; }
|
|
|
|
MidiChannel *getPercussionChannel() { return 0; }
|
2003-05-22 16:15:48 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct Part {
|
|
|
|
int _slot;
|
|
|
|
Part *_next, *_prev;
|
|
|
|
MidiChannel *_mc;
|
|
|
|
Player *_player;
|
|
|
|
int16 _pitchbend;
|
|
|
|
byte _pitchbend_factor;
|
|
|
|
int8 _transpose, _transpose_eff;
|
|
|
|
byte _vol, _vol_eff;
|
|
|
|
int8 _detune, _detune_eff;
|
|
|
|
int8 _pan, _pan_eff;
|
|
|
|
bool _on;
|
|
|
|
byte _modwheel;
|
|
|
|
bool _pedal;
|
|
|
|
int8 _pri;
|
|
|
|
byte _pri_eff;
|
|
|
|
byte _chan;
|
|
|
|
byte _effect_level;
|
|
|
|
byte _chorus;
|
|
|
|
byte _percussion;
|
|
|
|
byte _bank;
|
|
|
|
|
|
|
|
// New abstract instrument definition
|
|
|
|
Instrument _instrument;
|
|
|
|
bool _unassigned_instrument; // For diagnostic reporting purposes only
|
|
|
|
|
|
|
|
// Used to be in MidiDriver
|
|
|
|
uint16 _actives[8];
|
|
|
|
|
|
|
|
void key_on(byte note, byte velocity);
|
|
|
|
void key_off(byte note);
|
|
|
|
void set_param(byte param, int value) { }
|
|
|
|
void init();
|
|
|
|
void setup(Player *player);
|
|
|
|
void uninit();
|
|
|
|
void off();
|
|
|
|
void silence();
|
|
|
|
void set_instrument(uint b);
|
|
|
|
void set_instrument(byte *data);
|
|
|
|
void load_global_instrument (byte b);
|
|
|
|
|
|
|
|
void set_transpose(int8 transpose);
|
2003-05-23 04:19:47 +00:00
|
|
|
void setVolume(uint8 volume);
|
2003-05-22 16:15:48 +00:00
|
|
|
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);
|
|
|
|
|
|
|
|
int update_actives(uint16 *active);
|
|
|
|
void set_pitchbend_factor(uint8 value);
|
|
|
|
void set_onoff(bool on);
|
|
|
|
void fix_after_load();
|
|
|
|
|
|
|
|
void sendAll();
|
|
|
|
bool clearToTransmit();
|
|
|
|
|
|
|
|
Part() {
|
|
|
|
memset(this,0,sizeof(Part));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
class IMuseInternal {
|
2003-05-23 04:19:47 +00:00
|
|
|
friend class Player;
|
2003-05-22 16:15:48 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
bool _old_adlib_instruments;
|
|
|
|
bool _enable_multi_midi;
|
|
|
|
MidiDriver *_midi_adlib;
|
|
|
|
MidiDriver *_midi_native;
|
|
|
|
|
|
|
|
byte **_base_sounds;
|
|
|
|
|
|
|
|
private:
|
|
|
|
bool _paused;
|
|
|
|
bool _initialized;
|
|
|
|
|
|
|
|
int _tempoFactor;
|
|
|
|
|
2003-05-23 18:35:53 +00:00
|
|
|
int _player_limit; // Limits how many simultaneous music tracks are played
|
|
|
|
bool _recycle_players; // Can we stop a player in order to start another one?
|
|
|
|
|
2003-05-22 16:15:48 +00:00
|
|
|
uint _queue_end, _queue_pos, _queue_sound;
|
|
|
|
byte _queue_adding;
|
|
|
|
|
|
|
|
byte _queue_marker;
|
|
|
|
byte _queue_cleared;
|
|
|
|
byte _master_volume; // Master volume. 0-255
|
|
|
|
byte _music_volume; // Global music volume. 0-255
|
|
|
|
|
|
|
|
uint16 _trigger_count;
|
|
|
|
ImTrigger _snm_triggers[16]; // Sam & Max triggers
|
|
|
|
uint16 _snm_trigger_index;
|
|
|
|
|
|
|
|
uint16 _channel_volume[8];
|
|
|
|
uint16 _channel_volume_eff[8]; // No Save
|
|
|
|
uint16 _volchan_table[8];
|
|
|
|
|
|
|
|
Player _players[8];
|
|
|
|
Part _parts[32];
|
|
|
|
|
|
|
|
uint16 _active_notes[128];
|
|
|
|
Instrument _global_adlib_instruments[32];
|
|
|
|
CommandQueue _cmd_queue[64];
|
|
|
|
DeferredCommand _deferredCommands[4];
|
|
|
|
|
2003-05-23 18:35:53 +00:00
|
|
|
byte *findStartOfSound (int sound);
|
2003-05-22 16:15:48 +00:00
|
|
|
bool isMT32(int sound);
|
|
|
|
bool isGM(int sound);
|
|
|
|
int get_queue_sound_status(int sound);
|
|
|
|
void handle_marker(uint id, byte data);
|
|
|
|
int get_channel_volume(uint a);
|
|
|
|
void initMidiDriver (MidiDriver *midi);
|
|
|
|
void init_players();
|
|
|
|
void init_parts();
|
|
|
|
void init_queue();
|
|
|
|
|
|
|
|
void sequencer_timers (MidiDriver *midi);
|
|
|
|
|
|
|
|
MidiDriver *getBestMidiDriver (int sound);
|
|
|
|
Player *allocate_player(byte priority);
|
|
|
|
Part *allocate_part(byte pri, MidiDriver *midi);
|
|
|
|
|
|
|
|
int32 ImSetTrigger (int sound, int id, int a, int b, int c, int d);
|
|
|
|
int32 ImClearTrigger (int sound, int id);
|
|
|
|
int32 ImFireAllTriggers (int sound);
|
|
|
|
|
|
|
|
void addDeferredCommand (int time, int a, int b, int c, int d, int e, int f);
|
|
|
|
void handleDeferredCommands (MidiDriver *midi);
|
|
|
|
|
|
|
|
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);
|
2003-05-23 04:19:47 +00:00
|
|
|
Player *findActivePlayer (int id);
|
2003-05-22 16:15:48 +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();
|
|
|
|
|
|
|
|
int set_volchan(int sound, int volchan);
|
|
|
|
|
|
|
|
void fix_parts_after_load();
|
|
|
|
void fix_players_after_load(Scumm *scumm);
|
|
|
|
|
|
|
|
static int saveReference(void *me_ref, byte type, void *ref);
|
|
|
|
static void *loadReference(void *me_ref, byte type, int ref);
|
|
|
|
|
|
|
|
static void midiTimerCallback (void *data);
|
|
|
|
|
|
|
|
public:
|
2003-05-23 04:19:47 +00:00
|
|
|
IMuseInternal();
|
2003-05-22 16:15:48 +00:00
|
|
|
~IMuseInternal();
|
|
|
|
|
|
|
|
int initialize(OSystem *syst, MidiDriver *midi);
|
|
|
|
void reallocateMidiChannels (MidiDriver *midi);
|
|
|
|
void setGlobalAdlibInstrument (byte slot, byte *data);
|
|
|
|
void copyGlobalAdlibInstrument (byte slot, Instrument *dest);
|
|
|
|
|
|
|
|
// IMuse interface
|
|
|
|
|
|
|
|
void on_timer (MidiDriver *midi);
|
|
|
|
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();
|
|
|
|
bool startSound(int sound);
|
|
|
|
int stopSound(int sound);
|
|
|
|
int stop_all_sounds();
|
2003-05-23 18:35:53 +00:00
|
|
|
int getSoundStatus (int sound, bool ignoreFadeouts = true);
|
2003-05-22 16:15:48 +00:00
|
|
|
int32 doCommand(int a, int b, int c, int d, int e, int f, int g, int h);
|
|
|
|
int clear_queue();
|
|
|
|
void setBase(byte **base);
|
|
|
|
|
|
|
|
uint32 property(int prop, uint32 value);
|
|
|
|
MidiDriver *getMidiDriver();
|
|
|
|
|
|
|
|
static IMuseInternal *create(OSystem *syst, MidiDriver *midi);
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|