1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
|
/* 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 MM_SHARED_XEEN_SOUND_DRIVER_H
#define MM_SHARED_XEEN_SOUND_DRIVER_H
#include "audio/fmopl.h"
#include "audio/mixer.h"
#include "common/array.h"
#include "common/mutex.h"
#include "common/queue.h"
#include "common/stack.h"
#include "mm/shared/xeen/file.h"
#define CHANNEL_COUNT 9
// interrupt is every ~13.736ms, which is ~72.8 times a second
#define CALLBACKS_PER_SECOND 72.8f
namespace OPL {
class OPL;
}
namespace MM {
namespace Shared {
namespace Xeen {
enum MusicCommand {
STOP_SONG = 0, RESTART_SONG = 1, SET_VOLUME = 0x100, GET_STATUS = 0xFFE0
};
class SoundDriver;
typedef bool (SoundDriver:: *CommandFn)(const byte *&srcP, byte param);
/**
* Base class for sound drivers
*/
class SoundDriver {
protected:
struct Subroutine {
const byte *_returnP;
const byte *_jumpP;
Subroutine() : _returnP(nullptr), _jumpP(nullptr) {
}
Subroutine(const byte *returnP, const byte *endP) :
_returnP(returnP), _jumpP(endP) {
}
};
struct Channel {
bool _changeFrequency;
int _freqCtrChange;
int _freqChange;
int _freqCtr;
byte _volume;
byte _totalLevel;
bool _isFx;
uint _frequency;
Channel() : _changeFrequency(false), _freqCtr(0), _freqCtrChange(0),
_freqChange(0), _volume(0), _totalLevel(0), _frequency(0), _isFx(false) {
}
};
enum StreamType {
stMUSIC,
stFX,
stLAST
};
class Stream {
public:
Stream() {
}
Stream(const CommandFn *commands) : _playing(false), _countdownTimer(0), _dataPtr(nullptr), _startPtr(nullptr), _commands(commands) {
}
bool _playing;
int _countdownTimer;
const byte *_dataPtr;
const byte *_startPtr;
const CommandFn *_commands;
};
private:
static const CommandFn FX_COMMANDS[16];
static const CommandFn MUSIC_COMMANDS[16];
private:
Common::Stack<Subroutine> _musSubroutines, _fxSubroutines;
uint _frameCtr;
private:
/**
* Executes the next command
* @param srcP Command data pointer
* @returns If true, execution of commands for the current timer call stops
*/
bool command(const byte *&srcP);
Stream *tickStream();
protected:
Common::Array<Channel> _channels;
Stream _streams[stLAST];
protected:
/**
* Executes a series of commands until instructed to stop
*/
void execute();
// Music commands (with some also used by FX)
virtual bool musCallSubroutine(const byte *&srcP, byte param);
virtual bool musSetCountdown(const byte *&srcP, byte param);
virtual bool musSetInstrument(const byte *&srcP, byte param) = 0;
virtual bool cmdNoOperation(const byte *&srcP, byte param);
virtual bool musSetPitchWheel(const byte *&srcP, byte param) = 0;
virtual bool musSkipWord(const byte *&srcP, byte param);
virtual bool musSetPanning(const byte *&srcP, byte param) = 0;
virtual bool musFade(const byte *&srcP, byte param) = 0;
virtual bool musStartNote(const byte *&srcP, byte param) = 0;
virtual bool musSetVolume(const byte *&srcP, byte param) = 0;
virtual bool musInjectMidi(const byte *&srcP, byte param) = 0;
virtual bool musPlayInstrument(const byte *&srcP, byte param) = 0;
virtual bool cmdFreezeFrequency(const byte *&srcP, byte param) = 0;
virtual bool cmdChangeFrequency(const byte *&srcP, byte param) = 0;
virtual bool musEndSubroutine(const byte *&srcP, byte param);
// FX commands
virtual bool fxCallSubroutine(const byte *&srcP, byte param);
virtual bool fxSetCountdown(const byte *&srcP, byte param);
virtual bool fxSetInstrument(const byte *&srcP, byte param) = 0;
virtual bool fxSetVolume(const byte *&srcP, byte param) = 0;
virtual bool fxMidiReset(const byte *&srcP, byte param) = 0;
virtual bool fxMidiDword(const byte *&srcP, byte param) = 0;
virtual bool fxSetPanning(const byte *&srcP, byte param) = 0;
virtual bool fxChannelOff(const byte *&srcP, byte param) = 0;
virtual bool fxFade(const byte *&srcP, byte param) = 0;
virtual bool fxStartNote(const byte *&srcP, byte param) = 0;
virtual bool fxInjectMidi(const byte *&srcP, byte param) = 0;
virtual bool fxPlayInstrument(const byte *&srcP, byte param) = 0;
virtual bool fxEndSubroutine(const byte *&srcP, byte param);
/**
* Post-processing done when a pause countdown starts or is in progress
*/
virtual void pausePostProcess() = 0;
/**
* Does a reset of any sound effect
*/
virtual void resetFX() = 0;
public:
/**
* Constructor
*/
SoundDriver();
/**
* Destructor
*/
virtual ~SoundDriver();
/**
* Starts a special effect playing
*/
virtual void playFX(uint effectId, const byte *data);
/**
* Stop any playing FX
*/
void stopFX(bool force = false);
/**
* Plays a song
*/
virtual void playSong(const byte *data);
/**
* Executes special music command
*/
virtual int songCommand(uint commandId, byte musicVolume = 0, byte sfxVolume = 0);
/**
* Returns whether music is currently playing
*/
bool isPlaying() const {
return _streams[stMUSIC]._playing;
}
/**
* Sends SysEx message
*/
virtual void sysExMessage(const byte *&data) = 0;
};
} // namespace Xeen
} // namespace Shared
} // namespace MM
#endif
|