scummvm/engines/xeen/sound_driver.cpp

658 lines
17 KiB
C++
Raw Normal View History

2016-09-12 20:10:37 -04:00
/* 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 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.
*
*/
#include "common/md5.h"
#include "common/config-manager.h"
#include "xeen/sound_driver.h"
2016-09-12 20:10:37 -04:00
#include "xeen/xeen.h"
#include "xeen/files.h"
namespace Xeen {
2016-09-14 20:53:35 -04:00
#define CALLBACKS_PER_SECOND 73
2016-09-12 20:10:37 -04:00
2016-09-14 20:53:35 -04:00
/*------------------------------------------------------------------------*/
SoundDriver::SoundDriver() : _musicPlaying(false), _fxPlaying(false),
2016-09-14 20:53:35 -04:00
_musCountdownTimer(0), _fxCountdownTimer(0), _musDataPtr(nullptr),
_fxDataPtr(nullptr), _fxStartPtr(nullptr), _musStartPtr(nullptr),
_exclude7(false), _frameCtr(0) {
_channels.resize(CHANNEL_COUNT);
2016-09-12 20:10:37 -04:00
}
SoundDriver::~SoundDriver() {
_musicPlaying = _fxPlaying = false;
_musCountdownTimer = _fxCountdownTimer = 0;
}
void SoundDriver::execute() {
2016-09-14 20:53:35 -04:00
bool isFX = false;
const byte *srcP = nullptr;
const byte *startP = nullptr;
// Single iteration loop to avoid use of GOTO
do {
if (_musicPlaying) {
startP = _musStartPtr;
srcP = _musDataPtr;
isFX = false;
if (_musCountdownTimer == 0 || --_musCountdownTimer == 0)
break;
}
2016-09-14 20:53:35 -04:00
if (_fxPlaying) {
startP = _fxStartPtr;
srcP = _fxDataPtr;
isFX = true;
if (_fxCountdownTimer == 0 || --_fxCountdownTimer == 0)
break;
}
2016-09-14 20:53:35 -04:00
pausePostProcess();
2016-09-14 20:53:35 -04:00
return;
} while (0);
2016-09-14 20:53:35 -04:00
++_frameCtr;
debugC(3, kDebugSound, "\nSoundDriver frame - #%x", _frameCtr);
// Main loop
2016-09-14 20:53:35 -04:00
bool breakFlag = false;
while (!breakFlag) {
debugCN(3, kDebugSound, "MUSCODE %.4x - %.2x ", (uint)(srcP - startP), (uint)*srcP);
2016-09-14 20:53:35 -04:00
byte nextByte = *srcP++;
int cmd = (nextByte >> 4) & 15;
int param = (nextByte & 15);
CommandFn fn = isFX ? FX_COMMANDS[cmd] : MUSIC_COMMANDS[cmd];
breakFlag = (this->*fn)(srcP, param);
}
2016-09-12 20:10:37 -04:00
}
bool SoundDriver::musCallSubroutine(const byte *&srcP, byte param) {
debugC(3, kDebugSound, "musCallSubroutine");
2016-09-14 20:53:35 -04:00
if (_musSubroutines.size() < 16) {
const byte *returnP = srcP + 2;
srcP = _musStartPtr + READ_LE_UINT16(srcP);
_musSubroutines.push(Subroutine(returnP, srcP));
}
return false;
}
bool SoundDriver::musSetCountdown(const byte *&srcP, byte param) {
2016-09-14 20:53:35 -04:00
// Set the countdown timer
if (!param)
param = *srcP++;
2016-09-14 20:53:35 -04:00
_musCountdownTimer = param;
_musDataPtr = srcP;
debugC(3, kDebugSound, "musSetCountdown %d", param);
2016-09-12 20:10:37 -04:00
// Do paused handling and break out of processing loop
pausePostProcess();
2016-09-14 20:53:35 -04:00
return true;
}
2016-09-12 20:10:37 -04:00
bool SoundDriver::cmdNoOperation(const byte *&srcP, byte param) {
debugC(3, kDebugSound, "cmdNoOperation");
2016-09-14 20:53:35 -04:00
return false;
2016-09-12 20:10:37 -04:00
}
bool SoundDriver::musSkipWord(const byte *&srcP, byte param) {
debugC(3, kDebugSound, "musSkipWord");
2016-09-14 20:53:35 -04:00
srcP += 2;
return false;
2016-09-12 20:10:37 -04:00
}
bool SoundDriver::cmdFreezeFrequency(const byte *&srcP, byte param) {
2016-09-16 23:41:19 -04:00
debugC(3, kDebugSound, "cmdFreezeFrequency %d", param);
_channels[param]._changeFrequency = false;
2016-09-14 20:53:35 -04:00
return false;
}
bool SoundDriver::cmdChangeFrequency(const byte *&srcP, byte param) {
debugC(3, kDebugSound, "cmdChangeFrequency %d", param);
if (param != 7 || !_exclude7) {
_channels[param]._freqCtrChange = (int8)*srcP++;
_channels[param]._freqCtr = 0xFF;
_channels[param]._changeFrequency = true;
_channels[param]._freqChange = (int16)READ_BE_UINT16(srcP);
2016-09-14 20:53:35 -04:00
srcP += 2;
} else {
srcP += 3;
}
2016-09-12 20:10:37 -04:00
2017-11-11 11:56:56 -05:00
return false;
2016-09-14 20:53:35 -04:00
}
bool SoundDriver::musEndSubroutine(const byte *&srcP, byte param) {
debugC(3, kDebugSound, "musEndSubroutine %d", param);
2016-09-14 20:53:35 -04:00
if (param != 15) {
// Music has ended, so flag it stopped
_musicPlaying = false;
2016-09-14 20:53:35 -04:00
return true;
2016-09-12 20:10:37 -04:00
}
2016-09-14 20:53:35 -04:00
// Returning from subroutine, or looping back to start of music
2016-09-14 20:53:35 -04:00
srcP = _musSubroutines.empty() ? _musStartPtr : _musSubroutines.pop()._returnP;
return false;
2016-09-12 20:10:37 -04:00
}
bool SoundDriver::fxCallSubroutine(const byte *&srcP, byte param) {
debugC(3, kDebugSound, "fxCallSubroutine");
2016-09-14 20:53:35 -04:00
if (_fxSubroutines.size() < 16) {
const byte *startP = srcP + 2;
srcP = _musStartPtr + READ_LE_UINT16(srcP);
2016-09-12 22:34:59 -04:00
2016-09-14 20:53:35 -04:00
_fxSubroutines.push(Subroutine(startP, srcP));
2016-09-12 22:34:59 -04:00
}
2016-09-14 20:53:35 -04:00
return false;
}
2016-09-12 22:34:59 -04:00
bool SoundDriver::fxSetCountdown(const byte *&srcP, byte param) {
2016-09-14 20:53:35 -04:00
// Set the countdown timer
if (!param)
param = *srcP++;
2016-09-14 20:53:35 -04:00
_fxCountdownTimer = param;
2016-09-17 16:32:04 -04:00
_fxDataPtr = srcP;
debugC(3, kDebugSound, "fxSetCountdown %d", param);
2016-09-14 20:53:35 -04:00
// Do paused handling and break out of processing loop
pausePostProcess();
2016-09-14 20:53:35 -04:00
return true;
}
2016-09-12 22:34:59 -04:00
bool SoundDriver::fxEndSubroutine(const byte *&srcP, byte param) {
debugC(3, kDebugSound, "fxEndSubroutine %d", param);
2016-09-14 20:53:35 -04:00
if (param != 15) {
// FX has ended, so flag it stopped
_fxPlaying = false;
2016-09-14 20:53:35 -04:00
return true;
2016-09-12 22:34:59 -04:00
}
2016-09-14 20:53:35 -04:00
srcP = _fxSubroutines.empty() ? _fxStartPtr : _fxSubroutines.pop()._returnP;
return false;
2016-09-12 20:10:37 -04:00
}
void SoundDriver::playFX(uint effectId, const byte *data) {
if (!_fxPlaying || effectId < 7 || effectId >= 11) {
2016-09-14 20:53:35 -04:00
_fxDataPtr = _fxStartPtr = data;
_fxCountdownTimer = 0;
_channels[7]._changeFrequency = _channels[8]._changeFrequency = false;
resetFX();
_fxPlaying = true;
2016-09-14 20:53:35 -04:00
}
2016-09-17 16:32:04 -04:00
debugC(1, kDebugSound, "Starting FX %d", effectId);
2016-09-14 20:53:35 -04:00
}
void SoundDriver::stopFX() {
resetFX();
_fxPlaying = false;
_fxStartPtr = _fxDataPtr = nullptr;
}
void SoundDriver::playSong(const byte *data) {
_musDataPtr = _musStartPtr = data;
_musSubroutines.clear();
_musCountdownTimer = 0;
_musicPlaying = true;
debugC(1, kDebugSound, "Starting song");
}
int SoundDriver::songCommand(uint commandId, byte volume) {
if (commandId == STOP_SONG) {
_musicPlaying = false;
} else if (commandId == RESTART_SONG) {
_musicPlaying = true;
_musDataPtr = nullptr;
_musSubroutines.clear();
}
return 0;
}
2016-09-14 20:53:35 -04:00
const CommandFn SoundDriver::MUSIC_COMMANDS[16] = {
&SoundDriver::musCallSubroutine, &SoundDriver::musSetCountdown,
&SoundDriver::musSetInstrument, &SoundDriver::cmdNoOperation,
&SoundDriver::musSetPitchWheel, &SoundDriver::musSkipWord,
&SoundDriver::musSetPanning, &SoundDriver::cmdNoOperation,
&SoundDriver::musFade, &SoundDriver::musStartNote,
&SoundDriver::musSetVolume, &SoundDriver::musInjectMidi,
&SoundDriver::musPlayInstrument, &SoundDriver::cmdFreezeFrequency,
&SoundDriver::cmdChangeFrequency, &SoundDriver::musEndSubroutine
2016-09-14 20:53:35 -04:00
};
const CommandFn SoundDriver::FX_COMMANDS[16] = {
&SoundDriver::fxCallSubroutine, &SoundDriver::fxSetCountdown,
&SoundDriver::fxSetInstrument, &SoundDriver::fxSetVolume,
&SoundDriver::fxMidiReset, &SoundDriver::fxMidiDword,
&SoundDriver::fxSetPanning, &SoundDriver::fxChannelOff,
&SoundDriver::fxFade, &SoundDriver::fxStartNote,
&SoundDriver::cmdNoOperation, &SoundDriver::fxInjectMidi,
&SoundDriver::fxPlayInstrument, &SoundDriver::cmdFreezeFrequency,
&SoundDriver::cmdChangeFrequency, &SoundDriver::fxEndSubroutine
2016-09-14 20:53:35 -04:00
};
/*------------------------------------------------------------------------*/
AdlibSoundDriver::AdlibSoundDriver() : _field180(0), _field181(0), _field182(0),
_volume(127) {
2016-09-14 20:53:35 -04:00
Common::fill(&_musInstrumentPtrs[0], &_musInstrumentPtrs[16], (const byte *)nullptr);
Common::fill(&_fxInstrumentPtrs[0], &_fxInstrumentPtrs[16], (const byte *)nullptr);
_opl = OPL::Config::create();
_opl->init();
_opl->start(new Common::Functor0Mem<void, AdlibSoundDriver>(this, &AdlibSoundDriver::onTimer), CALLBACKS_PER_SECOND);
2016-09-14 20:53:35 -04:00
initialize();
}
AdlibSoundDriver::~AdlibSoundDriver() {
2016-09-14 20:53:35 -04:00
_opl->stop();
delete _opl;
}
void AdlibSoundDriver::onTimer() {
2016-09-14 20:53:35 -04:00
Common::StackLock slock(_driverMutex);
execute();
flush();
}
void AdlibSoundDriver::initialize() {
2016-09-14 20:53:35 -04:00
write(1, 0x20);
write(8, 0);
write(0xBD, 0);
resetFrequencies();
AdlibSoundDriver::resetFX();
2016-09-14 20:53:35 -04:00
}
void AdlibSoundDriver::playFX(uint effectId, const byte *data) {
Common::StackLock slock(_driverMutex);
SoundDriver::playFX(effectId, data);
}
void AdlibSoundDriver::playSong(const byte *data) {
Common::StackLock slock(_driverMutex);
SoundDriver::playSong(data);
_field180 = 0;
resetFrequencies();
}
int AdlibSoundDriver::songCommand(uint commandId, byte volume) {
Common::StackLock slock(_driverMutex);
SoundDriver::songCommand(commandId, volume);
if (commandId == STOP_SONG) {
_field180 = 0;
resetFrequencies();
} else if (commandId == RESTART_SONG) {
_field180 = 0;
_musicPlaying = true;
} else if (commandId < 0x100) {
if (_musicPlaying) {
_field180 = commandId;
_field182 = 63;
}
} else if (commandId == SET_VOLUME) {
_volume = volume;
} else if (commandId == GET_STATUS) {
return _field180;
}
return 0;
}
void AdlibSoundDriver::write(int reg, int val) {
2016-09-14 20:53:35 -04:00
_queue.push(RegisterValue(reg, val));
debugC(9, kDebugSound, "%.2x %.2x", reg, val);
2016-09-14 20:53:35 -04:00
}
void AdlibSoundDriver::flush() {
2016-09-14 20:53:35 -04:00
Common::StackLock slock(_driverMutex);
while (!_queue.empty()) {
RegisterValue v = _queue.pop();
_opl->writeReg(v._regNum, v._value);
}
}
void AdlibSoundDriver::pausePostProcess() {
if (_field180 && ((_field181 += _field180) < 0)) {
if (--_field182 < 0) {
_musicPlaying = false;
_field180 = 0;
resetFrequencies();
} else {
for (int channelNum = 6; channelNum >= 0; --channelNum) {
if (_channels[channelNum]._volume < 63)
setOutputLevel(channelNum, ++_channels[channelNum]._volume);
}
}
}
2017-11-17 19:23:51 -05:00
for (int channelNum = 8; channelNum > (_exclude7 ? 7 : 6); --channelNum) {
Channel &chan = _channels[channelNum];
if (!chan._changeFrequency || (chan._freqCtr += chan._freqCtrChange) >= 0)
continue;
uint freq = chan._frequency & 0x3FF;
uint val = chan._frequency >> 8;
byte val1 = val & 0x20;
byte val2 = val & 0x1C;
freq += chan._freqChange;
if (chan._freqChange < 0) {
if (freq <= 388) {
freq <<= 1;
if (!(freq & 0x3FF))
--freq;
}
val2 = (val2 - 4) & 0x1C;
} else {
if (freq >= 734) {
freq >>= 1;
if (!(freq & 0x3FF))
++freq;
}
val2 = (val2 + 4) & 0x1C;
}
freq &= 0x3FF;
freq |= (val2 << 8);
freq |= val1;
chan._frequency = freq;
setFrequency(channelNum, freq);
}
}
void AdlibSoundDriver::resetFX() {
if (!_exclude7) {
_channels[7]._frequency = 0;
setFrequency(7, 0);
_channels[7]._volume = 63;
setOutputLevel(7, 63);
}
_channels[8]._frequency = 0;
setFrequency(8, 0);
_channels[8]._volume = 63;
setOutputLevel(8, 63);
}
void AdlibSoundDriver::resetFrequencies() {
for (int opNum = 6; opNum >= 0; --opNum) {
_channels[opNum]._frequency = 0;
setFrequency(opNum, 0);
}
}
void AdlibSoundDriver::setFrequency(byte operatorNum, uint frequency) {
write(0xA0 + operatorNum, frequency & 0xff);
write(0xB0 + operatorNum, (frequency >> 8));
}
uint AdlibSoundDriver::calcFrequency(byte note) {
2016-09-14 20:53:35 -04:00
return WAVEFORMS[note & 0x1F] + ((note & 0xE0) << 5);
2016-09-12 22:34:59 -04:00
}
void AdlibSoundDriver::setOutputLevel(byte channelNum, uint level) {
2016-09-14 20:53:35 -04:00
write(0x40 + OPERATOR2_INDEXES[channelNum], level |
(_channels[channelNum]._scalingValue & 0xC0));
2016-09-12 22:34:59 -04:00
}
void AdlibSoundDriver::playInstrument(byte channelNum, const byte *data) {
2016-09-14 20:53:35 -04:00
byte op1 = OPERATOR1_INDEXES[channelNum];
byte op2 = OPERATOR2_INDEXES[channelNum];
debugC(2, kDebugSound, "---START-playInstrument - %d", channelNum);
2016-09-14 20:53:35 -04:00
write(0x20 + op1, *data++);
write(0x40 + op1, *data++);
write(0x60 + op1, *data++);
write(0x80 + op1, *data++);
write(0xE0 + op1, *data++);
write(0x20 + op2, *data++);
2016-09-12 22:34:59 -04:00
2016-09-14 20:53:35 -04:00
int scalingVal = *data++;
_channels[channelNum]._scalingValue = scalingVal;
2016-09-14 20:53:35 -04:00
scalingVal += (127 - _volume) / 2;
2016-09-12 22:34:59 -04:00
2016-09-14 20:53:35 -04:00
if (scalingVal > 63) {
scalingVal = 63;
if (_field180)
scalingVal = (scalingVal & 0xC0) | _field182;
}
write(0x40 + op2, scalingVal);
2016-09-12 22:34:59 -04:00
2016-09-14 20:53:35 -04:00
write(0x60 + op2, *data++);
write(0x80 + op2, *data++);
write(0xE0 + op2, *data++);
write(0xC0 + channelNum, *data++);
debugC(2, kDebugSound, "---END-playInstrument");
2016-09-12 22:34:59 -04:00
}
bool AdlibSoundDriver::musSetInstrument(const byte *&srcP, byte param) {
debugC(3, kDebugSound, "musSetInstrument %d", param);
2016-09-14 20:53:35 -04:00
_musInstrumentPtrs[param] = srcP;
srcP += 26;
2016-09-12 22:34:59 -04:00
2016-09-14 20:53:35 -04:00
return false;
2016-09-12 22:34:59 -04:00
}
bool AdlibSoundDriver::musSetPitchWheel(const byte *&srcP, byte param) {
2016-09-14 20:53:35 -04:00
// Adlib does not support this
debugC(3, kDebugSound, "musSetPitchWheel");
2016-09-14 20:53:35 -04:00
srcP += 2;
return false;
2016-09-12 22:34:59 -04:00
}
bool AdlibSoundDriver::musSetPanning(const byte *&srcP, byte param) {
2016-09-14 20:53:35 -04:00
// Adlib does not support this
debugC(3, kDebugSound, "musSetPanning");
2016-09-14 20:53:35 -04:00
++srcP;
return false;
2016-09-12 22:34:59 -04:00
}
bool AdlibSoundDriver::musFade(const byte *&srcP, byte param) {
2016-09-14 20:53:35 -04:00
++srcP;
if (param < 7)
setFrequency(param, _channels[param]._frequency);
debugC(3, kDebugSound, "musFade");
2016-09-12 22:34:59 -04:00
2016-09-14 20:53:35 -04:00
return false;
2016-09-12 22:34:59 -04:00
}
bool AdlibSoundDriver::musStartNote(const byte *&srcP, byte param) {
2016-09-14 20:53:35 -04:00
if (param < 7) {
byte note = *srcP++;
++srcP; // Second byte is fade, which is unused by Adlib
uint freq = calcFrequency(note);
debugC(3, kDebugSound, "musStartNote %x -> %x", note, freq);
2016-09-14 20:53:35 -04:00
setFrequency(param, freq);
2016-09-16 21:16:51 -04:00
freq |= 0x2000;
_channels[param]._frequency = freq;
2016-09-14 20:53:35 -04:00
setFrequency(param, freq);
} else {
srcP += 2;
debugC(3, kDebugSound, "musStartNote skipped");
2016-09-14 20:53:35 -04:00
}
return false;
2016-09-12 22:34:59 -04:00
}
bool AdlibSoundDriver::musSetVolume(const byte *&srcP, byte param) {
debugC(3, kDebugSound, "musSetVolume %d", (int)*srcP);
if (*srcP++ == 5 && !_field180) {
_channels[param]._volume = *srcP;
2016-09-14 20:53:35 -04:00
setOutputLevel(param, *srcP);
}
++srcP;
return false;
2016-09-12 22:34:59 -04:00
}
bool AdlibSoundDriver::musInjectMidi(const byte *&srcP, byte param) {
2016-09-14 20:53:35 -04:00
// Adlib does not support MIDI. So simply keep skipping over bytes
// until an 'F7' byte is found that flags the end of the MIDI data
debugC(3, kDebugSound, "musInjectMidi");
2016-09-14 20:53:35 -04:00
while (*srcP++ != 0xF7)
;
return false;
2016-09-12 22:34:59 -04:00
}
bool AdlibSoundDriver::musPlayInstrument(const byte *&srcP, byte param) {
byte instrument = *srcP++;
debugC(3, kDebugSound, "musPlayInstrument %d, %d", param, instrument);
2016-09-14 20:53:35 -04:00
if (param < 7)
playInstrument(param, _musInstrumentPtrs[instrument]);
2016-09-14 20:53:35 -04:00
return false;
2016-09-12 22:34:59 -04:00
}
bool AdlibSoundDriver::fxSetInstrument(const byte *&srcP, byte param) {
debugC(3, kDebugSound, "fxSetInstrument %d", param);
2016-09-14 20:53:35 -04:00
_fxInstrumentPtrs[param] = srcP;
srcP += 11;
return false;
2016-09-12 22:34:59 -04:00
}
bool AdlibSoundDriver::fxSetVolume(const byte *&srcP, byte param) {
debugC(3, kDebugSound, "fxSetVolume %d", (int)*srcP);
if (!_field180 && (!_exclude7 || param != 7)) {
_channels[param]._volume = *srcP;
2016-09-14 20:53:35 -04:00
setOutputLevel(param, *srcP);
}
++srcP;
return false;
2016-09-12 22:34:59 -04:00
}
bool AdlibSoundDriver::fxMidiReset(const byte *&srcP, byte param) {
debugC(3, kDebugSound, "fxMidiReset");
2016-09-14 20:53:35 -04:00
return false;
2016-09-12 22:34:59 -04:00
}
bool AdlibSoundDriver::fxMidiDword(const byte *&srcP, byte param) {
debugC(3, kDebugSound, "fxMidiDword");
2016-09-14 20:53:35 -04:00
return false;
2016-09-12 22:34:59 -04:00
}
bool AdlibSoundDriver::fxSetPanning(const byte *&srcP, byte param) {
2016-09-14 20:53:35 -04:00
byte note = *srcP++;
debugC(3, kDebugSound, "fxSetPanning - %x", note);
if (!_exclude7 || param != 7) {
2016-09-14 20:53:35 -04:00
uint freq = calcFrequency(note);
setFrequency(param, freq);
_channels[param]._frequency = freq;
2016-09-14 20:53:35 -04:00
}
return false;
2016-09-12 22:34:59 -04:00
}
bool AdlibSoundDriver::fxChannelOff(const byte *&srcP, byte param) {
debugC(3, kDebugSound, "fxChannelOff %d", param);
_channels[param]._frequency &= ~0x2000;
write(0xB0 + param, _channels[param]._frequency);
2016-09-14 20:53:35 -04:00
return false;
2016-09-12 22:34:59 -04:00
}
bool AdlibSoundDriver::fxFade(const byte *&srcP, byte param) {
2016-09-14 20:53:35 -04:00
uint freq = calcFrequency(*srcP++);
debugC(3, kDebugSound, "fxFade %d %x", param, freq);
if (!_exclude7 || param != 7) {
_channels[param]._frequency = freq;
2016-09-14 20:53:35 -04:00
setFrequency(param, freq);
}
return false;
2016-09-12 22:34:59 -04:00
}
bool AdlibSoundDriver::fxStartNote(const byte *&srcP, byte param) {
if (!_exclude7 || param != 7) {
2016-09-14 20:53:35 -04:00
byte note = *srcP++;
uint freq = calcFrequency(note);
debugC(3, kDebugSound, "fxStartNote %x -> %x", note, freq);
2016-09-14 20:53:35 -04:00
setFrequency(param, freq);
freq |= 0x2000;
_channels[param]._frequency = freq;
2016-09-14 20:53:35 -04:00
setFrequency(param, freq);
} else {
++srcP;
debugC(3, kDebugSound, "fxStartNote skipped");
2016-09-14 20:53:35 -04:00
}
return false;
2016-09-12 22:34:59 -04:00
}
bool AdlibSoundDriver::fxInjectMidi(const byte *&srcP, byte param) {
2016-09-14 20:53:35 -04:00
// Surpringly, unlike the musInjectMidi, this version doesn't have
// any logic to skip over following MIDI data. Which must mean the opcode
// and/or it's data aren't present in the admus driver file
debugC(3, kDebugSound, "fxInjectMidi");
2016-09-14 20:53:35 -04:00
return false;
}
2016-09-12 22:34:59 -04:00
bool AdlibSoundDriver::fxPlayInstrument(const byte *&srcP, byte param) {
2016-09-17 10:39:38 -04:00
byte instrument = *srcP++;
debugC(3, kDebugSound, "fxPlayInstrument %d, %d", param, instrument);
if (!_exclude7 || param != 7)
2016-09-17 10:39:38 -04:00
playInstrument(param, _fxInstrumentPtrs[instrument]);
2016-09-12 22:34:59 -04:00
2016-09-14 20:53:35 -04:00
return false;
}
/*------------------------------------------------------------------------*/
const byte AdlibSoundDriver::OPERATOR1_INDEXES[CHANNEL_COUNT] = {
0, 1, 2, 8, 9, 0xA, 0x10, 0x11, 0x12
};
const byte AdlibSoundDriver::OPERATOR2_INDEXES[CHANNEL_COUNT] = {
3, 4, 5, 0xB, 0xC, 0xD, 0x13, 0x14, 0x15
};
const uint AdlibSoundDriver::WAVEFORMS[24] = {
2016-09-14 20:53:35 -04:00
0, 347, 388, 436, 462, 519, 582, 646,
0, 362, 406, 455, 484, 542, 607, 680,
0, 327, 367, 412, 436, 489, 549, 618
};
2016-09-12 20:10:37 -04:00
} // End of namespace Xeen