mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-22 09:49:11 +00:00
033ff78ae9
svn-id: r12176
475 lines
12 KiB
C++
475 lines
12 KiB
C++
/* ScummVM - Scumm Interpreter
|
|
* Copyright (C) 2001 Ludvig Strigeus
|
|
* Copyright (C) 2001-2004 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
|
|
|
|
#include "common/scummsys.h"
|
|
#include "scumm/instrument.h"
|
|
#include "sound/mididrv.h"
|
|
|
|
class MidiParser;
|
|
class OSystem;
|
|
class SoundMixer;
|
|
|
|
namespace Scumm {
|
|
|
|
// Unremark this statement to activate some of
|
|
// the most common iMuse diagnostic messages.
|
|
// #define IMUSE_DEBUG
|
|
|
|
struct HookDatas;
|
|
struct ParameterFader;
|
|
struct DeferredCommand;
|
|
struct ImTrigger;
|
|
struct SustainingNotes;
|
|
struct CommandQueue;
|
|
struct IsNoteCmdData;
|
|
class Player;
|
|
struct Part;
|
|
class IMuseInternal;
|
|
|
|
// Some entities also referenced
|
|
class ScummEngine;
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
//
|
|
// Some constants
|
|
//
|
|
//////////////////////////////////////////////////
|
|
|
|
#define TICKS_PER_BEAT 480
|
|
|
|
#define TRIGGER_ID 0
|
|
#define COMMAND_ID 1
|
|
|
|
#define MDPG_TAG "MDpg"
|
|
|
|
|
|
////////////////////////////////////////
|
|
//
|
|
// Helper functions
|
|
//
|
|
////////////////////////////////////////
|
|
|
|
inline int clamp(int val, int min, int max) {
|
|
if(val < min)
|
|
return min;
|
|
if(val > max)
|
|
return max;
|
|
return val;
|
|
}
|
|
|
|
inline int transpose_clamp(int a, int b, int c) {
|
|
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);
|
|
HookDatas() { memset(this, 0, sizeof(HookDatas)); }
|
|
};
|
|
|
|
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 {
|
|
uint32 time_left;
|
|
int a, b, c, d, e, f;
|
|
DeferredCommand() { memset(this, 0, sizeof(DeferredCommand)); }
|
|
};
|
|
|
|
struct ImTrigger {
|
|
int sound;
|
|
byte id;
|
|
uint16 expire;
|
|
int command [8];
|
|
ImTrigger() { memset(this, 0, sizeof(ImTrigger)); }
|
|
};
|
|
|
|
struct CommandQueue {
|
|
uint16 array[8];
|
|
CommandQueue() { memset(this, 0, sizeof(CommandQueue)); }
|
|
};
|
|
|
|
class Player : public MidiDriver {
|
|
protected:
|
|
// Moved from IMuseInternal.
|
|
// This is only used by one player at a time.
|
|
static uint16 _active_notes[128];
|
|
|
|
protected:
|
|
MidiDriver *_midi;
|
|
MidiParser *_parser;
|
|
bool _passThrough; // Only respond to EOT, all else direct to MidiDriver
|
|
|
|
Part *_parts;
|
|
bool _active;
|
|
bool _scanning;
|
|
int _id;
|
|
byte _priority;
|
|
byte _volume;
|
|
int8 _pan;
|
|
int8 _transpose;
|
|
int8 _detune;
|
|
byte _vol_eff;
|
|
|
|
uint _track_index;
|
|
uint _loop_to_beat;
|
|
uint _loop_from_beat;
|
|
uint _loop_counter;
|
|
uint _loop_to_tick;
|
|
uint _loop_from_tick;
|
|
byte _speed;
|
|
bool _abort;
|
|
|
|
// 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;
|
|
|
|
HookDatas _hook;
|
|
ParameterFader _parameterFaders[4];
|
|
|
|
bool _isMT32;
|
|
bool _isGM;
|
|
|
|
protected:
|
|
// Player part
|
|
void hook_clear();
|
|
void uninit_parts();
|
|
byte *parse_midi(byte *s);
|
|
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);
|
|
void turn_off_pedals();
|
|
int query_part_param(int param, byte chan);
|
|
void turn_off_parts();
|
|
void play_active_notes();
|
|
|
|
void transitionParameters();
|
|
|
|
static void decode_sysex_bytes(const byte *src, byte *dst, int len);
|
|
|
|
// Sequencer part
|
|
int start_seq_sound(int sound, bool reset_vars = true);
|
|
int query_param(int param);
|
|
|
|
public:
|
|
IMuseInternal *_se;
|
|
uint _vol_chan;
|
|
|
|
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() const { return _detune; }
|
|
byte getEffectiveVolume() const { return _vol_eff; }
|
|
int getID() const { return _id; }
|
|
MidiDriver *getMidiDriver() const { return _midi; }
|
|
int getParam(int param, byte chan);
|
|
int8 getPan() const { return _pan; }
|
|
Part * getPart(uint8 part);
|
|
byte getPriority() const { return _priority; }
|
|
uint getTicksPerBeat() const { return TICKS_PER_BEAT; }
|
|
int8 getTranspose() const { return _transpose; }
|
|
byte getVolume() const { return _volume; }
|
|
bool isActive() const { return _active; }
|
|
bool isFadingOut() const;
|
|
bool isGM() const { return _isGM; }
|
|
bool isMT32() const { 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, bool passThrough);
|
|
int getMusicTimer() const;
|
|
|
|
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; }
|
|
};
|
|
|
|
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
|
|
|
|
// MidiChannel interface
|
|
// (We don't currently derive from MidiChannel,
|
|
// but if we ever do, this will make it easy.)
|
|
void noteOff(byte note);
|
|
void noteOn(byte note, byte velocity);
|
|
void programChange(byte value);
|
|
void pitchBend(int16 value);
|
|
void modulationWheel(byte value);
|
|
void volume(byte value);
|
|
void pitchBendFactor(byte value);
|
|
void sustain(bool value);
|
|
void effectLevel(byte value);
|
|
void chorusLevel(byte value);
|
|
void allNotesOff();
|
|
|
|
void set_param(byte param, int value) { }
|
|
void init();
|
|
void setup(Player *player);
|
|
void uninit();
|
|
void off();
|
|
void set_instrument(uint b);
|
|
void set_instrument(byte *data);
|
|
void load_global_instrument(byte b);
|
|
|
|
void set_transpose(int8 transpose);
|
|
void set_detune(int8 detune);
|
|
void set_pri(int8 pri);
|
|
void set_pan(int8 pan);
|
|
|
|
void set_onoff(bool on);
|
|
void fix_after_load();
|
|
|
|
void sendAll();
|
|
void sendPitchBend();
|
|
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 {
|
|
friend class Player;
|
|
|
|
protected:
|
|
bool _old_adlib_instruments;
|
|
bool _enable_multi_midi;
|
|
bool _native_mt32;
|
|
MidiDriver *_midi_adlib;
|
|
MidiDriver *_midi_native;
|
|
|
|
byte **_base_sounds;
|
|
|
|
SoundMixer *_mixer;
|
|
|
|
protected:
|
|
bool _paused;
|
|
bool _initialized;
|
|
|
|
int _tempoFactor;
|
|
|
|
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?
|
|
bool _direct_passthrough; // Pass data direct to MidiDriver (no interactivity)
|
|
|
|
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];
|
|
|
|
Instrument _global_adlib_instruments[32];
|
|
CommandQueue _cmd_queue[64];
|
|
DeferredCommand _deferredCommands[4];
|
|
|
|
protected:
|
|
byte *findStartOfSound(int sound);
|
|
bool isMT32(int sound);
|
|
bool isGM(int sound);
|
|
int get_queue_sound_status(int sound) const;
|
|
void handle_marker(uint id, byte data);
|
|
int get_channel_volume(uint a);
|
|
void initMidiDriver(MidiDriver *midi);
|
|
void initMT32(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, int e, int f, int g, int h);
|
|
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);
|
|
Player *findActivePlayer(int id);
|
|
|
|
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(ScummEngine *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:
|
|
IMuseInternal();
|
|
|
|
int initialize(OSystem *syst, SoundMixer *mixer, MidiDriver *midi);
|
|
void reallocateMidiChannels(MidiDriver *midi);
|
|
void setGlobalAdlibInstrument(byte slot, byte *data);
|
|
void copyGlobalAdlibInstrument(byte slot, Instrument *dest);
|
|
bool isNativeMT32() { return _native_mt32; }
|
|
|
|
// IMuse interface
|
|
|
|
void on_timer(MidiDriver *midi);
|
|
void pause(bool paused);
|
|
int terminate1();
|
|
int terminate2();
|
|
int save_or_load(Serializer *ser, ScummEngine *scumm);
|
|
int set_music_volume(uint vol);
|
|
int setMasterVolume(uint vol);
|
|
bool startSound(int sound);
|
|
int stopSound(int sound);
|
|
int stopAllSounds();
|
|
int getSoundStatus(int sound, bool ignoreFadeouts = true) const;
|
|
int getMusicTimer() const;
|
|
int32 doCommand (int a, int b, int c, int d, int e, int f, int g, int h);
|
|
int32 doCommand (int numargs, int args[]);
|
|
int clear_queue();
|
|
void setBase(byte **base);
|
|
uint32 property(int prop, uint32 value);
|
|
|
|
static IMuseInternal *create(OSystem *syst, SoundMixer *mixer, MidiDriver *midi);
|
|
};
|
|
|
|
} // End of namespace Scumm
|
|
|
|
#endif
|