aboutsummaryrefslogtreecommitdiff
path: root/engines/scumm/imuse/imuse_internal.h
diff options
context:
space:
mode:
Diffstat (limited to 'engines/scumm/imuse/imuse_internal.h')
-rw-r--r--engines/scumm/imuse/imuse_internal.h472
1 files changed, 472 insertions, 0 deletions
diff --git a/engines/scumm/imuse/imuse_internal.h b/engines/scumm/imuse/imuse_internal.h
new file mode 100644
index 0000000000..3640cafa64
--- /dev/null
+++ b/engines/scumm/imuse/imuse_internal.h
@@ -0,0 +1,472 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ */
+
+#ifndef DEFINED_IMUSE_INTERNAL
+#define DEFINED_IMUSE_INTERNAL
+
+#include "common/scummsys.h"
+#include "scumm/imuse/instrument.h"
+#include "scumm/saveload.h"
+#include "sound/mididrv.h"
+
+class MidiParser;
+class OSystem;
+
+namespace Scumm {
+
+// Unremark this statement to activate some of
+// the most common iMuse diagnostic messages.
+// #define IMUSE_DEBUG
+
+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 _isMIDI;
+
+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 isMIDI() const { return _isMIDI; }
+ 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);
+ void saveLoadWithSerializer(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 : public Serializable {
+ IMuseInternal *_se;
+ 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();
+
+ void saveLoadWithSerializer(Serializer *ser);
+};
+
+// 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;
+ friend struct Part;
+
+protected:
+ bool _native_mt32;
+ bool _enable_gs;
+ bool _sc55;
+ MidiDriver *_midi_adlib;
+ MidiDriver *_midi_native;
+
+ byte **_base_sounds;
+
+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 isMIDI(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 initGM(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 void midiTimerCallback(void *data);
+
+public:
+ IMuseInternal();
+
+ int initialize(OSystem *syst, MidiDriver *nativeMidiDriver, MidiDriver *adlibMidiDriver);
+ 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 setMusicVolume(uint vol);
+ int setImuseMasterVolume(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, MidiDriver *nativeMidiDriver, MidiDriver *adlibMidiDriver);
+};
+
+} // End of namespace Scumm
+
+#endif