mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-19 08:25:35 +00:00
3dd5568cab
This change improves the accuracy of the timing of the AdLib SFX of Elvira 2 and Waxworks. The frequency of the SFX script timer is now synchronized with the callback timer of the AdLib driver, which makes the timing of the OPL register writes match that of the original interpreter.
223 lines
7.5 KiB
C++
223 lines
7.5 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#ifndef AGOS_SFXPARSER_ACCOLADE_H
|
|
#define AGOS_SFXPARSER_ACCOLADE_H
|
|
|
|
#include "agos/drivers/accolade/adlib.h"
|
|
#include "agos/drivers/accolade/mt32.h"
|
|
|
|
#include "common/mutex.h"
|
|
#include "common/stream.h"
|
|
|
|
namespace AGOS {
|
|
|
|
class SfxParser_Accolade {
|
|
public:
|
|
// Size in bytes of MT-32 instrument data in the SFX data.
|
|
static const byte INSTRUMENT_SIZE_MT32 = 0xF9;
|
|
// Number of script ticks per second.
|
|
static const uint16 SCRIPT_TIMER_FREQUENCY = 292;
|
|
// Number of microseconds per script tick.
|
|
static const uint16 SCRIPT_TIMER_RATE = 1000000 / SCRIPT_TIMER_FREQUENCY;
|
|
|
|
protected:
|
|
// Size in bytes of AdLib instrument data in the SFX data.
|
|
static const byte INSTRUMENT_SIZE_ADLIB = 0x09;
|
|
// Maximum number of words in an SFX script.
|
|
static const byte MAX_SCRIPT_SIZE = 0x30;
|
|
// Maximum number of simultaneous sources for OPL2.
|
|
static const byte OPL2_NUM_SOURCES = 2;
|
|
// Maximum number of simultaneous sources for OPL3.
|
|
static const byte OPL3_NUM_SOURCES = 4;
|
|
|
|
// Data for a single SFX. Taken from the game's SFX bank.
|
|
struct SfxData {
|
|
// The instrument data for the used sound device (OPL or MT-32).
|
|
byte instrumentDefinition[INSTRUMENT_SIZE_MT32];
|
|
// The SFX script.
|
|
int16 scriptData[MAX_SCRIPT_SIZE];
|
|
// The size in words of the SFX script.
|
|
int scriptSize;
|
|
};
|
|
|
|
// State data a SFX playback slot.
|
|
struct SfxSlot {
|
|
SfxSlot();
|
|
|
|
// The data of the SFX currently played by this slot.
|
|
SfxData *sfxData;
|
|
|
|
// True if this slot has been allocated to playing a SFX.
|
|
bool allocated;
|
|
// True if SFX playback is active.
|
|
bool active;
|
|
// The source used to send data to the MIDI driver.
|
|
int8 source;
|
|
// Current position in the SFX script.
|
|
byte scriptPos;
|
|
|
|
// Current playback time in microseconds.
|
|
uint32 playTime;
|
|
// The timestamp of the last processed script tick.
|
|
uint32 lastEventTime;
|
|
// The last MIDI note that was sent as a note on event.
|
|
int16 lastPlayedNote;
|
|
// The current MIDI note (upper byte) and note fraction (1/256th notes;
|
|
// lower byte) value.
|
|
uint16 currentNoteFraction;
|
|
// True if the allocated channel on the MIDI device has been changed to
|
|
// the SFX instrument.
|
|
bool programChanged;
|
|
|
|
// Delta to the note fraction. This is added to/subtracted from the
|
|
// note fraction every script tick.
|
|
int16 noteFractionDelta;
|
|
// The vibrato time. The number of script ticks it takes for the note
|
|
// difference to go from lowest to highest (or the other way around).
|
|
int16 vibratoTime;
|
|
// The number of script ticks that have passed since the vibrato has
|
|
// started.
|
|
int16 vibratoCounter;
|
|
// Vibrato delta to the note fraction. This is added to/subtracted
|
|
// from the note fraction every script tick.
|
|
int16 vibratoDelta;
|
|
// The number of ticks that remain before the next script event is
|
|
// processed.
|
|
int16 waitCounter;
|
|
// The script position at which the current loop has started.
|
|
byte loopStart;
|
|
// The number of times the looped section will be repeated (-1 for
|
|
// infinite loop).
|
|
int16 loopCounter;
|
|
|
|
// Completely clears the SFX slot data.
|
|
void clear();
|
|
// Resets the SFX slot data as needed by the reset opcode.
|
|
void reset();
|
|
// True if the current position is at the end of the script.
|
|
bool atEndOfScript();
|
|
// Reads the next script word. Specify the opCode flag to return a
|
|
// valid opcode.
|
|
int16 readScript(bool opCode);
|
|
};
|
|
|
|
public:
|
|
SfxParser_Accolade();
|
|
virtual ~SfxParser_Accolade();
|
|
|
|
// Loads the specified sound effects bank (FXB file).
|
|
void load(Common::SeekableReadStream *in, int32 size);
|
|
|
|
// Sets the MIDI driver that should be used to output the SFX.
|
|
virtual void setMidiDriver(MidiDriver_Multisource *driver) = 0;
|
|
// Sets the number of microseconds between timer callbacks.
|
|
void setTimerRate(uint32 rate);
|
|
|
|
// Starts playback of the specified sound effect.
|
|
void play(uint8 sfxNumber);
|
|
// Stops all active SFX.
|
|
void stopAll();
|
|
// Pauses or unpauses all active SFX.
|
|
void pauseAll(bool paused);
|
|
|
|
void onTimer();
|
|
static void timerCallback(void *data);
|
|
|
|
protected:
|
|
// Stops the sound effect playing in the specified slot.
|
|
void stop(SfxSlot *sfxSlot);
|
|
// Processes the specified opcode for the specified slot.
|
|
void processOpCode(SfxSlot *sfxSlot, byte opCode);
|
|
|
|
// Returns the number of sources available for SFX playback.
|
|
virtual byte getNumberOfSfxSources() = 0;
|
|
// Reads the SFX instrument data into the specified SfxData from the
|
|
// specified SFX bank data. This is positioned at the start of the data of
|
|
// a sound effect in the bank; when the function returns is should be
|
|
// positioned right after all instrument data for the sound effect.
|
|
virtual void readInstrument(SfxData *sfxData, Common::SeekableReadStream *in) = 0;
|
|
|
|
// Loads the SFX instrument for the specified slot into the channel
|
|
// allocated to the sound effect. Returns true if the channel needs to be
|
|
// changed to the new instrument when the driver is ready.
|
|
virtual bool loadInstrument(SfxSlot *sfxSlot) = 0;
|
|
// Changes the channel allocated to the sound effect to the SFX instrument.
|
|
virtual void changeInstrument(SfxSlot *sfxSlot) { };
|
|
// Starts a note at the current note / note fraction for the slot.
|
|
virtual void noteOn(SfxSlot *sfxSlot);
|
|
// Stops the current note for the slot.
|
|
virtual void noteOff(SfxSlot *sfxSlot);
|
|
// Updates the note / note fraction for the slot.
|
|
virtual void updateNote(SfxSlot *sfxSlot) { };
|
|
|
|
Common::Mutex _mutex;
|
|
|
|
MidiDriver_Multisource *_driver;
|
|
uint32 _timerRate;
|
|
|
|
// Array of SFX data loaded from the SFX bank.
|
|
SfxData *_sfxData;
|
|
// The number of SFX data loaded.
|
|
uint16 _numSfx;
|
|
// The slots available for SFX playback.
|
|
SfxSlot _sfxSlots[4];
|
|
// The slot numbers allocated to the available SFX sources. -1 if no slot
|
|
// is using the source.
|
|
int8 _sourceAllocations[4];
|
|
|
|
// True if SFX playback is paused.
|
|
bool _paused;
|
|
};
|
|
|
|
class SfxParser_Accolade_AdLib : public SfxParser_Accolade {
|
|
public:
|
|
SfxParser_Accolade_AdLib() : _adLibDriver(nullptr) { }
|
|
|
|
protected:
|
|
void setMidiDriver(MidiDriver_Multisource *driver) override;
|
|
byte getNumberOfSfxSources() override;
|
|
void readInstrument(SfxData *sfxData, Common::SeekableReadStream *in) override;
|
|
bool loadInstrument(SfxSlot *sfxSlot) override;
|
|
void noteOn(SfxSlot *sfxSlot) override;
|
|
void updateNote(SfxSlot *sfxSlot) override;
|
|
|
|
MidiDriver_Accolade_AdLib *_adLibDriver;
|
|
};
|
|
|
|
class SfxParser_Accolade_MT32 : public SfxParser_Accolade {
|
|
public:
|
|
SfxParser_Accolade_MT32() : _mt32Driver(nullptr) { }
|
|
|
|
protected:
|
|
void setMidiDriver(MidiDriver_Multisource *driver) override;
|
|
byte getNumberOfSfxSources() override;
|
|
void readInstrument(SfxData *sfxData, Common::SeekableReadStream *in) override;
|
|
bool loadInstrument(SfxSlot *sfxSlot) override;
|
|
void changeInstrument(SfxSlot *sfxSlot) override;
|
|
|
|
MidiDriver_Accolade_MT32 *_mt32Driver;
|
|
};
|
|
|
|
} // End of namespace AGOS
|
|
|
|
#endif
|