aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--audio/adlib.cpp (renamed from audio/softsynth/adlib.cpp)50
-rw-r--r--audio/alsa_opl.cpp349
-rw-r--r--audio/fmopl.cpp178
-rw-r--r--audio/fmopl.h154
-rw-r--r--audio/miles_adlib.cpp51
-rw-r--r--audio/module.mk7
-rw-r--r--audio/softsynth/opl/dosbox.cpp12
-rw-r--r--audio/softsynth/opl/dosbox.h8
-rw-r--r--audio/softsynth/opl/mame.cpp14
-rw-r--r--audio/softsynth/opl/mame.h8
-rwxr-xr-xconfigure2
-rw-r--r--engines/agos/drivers/accolade/adlib.cpp48
-rw-r--r--engines/cine/sound.cpp127
-rw-r--r--engines/cruise/sound.cpp114
-rw-r--r--engines/gob/gob.cpp3
-rw-r--r--engines/gob/sound/adlib.cpp133
-rw-r--r--engines/gob/sound/adlib.h31
-rw-r--r--engines/gob/sound/adlplayer.cpp11
-rw-r--r--engines/gob/sound/adlplayer.h2
-rw-r--r--engines/gob/sound/musplayer.cpp22
-rw-r--r--engines/gob/sound/musplayer.h1
-rw-r--r--engines/gob/sound/sound.cpp10
-rw-r--r--engines/gob/sound/sound.h1
-rw-r--r--engines/kyra/sound_adlib.cpp57
-rw-r--r--engines/mads/nebular/sound_nebular.cpp62
-rw-r--r--engines/mads/nebular/sound_nebular.h60
-rw-r--r--engines/mads/sound.cpp3
-rw-r--r--engines/mads/sound.h2
-rw-r--r--engines/parallaction/adlib.cpp38
-rw-r--r--engines/queen/midiadlib.cpp139
-rw-r--r--engines/queen/midiadlib.h128
-rw-r--r--engines/queen/music.cpp8
-rw-r--r--engines/sci/sound/drivers/adlib.cpp53
-rw-r--r--engines/scumm/players/player_ad.cpp45
-rw-r--r--engines/scumm/players/player_ad.h16
-rw-r--r--engines/sherlock/scalpel/drivers/adlib.cpp46
-rw-r--r--engines/sky/music/adlibchannel.cpp12
-rw-r--r--engines/sky/music/adlibchannel.h5
-rw-r--r--engines/sky/music/adlibmusic.cpp56
-rw-r--r--engines/sky/music/adlibmusic.h18
-rw-r--r--engines/tsage/sound.cpp42
-rw-r--r--engines/tsage/sound.h24
-rw-r--r--gui/options.cpp6
43 files changed, 1308 insertions, 848 deletions
diff --git a/audio/softsynth/adlib.cpp b/audio/adlib.cpp
index 98519343b4..f609164495 100644
--- a/audio/softsynth/adlib.cpp
+++ b/audio/adlib.cpp
@@ -927,18 +927,20 @@ static void createLookupTable() {
//
////////////////////////////////////////
-class MidiDriver_ADLIB : public MidiDriver_Emulated {
+class MidiDriver_ADLIB : public MidiDriver {
friend class AdLibPart;
friend class AdLibPercussionChannel;
public:
- MidiDriver_ADLIB(Audio::Mixer *mixer);
+ MidiDriver_ADLIB();
int open();
void close();
void send(uint32 b);
void send(byte channel, uint32 b); // Supports higher than channel 15
uint32 property(int prop, uint32 param);
+ bool isOpen() const { return _isOpen; }
+ uint32 getBaseTempo() { return 1000000 / OPL::OPL::kDefaultCallbackFrequency; }
void setPitchBendRange(byte channel, uint range);
void sysEx_customInstrument(byte channel, uint32 type, const byte *instr);
@@ -946,10 +948,7 @@ public:
MidiChannel *allocateChannel();
MidiChannel *getPercussionChannel() { return &_percussion; } // Percussion partially supported
-
- // AudioStream API
- bool isStereo() const { return _opl->isStereo(); }
- int getRate() const { return _mixer->getOutputRate(); }
+ virtual void setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc);
private:
bool _scummSmallHeader; // FIXME: This flag controls a special mode for SCUMM V3 games
@@ -963,6 +962,9 @@ private:
byte *_regCacheSecondary;
#endif
+ Common::TimerManager::TimerProc _adlibTimerProc;
+ void *_adlibTimerParam;
+
int _timerCounter;
uint16 _channelTable2[9];
@@ -974,7 +976,8 @@ private:
AdLibPart _parts[32];
AdLibPercussionChannel _percussion;
- void generateSamples(int16 *buf, int len);
+ bool _isOpen;
+
void onTimer();
void partKeyOn(AdLibPart *part, const AdLibInstrument *instr, byte note, byte velocity, const AdLibInstrument *second, byte pan);
void partKeyOff(AdLibPart *part, byte note);
@@ -1376,8 +1379,7 @@ void AdLibPercussionChannel::sysEx_customInstrument(uint32 type, const byte *ins
// MidiDriver method implementations
-MidiDriver_ADLIB::MidiDriver_ADLIB(Audio::Mixer *mixer)
- : MidiDriver_Emulated(mixer) {
+MidiDriver_ADLIB::MidiDriver_ADLIB() {
uint i;
_scummSmallHeader = false;
@@ -1403,13 +1405,16 @@ MidiDriver_ADLIB::MidiDriver_ADLIB(Audio::Mixer *mixer)
_timerIncrease = 0xD69;
_timerThreshold = 0x411B;
_opl = 0;
+ _adlibTimerProc = 0;
+ _adlibTimerParam = 0;
+ _isOpen = false;
}
int MidiDriver_ADLIB::open() {
if (_isOpen)
return MERR_ALREADY_OPEN;
- MidiDriver_Emulated::open();
+ _isOpen = true;
int i;
AdLibVoice *voice;
@@ -1434,7 +1439,7 @@ int MidiDriver_ADLIB::open() {
_opl3Mode = false;
}
#endif
- _opl->init(getRate());
+ _opl->init();
_regCache = (byte *)calloc(256, 1);
@@ -1452,8 +1457,7 @@ int MidiDriver_ADLIB::open() {
}
#endif
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &_mixerSoundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
-
+ _opl->start(new Common::Functor0Mem<void, MidiDriver_ADLIB>(this, &MidiDriver_ADLIB::onTimer));
return 0;
}
@@ -1462,7 +1466,8 @@ void MidiDriver_ADLIB::close() {
return;
_isOpen = false;
- _mixer->stopHandle(_mixerSoundHandle);
+ // Stop the OPL timer
+ _opl->stop();
uint i;
for (i = 0; i < ARRAYSIZE(_voices); ++i) {
@@ -1616,14 +1621,10 @@ void MidiDriver_ADLIB::adlibWriteSecondary(byte reg, byte value) {
}
#endif
-void MidiDriver_ADLIB::generateSamples(int16 *data, int len) {
- if (_opl->isStereo()) {
- len *= 2;
- }
- _opl->readBuffer(data, len);
-}
-
void MidiDriver_ADLIB::onTimer() {
+ if (_adlibTimerProc)
+ (*_adlibTimerProc)(_adlibTimerParam);
+
_timerCounter += _timerIncrease;
while (_timerCounter >= _timerThreshold) {
_timerCounter -= _timerThreshold;
@@ -1655,6 +1656,11 @@ void MidiDriver_ADLIB::onTimer() {
}
}
+void MidiDriver_ADLIB::setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc) {
+ _adlibTimerProc = timerProc;
+ _adlibTimerParam = timerParam;
+}
+
void MidiDriver_ADLIB::mcOff(AdLibVoice *voice) {
AdLibVoice *tmp;
@@ -2300,7 +2306,7 @@ MusicDevices AdLibEmuMusicPlugin::getDevices() const {
}
Common::Error AdLibEmuMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const {
- *mididriver = new MidiDriver_ADLIB(g_system->getMixer());
+ *mididriver = new MidiDriver_ADLIB();
return Common::kNoError;
}
diff --git a/audio/alsa_opl.cpp b/audio/alsa_opl.cpp
new file mode 100644
index 0000000000..6b9e48e987
--- /dev/null
+++ b/audio/alsa_opl.cpp
@@ -0,0 +1,349 @@
+/* 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.
+ *
+ */
+
+/* OPL implementation for hardware OPL using ALSA Direct FM API.
+ *
+ * Caveats and limitations:
+ * - Pretends to be a softsynth (emitting silence).
+ * - Dual OPL2 mode requires OPL3 hardware.
+ * - Every register write leads to a series of register writes on the hardware,
+ * due to the lack of direct register access in the ALSA Direct FM API.
+ * - No timers
+ */
+
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+#include "common/scummsys.h"
+
+#include "common/debug.h"
+#include "common/str.h"
+#include "audio/fmopl.h"
+
+#include <sys/ioctl.h>
+#include <alsa/asoundlib.h>
+#include <sound/asound_fm.h>
+
+namespace OPL {
+namespace ALSA {
+
+class OPL : public ::OPL::RealOPL {
+private:
+ enum {
+ kOpl2Voices = 9,
+ kVoices = 18,
+ kOpl2Operators = 18,
+ kOperators = 36
+ };
+
+ Config::OplType _type;
+ int _iface;
+ snd_hwdep_t *_opl;
+ snd_dm_fm_voice _oper[kOperators];
+ snd_dm_fm_note _voice[kVoices];
+ snd_dm_fm_params _params;
+ int index[2];
+ static const int voiceToOper0[kVoices];
+ static const int regOffsetToOper[0x20];
+
+ void writeOplReg(int c, int r, int v);
+ void clear();
+
+public:
+ OPL(Config::OplType type);
+ ~OPL();
+
+ bool init();
+ void reset();
+
+ void write(int a, int v);
+ byte read(int a);
+
+ void writeReg(int r, int v);
+};
+
+const int OPL::voiceToOper0[OPL::kVoices] =
+ { 0, 1, 2, 6, 7, 8, 12, 13, 14, 18, 19, 20, 24, 25, 26, 30, 31, 32 };
+
+const int OPL::regOffsetToOper[0x20] =
+ { 0, 1, 2, 3, 4, 5, -1, -1, 6, 7, 8, 9, 10, 11, -1, -1,
+ 12, 13, 14, 15, 16, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
+
+OPL::OPL(Config::OplType type) : _type(type), _opl(nullptr), _iface(0) {
+}
+
+OPL::~OPL() {
+ stop();
+
+ if (_opl) {
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_RESET, nullptr);
+ snd_hwdep_close(_opl);
+ }
+}
+
+void OPL::clear() {
+ index[0] = index[1] = 0;
+
+ memset(_oper, 0, sizeof(_oper));
+ memset(_voice, 0, sizeof(_voice));
+ memset(&_params, 0, sizeof(_params));
+
+ for (int i = 0; i < kOperators; ++i) {
+ _oper[i].op = (i / 3) % 2;
+ _oper[i].voice = (i / 6) * 3 + (i % 3);
+ }
+
+ for (int i = 0; i < kVoices; ++i)
+ _voice[i].voice = i;
+
+ // For OPL3 hardware we need to set up the panning in OPL2 modes
+ if (_iface == SND_HWDEP_IFACE_OPL3) {
+ if (_type == Config::kDualOpl2) {
+ for (int i = 0; i < kOpl2Operators; ++i)
+ _oper[i].left = 1; // FIXME below
+ for (int i = kOpl2Operators; i < kOperators; ++i)
+ _oper[i].right = 1;
+ } else if (_type == Config::kOpl2) {
+ for (int i = 0; i < kOpl2Operators; ++i) {
+ _oper[i].left = 1;
+ _oper[i].right = 1;
+ }
+ }
+ }
+}
+
+bool OPL::init() {
+ clear();
+
+ int card = -1;
+ snd_ctl_t *ctl;
+ snd_hwdep_info_t *info;
+ snd_hwdep_info_alloca(&info);
+
+ int iface = SND_HWDEP_IFACE_OPL3;
+ if (_type == Config::kOpl2)
+ iface = SND_HWDEP_IFACE_OPL2;
+
+ // Look for OPL hwdep interface
+ while (!snd_card_next(&card) && card >= 0) {
+ int dev = -1;
+ Common::String name = Common::String::format("hw:%d", card);
+
+ if (snd_ctl_open(&ctl, name.c_str(), 0) < 0)
+ continue;
+
+ while (!snd_ctl_hwdep_next_device(ctl, &dev) && dev >= 0) {
+ name = Common::String::format("hw:%d,%d", card, dev);
+
+ if (snd_hwdep_open(&_opl, name.c_str(), SND_HWDEP_OPEN_WRITE) < 0)
+ continue;
+
+ if (!snd_hwdep_info(_opl, info)) {
+ int found = snd_hwdep_info_get_iface(info);
+ // OPL3 can be used for (Dual) OPL2 mode
+ if (found == iface || found == SND_HWDEP_IFACE_OPL3) {
+ snd_ctl_close(ctl);
+ _iface = found;
+ reset();
+ return true;
+ }
+ }
+
+ // Wrong interface, try next device
+ snd_hwdep_close(_opl);
+ _opl = nullptr;
+ }
+
+ snd_ctl_close(ctl);
+ }
+
+ return false;
+}
+
+void OPL::reset() {
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_RESET, nullptr);
+ if (_iface == SND_HWDEP_IFACE_OPL3)
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_MODE, (void *)SNDRV_DM_FM_MODE_OPL3);
+
+ clear();
+
+ // Sync up with the hardware
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_PARAMS, (void *)&_params);
+ for (uint i = 0; i < (_iface == SND_HWDEP_IFACE_OPL3 ? kVoices : kOpl2Voices); ++i)
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_PLAY_NOTE, (void *)&_voice[i]);
+ for (uint i = 0; i < (_iface == SND_HWDEP_IFACE_OPL3 ? kOperators : kOpl2Operators); ++i)
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_VOICE, (void *)&_oper[i]);
+}
+
+void OPL::write(int port, int val) {
+ val &= 0xff;
+ int chip = (port & 2) >> 1;
+
+ if (port & 1) {
+ switch(_type) {
+ case Config::kOpl2:
+ writeOplReg(0, index[0], val);
+ break;
+ case Config::kDualOpl2:
+ if (port & 8) {
+ writeOplReg(0, index[0], val);
+ writeOplReg(1, index[1], val);
+ } else
+ writeOplReg(chip, index[chip], val);
+ break;
+ case Config::kOpl3:
+ writeOplReg(chip, index[chip], val);
+ }
+ } else {
+ switch(_type) {
+ case Config::kOpl2:
+ index[0] = val;
+ break;
+ case Config::kDualOpl2:
+ if (port & 8) {
+ index[0] = val;
+ index[1] = val;
+ } else
+ index[chip] = val;
+ break;
+ case Config::kOpl3:
+ index[chip] = val;
+ }
+ }
+}
+
+byte OPL::read(int port) {
+ return 0;
+}
+
+void OPL::writeReg(int r, int v) {
+ switch (_type) {
+ case Config::kOpl2:
+ writeOplReg(0, r, v);
+ break;
+ case Config::kDualOpl2:
+ writeOplReg(0, r, v);
+ writeOplReg(1, r, v);
+ break;
+ case Config::kOpl3:
+ writeOplReg(r >= 0x100, r & 0xff, v);
+ }
+}
+
+void OPL::writeOplReg(int c, int r, int v) {
+ if (r == 0x04 && c == 1 && _type == Config::kOpl3) {
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_CONNECTION, reinterpret_cast<void *>(v & 0x3f));
+ } else if (r == 0x08 && c == 0) {
+ _params.kbd_split = (v >> 6) & 0x1;
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_PARAMS, (void *)&_params);
+ } else if (r == 0xbd && c == 0) {
+ _params.hihat = v & 0x1;
+ _params.cymbal = (v >> 1) & 0x1;
+ _params.tomtom = (v >> 2) & 0x1;
+ _params.snare = (v >> 3) & 0x1;
+ _params.bass = (v >> 4) & 0x1;
+ _params.rhythm = (v >> 5) & 0x1;
+ _params.vib_depth = (v >> 6) & 0x1;
+ _params.am_depth = (v >> 7) & 0x1;
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_PARAMS, (void *)&_params);
+ } else if (r < 0xa0 || r >= 0xe0) {
+ // Operator
+ int idx = regOffsetToOper[r & 0x1f];
+
+ if (idx == -1)
+ return;
+
+ if (c == 1)
+ idx += kOpl2Operators;
+
+ switch (r & 0xf0) {
+ case 0x20:
+ case 0x30:
+ _oper[idx].harmonic = v & 0xf;
+ _oper[idx].kbd_scale = (v >> 4) & 0x1;
+ _oper[idx].do_sustain = (v >> 5) & 0x1;
+ _oper[idx].vibrato = (v >> 6) & 0x1;
+ _oper[idx].am = (v >> 7) & 0x1;
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_VOICE, (void *)&_oper[idx]);
+ break;
+ case 0x40:
+ case 0x50:
+ _oper[idx].volume = ~v & 0x3f;
+ _oper[idx].scale_level = (v >> 6) & 0x3;
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_VOICE, (void *)&_oper[idx]);
+ break;
+ case 0x60:
+ case 0x70:
+ _oper[idx].decay = v & 0xf;
+ _oper[idx].attack = (v >> 4) & 0xf;
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_VOICE, (void *)&_oper[idx]);
+ break;
+ case 0x80:
+ case 0x90:
+ _oper[idx].release = v & 0xf;
+ _oper[idx].sustain = (v >> 4) & 0xf;
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_VOICE, (void *)&_oper[idx]);
+ break;
+ case 0xe0:
+ case 0xf0:
+ _oper[idx].waveform = v & (_type == Config::kOpl3 ? 0x7 : 0x3);
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_VOICE, (void *)&_oper[idx]);
+ }
+ } else {
+ // Voice
+ int idx = r & 0xf;
+
+ if (idx >= kOpl2Voices)
+ return;
+
+ if (c == 1)
+ idx += kOpl2Voices;
+
+ int opIdx = voiceToOper0[idx];
+
+ switch (r & 0xf0) {
+ case 0xa0:
+ _voice[idx].fnum = (_voice[idx].fnum & 0x300) | (v & 0xff);
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_PLAY_NOTE, (void *)&_voice[idx]);
+ break;
+ case 0xb0:
+ _voice[idx].fnum = ((v << 8) & 0x300) | (_voice[idx].fnum & 0xff);
+ _voice[idx].octave = (v >> 2) & 0x7;
+ _voice[idx].key_on = (v >> 5) & 0x1;
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_PLAY_NOTE, (void *)&_voice[idx]);
+ break;
+ case 0xc0:
+ _oper[opIdx].connection = _oper[opIdx + 3].connection = v & 0x1;
+ _oper[opIdx].feedback = _oper[opIdx + 3].feedback = (v >> 1) & 0x7;
+ if (_type == Config::kOpl3) {
+ _oper[opIdx].left = _oper[opIdx + 3].left = (v >> 4) & 0x1;
+ _oper[opIdx].right = _oper[opIdx + 3].right = (v >> 5) & 0x1;
+ }
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_VOICE, (void *)&_oper[opIdx]);
+ }
+ }
+}
+
+OPL *create(Config::OplType type) {
+ return new OPL(type);
+}
+
+} // End of namespace ALSA
+} // End of namespace OPL
diff --git a/audio/fmopl.cpp b/audio/fmopl.cpp
index 30229ea6bf..cc00ace264 100644
--- a/audio/fmopl.cpp
+++ b/audio/fmopl.cpp
@@ -22,21 +22,33 @@
#include "audio/fmopl.h"
+#include "audio/mixer.h"
#include "audio/softsynth/opl/dosbox.h"
#include "audio/softsynth/opl/mame.h"
#include "common/config-manager.h"
+#include "common/system.h"
#include "common/textconsole.h"
+#include "common/timer.h"
#include "common/translation.h"
namespace OPL {
+// Factory functions
+
+#ifdef USE_ALSA
+namespace ALSA {
+ OPL *create(Config::OplType type);
+} // End of namespace ALSA
+#endif // USE_ALSA
+
// Config implementation
enum OplEmulator {
kAuto = 0,
kMame = 1,
- kDOSBox = 2
+ kDOSBox = 2,
+ kALSA = 3
};
OPL::OPL() {
@@ -51,6 +63,9 @@ const Config::EmulatorDescription Config::_drivers[] = {
#ifndef DISABLE_DOSBOX_OPL
{ "db", _s("DOSBox OPL emulator"), kDOSBox, kFlagOpl2 | kFlagDualOpl2 | kFlagOpl3 },
#endif
+#ifdef USE_ALSA
+ { "alsa", _s("ALSA Direct FM"), kALSA, kFlagOpl2 | kFlagDualOpl2 | kFlagOpl3 },
+#endif
{ 0, 0, 0, 0 }
};
@@ -63,6 +78,15 @@ Config::DriverId Config::parse(const Common::String &name) {
return -1;
}
+const Config::EmulatorDescription *Config::findDriver(DriverId id) {
+ for (int i = 0; _drivers[i].name; ++i) {
+ if (_drivers[i].id == id)
+ return &_drivers[i];
+ }
+
+ return 0;
+}
+
Config::DriverId Config::detect(OplType type) {
uint32 flags = 0;
switch (type) {
@@ -90,8 +114,11 @@ Config::DriverId Config::detect(OplType type) {
// When a valid driver is selected, check whether it supports
// the requested OPL chip.
if (drv != -1 && drv != kAuto) {
+ const EmulatorDescription *driverDesc = findDriver(drv);
// If the chip is supported, just use the driver.
- if ((flags & _drivers[drv].flags)) {
+ if (!driverDesc) {
+ warning("The selected OPL driver %d could not be found", drv);
+ } else if ((flags & driverDesc->flags)) {
return drv;
} else {
// Else we will output a warning and just
@@ -151,6 +178,11 @@ OPL *Config::create(DriverId driver, OplType type) {
return new DOSBox::OPL(type);
#endif
+#ifdef USE_ALSA
+ case kALSA:
+ return ALSA::create(type);
+#endif
+
default:
warning("Unsupported OPL emulator %d", driver);
// TODO: Maybe we should add some dummy emulator too, which just outputs
@@ -159,43 +191,143 @@ OPL *Config::create(DriverId driver, OplType type) {
}
}
+void OPL::start(TimerCallback *callback, int timerFrequency) {
+ _callback.reset(callback);
+ startCallbacks(timerFrequency);
+}
+
+void OPL::stop() {
+ stopCallbacks();
+ _callback.reset();
+}
+
bool OPL::_hasInstance = false;
-} // End of namespace OPL
+RealOPL::RealOPL() : _baseFreq(0), _remainingTicks(0) {
+}
+
+RealOPL::~RealOPL() {
+ // Stop callbacks, just in case. If it's still playing at this
+ // point, there's probably a bigger issue, though. The subclass
+ // needs to call stop() or the pointer can still use be used in
+ // the mixer thread at the same time.
+ stop();
+}
+
+void RealOPL::setCallbackFrequency(int timerFrequency) {
+ stopCallbacks();
+ startCallbacks(timerFrequency);
+}
+
+void RealOPL::startCallbacks(int timerFrequency) {
+ _baseFreq = timerFrequency;
+ assert(_baseFreq > 0);
+
+ // We can't request more a timer faster than 100Hz. We'll handle this by calling
+ // the proc multiple times in onTimer() later on.
+ if (timerFrequency > kMaxFreq)
+ timerFrequency = kMaxFreq;
-void OPLDestroy(FM_OPL *OPL) {
- delete OPL;
+ _remainingTicks = 0;
+ g_system->getTimerManager()->installTimerProc(timerProc, 1000000 / timerFrequency, this, "RealOPL");
}
-void OPLResetChip(FM_OPL *OPL) {
- OPL->reset();
+void RealOPL::stopCallbacks() {
+ g_system->getTimerManager()->removeTimerProc(timerProc);
+ _baseFreq = 0;
+ _remainingTicks = 0;
}
-void OPLWrite(FM_OPL *OPL, int a, int v) {
- OPL->write(a, v);
+void RealOPL::timerProc(void *refCon) {
+ static_cast<RealOPL *>(refCon)->onTimer();
}
-unsigned char OPLRead(FM_OPL *OPL, int a) {
- return OPL->read(a);
+void RealOPL::onTimer() {
+ uint callbacks = 1;
+
+ if (_baseFreq > kMaxFreq) {
+ // We run faster than our max, so run the callback multiple
+ // times to approximate the actual timer callback frequency.
+ uint totalTicks = _baseFreq + _remainingTicks;
+ callbacks = totalTicks / kMaxFreq;
+ _remainingTicks = totalTicks % kMaxFreq;
+ }
+
+ // Call the callback multiple times. The if is on the inside of the
+ // loop in case the callback removes itself.
+ for (uint i = 0; i < callbacks; i++)
+ if (_callback && _callback->isValid())
+ (*_callback)();
}
-void OPLWriteReg(FM_OPL *OPL, int r, int v) {
- OPL->writeReg(r, v);
+EmulatedOPL::EmulatedOPL() :
+ _nextTick(0),
+ _samplesPerTick(0),
+ _baseFreq(0),
+ _handle(new Audio::SoundHandle()) {
}
-void YM3812UpdateOne(FM_OPL *OPL, int16 *buffer, int length) {
- OPL->readBuffer(buffer, length);
+EmulatedOPL::~EmulatedOPL() {
+ // Stop callbacks, just in case. If it's still playing at this
+ // point, there's probably a bigger issue, though. The subclass
+ // needs to call stop() or the pointer can still use be used in
+ // the mixer thread at the same time.
+ stop();
+
+ delete _handle;
}
-FM_OPL *makeAdLibOPL(int rate) {
- FM_OPL *opl = OPL::Config::create();
+int EmulatedOPL::readBuffer(int16 *buffer, const int numSamples) {
+ const int stereoFactor = isStereo() ? 2 : 1;
+ int len = numSamples / stereoFactor;
+ int step;
+
+ do {
+ step = len;
+ if (step > (_nextTick >> FIXP_SHIFT))
+ step = (_nextTick >> FIXP_SHIFT);
+
+ generateSamples(buffer, step * stereoFactor);
- if (opl) {
- if (!opl->init(rate)) {
- delete opl;
- opl = 0;
+ _nextTick -= step << FIXP_SHIFT;
+ if (!(_nextTick >> FIXP_SHIFT)) {
+ if (_callback && _callback->isValid())
+ (*_callback)();
+
+ _nextTick += _samplesPerTick;
}
- }
- return opl;
+ buffer += step * stereoFactor;
+ len -= step;
+ } while (len);
+
+ return numSamples;
+}
+
+int EmulatedOPL::getRate() const {
+ return g_system->getMixer()->getOutputRate();
}
+
+void EmulatedOPL::startCallbacks(int timerFrequency) {
+ setCallbackFrequency(timerFrequency);
+ g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, _handle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+}
+
+void EmulatedOPL::stopCallbacks() {
+ g_system->getMixer()->stopHandle(*_handle);
+}
+
+void EmulatedOPL::setCallbackFrequency(int timerFrequency) {
+ _baseFreq = timerFrequency;
+ assert(_baseFreq != 0);
+
+ int d = getRate() / _baseFreq;
+ int r = getRate() % _baseFreq;
+
+ // This is equivalent to (getRate() << FIXP_SHIFT) / BASE_FREQ
+ // but less prone to arithmetic overflow.
+
+ _samplesPerTick = (d << FIXP_SHIFT) + (r << FIXP_SHIFT) / _baseFreq;
+}
+
+} // End of namespace OPL
diff --git a/audio/fmopl.h b/audio/fmopl.h
index 85ac606c7a..ba0872d87b 100644
--- a/audio/fmopl.h
+++ b/audio/fmopl.h
@@ -23,8 +23,16 @@
#ifndef AUDIO_FMOPL_H
#define AUDIO_FMOPL_H
+#include "audio/audiostream.h"
+
+#include "common/func.h"
+#include "common/ptr.h"
#include "common/scummsys.h"
+namespace Audio {
+class SoundHandle;
+}
+
namespace Common {
class String;
}
@@ -71,6 +79,12 @@ public:
static DriverId parse(const Common::String &name);
/**
+ * @return The driver description for the given id or 0 in case it is not
+ * available.
+ */
+ static const EmulatorDescription *findDriver(DriverId id);
+
+ /**
* Detects a driver for the specific type.
*
* @return Returns a valid driver id on success, -1 otherwise.
@@ -92,6 +106,14 @@ private:
static const EmulatorDescription _drivers[];
};
+/**
+ * The type of the OPL timer callback functor.
+ */
+typedef Common::Functor0<void> TimerCallback;
+
+/**
+ * A representation of a Yamaha OPL chip.
+ */
class OPL {
private:
static bool _hasInstance;
@@ -102,10 +124,9 @@ public:
/**
* Initializes the OPL emulator.
*
- * @param rate output sample rate
* @return true on success, false on failure
*/
- virtual bool init(int rate) = 0;
+ virtual bool init() = 0;
/**
* Reinitializes the OPL emulator
@@ -140,6 +161,101 @@ public:
virtual void writeReg(int r, int v) = 0;
/**
+ * Start the OPL with callbacks.
+ */
+ void start(TimerCallback *callback, int timerFrequency = kDefaultCallbackFrequency);
+
+ /**
+ * Stop the OPL
+ */
+ void stop();
+
+ /**
+ * Change the callback frequency. This must only be called from a
+ * timer proc.
+ */
+ virtual void setCallbackFrequency(int timerFrequency) = 0;
+
+ enum {
+ /**
+ * The default callback frequency that start() uses
+ */
+ kDefaultCallbackFrequency = 250
+ };
+
+protected:
+ /**
+ * Start the callbacks.
+ */
+ virtual void startCallbacks(int timerFrequency) = 0;
+
+ /**
+ * Stop the callbacks.
+ */
+ virtual void stopCallbacks() = 0;
+
+ /**
+ * The functor for callbacks.
+ */
+ Common::ScopedPtr<TimerCallback> _callback;
+};
+
+/**
+ * An OPL that represents a real OPL, as opposed to an emulated one.
+ *
+ * This will use an actual timer instead of using one calculated from
+ * the number of samples in an AudioStream::readBuffer call.
+ */
+class RealOPL : public OPL {
+public:
+ RealOPL();
+ virtual ~RealOPL();
+
+ // OPL API
+ void setCallbackFrequency(int timerFrequency);
+
+protected:
+ // OPL API
+ void startCallbacks(int timerFrequency);
+ void stopCallbacks();
+
+private:
+ static void timerProc(void *refCon);
+ void onTimer();
+
+ uint _baseFreq;
+ uint _remainingTicks;
+
+ enum {
+ kMaxFreq = 100
+ };
+};
+
+/**
+ * An OPL that represents an emulated OPL.
+ *
+ * This will send callbacks based on the number of samples
+ * decoded in readBuffer().
+ */
+class EmulatedOPL : public OPL, protected Audio::AudioStream {
+public:
+ EmulatedOPL();
+ virtual ~EmulatedOPL();
+
+ // OPL API
+ void setCallbackFrequency(int timerFrequency);
+
+ // AudioStream API
+ int readBuffer(int16 *buffer, const int numSamples);
+ int getRate() const;
+ bool endOfData() const { return false; }
+
+protected:
+ // OPL API
+ void startCallbacks(int timerFrequency);
+ void stopCallbacks();
+
+ /**
* Read up to 'length' samples.
*
* Data will be in native endianess, 16 bit per sample, signed.
@@ -149,33 +265,21 @@ public:
* So if you request 4 samples from a stereo OPL, you will get
* a total of two left channel and two right channel samples.
*/
- virtual void readBuffer(int16 *buffer, int length) = 0;
-
- /**
- * Returns whether the setup OPL mode is stereo or not
- */
- virtual bool isStereo() const = 0;
-};
+ virtual void generateSamples(int16 *buffer, int numSamples) = 0;
-} // End of namespace OPL
+private:
+ int _baseFreq;
-// Legacy API
-// !You should not write any new code using the legacy API!
-typedef OPL::OPL FM_OPL;
+ enum {
+ FIXP_SHIFT = 16
+ };
-void OPLDestroy(FM_OPL *OPL);
+ int _nextTick;
+ int _samplesPerTick;
-void OPLResetChip(FM_OPL *OPL);
-void OPLWrite(FM_OPL *OPL, int a, int v);
-unsigned char OPLRead(FM_OPL *OPL, int a);
-void OPLWriteReg(FM_OPL *OPL, int r, int v);
-void YM3812UpdateOne(FM_OPL *OPL, int16 *buffer, int length);
+ Audio::SoundHandle *_handle;
+};
-/**
- * Legacy factory to create an AdLib (OPL2) chip.
- *
- * !You should not write any new code using the legacy API!
- */
-FM_OPL *makeAdLibOPL(int rate);
+} // End of namespace OPL
#endif
diff --git a/audio/miles_adlib.cpp b/audio/miles_adlib.cpp
index 903b0a92be..bf5c9d4a73 100644
--- a/audio/miles_adlib.cpp
+++ b/audio/miles_adlib.cpp
@@ -116,9 +116,9 @@ uint16 milesAdLibVolumeSensitivityTable[] = {
};
-class MidiDriver_Miles_AdLib : public MidiDriver_Emulated {
+class MidiDriver_Miles_AdLib : public MidiDriver {
public:
- MidiDriver_Miles_AdLib(Audio::Mixer *mixer, InstrumentEntry *instrumentTablePtr, uint16 instrumentTableCount);
+ MidiDriver_Miles_AdLib(InstrumentEntry *instrumentTablePtr, uint16 instrumentTableCount);
virtual ~MidiDriver_Miles_AdLib();
// MidiDriver
@@ -128,18 +128,14 @@ public:
MidiChannel *allocateChannel() { return NULL; }
MidiChannel *getPercussionChannel() { return NULL; }
- // AudioStream
- bool isStereo() const { return _modeStereo; }
- int getRate() const { return _mixer->getOutputRate(); }
- int getPolyphony() const { return _modePhysicalFmVoicesCount; }
- bool hasRhythmChannel() const { return false; }
-
- // MidiDriver_Emulated
- void generateSamples(int16 *buf, int len);
+ bool isOpen() const { return _isOpen; }
+ uint32 getBaseTempo() { return 1000000 / OPL::OPL::kDefaultCallbackFrequency; }
void setVolume(byte volume);
virtual uint32 property(int prop, uint32 param);
+ void setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc);
+
private:
bool _modeOPL3;
byte _modePhysicalFmVoicesCount;
@@ -222,6 +218,11 @@ private:
OPL::OPL *_opl;
int _masterVolume;
+ Common::TimerManager::TimerProc _adlibTimerProc;
+ void *_adlibTimerParam;
+
+ bool _isOpen;
+
// stores information about all MIDI channels (not the actual OPL FM voice channels!)
MidiChannelEntry _midiChannels[MILES_MIDI_CHANNEL_COUNT];
@@ -238,10 +239,8 @@ private:
bool circularPhysicalAssignment;
byte circularPhysicalAssignmentFmVoice;
-protected:
void onTimer();
-private:
void resetData();
void resetAdLib();
void resetAdLibOperatorRegisters(byte baseRegister, byte value);
@@ -271,8 +270,9 @@ private:
void pitchBendChange(byte MIDIchannel, byte parameter1, byte parameter2);
};
-MidiDriver_Miles_AdLib::MidiDriver_Miles_AdLib(Audio::Mixer *mixer, InstrumentEntry *instrumentTablePtr, uint16 instrumentTableCount)
- : MidiDriver_Emulated(mixer), _masterVolume(15), _opl(0) {
+MidiDriver_Miles_AdLib::MidiDriver_Miles_AdLib(InstrumentEntry *instrumentTablePtr, uint16 instrumentTableCount)
+ : _masterVolume(15), _opl(0),
+ _adlibTimerProc(0), _adlibTimerParam(0), _isOpen(false) {
_instrumentTablePtr = instrumentTablePtr;
_instrumentTableCount = instrumentTableCount;
@@ -298,8 +298,6 @@ MidiDriver_Miles_AdLib::~MidiDriver_Miles_AdLib() {
}
int MidiDriver_Miles_AdLib::open() {
- int rate = _mixer->getOutputRate();
-
if (_modeOPL3) {
// Try to create OPL3 first
_opl = OPL::Config::create(OPL::Config::kOpl3);
@@ -319,11 +317,11 @@ int MidiDriver_Miles_AdLib::open() {
return -1;
}
- _opl->init(rate);
+ _opl->init();
- MidiDriver_Emulated::open();
+ _isOpen = true;
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &_mixerSoundHandle, this, -1, _mixer->kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+ _opl->start(new Common::Functor0Mem<void, MidiDriver_Miles_AdLib>(this, &MidiDriver_Miles_AdLib::onTimer));
resetAdLib();
@@ -331,9 +329,8 @@ int MidiDriver_Miles_AdLib::open() {
}
void MidiDriver_Miles_AdLib::close() {
- _mixer->stopHandle(_mixerSoundHandle);
-
delete _opl;
+ _isOpen = false;
}
void MidiDriver_Miles_AdLib::setVolume(byte volume) {
@@ -342,6 +339,8 @@ void MidiDriver_Miles_AdLib::setVolume(byte volume) {
}
void MidiDriver_Miles_AdLib::onTimer() {
+ if (_adlibTimerProc)
+ (*_adlibTimerProc)(_adlibTimerParam);
}
void MidiDriver_Miles_AdLib::resetData() {
@@ -438,11 +437,9 @@ void MidiDriver_Miles_AdLib::send(uint32 b) {
}
}
-void MidiDriver_Miles_AdLib::generateSamples(int16 *data, int len) {
- if (_modeStereo)
- len *= 2;
-
- _opl->readBuffer(data, len);
+void MidiDriver_Miles_AdLib::setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc) {
+ _adlibTimerProc = timerProc;
+ _adlibTimerParam = timerParam;
}
int16 MidiDriver_Miles_AdLib::searchFreeVirtualFmVoiceChannel() {
@@ -1271,7 +1268,7 @@ MidiDriver *MidiDriver_Miles_AdLib_create(const Common::String &filenameAdLib, c
// Free instrument file/stream data
delete[] streamDataPtr;
- return new MidiDriver_Miles_AdLib(g_system->getMixer(), instrumentTablePtr, instrumentTableCount);
+ return new MidiDriver_Miles_AdLib(instrumentTablePtr, instrumentTableCount);
}
} // End of namespace Audio
diff --git a/audio/module.mk b/audio/module.mk
index abbeed6184..9e002d57ba 100644
--- a/audio/module.mk
+++ b/audio/module.mk
@@ -1,6 +1,7 @@
MODULE := audio
MODULE_OBJS := \
+ adlib.o \
audiostream.o \
fmopl.o \
mididrv.o \
@@ -39,7 +40,6 @@ MODULE_OBJS := \
mods/rjp1.o \
mods/soundfx.o \
mods/tfmx.o \
- softsynth/adlib.o \
softsynth/cms.o \
softsynth/opl/dbopl.o \
softsynth/opl/dosbox.o \
@@ -58,6 +58,11 @@ MODULE_OBJS := \
softsynth/sid.o \
softsynth/wave6581.o
+ifdef USE_ALSA
+MODULE_OBJS += \
+ alsa_opl.o
+endif
+
ifndef USE_ARM_SOUND_ASM
MODULE_OBJS += \
rate.o
diff --git a/audio/softsynth/opl/dosbox.cpp b/audio/softsynth/opl/dosbox.cpp
index 5c3d833f54..3d90ec93d0 100644
--- a/audio/softsynth/opl/dosbox.cpp
+++ b/audio/softsynth/opl/dosbox.cpp
@@ -32,6 +32,7 @@
#include "dosbox.h"
#include "dbopl.h"
+#include "audio/mixer.h"
#include "common/system.h"
#include "common/scummsys.h"
#include "common/util.h"
@@ -148,6 +149,7 @@ OPL::OPL(Config::OplType type) : _type(type), _rate(0), _emulator(0) {
}
OPL::~OPL() {
+ stop();
free();
}
@@ -156,7 +158,7 @@ void OPL::free() {
_emulator = 0;
}
-bool OPL::init(int rate) {
+bool OPL::init() {
free();
memset(&_reg, 0, sizeof(_reg));
@@ -167,19 +169,19 @@ bool OPL::init(int rate) {
return false;
DBOPL::InitTables();
- _emulator->Setup(rate);
+ _rate = g_system->getMixer()->getOutputRate();
+ _emulator->Setup(_rate);
if (_type == Config::kDualOpl2) {
// Setup opl3 mode in the hander
_emulator->WriteReg(0x105, 1);
}
- _rate = rate;
return true;
}
void OPL::reset() {
- init(_rate);
+ init();
}
void OPL::write(int port, int val) {
@@ -307,7 +309,7 @@ void OPL::dualWrite(uint8 index, uint8 reg, uint8 val) {
_emulator->WriteReg(fullReg, val);
}
-void OPL::readBuffer(int16 *buffer, int length) {
+void OPL::generateSamples(int16 *buffer, int length) {
// For stereo OPL cards, we divide the sample count by 2,
// to match stereo AudioStream behavior.
if (_type != Config::kOpl2)
diff --git a/audio/softsynth/opl/dosbox.h b/audio/softsynth/opl/dosbox.h
index 513a49f6b8..c52f06761a 100644
--- a/audio/softsynth/opl/dosbox.h
+++ b/audio/softsynth/opl/dosbox.h
@@ -69,7 +69,7 @@ namespace DBOPL {
struct Chip;
} // end of namespace DBOPL
-class OPL : public ::OPL::OPL {
+class OPL : public ::OPL::EmulatedOPL {
private:
Config::OplType _type;
uint _rate;
@@ -87,7 +87,7 @@ public:
OPL(Config::OplType type);
~OPL();
- bool init(int rate);
+ bool init();
void reset();
void write(int a, int v);
@@ -95,8 +95,10 @@ public:
void writeReg(int r, int v);
- void readBuffer(int16 *buffer, int length);
bool isStereo() const { return _type != Config::kOpl2; }
+
+protected:
+ void generateSamples(int16 *buffer, int length);
};
} // End of namespace DOSBox
diff --git a/audio/softsynth/opl/mame.cpp b/audio/softsynth/opl/mame.cpp
index da75ba76ba..696169be09 100644
--- a/audio/softsynth/opl/mame.cpp
+++ b/audio/softsynth/opl/mame.cpp
@@ -31,6 +31,8 @@
#include "mame.h"
+#include "audio/mixer.h"
+#include "common/system.h"
#include "common/textconsole.h"
#include "common/util.h"
@@ -46,15 +48,19 @@ namespace OPL {
namespace MAME {
OPL::~OPL() {
+ stop();
MAME::OPLDestroy(_opl);
_opl = 0;
}
-bool OPL::init(int rate) {
- if (_opl)
+bool OPL::init() {
+ if (_opl) {
+ stopCallbacks();
MAME::OPLDestroy(_opl);
+ }
+
+ _opl = MAME::makeAdLibOPL(g_system->getMixer()->getOutputRate());
- _opl = MAME::makeAdLibOPL(rate);
return (_opl != 0);
}
@@ -74,7 +80,7 @@ void OPL::writeReg(int r, int v) {
MAME::OPLWriteReg(_opl, r, v);
}
-void OPL::readBuffer(int16 *buffer, int length) {
+void OPL::generateSamples(int16 *buffer, int length) {
MAME::YM3812UpdateOne(_opl, buffer, length);
}
diff --git a/audio/softsynth/opl/mame.h b/audio/softsynth/opl/mame.h
index bd479d9e45..67d80bb193 100644
--- a/audio/softsynth/opl/mame.h
+++ b/audio/softsynth/opl/mame.h
@@ -174,14 +174,14 @@ void YM3812UpdateOne(FM_OPL *OPL, int16 *buffer, int length);
FM_OPL *makeAdLibOPL(int rate);
// OPL API implementation
-class OPL : public ::OPL::OPL {
+class OPL : public ::OPL::EmulatedOPL {
private:
FM_OPL *_opl;
public:
OPL() : _opl(0) {}
~OPL();
- bool init(int rate);
+ bool init();
void reset();
void write(int a, int v);
@@ -189,8 +189,10 @@ public:
void writeReg(int r, int v);
- void readBuffer(int16 *buffer, int length);
bool isStereo() const { return false; }
+
+protected:
+ void generateSamples(int16 *buffer, int length);
};
} // End of namespace MAME
diff --git a/configure b/configure
index 78f147f4b2..48dfdbda14 100755
--- a/configure
+++ b/configure
@@ -3556,7 +3556,7 @@ if test "$_alsa" = yes ; then
LIBS="$LIBS $ALSA_LIBS -lasound"
INCLUDES="$INCLUDES $ALSA_CFLAGS"
fi
-define_in_config_h_if_yes "$_alsa" 'USE_ALSA'
+define_in_config_if_yes "$_alsa" 'USE_ALSA'
echo "$_alsa"
#
diff --git a/engines/agos/drivers/accolade/adlib.cpp b/engines/agos/drivers/accolade/adlib.cpp
index 11edc7c5f7..d22710664d 100644
--- a/engines/agos/drivers/accolade/adlib.cpp
+++ b/engines/agos/drivers/accolade/adlib.cpp
@@ -112,9 +112,9 @@ const uint16 frequencyLookUpTableMusicDrv[12] = {
//
// I have currently not implemented dynamic channel allocation.
-class MidiDriver_Accolade_AdLib : public MidiDriver_Emulated {
+class MidiDriver_Accolade_AdLib : public MidiDriver {
public:
- MidiDriver_Accolade_AdLib(Audio::Mixer *mixer);
+ MidiDriver_Accolade_AdLib();
virtual ~MidiDriver_Accolade_AdLib();
// MidiDriver
@@ -124,20 +124,16 @@ public:
MidiChannel *allocateChannel() { return NULL; }
MidiChannel *getPercussionChannel() { return NULL; }
- // AudioStream
- bool isStereo() const { return false; }
- int getRate() const { return _mixer->getOutputRate(); }
- int getPolyphony() const { return AGOS_ADLIB_VOICES_COUNT; }
- bool hasRhythmChannel() const { return false; }
-
- // MidiDriver_Emulated
- void generateSamples(int16 *buf, int len);
+ bool isOpen() const { return _isOpen; }
+ uint32 getBaseTempo() { return 1000000 / OPL::OPL::kDefaultCallbackFrequency; }
void setVolume(byte volume);
virtual uint32 property(int prop, uint32 param);
bool setupInstruments(byte *instrumentData, uint16 instrumentDataSize, bool useMusicDrvFile);
+ void setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc);
+
private:
bool _musicDrvMode;
@@ -170,16 +166,19 @@ private:
OPL::OPL *_opl;
int _masterVolume;
+ Common::TimerManager::TimerProc _adlibTimerProc;
+ void *_adlibTimerParam;
+
+ bool _isOpen;
+
// points to a MIDI channel for each of the new voice channels
byte _voiceChannelMapping[AGOS_ADLIB_VOICES_COUNT];
// stores information about all FM voice channels
ChannelEntry _channels[AGOS_ADLIB_VOICES_COUNT];
-protected:
void onTimer();
-private:
void resetAdLib();
void resetAdLibOperatorRegisters(byte baseRegister, byte value);
void resetAdLibFMVoiceChannelRegisters(byte baseRegister, byte value);
@@ -192,8 +191,9 @@ private:
void noteOff(byte FMvoiceChannel, byte note, bool dontCheckNote);
};
-MidiDriver_Accolade_AdLib::MidiDriver_Accolade_AdLib(Audio::Mixer *mixer)
- : MidiDriver_Emulated(mixer), _masterVolume(15), _opl(0) {
+MidiDriver_Accolade_AdLib::MidiDriver_Accolade_AdLib()
+ : _masterVolume(15), _opl(0),
+ _adlibTimerProc(0), _adlibTimerParam(0), _isOpen(false) {
memset(_channelMapping, 0, sizeof(_channelMapping));
memset(_instrumentMapping, 0, sizeof(_instrumentMapping));
memset(_instrumentVolumeAdjust, 0, sizeof(_instrumentVolumeAdjust));
@@ -213,8 +213,6 @@ MidiDriver_Accolade_AdLib::~MidiDriver_Accolade_AdLib() {
}
int MidiDriver_Accolade_AdLib::open() {
- int rate = _mixer->getOutputRate();
-
// debugC(kDebugLevelAdLibDriver, "AdLib: starting driver");
_opl = OPL::Config::create(OPL::Config::kOpl2);
@@ -222,11 +220,11 @@ int MidiDriver_Accolade_AdLib::open() {
if (!_opl)
return -1;
- _opl->init(rate);
+ _opl->init();
- MidiDriver_Emulated::open();
+ _isOpen = true;
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &_mixerSoundHandle, this, -1, _mixer->kMaxChannelVolume, 0, DisposeAfterUse::NO);
+ _opl->start(new Common::Functor0Mem<void, MidiDriver_Accolade_AdLib>(this, &MidiDriver_Accolade_AdLib::onTimer));
resetAdLib();
@@ -260,9 +258,8 @@ int MidiDriver_Accolade_AdLib::open() {
}
void MidiDriver_Accolade_AdLib::close() {
- _mixer->stopHandle(_mixerSoundHandle);
-
delete _opl;
+ _isOpen = false;
}
void MidiDriver_Accolade_AdLib::setVolume(byte volume) {
@@ -271,6 +268,8 @@ void MidiDriver_Accolade_AdLib::setVolume(byte volume) {
}
void MidiDriver_Accolade_AdLib::onTimer() {
+ if (_adlibTimerProc)
+ (*_adlibTimerProc)(_adlibTimerParam);
}
void MidiDriver_Accolade_AdLib::resetAdLib() {
@@ -368,8 +367,9 @@ void MidiDriver_Accolade_AdLib::send(uint32 b) {
}
}
-void MidiDriver_Accolade_AdLib::generateSamples(int16 *data, int len) {
- _opl->readBuffer(data, len);
+void MidiDriver_Accolade_AdLib::setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc) {
+ _adlibTimerProc = timerProc;
+ _adlibTimerParam = timerParam;
}
void MidiDriver_Accolade_AdLib::noteOn(byte FMvoiceChannel, byte note, byte velocity) {
@@ -871,7 +871,7 @@ MidiDriver *MidiDriver_Accolade_AdLib_create(Common::String driverFilename) {
if (!driverData)
error("ACCOLADE-ADLIB: error during readDriver()");
- MidiDriver_Accolade_AdLib *driver = new MidiDriver_Accolade_AdLib(g_system->getMixer());
+ MidiDriver_Accolade_AdLib *driver = new MidiDriver_Accolade_AdLib();
if (driver) {
if (!driver->setupInstruments(driverData, driverDataSize, isMusicDrvFile)) {
delete driver;
diff --git a/engines/cine/sound.cpp b/engines/cine/sound.cpp
index 069a4787ac..0c788b816c 100644
--- a/engines/cine/sound.cpp
+++ b/engines/cine/sound.cpp
@@ -101,7 +101,7 @@ struct AdLibSoundInstrument {
byte amDepth;
};
-class AdLibSoundDriver : public PCSoundDriver, Audio::AudioStream {
+class AdLibSoundDriver : public PCSoundDriver {
public:
AdLibSoundDriver(Audio::Mixer *mixer);
virtual ~AdLibSoundDriver();
@@ -112,14 +112,8 @@ public:
virtual void stopChannel(int channel);
virtual void stopAll();
- // AudioStream interface
- virtual int readBuffer(int16 *buffer, const int numSamples);
- virtual bool isStereo() const { return false; }
- virtual bool endOfData() const { return false; }
- virtual int getRate() const { return _sampleRate; }
-
void initCard();
- void update(int16 *buf, int len);
+ void onTimer();
void setupInstrument(const byte *data, int channel);
void loadRegisterInstrument(const byte *data, AdLibRegisterSoundInstrument *reg);
virtual void loadInstrument(const byte *data, AdLibSoundInstrument *asi) = 0;
@@ -128,10 +122,8 @@ protected:
UpdateCallback _upCb;
void *_upRef;
- FM_OPL *_opl;
- int _sampleRate;
+ OPL::OPL *_opl;
Audio::Mixer *_mixer;
- Audio::SoundHandle _soundHandle;
byte _vibrato;
int _channelsVolumeTable[4];
@@ -282,17 +274,19 @@ void PCSoundDriver::resetChannel(int channel) {
AdLibSoundDriver::AdLibSoundDriver(Audio::Mixer *mixer)
: _upCb(0), _upRef(0), _mixer(mixer) {
- _sampleRate = _mixer->getOutputRate();
- _opl = makeAdLibOPL(_sampleRate);
+
+ _opl = OPL::Config::create();
+ if (!_opl || !_opl->init())
+ error("Failed to create OPL");
+
memset(_channelsVolumeTable, 0, sizeof(_channelsVolumeTable));
memset(_instrumentsTable, 0, sizeof(_instrumentsTable));
initCard();
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+ _opl->start(new Common::Functor0Mem<void, AdLibSoundDriver>(this, &AdLibSoundDriver::onTimer), 50);
}
AdLibSoundDriver::~AdLibSoundDriver() {
- _mixer->stopHandle(_soundHandle);
- OPLDestroy(_opl);
+ delete _opl;
}
void AdLibSoundDriver::setUpdateCallback(UpdateCallback upCb, void *ref) {
@@ -322,71 +316,52 @@ void AdLibSoundDriver::stopChannel(int channel) {
channel = 6;
}
if (ins->mode == 0 || channel == 6) {
- OPLWriteReg(_opl, 0xB0 | channel, 0);
+ _opl->writeReg(0xB0 | channel, 0);
}
if (ins->mode != 0) {
_vibrato &= ~(1 << (10 - ins->channel));
- OPLWriteReg(_opl, 0xBD, _vibrato);
+ _opl->writeReg(0xBD, _vibrato);
}
}
void AdLibSoundDriver::stopAll() {
int i;
for (i = 0; i < 18; ++i) {
- OPLWriteReg(_opl, 0x40 | _operatorsTable[i], 63);
+ _opl->writeReg(0x40 | _operatorsTable[i], 63);
}
for (i = 0; i < 9; ++i) {
- OPLWriteReg(_opl, 0xB0 | i, 0);
+ _opl->writeReg(0xB0 | i, 0);
}
- OPLWriteReg(_opl, 0xBD, 0);
-}
-
-int AdLibSoundDriver::readBuffer(int16 *buffer, const int numSamples) {
- update(buffer, numSamples);
- return numSamples;
+ _opl->writeReg(0xBD, 0);
}
void AdLibSoundDriver::initCard() {
_vibrato = 0x20;
- OPLWriteReg(_opl, 0xBD, _vibrato);
- OPLWriteReg(_opl, 0x08, 0x40);
+ _opl->writeReg(0xBD, _vibrato);
+ _opl->writeReg(0x08, 0x40);
static const int oplRegs[] = { 0x40, 0x60, 0x80, 0x20, 0xE0 };
for (int i = 0; i < 9; ++i) {
- OPLWriteReg(_opl, 0xB0 | i, 0);
+ _opl->writeReg(0xB0 | i, 0);
}
for (int i = 0; i < 9; ++i) {
- OPLWriteReg(_opl, 0xC0 | i, 0);
+ _opl->writeReg(0xC0 | i, 0);
}
for (int j = 0; j < 5; j++) {
for (int i = 0; i < 18; ++i) {
- OPLWriteReg(_opl, oplRegs[j] | _operatorsTable[i], 0);
+ _opl->writeReg(oplRegs[j] | _operatorsTable[i], 0);
}
}
- OPLWriteReg(_opl, 1, 0x20);
- OPLWriteReg(_opl, 1, 0);
+ _opl->writeReg(1, 0x20);
+ _opl->writeReg(1, 0);
}
-void AdLibSoundDriver::update(int16 *buf, int len) {
- static int samplesLeft = 0;
- while (len != 0) {
- int count = samplesLeft;
- if (count > len) {
- count = len;
- }
- samplesLeft -= count;
- len -= count;
- YM3812UpdateOne(_opl, buf, count);
- if (samplesLeft == 0) {
- if (_upCb) {
- (*_upCb)(_upRef);
- }
- samplesLeft = _sampleRate / 50;
- }
- buf += count;
+void AdLibSoundDriver::onTimer() {
+ if (_upCb) {
+ (*_upCb)(_upRef);
}
}
@@ -408,32 +383,32 @@ void AdLibSoundDriver::setupInstrument(const byte *data, int channel) {
if (ins->mode == 0 || ins->channel == 6) {
reg = &ins->regMod;
- OPLWriteReg(_opl, 0x20 | mod, reg->vibrato);
+ _opl->writeReg(0x20 | mod, reg->vibrato);
if (reg->freqMod) {
tmp = reg->outputLevel & 0x3F;
} else {
tmp = (63 - (reg->outputLevel & 0x3F)) * _channelsVolumeTable[channel];
tmp = 63 - (2 * tmp + 127) / (2 * 127);
}
- OPLWriteReg(_opl, 0x40 | mod, tmp | (reg->keyScaling << 6));
- OPLWriteReg(_opl, 0x60 | mod, reg->attackDecay);
- OPLWriteReg(_opl, 0x80 | mod, reg->sustainRelease);
+ _opl->writeReg(0x40 | mod, tmp | (reg->keyScaling << 6));
+ _opl->writeReg(0x60 | mod, reg->attackDecay);
+ _opl->writeReg(0x80 | mod, reg->sustainRelease);
if (ins->mode != 0) {
- OPLWriteReg(_opl, 0xC0 | ins->channel, reg->feedbackStrength);
+ _opl->writeReg(0xC0 | ins->channel, reg->feedbackStrength);
} else {
- OPLWriteReg(_opl, 0xC0 | channel, reg->feedbackStrength);
+ _opl->writeReg(0xC0 | channel, reg->feedbackStrength);
}
- OPLWriteReg(_opl, 0xE0 | mod, ins->waveSelectMod);
+ _opl->writeReg(0xE0 | mod, ins->waveSelectMod);
}
reg = &ins->regCar;
- OPLWriteReg(_opl, 0x20 | car, reg->vibrato);
+ _opl->writeReg(0x20 | car, reg->vibrato);
tmp = (63 - (reg->outputLevel & 0x3F)) * _channelsVolumeTable[channel];
tmp = 63 - (2 * tmp + 127) / (2 * 127);
- OPLWriteReg(_opl, 0x40 | car, tmp | (reg->keyScaling << 6));
- OPLWriteReg(_opl, 0x60 | car, reg->attackDecay);
- OPLWriteReg(_opl, 0x80 | car, reg->sustainRelease);
- OPLWriteReg(_opl, 0xE0 | car, ins->waveSelectCar);
+ _opl->writeReg(0x40 | car, tmp | (reg->keyScaling << 6));
+ _opl->writeReg(0x60 | car, reg->attackDecay);
+ _opl->writeReg(0x80 | car, reg->sustainRelease);
+ _opl->writeReg(0xE0 | car, ins->waveSelectCar);
}
void AdLibSoundDriver::loadRegisterInstrument(const byte *data, AdLibRegisterSoundInstrument *reg) {
@@ -490,16 +465,16 @@ void AdLibSoundDriverINS::setChannelFrequency(int channel, int frequency) {
if (channel == 6)
oct = 0;
freq = _freqTable[note % 12];
- OPLWriteReg(_opl, 0xA0 | channel, freq);
+ _opl->writeReg(0xA0 | channel, freq);
freq = (oct << 2) | ((freq & 0x300) >> 8);
if (ins->mode == 0) {
freq |= 0x20;
}
- OPLWriteReg(_opl, 0xB0 | channel, freq);
+ _opl->writeReg(0xB0 | channel, freq);
}
if (ins->mode != 0) {
_vibrato |= 1 << (10 - ins->channel);
- OPLWriteReg(_opl, 0xBD, _vibrato);
+ _opl->writeReg(0xBD, _vibrato);
}
}
@@ -515,16 +490,16 @@ void AdLibSoundDriverINS::playSample(const byte *data, int size, int channel, in
if (ins->mode == 0 || channel == 6) {
uint16 note = 12;
int freq = _freqTable[note % 12];
- OPLWriteReg(_opl, 0xA0 | channel, freq);
+ _opl->writeReg(0xA0 | channel, freq);
freq = ((note / 12) << 2) | ((freq & 0x300) >> 8);
if (ins->mode == 0) {
freq |= 0x20;
}
- OPLWriteReg(_opl, 0xB0 | channel, freq);
+ _opl->writeReg(0xB0 | channel, freq);
}
if (ins->mode != 0) {
_vibrato |= 1 << (10 - ins->channel);
- OPLWriteReg(_opl, 0xBD, _vibrato);
+ _opl->writeReg(0xBD, _vibrato);
}
}
@@ -562,15 +537,15 @@ void AdLibSoundDriverADL::setChannelFrequency(int channel, int frequency) {
}
freq = _freqTable[note % 12];
- OPLWriteReg(_opl, 0xA0 | channel, freq);
+ _opl->writeReg(0xA0 | channel, freq);
freq = (oct << 2) | ((freq & 0x300) >> 8);
if (ins->mode == 0) {
freq |= 0x20;
}
- OPLWriteReg(_opl, 0xB0 | channel, freq);
+ _opl->writeReg(0xB0 | channel, freq);
if (ins->mode != 0) {
_vibrato |= 1 << (10 - channel);
- OPLWriteReg(_opl, 0xBD, _vibrato);
+ _opl->writeReg(0xBD, _vibrato);
}
}
@@ -580,11 +555,11 @@ void AdLibSoundDriverADL::playSample(const byte *data, int size, int channel, in
setupInstrument(data, channel);
AdLibSoundInstrument *ins = &_instrumentsTable[channel];
if (ins->mode != 0 && ins->channel == 6) {
- OPLWriteReg(_opl, 0xB0 | channel, 0);
+ _opl->writeReg(0xB0 | channel, 0);
}
if (ins->mode != 0) {
_vibrato &= ~(1 << (10 - ins->channel));
- OPLWriteReg(_opl, 0xBD, _vibrato);
+ _opl->writeReg(0xBD, _vibrato);
}
if (ins->mode != 0) {
channel = ins->channel;
@@ -599,15 +574,15 @@ void AdLibSoundDriverADL::playSample(const byte *data, int size, int channel, in
note = ins->amDepth;
}
int freq = _freqTable[note % 12];
- OPLWriteReg(_opl, 0xA0 | channel, freq);
+ _opl->writeReg(0xA0 | channel, freq);
freq = ((note / 12) << 2) | ((freq & 0x300) >> 8);
if (ins->mode == 0) {
freq |= 0x20;
}
- OPLWriteReg(_opl, 0xB0 | channel, freq);
+ _opl->writeReg(0xB0 | channel, freq);
if (ins->mode != 0) {
_vibrato |= 1 << (10 - channel);
- OPLWriteReg(_opl, 0xBD, _vibrato);
+ _opl->writeReg(0xBD, _vibrato);
}
}
diff --git a/engines/cruise/sound.cpp b/engines/cruise/sound.cpp
index 0b0fab8c4a..f57435f4f7 100644
--- a/engines/cruise/sound.cpp
+++ b/engines/cruise/sound.cpp
@@ -108,7 +108,7 @@ struct VolumeEntry {
int adjusted;
};
-class AdLibSoundDriver : public PCSoundDriver, Audio::AudioStream {
+class AdLibSoundDriver : public PCSoundDriver {
public:
AdLibSoundDriver(Audio::Mixer *mixer);
virtual ~AdLibSoundDriver();
@@ -118,14 +118,8 @@ public:
virtual void stopChannel(int channel);
virtual void stopAll();
- // AudioStream interface
- virtual int readBuffer(int16 *buffer, const int numSamples);
- virtual bool isStereo() const { return false; }
- virtual bool endOfData() const { return false; }
- virtual int getRate() const { return _sampleRate; }
-
void initCard();
- void update(int16 *buf, int len);
+ void onTimer();
void setupInstrument(const byte *data, int channel);
void setupInstrument(const AdLibSoundInstrument *ins, int channel);
void loadRegisterInstrument(const byte *data, AdLibRegisterSoundInstrument *reg);
@@ -135,10 +129,8 @@ public:
void adjustVolume(int channel, int volume);
protected:
- FM_OPL *_opl;
- int _sampleRate;
+ OPL::OPL *_opl;
Audio::Mixer *_mixer;
- Audio::SoundHandle _soundHandle;
byte _vibrato;
VolumeEntry _channelsVolumeTable[5];
@@ -302,8 +294,9 @@ void PCSoundDriver::syncSounds() {
AdLibSoundDriver::AdLibSoundDriver(Audio::Mixer *mixer)
: _mixer(mixer) {
- _sampleRate = _mixer->getOutputRate();
- _opl = makeAdLibOPL(_sampleRate);
+ _opl = OPL::Config::create();
+ if (!_opl || !_opl->init())
+ error("Failed to create OPL");
for (int i = 0; i < 5; ++i) {
_channelsVolumeTable[i].original = 0;
@@ -311,15 +304,15 @@ AdLibSoundDriver::AdLibSoundDriver(Audio::Mixer *mixer)
}
memset(_instrumentsTable, 0, sizeof(_instrumentsTable));
initCard();
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
_musicVolume = ConfMan.getBool("music_mute") ? 0 : MIN(255, ConfMan.getInt("music_volume"));
_sfxVolume = ConfMan.getBool("sfx_mute") ? 0 : MIN(255, ConfMan.getInt("sfx_volume"));
+
+ _opl->start(new Common::Functor0Mem<void, AdLibSoundDriver>(this, &AdLibSoundDriver::onTimer), 50);
}
AdLibSoundDriver::~AdLibSoundDriver() {
- _mixer->stopHandle(_soundHandle);
- OPLDestroy(_opl);
+ delete _opl;
}
void AdLibSoundDriver::syncSounds() {
@@ -368,70 +361,51 @@ void AdLibSoundDriver::stopChannel(int channel) {
channel = 6;
}
if (ins->mode == 0 || channel == 6) {
- OPLWriteReg(_opl, 0xB0 | channel, 0);
+ _opl->writeReg(0xB0 | channel, 0);
}
if (ins->mode != 0) {
_vibrato &= ~(1 << (10 - ins->channel));
- OPLWriteReg(_opl, 0xBD, _vibrato);
+ _opl->writeReg(0xBD, _vibrato);
}
}
void AdLibSoundDriver::stopAll() {
for (int i = 0; i < 18; ++i)
- OPLWriteReg(_opl, 0x40 | _operatorsTable[i], 63);
+ _opl->writeReg(0x40 | _operatorsTable[i], 63);
for (int i = 0; i < 9; ++i)
- OPLWriteReg(_opl, 0xB0 | i, 0);
-
- OPLWriteReg(_opl, 0xBD, 0);
-}
+ _opl->writeReg(0xB0 | i, 0);
-int AdLibSoundDriver::readBuffer(int16 *buffer, const int numSamples) {
- update(buffer, numSamples);
- return numSamples;
+ _opl->writeReg(0xBD, 0);
}
void AdLibSoundDriver::initCard() {
_vibrato = 0x20;
- OPLWriteReg(_opl, 0xBD, _vibrato);
- OPLWriteReg(_opl, 0x08, 0x40);
+ _opl->writeReg(0xBD, _vibrato);
+ _opl->writeReg(0x08, 0x40);
static const int oplRegs[] = { 0x40, 0x60, 0x80, 0x20, 0xE0 };
for (int i = 0; i < 9; ++i) {
- OPLWriteReg(_opl, 0xB0 | i, 0);
+ _opl->writeReg(0xB0 | i, 0);
}
for (int i = 0; i < 9; ++i) {
- OPLWriteReg(_opl, 0xC0 | i, 0);
+ _opl->writeReg(0xC0 | i, 0);
}
for (int j = 0; j < 5; j++) {
for (int i = 0; i < 18; ++i) {
- OPLWriteReg(_opl, oplRegs[j] | _operatorsTable[i], 0);
+ _opl->writeReg(oplRegs[j] | _operatorsTable[i], 0);
}
}
- OPLWriteReg(_opl, 1, 0x20);
- OPLWriteReg(_opl, 1, 0);
+ _opl->writeReg(1, 0x20);
+ _opl->writeReg(1, 0);
}
-void AdLibSoundDriver::update(int16 *buf, int len) {
- static int samplesLeft = 0;
- while (len != 0) {
- int count = samplesLeft;
- if (count > len) {
- count = len;
- }
- samplesLeft -= count;
- len -= count;
- YM3812UpdateOne(_opl, buf, count);
- if (samplesLeft == 0) {
- if (_upCb) {
- (*_upCb)(_upRef);
- }
- samplesLeft = _sampleRate / 50;
- }
- buf += count;
+void AdLibSoundDriver::onTimer() {
+ if (_upCb) {
+ (*_upCb)(_upRef);
}
}
@@ -457,32 +431,32 @@ void AdLibSoundDriver::setupInstrument(const AdLibSoundInstrument *ins, int chan
if (ins->mode == 0 || ins->channel == 6) {
reg = &ins->regMod;
- OPLWriteReg(_opl, 0x20 | mod, reg->vibrato);
+ _opl->writeReg(0x20 | mod, reg->vibrato);
if (reg->freqMod) {
tmp = reg->outputLevel & 0x3F;
} else {
tmp = (63 - (reg->outputLevel & 0x3F)) * _channelsVolumeTable[channel].adjusted;
tmp = 63 - (2 * tmp + 127) / (2 * 127);
}
- OPLWriteReg(_opl, 0x40 | mod, tmp | (reg->keyScaling << 6));
- OPLWriteReg(_opl, 0x60 | mod, reg->attackDecay);
- OPLWriteReg(_opl, 0x80 | mod, reg->sustainRelease);
+ _opl->writeReg(0x40 | mod, tmp | (reg->keyScaling << 6));
+ _opl->writeReg(0x60 | mod, reg->attackDecay);
+ _opl->writeReg(0x80 | mod, reg->sustainRelease);
if (ins->mode != 0) {
- OPLWriteReg(_opl, 0xC0 | ins->channel, reg->feedbackStrength);
+ _opl->writeReg(0xC0 | ins->channel, reg->feedbackStrength);
} else {
- OPLWriteReg(_opl, 0xC0 | channel, reg->feedbackStrength);
+ _opl->writeReg(0xC0 | channel, reg->feedbackStrength);
}
- OPLWriteReg(_opl, 0xE0 | mod, ins->waveSelectMod);
+ _opl->writeReg(0xE0 | mod, ins->waveSelectMod);
}
reg = &ins->regCar;
- OPLWriteReg(_opl, 0x20 | car, reg->vibrato);
+ _opl->writeReg(0x20 | car, reg->vibrato);
tmp = (63 - (reg->outputLevel & 0x3F)) * _channelsVolumeTable[channel].adjusted;
tmp = 63 - (2 * tmp + 127) / (2 * 127);
- OPLWriteReg(_opl, 0x40 | car, tmp | (reg->keyScaling << 6));
- OPLWriteReg(_opl, 0x60 | car, reg->attackDecay);
- OPLWriteReg(_opl, 0x80 | car, reg->sustainRelease);
- OPLWriteReg(_opl, 0xE0 | car, ins->waveSelectCar);
+ _opl->writeReg(0x40 | car, tmp | (reg->keyScaling << 6));
+ _opl->writeReg(0x60 | car, reg->attackDecay);
+ _opl->writeReg(0x80 | car, reg->sustainRelease);
+ _opl->writeReg(0xE0 | car, ins->waveSelectCar);
}
void AdLibSoundDriver::loadRegisterInstrument(const byte *data, AdLibRegisterSoundInstrument *reg) {
@@ -551,15 +525,15 @@ void AdLibSoundDriverADL::setChannelFrequency(int channel, int frequency) {
}
freq = _freqTable[note % 12];
- OPLWriteReg(_opl, 0xA0 | channel, freq);
+ _opl->writeReg(0xA0 | channel, freq);
freq = ((note / 12) << 2) | ((freq & 0x300) >> 8);
if (ins->mode == 0) {
freq |= 0x20;
}
- OPLWriteReg(_opl, 0xB0 | channel, freq);
+ _opl->writeReg(0xB0 | channel, freq);
if (ins->mode != 0) {
_vibrato |= 1 << (10 - channel);
- OPLWriteReg(_opl, 0xBD, _vibrato);
+ _opl->writeReg(0xBD, _vibrato);
}
}
@@ -570,11 +544,11 @@ void AdLibSoundDriverADL::playSample(const byte *data, int size, int channel, in
setupInstrument(data, channel);
AdLibSoundInstrument *ins = &_instrumentsTable[channel];
if (ins->mode != 0 && ins->channel == 6) {
- OPLWriteReg(_opl, 0xB0 | channel, 0);
+ _opl->writeReg(0xB0 | channel, 0);
}
if (ins->mode != 0) {
_vibrato &= ~(1 << (10 - ins->channel));
- OPLWriteReg(_opl, 0xBD, _vibrato);
+ _opl->writeReg(0xBD, _vibrato);
}
if (ins->mode != 0) {
channel = ins->channel;
@@ -589,15 +563,15 @@ void AdLibSoundDriverADL::playSample(const byte *data, int size, int channel, in
note = ins->amDepth;
}
int freq = _freqTable[note % 12];
- OPLWriteReg(_opl, 0xA0 | channel, freq);
+ _opl->writeReg(0xA0 | channel, freq);
freq = ((note / 12) << 2) | ((freq & 0x300) >> 8);
if (ins->mode == 0) {
freq |= 0x20;
}
- OPLWriteReg(_opl, 0xB0 | channel, freq);
+ _opl->writeReg(0xB0 | channel, freq);
if (ins->mode != 0) {
_vibrato |= 1 << (10 - channel);
- OPLWriteReg(_opl, 0xBD, _vibrato);
+ _opl->writeReg(0xBD, _vibrato);
}
}
diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp
index 5ab3271a8f..24bdb858d8 100644
--- a/engines/gob/gob.cpp
+++ b/engines/gob/gob.cpp
@@ -389,6 +389,9 @@ void GobEngine::syncSoundSettings() {
Engine::syncSoundSettings();
_init->updateConfig();
+
+ if (_sound)
+ _sound->adlibSyncVolume();
}
void GobEngine::pauseGame() {
diff --git a/engines/gob/sound/adlib.cpp b/engines/gob/sound/adlib.cpp
index 65b43cae7a..995cc48824 100644
--- a/engines/gob/sound/adlib.cpp
+++ b/engines/gob/sound/adlib.cpp
@@ -37,6 +37,28 @@ static const int kPitchTomToSnare = 7;
static const int kPitchSnareDrum = kPitchTom + kPitchTomToSnare;
+// Attenuation map for GUI volume slider
+// Note: no volume control in the original engine
+const uint8 AdLib::kVolumeTable[Audio::Mixer::kMaxMixerVolume + 1] = {
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 62, 61, 59, 57, 56, 55,
+ 53, 52, 51, 50, 49, 48, 47, 46, 46, 45, 44, 43, 43, 42, 41, 41,
+ 40, 39, 39, 38, 38, 37, 37, 36, 36, 35, 35, 34, 34, 33, 33, 33,
+ 32, 32, 31, 31, 31, 30, 30, 30, 29, 29, 29, 28, 28, 28, 27, 27,
+ 27, 26, 26, 26, 26, 25, 25, 25, 24, 24, 24, 24, 23, 23, 23, 23,
+ 22, 22, 22, 22, 21, 21, 21, 21, 21, 20, 20, 20, 20, 19, 19, 19,
+ 19, 19, 18, 18, 18, 18, 18, 18, 17, 17, 17, 17, 17, 16, 16, 16,
+ 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 13,
+ 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11,
+ 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9,
+ 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+ 0
+};
+
// Is the operator a modulator (0) or a carrier (1)?
const uint8 AdLib::kOperatorType[kOperatorCount] = {
0, 0, 0, 1, 1, 1,
@@ -93,23 +115,20 @@ const uint16 AdLib::kHihatParams [kParamCount] = {
0, 1, 0, 15, 11, 0, 7, 5, 0, 0, 0, 0, 0, 0 };
-AdLib::AdLib(Audio::Mixer &mixer) : _mixer(&mixer), _opl(0),
- _toPoll(0), _repCount(0), _first(true), _playing(false), _ended(true) {
-
- _rate = _mixer->getOutputRate();
+AdLib::AdLib(Audio::Mixer &mixer, int callbackFreq) : _mixer(&mixer), _opl(0),
+ _toPoll(0), _repCount(0), _first(true), _playing(false), _ended(true), _volume(0) {
initFreqs();
createOPL();
initOPL();
- _mixer->playStream(Audio::Mixer::kMusicSoundType, &_handle,
- this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+ syncVolume();
+
+ _opl->start(new Common::Functor0Mem<void, AdLib>(this, &AdLib::onTimer), callbackFreq);
}
AdLib::~AdLib() {
- _mixer->stopHandle(_handle);
-
delete _opl;
}
@@ -136,46 +155,38 @@ void AdLib::createOPL() {
}
_opl = OPL::Config::create(OPL::Config::parse(oplDriver), OPL::Config::kOpl2);
- if (!_opl || !_opl->init(_rate)) {
+ if (!_opl || !_opl->init()) {
delete _opl;
error("Could not create an AdLib emulator");
}
}
-int AdLib::readBuffer(int16 *buffer, const int numSamples) {
+void AdLib::onTimer() {
Common::StackLock slock(_mutex);
- // Nothing to do, fill with silence
- if (!_playing) {
- memset(buffer, 0, numSamples * sizeof(int16));
- return numSamples;
+ // Nothing to do
+ if (!_playing)
+ return;
+
+ // Check if there's anything to do on this step
+ // If not, decrease the poll number and move on
+ if (_toPoll > 0) {
+ _toPoll--;
+ return;
}
- // Read samples from the OPL, polling in more music when necessary
- uint32 samples = numSamples;
- while (samples && _playing) {
- if (_toPoll) {
- const uint32 render = MIN(samples, _toPoll);
-
- _opl->readBuffer(buffer, render);
-
- buffer += render;
- samples -= render;
- _toPoll -= render;
-
- } else {
- // Song ended, fill the rest with silence
- if (_ended) {
- memset(buffer, 0, samples * sizeof(int16));
- samples = 0;
- break;
- }
-
- // Poll more music
- _toPoll = pollMusic(_first);
- _first = false;
+ // Poll until we have to delay until the next poll
+ while (_toPoll == 0 && _playing) {
+ // Song ended, break out
+ if (_ended) {
+ _toPoll = 0;
+ break;
}
+
+ // Poll more music
+ _toPoll = pollMusic(_first);
+ _first = false;
}
// Song ended, loop if requested
@@ -195,24 +206,6 @@ int AdLib::readBuffer(int16 *buffer, const int numSamples) {
} else
_playing = false;
}
-
- return numSamples;
-}
-
-bool AdLib::isStereo() const {
- return _opl->isStereo();
-}
-
-bool AdLib::endOfData() const {
- return !_playing;
-}
-
-bool AdLib::endOfStream() const {
- return false;
-}
-
-int AdLib::getRate() const {
- return _rate;
}
bool AdLib::isPlaying() const {
@@ -231,10 +224,6 @@ void AdLib::setRepeating(int32 repCount) {
_repCount = repCount;
}
-uint32 AdLib::getSamplesPerSecond() const {
- return _rate * (isStereo() ? 2 : 1);
-}
-
void AdLib::startPlay() {
Common::StackLock slock(_mutex);
@@ -442,6 +431,13 @@ void AdLib::writeKeyScaleLevelVolume(uint8 oper) {
volume = (63 - (_operatorParams[oper][kParamLevel] & 0x3F)) * _operatorVolume[oper];
volume = 63 - ((2 * volume + kMaxVolume) / (2 * kMaxVolume));
+ // Adjust carriers for GUI volume slider
+ if (kOperatorType[oper] == 1) {
+ volume += kVolumeTable[_volume];
+ if (volume > 63)
+ volume = 63;
+ }
+
uint8 keyScale = _operatorParams[oper][kParamKeyScaleLevel] << 6;
writeOPL(0x40 + kOperatorOffset[oper], volume | keyScale);
@@ -639,4 +635,23 @@ void AdLib::setFreq(uint8 voice, uint16 note, bool on) {
writeOPL(0xB0 + voice, value);
}
+void AdLib::setTimerFrequency(int timerFrequency) {
+ _opl->setCallbackFrequency(timerFrequency);
+}
+
+void AdLib::syncVolume() {
+ Common::StackLock slock(_mutex);
+
+ bool mute = false;
+ if (ConfMan.hasKey("mute"))
+ mute = ConfMan.getBool("mute");
+
+ _volume = (mute ? 0 : ConfMan.getInt("music_volume"));
+
+ if (_playing) {
+ for(int i = 0; i < kOperatorCount; i++)
+ writeKeyScaleLevelVolume(i);
+ }
+}
+
} // End of namespace Gob
diff --git a/engines/gob/sound/adlib.h b/engines/gob/sound/adlib.h
index 8071249374..28ebf9d998 100644
--- a/engines/gob/sound/adlib.h
+++ b/engines/gob/sound/adlib.h
@@ -35,9 +35,9 @@ namespace OPL {
namespace Gob {
/** Base class for a player of an AdLib music format. */
-class AdLib : public Audio::AudioStream {
+class AdLib {
public:
- AdLib(Audio::Mixer &mixer);
+ AdLib(Audio::Mixer &mixer, int callbackFrequency);
virtual ~AdLib();
bool isPlaying() const; ///< Are we currently playing?
@@ -53,13 +53,7 @@ public:
void startPlay();
void stopPlay();
-
-// AudioStream API
- int readBuffer(int16 *buffer, const int numSamples);
- bool isStereo() const;
- bool endOfData() const;
- bool endOfStream() const;
- int getRate() const;
+ void syncVolume();
protected:
enum kVoice {
@@ -120,8 +114,6 @@ protected:
static const int kOPLMidC = 48; ///< A mid C for the OPL.
- /** Return the number of samples per second. */
- uint32 getSamplesPerSecond() const;
/** Write a value into an OPL register. */
void writeOPL(byte reg, byte val);
@@ -135,7 +127,7 @@ protected:
/** The callback function that's called for polling more AdLib commands.
*
* @param first Is this the first poll since the start of the song?
- * @return The number of samples until the next poll.
+ * @return The number of ticks until the next poll.
*/
virtual uint32 pollMusic(bool first) = 0;
@@ -207,7 +199,14 @@ protected:
/** Switch a voice off. */
void noteOff(uint8 voice);
+ /**
+ * Set the OPL timer frequency
+ */
+ void setTimerFrequency(int timerFrequency);
+
private:
+ static const uint8 kVolumeTable[Audio::Mixer::kMaxMixerVolume + 1];
+
static const uint8 kOperatorType [kOperatorCount];
static const uint8 kOperatorOffset[kOperatorCount];
static const uint8 kOperatorVoice [kOperatorCount];
@@ -227,11 +226,12 @@ private:
Audio::Mixer *_mixer;
- Audio::SoundHandle _handle;
OPL::OPL *_opl;
Common::Mutex _mutex;
+ int _volume;
+
uint32 _rate;
uint32 _toPoll;
@@ -300,6 +300,11 @@ private:
void changePitch(uint8 voice, uint16 pitchBend);
void setFreq(uint8 voice, uint16 note, bool on);
+
+ /**
+ * Callback function for OPL
+ */
+ void onTimer();
};
} // End of namespace Gob
diff --git a/engines/gob/sound/adlplayer.cpp b/engines/gob/sound/adlplayer.cpp
index 384a928360..e5a276032b 100644
--- a/engines/gob/sound/adlplayer.cpp
+++ b/engines/gob/sound/adlplayer.cpp
@@ -28,7 +28,7 @@
namespace Gob {
-ADLPlayer::ADLPlayer(Audio::Mixer &mixer) : AdLib(mixer),
+ADLPlayer::ADLPlayer(Audio::Mixer &mixer) : AdLib(mixer, 1000),
_songData(0), _songDataSize(0), _playPos(0) {
}
@@ -135,14 +135,7 @@ uint32 ADLPlayer::pollMusic(bool first) {
if (delay & 0x80)
delay = ((delay & 3) << 8) | *_playPos++;
- return getSampleDelay(delay);
-}
-
-uint32 ADLPlayer::getSampleDelay(uint16 delay) const {
- if (delay == 0)
- return 0;
-
- return ((uint32)delay * getSamplesPerSecond()) / 1000;
+ return delay;
}
void ADLPlayer::rewind() {
diff --git a/engines/gob/sound/adlplayer.h b/engines/gob/sound/adlplayer.h
index 3edd238343..bd43cc091c 100644
--- a/engines/gob/sound/adlplayer.h
+++ b/engines/gob/sound/adlplayer.h
@@ -76,8 +76,6 @@ private:
bool readHeader (Common::SeekableReadStream &adl, int &timbreCount);
bool readTimbres (Common::SeekableReadStream &adl, int timbreCount);
bool readSongData(Common::SeekableReadStream &adl);
-
- uint32 getSampleDelay(uint16 delay) const;
};
} // End of namespace Gob
diff --git a/engines/gob/sound/musplayer.cpp b/engines/gob/sound/musplayer.cpp
index 7001a5724b..2c0330e70a 100644
--- a/engines/gob/sound/musplayer.cpp
+++ b/engines/gob/sound/musplayer.cpp
@@ -27,7 +27,7 @@
namespace Gob {
-MUSPlayer::MUSPlayer(Audio::Mixer &mixer) : AdLib(mixer),
+MUSPlayer::MUSPlayer(Audio::Mixer &mixer) : AdLib(mixer, 60),
_songData(0), _songDataSize(0), _playPos(0), _songID(0) {
}
@@ -43,15 +43,6 @@ void MUSPlayer::unload() {
unloadMUS();
}
-uint32 MUSPlayer::getSampleDelay(uint16 delay) const {
- if (delay == 0)
- return 0;
-
- uint32 freq = (_ticksPerBeat * _tempo) / 60;
-
- return ((uint32)delay * getSamplesPerSecond()) / freq;
-}
-
void MUSPlayer::skipToTiming() {
while (*_playPos < 0x80)
_playPos++;
@@ -66,8 +57,12 @@ uint32 MUSPlayer::pollMusic(bool first) {
return 0;
}
- if (first)
- return getSampleDelay(*_playPos++);
+ if (first) {
+ // Set the timer frequency on first run.
+ // Do not set it in rewind() for thread safety reasons.
+ setTimerFrequency((_ticksPerBeat * _tempo) / 60);
+ return *_playPos++;
+ }
uint16 delay = 0;
while (delay == 0) {
@@ -100,6 +95,7 @@ uint32 MUSPlayer::pollMusic(bool first) {
uint32 denom = *_playPos++;
_tempo = _baseTempo * num + ((_baseTempo * denom) >> 7);
+ setTimerFrequency((_ticksPerBeat * _tempo) / 60);
_playPos++;
} else {
@@ -182,7 +178,7 @@ uint32 MUSPlayer::pollMusic(bool first) {
delay += *_playPos++;
}
- return getSampleDelay(delay);
+ return delay;
}
void MUSPlayer::rewind() {
diff --git a/engines/gob/sound/musplayer.h b/engines/gob/sound/musplayer.h
index c76c5aab38..7c1189b84b 100644
--- a/engines/gob/sound/musplayer.h
+++ b/engines/gob/sound/musplayer.h
@@ -97,7 +97,6 @@ private:
bool readMUSHeader(Common::SeekableReadStream &mus);
bool readMUSSong (Common::SeekableReadStream &mus);
- uint32 getSampleDelay(uint16 delay) const;
void setInstrument(uint8 voice, uint8 instrument);
void skipToTiming();
diff --git a/engines/gob/sound/sound.cpp b/engines/gob/sound/sound.cpp
index d2b2d3d6e8..9b19b9c52c 100644
--- a/engines/gob/sound/sound.cpp
+++ b/engines/gob/sound/sound.cpp
@@ -425,6 +425,16 @@ int32 Sound::adlibGetRepeating() const {
return false;
}
+void Sound::adlibSyncVolume() {
+ if (!_hasAdLib)
+ return;
+
+ if (_adlPlayer)
+ _adlPlayer->syncVolume();
+ if (_mdyPlayer)
+ _mdyPlayer->syncVolume();
+}
+
void Sound::adlibSetRepeating(int32 repCount) {
if (!_hasAdLib)
return;
diff --git a/engines/gob/sound/sound.h b/engines/gob/sound/sound.h
index c959959755..6ebc323b18 100644
--- a/engines/gob/sound/sound.h
+++ b/engines/gob/sound/sound.h
@@ -96,6 +96,7 @@ public:
int32 adlibGetRepeating() const;
void adlibSetRepeating(int32 repCount);
+ void adlibSyncVolume();
// Infogrames
diff --git a/engines/kyra/sound_adlib.cpp b/engines/kyra/sound_adlib.cpp
index c0e0f67b8e..1d741d8bd0 100644
--- a/engines/kyra/sound_adlib.cpp
+++ b/engines/kyra/sound_adlib.cpp
@@ -55,7 +55,7 @@
namespace Kyra {
-class AdLibDriver : public Audio::AudioStream {
+class AdLibDriver {
public:
AdLibDriver(Audio::Mixer *mixer, int version);
~AdLibDriver();
@@ -70,34 +70,6 @@ public:
void callback();
- // AudioStream API
- int readBuffer(int16 *buffer, const int numSamples) {
- int32 samplesLeft = numSamples;
- memset(buffer, 0, sizeof(int16) * numSamples);
- while (samplesLeft) {
- if (!_samplesTillCallback) {
- callback();
- _samplesTillCallback = _samplesPerCallback;
- _samplesTillCallbackRemainder += _samplesPerCallbackRemainder;
- if (_samplesTillCallbackRemainder >= CALLBACKS_PER_SECOND) {
- _samplesTillCallback++;
- _samplesTillCallbackRemainder -= CALLBACKS_PER_SECOND;
- }
- }
-
- int32 render = MIN(samplesLeft, _samplesTillCallback);
- samplesLeft -= render;
- _samplesTillCallback -= render;
- YM3812UpdateOne(_adlib, buffer, render);
- buffer += render;
- }
- return numSamples;
- }
-
- bool isStereo() const { return false; }
- bool endOfData() const { return false; }
- int getRate() const { return _mixer->getOutputRate(); }
-
void setSyncJumpMask(uint16 mask) { _syncJumpMask = mask; }
void setMusicVolume(uint8 volume);
@@ -334,11 +306,6 @@ private:
// _unkTable2_2[] - One of the tables in _unkTable2[]
// _unkTable2_3[] - One of the tables in _unkTable2[]
- int32 _samplesPerCallback;
- int32 _samplesPerCallbackRemainder;
- int32 _samplesTillCallback;
- int32 _samplesTillCallbackRemainder;
-
int _curChannel;
uint8 _soundTrigger;
@@ -365,7 +332,7 @@ private:
uint8 _unkValue19;
uint8 _unkValue20;
- FM_OPL *_adlib;
+ OPL::OPL *_adlib;
uint8 *_soundData;
uint32 _soundDataSize;
@@ -411,7 +378,6 @@ private:
Common::Mutex _mutex;
Audio::Mixer *_mixer;
- Audio::SoundHandle _soundHandle;
uint8 _musicVolume, _sfxVolume;
@@ -427,8 +393,9 @@ AdLibDriver::AdLibDriver(Audio::Mixer *mixer, int version) {
_mixer = mixer;
- _adlib = makeAdLibOPL(getRate());
- assert(_adlib);
+ _adlib = OPL::Config::create();
+ if (!_adlib || !_adlib->init())
+ error("Failed to create OPL");
memset(_channels, 0, sizeof(_channels));
_soundData = 0;
@@ -451,13 +418,6 @@ AdLibDriver::AdLibDriver(Audio::Mixer *mixer, int version) {
_tablePtr1 = _tablePtr2 = 0;
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
-
- _samplesPerCallback = getRate() / CALLBACKS_PER_SECOND;
- _samplesPerCallbackRemainder = getRate() % CALLBACKS_PER_SECOND;
- _samplesTillCallback = 0;
- _samplesTillCallbackRemainder = 0;
-
_syncJumpMask = 0;
_musicVolume = 0;
@@ -467,11 +427,12 @@ AdLibDriver::AdLibDriver(Audio::Mixer *mixer, int version) {
_programQueueStart = _programQueueEnd = 0;
_retrySounds = false;
+
+ _adlib->start(new Common::Functor0Mem<void, AdLibDriver>(this, &AdLibDriver::callback), CALLBACKS_PER_SECOND);
}
AdLibDriver::~AdLibDriver() {
- _mixer->stopHandle(_soundHandle);
- OPLDestroy(_adlib);
+ delete _adlib;
_adlib = 0;
}
@@ -877,7 +838,7 @@ void AdLibDriver::resetAdLibState() {
// New calling style: writeOPL(0xAB, 0xCD)
void AdLibDriver::writeOPL(byte reg, byte val) {
- OPLWriteReg(_adlib, reg, val);
+ _adlib->writeReg(reg, val);
}
void AdLibDriver::initChannel(Channel &channel) {
diff --git a/engines/mads/nebular/sound_nebular.cpp b/engines/mads/nebular/sound_nebular.cpp
index 240c18f6dc..711f82a05b 100644
--- a/engines/mads/nebular/sound_nebular.cpp
+++ b/engines/mads/nebular/sound_nebular.cpp
@@ -21,6 +21,7 @@
*/
#include "audio/audiostream.h"
+#include "audio/fmopl.h"
#include "audio/decoders/raw.h"
#include "common/algorithm.h"
#include "common/debug.h"
@@ -156,7 +157,7 @@ AdlibSample::AdlibSample(Common::SeekableReadStream &s) {
/*-----------------------------------------------------------------------*/
-ASound::ASound(Audio::Mixer *mixer, FM_OPL *opl, const Common::String &filename, int dataOffset) {
+ASound::ASound(Audio::Mixer *mixer, OPL::OPL *opl, const Common::String &filename, int dataOffset) {
// Open up the appropriate sound file
if (!_soundFile.open(filename))
error("Could not open file - %s", filename.c_str());
@@ -188,11 +189,6 @@ ASound::ASound(Audio::Mixer *mixer, FM_OPL *opl, const Common::String &filename,
_randomSeed = 1234;
_amDep = _vibDep = _splitPoint = true;
- _samplesTillCallback = 0;
- _samplesTillCallbackRemainder = 0;
- _samplesPerCallback = getRate() / CALLBACKS_PER_SECOND;
- _samplesPerCallbackRemainder = getRate() % CALLBACKS_PER_SECOND;
-
for (int i = 0; i < 11; ++i) {
_channelData[i]._field0 = 0;
_channelData[i]._freqMask = 0;
@@ -210,23 +206,19 @@ ASound::ASound(Audio::Mixer *mixer, FM_OPL *opl, const Common::String &filename,
_mixer = mixer;
_opl = opl;
- _opl->init(getRate());
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1,
- Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
-
// Initialize the Adlib
adlibInit();
// Reset the adlib
command0();
+
+ _opl->start(new Common::Functor0Mem<void, ASound>(this, &ASound::onTimer), CALLBACKS_PER_SECOND);
}
ASound::~ASound() {
Common::List<CachedDataEntry>::iterator i;
for (i = _dataCache.begin(); i != _dataCache.end(); ++i)
delete[] (*i)._data;
-
- _mixer->stopHandle(_soundHandle);
}
void ASound::validate() {
@@ -832,32 +824,10 @@ void ASound::updateFNumber() {
write2(8, hiReg, val2);
}
-int ASound::readBuffer(int16 *buffer, const int numSamples) {
+void ASound::onTimer() {
Common::StackLock slock(_driverMutex);
-
- int32 samplesLeft = numSamples;
- memset(buffer, 0, sizeof(int16) * numSamples);
- while (samplesLeft) {
- if (!_samplesTillCallback) {
- poll();
- flush();
-
- _samplesTillCallback = _samplesPerCallback;
- _samplesTillCallbackRemainder += _samplesPerCallbackRemainder;
- if (_samplesTillCallbackRemainder >= CALLBACKS_PER_SECOND) {
- _samplesTillCallback++;
- _samplesTillCallbackRemainder -= CALLBACKS_PER_SECOND;
- }
- }
-
- int32 render = MIN<int>(samplesLeft, _samplesTillCallback);
- samplesLeft -= render;
- _samplesTillCallback -= render;
-
- _opl->readBuffer(buffer, render);
- buffer += render;
- }
- return numSamples;
+ poll();
+ flush();
}
void ASound::setVolume(int volume) {
@@ -984,7 +954,7 @@ const ASound1::CommandPtr ASound1::_commandList[42] = {
&ASound1::command40, &ASound1::command41
};
-ASound1::ASound1(Audio::Mixer *mixer, FM_OPL *opl)
+ASound1::ASound1(Audio::Mixer *mixer, OPL::OPL *opl)
: ASound(mixer, opl, "asound.001", 0x1520) {
_cmd23Toggle = false;
@@ -1285,7 +1255,7 @@ const ASound2::CommandPtr ASound2::_commandList[44] = {
&ASound2::command40, &ASound2::command41, &ASound2::command42, &ASound2::command43
};
-ASound2::ASound2(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.002", 0x15E0) {
+ASound2::ASound2(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.002", 0x15E0) {
_command12Param = 0xFD;
// Load sound samples
@@ -1656,7 +1626,7 @@ const ASound3::CommandPtr ASound3::_commandList[61] = {
&ASound3::command60
};
-ASound3::ASound3(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.003", 0x15B0) {
+ASound3::ASound3(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.003", 0x15B0) {
_command39Flag = false;
// Load sound samples
@@ -2060,7 +2030,7 @@ const ASound4::CommandPtr ASound4::_commandList[61] = {
&ASound4::command60
};
-ASound4::ASound4(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.004", 0x14F0) {
+ASound4::ASound4(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.004", 0x14F0) {
// Load sound samples
_soundFile.seek(_dataOffset + 0x122);
for (int i = 0; i < 210; ++i)
@@ -2316,7 +2286,7 @@ const ASound5::CommandPtr ASound5::_commandList[42] = {
&ASound5::command40, &ASound5::command41
};
-ASound5::ASound5(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.002", 0x15E0) {
+ASound5::ASound5(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.002", 0x15E0) {
// Load sound samples
_soundFile.seek(_dataOffset + 0x144);
for (int i = 0; i < 164; ++i)
@@ -2557,7 +2527,7 @@ const ASound6::CommandPtr ASound6::_commandList[30] = {
&ASound6::nullCommand, &ASound6::command29
};
-ASound6::ASound6(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.006", 0x1390) {
+ASound6::ASound6(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.006", 0x1390) {
// Load sound samples
_soundFile.seek(_dataOffset + 0x122);
for (int i = 0; i < 200; ++i)
@@ -2713,7 +2683,7 @@ const ASound7::CommandPtr ASound7::_commandList[38] = {
&ASound7::command36, &ASound7::command37
};
-ASound7::ASound7(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.007", 0x1460) {
+ASound7::ASound7(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.007", 0x1460) {
// Load sound samples
_soundFile.seek(_dataOffset + 0x122);
for (int i = 0; i < 214; ++i)
@@ -2919,7 +2889,7 @@ const ASound8::CommandPtr ASound8::_commandList[38] = {
&ASound8::command36, &ASound8::command37
};
-ASound8::ASound8(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.008", 0x1490) {
+ASound8::ASound8(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.008", 0x1490) {
// Load sound samples
_soundFile.seek(_dataOffset + 0x122);
for (int i = 0; i < 174; ++i)
@@ -3175,7 +3145,7 @@ const ASound9::CommandPtr ASound9::_commandList[52] = {
&ASound9::command48, &ASound9::command49, &ASound9::command50, &ASound9::command51
};
-ASound9::ASound9(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.009", 0x16F0) {
+ASound9::ASound9(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.009", 0x16F0) {
_v1 = _v2 = 0;
_soundPtr = nullptr;
diff --git a/engines/mads/nebular/sound_nebular.h b/engines/mads/nebular/sound_nebular.h
index 9bc1a49458..2b80b08d89 100644
--- a/engines/mads/nebular/sound_nebular.h
+++ b/engines/mads/nebular/sound_nebular.h
@@ -28,9 +28,12 @@
#include "common/mutex.h"
#include "common/queue.h"
#include "audio/audiostream.h"
-#include "audio/fmopl.h"
#include "audio/mixer.h"
+namespace OPL {
+class OPL;
+}
+
namespace MADS {
class SoundManager;
@@ -142,7 +145,7 @@ struct CachedDataEntry {
/**
* Base class for the sound player resource files
*/
-class ASound : public Audio::AudioStream {
+class ASound {
private:
Common::List<CachedDataEntry> _dataCache;
uint16 _randomSeed;
@@ -192,6 +195,11 @@ private:
void processSample();
void updateFNumber();
+
+ /**
+ * Timer function for OPL
+ */
+ void onTimer();
protected:
int _commandParam;
@@ -273,8 +281,7 @@ protected:
int nullCommand() { return 0; }
public:
Audio::Mixer *_mixer;
- FM_OPL *_opl;
- Audio::SoundHandle _soundHandle;
+ OPL::OPL *_opl;
AdlibChannel _channels[ADLIB_CHANNEL_COUNT];
AdlibChannel *_activeChannelPtr;
AdlibChannelData _channelData[11];
@@ -306,10 +313,6 @@ public:
int _activeChannelReg;
int _v11;
bool _amDep, _vibDep, _splitPoint;
- int _samplesPerCallback;
- int _samplesPerCallbackRemainder;
- int _samplesTillCallback;
- int _samplesTillCallbackRemainder;
public:
/**
* Constructor
@@ -318,7 +321,7 @@ public:
* @param filename Specifies the adlib sound player file to use
* @param dataOffset Offset in the file of the data segment
*/
- ASound(Audio::Mixer *mixer, FM_OPL *opl, const Common::String &filename, int dataOffset);
+ ASound(Audio::Mixer *mixer, OPL::OPL *opl, const Common::String &filename, int dataOffset);
/**
* Destructor
@@ -363,27 +366,6 @@ public:
*/
CachedDataEntry &getCachedData(byte *pData);
- // AudioStream interface
- /**
- * Main buffer read
- */
- virtual int readBuffer(int16 *buffer, const int numSamples);
-
- /**
- * Mono sound only
- */
- virtual bool isStereo() const { return false; }
-
- /**
- * Data is continuously pushed, so definitive end
- */
- virtual bool endOfData() const { return false; }
-
- /**
- * Return sample rate
- */
- virtual int getRate() const { return 11025; }
-
/**
* Set the volume
*/
@@ -433,7 +415,7 @@ private:
void command111213();
int command2627293032();
public:
- ASound1(Audio::Mixer *mixer, FM_OPL *opl);
+ ASound1(Audio::Mixer *mixer, OPL::OPL *opl);
virtual int command(int commandId, int param);
};
@@ -485,7 +467,7 @@ private:
void command9Randomize();
void command9Apply(byte *data, int val, int incr);
public:
- ASound2(Audio::Mixer *mixer, FM_OPL *opl);
+ ASound2(Audio::Mixer *mixer, OPL::OPL *opl);
virtual int command(int commandId, int param);
};
@@ -545,7 +527,7 @@ private:
void command9Randomize();
void command9Apply(byte *data, int val, int incr);
public:
- ASound3(Audio::Mixer *mixer, FM_OPL *opl);
+ ASound3(Audio::Mixer *mixer, OPL::OPL *opl);
virtual int command(int commandId, int param);
};
@@ -583,7 +565,7 @@ private:
void method1();
public:
- ASound4(Audio::Mixer *mixer, FM_OPL *opl);
+ ASound4(Audio::Mixer *mixer, OPL::OPL *opl);
virtual int command(int commandId, int param);
};
@@ -629,7 +611,7 @@ private:
int command42();
int command43();
public:
- ASound5(Audio::Mixer *mixer, FM_OPL *opl);
+ ASound5(Audio::Mixer *mixer, OPL::OPL *opl);
virtual int command(int commandId, int param);
};
@@ -658,7 +640,7 @@ private:
int command25();
int command29();
public:
- ASound6(Audio::Mixer *mixer, FM_OPL *opl);
+ ASound6(Audio::Mixer *mixer, OPL::OPL *opl);
virtual int command(int commandId, int param);
};
@@ -690,7 +672,7 @@ private:
int command36();
int command37();
public:
- ASound7(Audio::Mixer *mixer, FM_OPL *opl);
+ ASound7(Audio::Mixer *mixer, OPL::OPL *opl);
virtual int command(int commandId, int param);
};
@@ -733,7 +715,7 @@ private:
void method1(byte *pData);
void adjustRange(byte *pData, byte v, int incr);
public:
- ASound8(Audio::Mixer *mixer, FM_OPL *opl);
+ ASound8(Audio::Mixer *mixer, OPL::OPL *opl);
virtual int command(int commandId, int param);
};
@@ -792,7 +774,7 @@ private:
int command59();
int command60();
public:
- ASound9(Audio::Mixer *mixer, FM_OPL *opl);
+ ASound9(Audio::Mixer *mixer, OPL::OPL *opl);
virtual int command(int commandId, int param);
};
diff --git a/engines/mads/sound.cpp b/engines/mads/sound.cpp
index 7b9388eee3..4a35edb80f 100644
--- a/engines/mads/sound.cpp
+++ b/engines/mads/sound.cpp
@@ -21,6 +21,7 @@
*/
#include "audio/audiostream.h"
+#include "audio/fmopl.h"
#include "audio/decoders/raw.h"
#include "common/memstream.h"
#include "mads/sound.h"
@@ -39,7 +40,7 @@ SoundManager::SoundManager(MADSEngine *vm, Audio::Mixer *mixer) {
_masterVolume = 255;
_opl = OPL::Config::create();
- _opl->init(11025);
+ _opl->init();
// Validate sound files
switch (_vm->getGameID()) {
diff --git a/engines/mads/sound.h b/engines/mads/sound.h
index 16128f8284..9882f65e5a 100644
--- a/engines/mads/sound.h
+++ b/engines/mads/sound.h
@@ -37,7 +37,7 @@ class SoundManager {
private:
MADSEngine *_vm;
Audio::Mixer *_mixer;
- FM_OPL *_opl;
+ OPL::OPL *_opl;
Nebular::ASound *_driver;
bool _pollSoundEnabled;
bool _soundPollFlag;
diff --git a/engines/parallaction/adlib.cpp b/engines/parallaction/adlib.cpp
index 7c1dd1681f..568ad190aa 100644
--- a/engines/parallaction/adlib.cpp
+++ b/engines/parallaction/adlib.cpp
@@ -25,7 +25,7 @@
#include "audio/fmopl.h"
#include "audio/mpu401.h"
-#include "audio/softsynth/emumidi.h"
+#include "audio/mididrv.h"
namespace Parallaction {
@@ -270,11 +270,13 @@ struct MelodicVoice {
int8 _octave;
};
-class AdLibDriver : public MidiDriver_Emulated {
+class AdLibDriver : public MidiDriver {
public:
- AdLibDriver(Audio::Mixer *mixer) : MidiDriver_Emulated(mixer) {
+ AdLibDriver(Audio::Mixer *mixer) {
for (uint i = 0; i < 16; ++i)
_channels[i].init(this, i);
+
+ _isOpen = false;
}
int open();
@@ -282,11 +284,13 @@ public:
void send(uint32 b);
MidiChannel *allocateChannel();
MidiChannel *getPercussionChannel() { return &_channels[9]; }
+ bool isOpen() const { return _isOpen; }
+ uint32 getBaseTempo() { return 1000000 / OPL::OPL::kDefaultCallbackFrequency; }
- bool isStereo() const { return false; }
- int getRate() const { return _mixer->getOutputRate(); }
-
- void generateSamples(int16 *buf, int len);
+ virtual void setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc) {
+ _adlibTimerProc = timerProc;
+ _adlibTimerParam = timerParam;
+ }
protected:
OPL::OPL *_opl;
@@ -320,6 +324,13 @@ protected:
void muteMelodicVoice(uint8 voice);
void initVoices();
+
+private:
+ void onTimer();
+
+ Common::TimerManager::TimerProc _adlibTimerProc;
+ void *_adlibTimerParam;
+ bool _isOpen;
};
MidiDriver *createAdLibDriver() {
@@ -348,10 +359,10 @@ int AdLibDriver::open() {
if (_isOpen)
return MERR_ALREADY_OPEN;
- MidiDriver_Emulated::open();
+ _isOpen = true;
_opl = OPL::Config::create();
- _opl->init(getRate());
+ _opl->init();
_opl->writeReg(0x1, 0x20); // set bit 5 (enable all waveforms)
// Reset the OPL registers.
@@ -364,7 +375,7 @@ int AdLibDriver::open() {
initVoices();
- _mixer->playStream(Audio::Mixer::kMusicSoundType, &_mixerSoundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+ _opl->start(new Common::Functor0Mem<void, AdLibDriver>(this, &AdLibDriver::onTimer));
return 0;
}
@@ -373,7 +384,6 @@ void AdLibDriver::close() {
return;
_isOpen = false;
- _mixer->stopHandle(_mixerSoundHandle);
delete _opl;
}
@@ -777,9 +787,9 @@ MidiChannel *AdLibDriver::allocateChannel() {
return NULL;
}
-void AdLibDriver::generateSamples(int16 *buf, int len) {
- memset(buf, 0, sizeof(int16) * len);
- _opl->readBuffer(buf, len);
+void AdLibDriver::onTimer() {
+ if (_adlibTimerProc)
+ (*_adlibTimerProc)(_adlibTimerParam);
}
void AdLibDriver::initVoices() {
diff --git a/engines/queen/midiadlib.cpp b/engines/queen/midiadlib.cpp
index 25175c21d7..f5bc0f4d58 100644
--- a/engines/queen/midiadlib.cpp
+++ b/engines/queen/midiadlib.cpp
@@ -23,118 +23,29 @@
#include "common/endian.h"
#include "common/textconsole.h"
-#include "audio/fmopl.h"
-#include "audio/softsynth/emumidi.h"
+#include "engines/queen/midiadlib.h"
namespace Queen {
-class AdLibMidiDriver : public MidiDriver_Emulated {
-public:
-
- AdLibMidiDriver(Audio::Mixer *mixer) : MidiDriver_Emulated(mixer) { _adlibWaveformSelect = 0; }
- ~AdLibMidiDriver() {}
-
- // MidiDriver
- int open();
- void close();
- void send(uint32 b);
- void metaEvent(byte type, byte *data, uint16 length);
- MidiChannel *allocateChannel() { return 0; }
- MidiChannel *getPercussionChannel() { return 0; }
-
- // AudioStream
- bool isStereo() const { return false; }
- int getRate() const { return _mixer->getOutputRate(); }
-
- // MidiDriver_Emulated
- void generateSamples(int16 *buf, int len);
-
-private:
-
- void handleMidiEvent0x90_NoteOn(int channel, int param1, int param2);
- void handleSequencerSpecificMetaEvent1(int channel, const uint8 *data);
- void handleSequencerSpecificMetaEvent2(uint8 value);
- void handleSequencerSpecificMetaEvent3(uint8 value);
-
- void adlibWrite(uint8 port, uint8 value);
- void adlibSetupCard();
- void adlibSetupChannels(int fl);
- void adlibResetAmpVibratoRhythm(int am, int vib, int kso);
- void adlibResetChannels();
- void adlibSetAmpVibratoRhythm();
- void adlibSetCSMKeyboardSplit();
- void adlibSetNoteMul(int mul);
- void adlibSetWaveformSelect(int fl);
- void adlibSetPitchBend(int channel, int range);
- void adlibPlayNote(int channel);
- uint8 adlibPlayNoteHelper(int channel, int note1, int note2, int oct);
- void adlibTurnNoteOff(int channel);
- void adlibTurnNoteOn(int channel, int note);
- void adlibSetupChannelFromSequence(int channel, const uint8 *src, int fl);
- void adlibSetupChannel(int channel, const uint16 *src, int fl);
- void adlibSetNoteVolume(int channel, int volume);
- void adlibSetupChannelHelper(int channel);
- void adlibSetChannel0x40(int channel);
- void adlibSetChannel0xC0(int channel);
- void adlibSetChannel0x60(int channel);
- void adlibSetChannel0x80(int channel);
- void adlibSetChannel0x20(int channel);
- void adlibSetChannel0xE0(int channel);
-
- FM_OPL *_opl;
- int _midiNumberOfChannels;
- int _adlibNoteMul;
- int _adlibWaveformSelect;
- int _adlibAMDepthEq48;
- int _adlibVibratoDepthEq14;
- int _adlibRhythmEnabled;
- int _adlibKeyboardSplitOn;
- int _adlibVibratoRhythm;
- uint8 _midiChannelsFreqTable[9];
- uint8 _adlibChannelsLevelKeyScalingTable[11];
- uint8 _adlibSetupChannelSequence1[14 * 18];
- uint16 _adlibSetupChannelSequence2[14];
- int16 _midiChannelsNote2Table[9];
- uint8 _midiChannelsNote1Table[9];
- uint8 _midiChannelsOctTable[9];
- uint16 _adlibChannelsVolume[11];
- uint16 _adlibMetaSequenceData[28];
-
- static const uint8 _adlibChannelsMappingTable1[];
- static const uint8 _adlibChannelsNoFeedback[];
- static const uint8 _adlibChannelsMappingTable2[];
- static const uint8 _adlibChannelsMappingTable3[];
- static const uint8 _adlibChannelsKeyScalingTable1[];
- static const uint8 _adlibChannelsKeyScalingTable2[];
- static const uint8 _adlibChannelsVolumeTable[];
- static const uint8 _adlibInitSequenceData1[];
- static const uint8 _adlibInitSequenceData2[];
- static const uint8 _adlibInitSequenceData3[];
- static const uint8 _adlibInitSequenceData4[];
- static const uint8 _adlibInitSequenceData5[];
- static const uint8 _adlibInitSequenceData6[];
- static const uint8 _adlibInitSequenceData7[];
- static const uint8 _adlibInitSequenceData8[];
- static const int16 _midiChannelsNoteTable[];
- static const int16 _midiNoteFreqTable[];
-};
-
int AdLibMidiDriver::open() {
- MidiDriver_Emulated::open();
- _opl = makeAdLibOPL(getRate());
+ _isOpen = true;
+ _opl = OPL::Config::create();
+ if (!_opl || !_opl->init())
+ error("Failed to create OPL");
+
adlibSetupCard();
for (int i = 0; i < 11; ++i) {
_adlibChannelsVolume[i] = 0;
adlibSetNoteVolume(i, 0);
adlibTurnNoteOff(i);
}
- _mixer->playStream(Audio::Mixer::kMusicSoundType, &_mixerSoundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+
+ _opl->start(new Common::Functor0Mem<void, AdLibMidiDriver>(this, &AdLibMidiDriver::onTimer));
return 0;
}
void AdLibMidiDriver::close() {
- _mixer->stopHandle(_mixerSoundHandle);
- OPLDestroy(_opl);
+ delete _opl;
}
void AdLibMidiDriver::send(uint32 b) {
@@ -164,6 +75,11 @@ void AdLibMidiDriver::send(uint32 b) {
}
}
+void AdLibMidiDriver::setVolume(uint32 volume) {
+ for (int i = 0; i < _midiNumberOfChannels; ++i)
+ adlibSetChannelVolume(i, volume * 64 / 256 + 64);
+}
+
void AdLibMidiDriver::metaEvent(byte type, byte *data, uint16 length) {
int event = 0;
if (length > 4 && READ_BE_UINT32(data) == 0x3F00) {
@@ -192,9 +108,14 @@ void AdLibMidiDriver::metaEvent(byte type, byte *data, uint16 length) {
warning("Unhandled meta event %d len %d", event, length);
}
-void AdLibMidiDriver::generateSamples(int16 *data, int len) {
- memset(data, 0, sizeof(int16) * len);
- YM3812UpdateOne(_opl, data, len);
+void AdLibMidiDriver::setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc) {
+ _adlibTimerProc = timerProc;
+ _adlibTimerParam = timerParam;
+}
+
+void AdLibMidiDriver::onTimer() {
+ if (_adlibTimerProc)
+ (*_adlibTimerProc)(_adlibTimerParam);
}
void AdLibMidiDriver::handleSequencerSpecificMetaEvent1(int channel, const uint8 *data) {
@@ -238,7 +159,7 @@ void AdLibMidiDriver::handleMidiEvent0x90_NoteOn(int channel, int param1, int pa
}
void AdLibMidiDriver::adlibWrite(uint8 port, uint8 value) {
- OPLWriteReg(_opl, port, value);
+ _opl->writeReg(port, value);
}
void AdLibMidiDriver::adlibSetupCard() {
@@ -253,6 +174,7 @@ void AdLibMidiDriver::adlibSetupCard() {
_midiChannelsFreqTable[i] = 0;
}
memset(_adlibChannelsLevelKeyScalingTable, 127, 11);
+ memset(_adlibChannelsVolumeTable, 128, 11);
adlibSetupChannels(0);
adlibResetAmpVibratoRhythm(0, 0, 0);
adlibSetNoteMul(1);
@@ -448,6 +370,11 @@ void AdLibMidiDriver::adlibSetNoteVolume(int channel, int volume) {
}
}
+void AdLibMidiDriver::adlibSetChannelVolume(int channel, uint8 volume) {
+ if (channel < (_adlibRhythmEnabled ? 11 : 9))
+ _adlibChannelsVolumeTable[channel] = volume;
+}
+
void AdLibMidiDriver::adlibSetupChannelHelper(int channel) {
adlibSetAmpVibratoRhythm();
adlibSetCSMKeyboardSplit();
@@ -558,10 +485,6 @@ const uint8 AdLibMidiDriver::_adlibChannelsKeyScalingTable2[] = {
0, 3, 1, 4, 2, 5, 6, 9, 7, 10, 8, 11, 12, 15, 16, 255, 14, 255, 17, 255, 13, 255
};
-const uint8 AdLibMidiDriver::_adlibChannelsVolumeTable[] = {
- 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128
-};
-
const uint8 AdLibMidiDriver::_adlibInitSequenceData1[] = {
1, 1, 3, 15, 5, 0, 1, 3, 15, 0, 0, 0, 1, 0
};
@@ -617,8 +540,4 @@ const int16 AdLibMidiDriver::_midiNoteFreqTable[] = {
-363, -361, -359, -356, -354, -351, -349, -347, -344, -342, -339, -337
};
-MidiDriver *C_Player_CreateAdLibMidiDriver(Audio::Mixer *mixer) {
- return new AdLibMidiDriver(mixer);
-}
-
} // End of namespace Queen
diff --git a/engines/queen/midiadlib.h b/engines/queen/midiadlib.h
new file mode 100644
index 0000000000..8692e51840
--- /dev/null
+++ b/engines/queen/midiadlib.h
@@ -0,0 +1,128 @@
+/* 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 "audio/fmopl.h"
+#include "audio/mididrv.h"
+
+namespace Queen {
+
+class AdLibMidiDriver : public MidiDriver {
+public:
+
+ AdLibMidiDriver() {
+ _adlibWaveformSelect = 0;
+ _isOpen = false;
+ }
+
+ ~AdLibMidiDriver() {}
+
+ // MidiDriver
+ int open();
+ void close();
+ void send(uint32 b);
+ void metaEvent(byte type, byte *data, uint16 length);
+ MidiChannel *allocateChannel() { return 0; }
+ MidiChannel *getPercussionChannel() { return 0; }
+ void setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc);
+ bool isOpen() const { return _isOpen; }
+ uint32 getBaseTempo() { return 1000000 / OPL::OPL::kDefaultCallbackFrequency; }
+
+ void setVolume(uint32 volume);
+
+private:
+
+ void handleMidiEvent0x90_NoteOn(int channel, int param1, int param2);
+ void handleSequencerSpecificMetaEvent1(int channel, const uint8 *data);
+ void handleSequencerSpecificMetaEvent2(uint8 value);
+ void handleSequencerSpecificMetaEvent3(uint8 value);
+
+ void adlibWrite(uint8 port, uint8 value);
+ void adlibSetupCard();
+ void adlibSetupChannels(int fl);
+ void adlibResetAmpVibratoRhythm(int am, int vib, int kso);
+ void adlibResetChannels();
+ void adlibSetAmpVibratoRhythm();
+ void adlibSetCSMKeyboardSplit();
+ void adlibSetNoteMul(int mul);
+ void adlibSetWaveformSelect(int fl);
+ void adlibSetPitchBend(int channel, int range);
+ void adlibPlayNote(int channel);
+ uint8 adlibPlayNoteHelper(int channel, int note1, int note2, int oct);
+ void adlibTurnNoteOff(int channel);
+ void adlibTurnNoteOn(int channel, int note);
+ void adlibSetupChannelFromSequence(int channel, const uint8 *src, int fl);
+ void adlibSetupChannel(int channel, const uint16 *src, int fl);
+ void adlibSetNoteVolume(int channel, int volume);
+ void adlibSetChannelVolume(int channel, uint8 volume);
+ void adlibSetupChannelHelper(int channel);
+ void adlibSetChannel0x40(int channel);
+ void adlibSetChannel0xC0(int channel);
+ void adlibSetChannel0x60(int channel);
+ void adlibSetChannel0x80(int channel);
+ void adlibSetChannel0x20(int channel);
+ void adlibSetChannel0xE0(int channel);
+
+ void onTimer();
+
+ OPL::OPL *_opl;
+ int _midiNumberOfChannels;
+ int _adlibNoteMul;
+ int _adlibWaveformSelect;
+ int _adlibAMDepthEq48;
+ int _adlibVibratoDepthEq14;
+ int _adlibRhythmEnabled;
+ int _adlibKeyboardSplitOn;
+ int _adlibVibratoRhythm;
+ uint8 _midiChannelsFreqTable[9];
+ uint8 _adlibChannelsLevelKeyScalingTable[11];
+ uint8 _adlibSetupChannelSequence1[14 * 18];
+ uint16 _adlibSetupChannelSequence2[14];
+ int16 _midiChannelsNote2Table[9];
+ uint8 _midiChannelsNote1Table[9];
+ uint8 _midiChannelsOctTable[9];
+ uint16 _adlibChannelsVolume[11];
+ uint16 _adlibMetaSequenceData[28];
+ uint8 _adlibChannelsVolumeTable[11];
+
+ bool _isOpen;
+ Common::TimerManager::TimerProc _adlibTimerProc;
+ void *_adlibTimerParam;
+
+ static const uint8 _adlibChannelsMappingTable1[];
+ static const uint8 _adlibChannelsNoFeedback[];
+ static const uint8 _adlibChannelsMappingTable2[];
+ static const uint8 _adlibChannelsMappingTable3[];
+ static const uint8 _adlibChannelsKeyScalingTable1[];
+ static const uint8 _adlibChannelsKeyScalingTable2[];
+ static const uint8 _adlibInitSequenceData1[];
+ static const uint8 _adlibInitSequenceData2[];
+ static const uint8 _adlibInitSequenceData3[];
+ static const uint8 _adlibInitSequenceData4[];
+ static const uint8 _adlibInitSequenceData5[];
+ static const uint8 _adlibInitSequenceData6[];
+ static const uint8 _adlibInitSequenceData7[];
+ static const uint8 _adlibInitSequenceData8[];
+ static const int16 _midiChannelsNoteTable[];
+ static const int16 _midiNoteFreqTable[];
+};
+
+} // End of namespace Queen
diff --git a/engines/queen/music.cpp b/engines/queen/music.cpp
index 93d6527622..9f74aab915 100644
--- a/engines/queen/music.cpp
+++ b/engines/queen/music.cpp
@@ -23,6 +23,7 @@
#include "common/config-manager.h"
#include "common/events.h"
+#include "queen/midiadlib.h"
#include "queen/music.h"
#include "queen/queen.h"
#include "queen/resource.h"
@@ -33,8 +34,6 @@
namespace Queen {
-extern MidiDriver *C_Player_CreateAdLibMidiDriver(Audio::Mixer *);
-
MidiMusic::MidiMusic(QueenEngine *vm)
: _isPlaying(false), _isLooping(false),
_randomLoop(false), _masterVolume(192),
@@ -69,7 +68,7 @@ MidiMusic::MidiMusic(QueenEngine *vm)
// if (READ_LE_UINT16(_musicData + 2) != infoOffset) {
// defaultAdLibVolume = _musicData[infoOffset];
// }
- _driver = C_Player_CreateAdLibMidiDriver(vm->_mixer);
+ _driver = new AdLibMidiDriver();
} else {
_driver = MidiDriver::createMidi(dev);
if (_nativeMT32) {
@@ -117,6 +116,9 @@ void MidiMusic::setVolume(int volume) {
if (_channelsTable[i])
_channelsTable[i]->volume(_channelsVolume[i] * _masterVolume / 255);
}
+
+ if (_adlib)
+ static_cast<AdLibMidiDriver*>(_driver)->setVolume(volume);
}
void MidiMusic::playSong(uint16 songNum) {
diff --git a/engines/sci/sound/drivers/adlib.cpp b/engines/sci/sound/drivers/adlib.cpp
index fcfda2f532..4f557be95e 100644
--- a/engines/sci/sound/drivers/adlib.cpp
+++ b/engines/sci/sound/drivers/adlib.cpp
@@ -27,7 +27,7 @@
#include "common/textconsole.h"
#include "audio/fmopl.h"
-#include "audio/softsynth/emumidi.h"
+#include "audio/mididrv.h"
#include "sci/resource.h"
#include "sci/sound/drivers/mididriver.h"
@@ -43,29 +43,30 @@ namespace Sci {
// FIXME: We don't seem to be sending the polyphony init data, so disable this for now
#define ADLIB_DISABLE_VOICE_MAPPING
-class MidiDriver_AdLib : public MidiDriver_Emulated {
+class MidiDriver_AdLib : public MidiDriver {
public:
enum {
kVoices = 9,
kRhythmKeys = 62
};
- MidiDriver_AdLib(Audio::Mixer *mixer) : MidiDriver_Emulated(mixer), _playSwitch(true), _masterVolume(15), _rhythmKeyMap(0), _opl(0) { }
+ MidiDriver_AdLib(Audio::Mixer *mixer) :_playSwitch(true), _masterVolume(15), _rhythmKeyMap(0), _opl(0), _isOpen(false) { }
virtual ~MidiDriver_AdLib() { }
// MidiDriver
+ int open() { return -1; } // Dummy implementation (use openAdLib)
int openAdLib(bool isSCI0);
void close();
void send(uint32 b);
MidiChannel *allocateChannel() { return NULL; }
MidiChannel *getPercussionChannel() { return NULL; }
+ bool isOpen() const { return _isOpen; }
+ uint32 getBaseTempo() { return 1000000 / OPL::OPL::kDefaultCallbackFrequency; }
- // AudioStream
- bool isStereo() const { return _stereo; }
- int getRate() const { return _mixer->getOutputRate(); }
+ // MidiDriver
+ void setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc);
- // MidiDriver_Emulated
- void generateSamples(int16 *buf, int len);
+ void onTimer();
void setVolume(byte volume);
void playSwitch(bool play);
@@ -133,6 +134,7 @@ private:
bool _stereo;
bool _isSCI0;
OPL::OPL *_opl;
+ bool _isOpen;
bool _playSwitch;
int _masterVolume;
Channel _channels[MIDI_CHANNELS];
@@ -140,6 +142,9 @@ private:
byte *_rhythmKeyMap;
Common::Array<AdLibPatch> _patches;
+ Common::TimerManager::TimerProc _adlibTimerProc;
+ void *_adlibTimerParam;
+
void loadInstrument(const byte *ins);
void voiceOn(int voice, int note, int velocity);
void voiceOff(int voice);
@@ -215,14 +220,12 @@ static const int ym3812_note[13] = {
};
int MidiDriver_AdLib::openAdLib(bool isSCI0) {
- int rate = _mixer->getOutputRate();
-
_stereo = STEREO;
debug(3, "ADLIB: Starting driver in %s mode", (isSCI0 ? "SCI0" : "SCI1"));
_isSCI0 = isSCI0;
- _opl = OPL::Config::create(isStereo() ? OPL::Config::kDualOpl2 : OPL::Config::kOpl2);
+ _opl = OPL::Config::create(_stereo ? OPL::Config::kDualOpl2 : OPL::Config::kOpl2);
// Try falling back to mono, thus plain OPL2 emualtor, when no Dual OPL2 is available.
if (!_opl && _stereo) {
@@ -233,22 +236,24 @@ int MidiDriver_AdLib::openAdLib(bool isSCI0) {
if (!_opl)
return -1;
- _opl->init(rate);
+ if (!_opl->init()) {
+ delete _opl;
+ _opl = nullptr;
+ return -1;
+ }
setRegister(0xBD, 0);
setRegister(0x08, 0);
setRegister(0x01, 0x20);
- MidiDriver_Emulated::open();
+ _isOpen = true;
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &_mixerSoundHandle, this, -1, _mixer->kMaxChannelVolume, 0, DisposeAfterUse::NO);
+ _opl->start(new Common::Functor0Mem<void, MidiDriver_AdLib>(this, &MidiDriver_AdLib::onTimer));
return 0;
}
void MidiDriver_AdLib::close() {
- _mixer->stopHandle(_mixerSoundHandle);
-
delete _opl;
delete[] _rhythmKeyMap;
}
@@ -325,10 +330,14 @@ void MidiDriver_AdLib::send(uint32 b) {
}
}
-void MidiDriver_AdLib::generateSamples(int16 *data, int len) {
- if (isStereo())
- len <<= 1;
- _opl->readBuffer(data, len);
+void MidiDriver_AdLib::setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc) {
+ _adlibTimerProc = timerProc;
+ _adlibTimerParam = timerParam;
+}
+
+void MidiDriver_AdLib::onTimer() {
+ if (_adlibTimerProc)
+ (*_adlibTimerProc)(_adlibTimerParam);
// Increase the age of the notes
for (int i = 0; i < kVoices; i++) {
@@ -684,7 +693,7 @@ void MidiDriver_AdLib::setVelocityReg(int regOffset, int velocity, int kbScaleLe
if (!_playSwitch)
velocity = 0;
- if (isStereo()) {
+ if (_stereo) {
int velLeft = velocity;
int velRight = velocity;
@@ -734,7 +743,7 @@ void MidiDriver_AdLib::setRegister(int reg, int value, int channels) {
_opl->write(0x221, value);
}
- if (isStereo()) {
+ if (_stereo) {
if (channels & kRightChannel) {
_opl->write(0x222, reg);
_opl->write(0x223, value);
diff --git a/engines/scumm/players/player_ad.cpp b/engines/scumm/players/player_ad.cpp
index adcda68e10..5c0d443105 100644
--- a/engines/scumm/players/player_ad.cpp
+++ b/engines/scumm/players/player_ad.cpp
@@ -36,25 +36,18 @@ namespace Scumm {
#define AD_CALLBACK_FREQUENCY 472
Player_AD::Player_AD(ScummEngine *scumm, Audio::Mixer *mixer)
- : _vm(scumm), _mixer(mixer), _rate(mixer->getOutputRate()) {
+ : _vm(scumm), _mixer(mixer) {
_opl2 = OPL::Config::create();
- if (!_opl2->init(_rate)) {
+ if (!_opl2->init()) {
error("Could not initialize OPL2 emulator");
}
- _samplesPerCallback = _rate / AD_CALLBACK_FREQUENCY;
- _samplesPerCallbackRemainder = _rate % AD_CALLBACK_FREQUENCY;
- _samplesTillCallback = 0;
- _samplesTillCallbackRemainder = 0;
-
memset(_registerBackUpTable, 0, sizeof(_registerBackUpTable));
writeReg(0x01, 0x00);
writeReg(0xBD, 0x00);
writeReg(0x08, 0x00);
writeReg(0x01, 0x20);
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
-
_engineMusicTimer = 0;
_soundPlaying = -1;
@@ -78,11 +71,11 @@ Player_AD::Player_AD(ScummEngine *scumm, Audio::Mixer *mixer)
_musicVolume = _sfxVolume = 255;
_isSeeking = false;
+
+ _opl2->start(new Common::Functor0Mem<void, Player_AD>(this, &Player_AD::onTimer), AD_CALLBACK_FREQUENCY);
}
Player_AD::~Player_AD() {
- _mixer->stopHandle(_soundHandle);
-
stopAllSounds();
Common::StackLock lock(_mutex);
delete _opl2;
@@ -244,36 +237,14 @@ void Player_AD::saveLoadWithSerializer(Serializer *ser) {
}
}
-int Player_AD::readBuffer(int16 *buffer, const int numSamples) {
+void Player_AD::onTimer() {
Common::StackLock lock(_mutex);
- int len = numSamples;
-
- while (len > 0) {
- if (!_samplesTillCallback) {
- if (_curOffset) {
- updateMusic();
- }
-
- updateSfx();
-
- _samplesTillCallback = _samplesPerCallback;
- _samplesTillCallbackRemainder += _samplesPerCallbackRemainder;
- if (_samplesTillCallbackRemainder >= AD_CALLBACK_FREQUENCY) {
- ++_samplesTillCallback;
- _samplesTillCallbackRemainder -= AD_CALLBACK_FREQUENCY;
- }
- }
-
- const int samplesToRead = MIN(len, _samplesTillCallback);
- _opl2->readBuffer(buffer, samplesToRead);
-
- buffer += samplesToRead;
- len -= samplesToRead;
- _samplesTillCallback -= samplesToRead;
+ if (_curOffset) {
+ updateMusic();
}
- return numSamples;
+ updateSfx();
}
void Player_AD::setupVolume() {
diff --git a/engines/scumm/players/player_ad.h b/engines/scumm/players/player_ad.h
index 63a8503f47..b8cd8dc359 100644
--- a/engines/scumm/players/player_ad.h
+++ b/engines/scumm/players/player_ad.h
@@ -41,7 +41,7 @@ class ScummEngine;
/**
* Sound output for v3/v4 AdLib data.
*/
-class Player_AD : public MusicEngine, public Audio::AudioStream {
+class Player_AD : public MusicEngine {
public:
Player_AD(ScummEngine *scumm, Audio::Mixer *mixer);
virtual ~Player_AD();
@@ -56,18 +56,13 @@ public:
virtual void saveLoadWithSerializer(Serializer *ser);
- // AudioStream API
- virtual int readBuffer(int16 *buffer, const int numSamples);
- virtual bool isStereo() const { return false; }
- virtual bool endOfData() const { return false; }
- virtual int getRate() const { return _rate; }
+ // Timer callback
+ void onTimer();
private:
ScummEngine *const _vm;
Common::Mutex _mutex;
Audio::Mixer *const _mixer;
- const int _rate;
- Audio::SoundHandle _soundHandle;
void setupVolume();
int _musicVolume;
@@ -75,11 +70,6 @@ private:
OPL::OPL *_opl2;
- int _samplesPerCallback;
- int _samplesPerCallbackRemainder;
- int _samplesTillCallback;
- int _samplesTillCallbackRemainder;
-
int _soundPlaying;
int32 _engineMusicTimer;
diff --git a/engines/sherlock/scalpel/drivers/adlib.cpp b/engines/sherlock/scalpel/drivers/adlib.cpp
index 91641fcccd..29a39f0c39 100644
--- a/engines/sherlock/scalpel/drivers/adlib.cpp
+++ b/engines/sherlock/scalpel/drivers/adlib.cpp
@@ -216,10 +216,11 @@ uint16 frequencyLookUpTable[SHERLOCK_ADLIB_NOTES_COUNT] = {
0x1DE6, 0x1E03, 0x1E22, 0x1E42, 0x1E65, 0x1E89
};
-class MidiDriver_SH_AdLib : public MidiDriver_Emulated {
+class MidiDriver_SH_AdLib : public MidiDriver {
public:
MidiDriver_SH_AdLib(Audio::Mixer *mixer)
- : MidiDriver_Emulated(mixer), _masterVolume(15), _opl(0) {
+ : _masterVolume(15), _opl(0),
+ _adlibTimerProc(0), _adlibTimerParam(0), _isOpen(false) {
memset(_voiceChannelMapping, 0, sizeof(_voiceChannelMapping));
}
virtual ~MidiDriver_SH_AdLib() { }
@@ -230,15 +231,13 @@ public:
void send(uint32 b);
MidiChannel *allocateChannel() { return NULL; }
MidiChannel *getPercussionChannel() { return NULL; }
+ bool isOpen() const { return _isOpen; }
+ uint32 getBaseTempo() { return 1000000 / OPL::OPL::kDefaultCallbackFrequency; }
- // AudioStream
- bool isStereo() const { return false; }
- int getRate() const { return _mixer->getOutputRate(); }
int getPolyphony() const { return SHERLOCK_ADLIB_VOICES_COUNT; }
bool hasRhythmChannel() const { return false; }
- // MidiDriver_Emulated
- void generateSamples(int16 *buf, int len);
+ virtual void setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc);
void setVolume(byte volume);
virtual uint32 property(int prop, uint32 param);
@@ -261,16 +260,19 @@ private:
OPL::OPL *_opl;
int _masterVolume;
+ Common::TimerManager::TimerProc _adlibTimerProc;
+ void *_adlibTimerParam;
+
+ bool _isOpen;
+
// points to a MIDI channel for each of the new voice channels
byte _voiceChannelMapping[SHERLOCK_ADLIB_VOICES_COUNT];
// stores information about all FM voice channels
adlib_ChannelEntry _channels[SHERLOCK_ADLIB_VOICES_COUNT];
-protected:
void onTimer();
-private:
void resetAdLib();
void resetAdLibOperatorRegisters(byte baseRegister, byte value);
void resetAdLibFMVoiceChannelRegisters(byte baseRegister, byte value);
@@ -285,8 +287,6 @@ private:
};
int MidiDriver_SH_AdLib::open() {
- int rate = _mixer->getOutputRate();
-
debugC(kDebugLevelAdLibDriver, "AdLib: starting driver");
_opl = OPL::Config::create(OPL::Config::kOpl2);
@@ -294,17 +294,18 @@ int MidiDriver_SH_AdLib::open() {
if (!_opl)
return -1;
- _opl->init(rate);
+ _opl->init();
- MidiDriver_Emulated::open();
+ _isOpen = true;
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &_mixerSoundHandle, this, -1, _mixer->kMaxChannelVolume, 0, DisposeAfterUse::NO);
+ _opl->start(new Common::Functor0Mem<void, MidiDriver_SH_AdLib>(this, &MidiDriver_SH_AdLib::onTimer));
return 0;
}
void MidiDriver_SH_AdLib::close() {
- _mixer->stopHandle(_mixerSoundHandle);
+ // Stop the OPL timer
+ _opl->stop();
delete _opl;
}
@@ -318,6 +319,12 @@ void MidiDriver_SH_AdLib::setVolume(byte volume) {
// original driver did this before MIDI data processing on each tick
// we do it atm after MIDI data processing
void MidiDriver_SH_AdLib::onTimer() {
+ if (_adlibTimerProc)
+ (*_adlibTimerProc)(_adlibTimerParam);
+
+ // this should/must get called per tick
+ // original driver did this before MIDI data processing on each tick
+ // we do it atm after MIDI data processing
for (byte FMvoiceChannel = 0; FMvoiceChannel < SHERLOCK_ADLIB_VOICES_COUNT; FMvoiceChannel++) {
if (_channels[FMvoiceChannel].inUse) {
_channels[FMvoiceChannel].inUseTimer++;
@@ -417,10 +424,6 @@ void MidiDriver_SH_AdLib::send(uint32 b) {
}
}
-void MidiDriver_SH_AdLib::generateSamples(int16 *data, int len) {
- _opl->readBuffer(data, len);
-}
-
void MidiDriver_SH_AdLib::noteOn(byte MIDIchannel, byte note, byte velocity) {
int16 oldestInUseChannel = -1;
uint16 oldestInUseTimer = 0;
@@ -627,6 +630,11 @@ uint32 MidiDriver_SH_AdLib::property(int prop, uint32 param) {
return 0;
}
+void MidiDriver_SH_AdLib::setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc) {
+ _adlibTimerProc = timerProc;
+ _adlibTimerParam = timerParam;
+}
+
MidiDriver *MidiDriver_SH_AdLib_create() {
return new MidiDriver_SH_AdLib(g_system->getMixer());
}
diff --git a/engines/sky/music/adlibchannel.cpp b/engines/sky/music/adlibchannel.cpp
index 8400fef6eb..c7acb9b6c1 100644
--- a/engines/sky/music/adlibchannel.cpp
+++ b/engines/sky/music/adlibchannel.cpp
@@ -29,7 +29,7 @@
namespace Sky {
-AdLibChannel::AdLibChannel(FM_OPL *opl, uint8 *pMusicData, uint16 startOfData) {
+AdLibChannel::AdLibChannel(OPL::OPL *opl, uint8 *pMusicData, uint16 startOfData) {
_opl = opl;
_musicData = pMusicData;
_channelData.loopPoint = startOfData;
@@ -45,6 +45,8 @@ AdLibChannel::AdLibChannel(FM_OPL *opl, uint8 *pMusicData, uint16 startOfData) {
_channelData.frequency = 0;
_channelData.instrumentData = NULL;
+ _musicVolume = 128;
+
uint16 instrumentDataLoc;
if (SkyEngine::_systemVars.gameVersion == 109) {
@@ -86,7 +88,7 @@ bool AdLibChannel::isActive() {
}
void AdLibChannel::updateVolume(uint16 pVolume) {
- // Do nothing. The mixer handles the music volume for us.
+ _musicVolume = pVolume;
}
/* This class uses the same area for the register mirror as the original
@@ -95,7 +97,7 @@ void AdLibChannel::updateVolume(uint16 pVolume) {
*/
void AdLibChannel::setRegister(uint8 regNum, uint8 value) {
if (_adlibRegMirror[regNum] != value) {
- OPLWriteReg (_opl, regNum, value);
+ _opl->writeReg(regNum, value);
_adlibRegMirror[regNum] = value;
}
}
@@ -208,6 +210,8 @@ void AdLibChannel::setupChannelVolume(uint8 volume) {
uint32 resVol = ((volume + 1) * (_channelData.instrumentData->totOutLev_Op2 + 1)) << 1;
resVol &= 0xFFFF;
resVol *= (_channelData.channelVolume + 1) << 1;
+ resVol >>= 8;
+ resVol *= _musicVolume << 1;
resVol >>= 16;
assert(resVol < 0x81);
resultOp = ((_channelData.instrumentData->scalingLevel << 6) & 0xC0) | _opOutputTable[resVol];
@@ -216,6 +220,8 @@ void AdLibChannel::setupChannelVolume(uint8 volume) {
resVol = ((volume + 1) * (_channelData.instrumentData->totOutLev_Op1 + 1)) << 1;
resVol &= 0xFFFF;
resVol *= (_channelData.channelVolume + 1) << 1;
+ resVol >>= 8;
+ resVol *= _musicVolume << 1;
resVol >>= 16;
} else
resVol = _channelData.instrumentData->totOutLev_Op1;
diff --git a/engines/sky/music/adlibchannel.h b/engines/sky/music/adlibchannel.h
index 80dae93b2c..4504e3b570 100644
--- a/engines/sky/music/adlibchannel.h
+++ b/engines/sky/music/adlibchannel.h
@@ -60,14 +60,15 @@ typedef struct {
class AdLibChannel : public ChannelBase {
public:
- AdLibChannel (FM_OPL *opl, uint8 *pMusicData, uint16 startOfData);
+ AdLibChannel (OPL::OPL *opl, uint8 *pMusicData, uint16 startOfData);
virtual ~AdLibChannel();
virtual uint8 process(uint16 aktTime);
virtual void updateVolume(uint16 pVolume);
virtual bool isActive();
private:
- FM_OPL *_opl;
+ OPL::OPL *_opl;
uint8 *_musicData;
+ uint16 _musicVolume;
AdLibChannelType _channelData;
InstrumentStruct *_instruments;
diff --git a/engines/sky/music/adlibmusic.cpp b/engines/sky/music/adlibmusic.cpp
index dd64c5bc81..be5e7b2353 100644
--- a/engines/sky/music/adlibmusic.cpp
+++ b/engines/sky/music/adlibmusic.cpp
@@ -22,6 +22,7 @@
#include "common/endian.h"
+#include "common/textconsole.h"
#include "sky/music/adlibmusic.h"
#include "sky/music/adlibchannel.h"
@@ -32,44 +33,21 @@ namespace Sky {
AdLibMusic::AdLibMusic(Audio::Mixer *pMixer, Disk *pDisk) : MusicBase(pMixer, pDisk) {
_driverFileBase = 60202;
- _sampleRate = pMixer->getOutputRate();
- _opl = makeAdLibOPL(_sampleRate);
+ _opl = OPL::Config::create();
+ if (!_opl || !_opl->init())
+ error("Failed to create OPL");
- _mixer->playStream(Audio::Mixer::kMusicSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+ _opl->start(new Common::Functor0Mem<void, AdLibMusic>(this, &AdLibMusic::onTimer), 50);
}
AdLibMusic::~AdLibMusic() {
- OPLDestroy(_opl);
- _mixer->stopHandle(_soundHandle);
+ delete _opl;
}
-int AdLibMusic::readBuffer(int16 *data, const int numSamples) {
- if (_musicData == NULL) {
- // no music loaded
- memset(data, 0, numSamples * sizeof(int16));
- } else if ((_currentMusic == 0) || (_numberOfChannels == 0)) {
- // music loaded but not played as of yet
- memset(data, 0, numSamples * sizeof(int16));
- // poll anyways as pollMusic() can activate the music
+void AdLibMusic::onTimer() {
+ if (_musicData != NULL)
pollMusic();
- _nextMusicPoll = _sampleRate / 50;
- } else {
- uint32 render;
- uint remaining = numSamples;
- while (remaining) {
- render = (remaining > _nextMusicPoll) ? _nextMusicPoll : remaining;
- remaining -= render;
- _nextMusicPoll -= render;
- YM3812UpdateOne(_opl, data, render);
- data += render;
- if (_nextMusicPoll == 0) {
- pollMusic();
- _nextMusicPoll = _sampleRate / 50;
- }
- }
- }
- return numSamples;
}
void AdLibMusic::setupPointers() {
@@ -87,7 +65,6 @@ void AdLibMusic::setupPointers() {
_musicDataLoc = READ_LE_UINT16(_musicData + 0x1201);
_initSequence = _musicData + 0xE91;
}
- _nextMusicPoll = 0;
}
void AdLibMusic::setupChannels(uint8 *channelData) {
@@ -102,26 +79,15 @@ void AdLibMusic::setupChannels(uint8 *channelData) {
void AdLibMusic::startDriver() {
uint16 cnt = 0;
while (_initSequence[cnt] || _initSequence[cnt + 1]) {
- OPLWriteReg (_opl, _initSequence[cnt], _initSequence[cnt + 1]);
+ _opl->writeReg(_initSequence[cnt], _initSequence[cnt + 1]);
cnt += 2;
}
}
void AdLibMusic::setVolume(uint16 param) {
_musicVolume = param;
- _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, 2 * param);
-}
-
-bool AdLibMusic::isStereo() const {
- return false;
-}
-
-bool AdLibMusic::endOfData() const {
- return false;
-}
-
-int AdLibMusic::getRate() const {
- return _sampleRate;
+ for (uint8 cnt = 0; cnt < _numberOfChannels; cnt++)
+ _channels[cnt]->updateVolume(_musicVolume);
}
} // End of namespace Sky
diff --git a/engines/sky/music/adlibmusic.h b/engines/sky/music/adlibmusic.h
index 886eef026e..7b51f2d3a0 100644
--- a/engines/sky/music/adlibmusic.h
+++ b/engines/sky/music/adlibmusic.h
@@ -25,32 +25,32 @@
#include "sky/music/musicbase.h"
#include "audio/audiostream.h"
-#include "audio/fmopl.h"
+
+namespace OPL {
+class OPL;
+}
namespace Sky {
-class AdLibMusic : public Audio::AudioStream, public MusicBase {
+class AdLibMusic : public MusicBase {
public:
AdLibMusic(Audio::Mixer *pMixer, Disk *pDisk);
~AdLibMusic();
// AudioStream API
- int readBuffer(int16 *buffer, const int numSamples);
- bool isStereo() const;
- bool endOfData() const;
- int getRate() const;
virtual void setVolume(uint16 param);
private:
- FM_OPL *_opl;
- Audio::SoundHandle _soundHandle;
+ OPL::OPL *_opl;
uint8 *_initSequence;
- uint32 _sampleRate, _nextMusicPoll;
+ uint32 _sampleRate;
virtual void setupPointers();
virtual void setupChannels(uint8 *channelData);
virtual void startDriver();
void premixerCall(int16 *buf, uint len);
+
+ void onTimer();
};
} // End of namespace Sky
diff --git a/engines/tsage/sound.cpp b/engines/tsage/sound.cpp
index b95b614f09..0d3fb55dd3 100644
--- a/engines/tsage/sound.cpp
+++ b/engines/tsage/sound.cpp
@@ -20,9 +20,9 @@
*
*/
+#include "audio/fmopl.h"
#include "audio/decoders/raw.h"
#include "common/config-manager.h"
-#include "audio/decoders/raw.h"
#include "audio/audiostream.h"
#include "tsage/core.h"
#include "tsage/globals.h"
@@ -2743,17 +2743,9 @@ AdlibSoundDriver::AdlibSoundDriver(): SoundDriver() {
_groupData._pData = &adlib_group_data[0];
_mixer = g_vm->_mixer;
- _sampleRate = _mixer->getOutputRate();
_opl = OPL::Config::create();
assert(_opl);
- _opl->init(_sampleRate);
-
- _samplesTillCallback = 0;
- _samplesTillCallbackRemainder = 0;
- _samplesPerCallback = getRate() / CALLBACKS_PER_SECOND;
- _samplesPerCallbackRemainder = getRate() % CALLBACKS_PER_SECOND;
-
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+ _opl->init();
Common::fill(_channelVoiced, _channelVoiced + ADLIB_CHANNEL_COUNT, false);
memset(_channelVolume, 0, ADLIB_CHANNEL_COUNT * sizeof(int));
@@ -2772,11 +2764,12 @@ AdlibSoundDriver::AdlibSoundDriver(): SoundDriver() {
_channelVoiced[i] = false;
_pitchBlend[i] = 0;
}
+
+ _opl->start(new Common::Functor0Mem<void, AdlibSoundDriver>(this, &AdlibSoundDriver::onTimer), CALLBACKS_PER_SECOND);
}
AdlibSoundDriver::~AdlibSoundDriver() {
DEALLOCATE(_patchData);
- _mixer->stopHandle(_soundHandle);
delete _opl;
}
@@ -3019,33 +3012,12 @@ void AdlibSoundDriver::setFrequency(int channel) {
((dataWord >> 8) & 3) | (var2 << 2));
}
-int AdlibSoundDriver::readBuffer(int16 *buffer, const int numSamples) {
+void AdlibSoundDriver::onTimer() {
Common::StackLock slock1(SoundManager::sfManager()._serverDisabledMutex);
Common::StackLock slock2(SoundManager::sfManager()._serverSuspendedMutex);
- int32 samplesLeft = numSamples;
- memset(buffer, 0, sizeof(int16) * numSamples);
- while (samplesLeft) {
- if (!_samplesTillCallback) {
- SoundManager::sfUpdateCallback(NULL);
- flush();
-
- _samplesTillCallback = _samplesPerCallback;
- _samplesTillCallbackRemainder += _samplesPerCallbackRemainder;
- if (_samplesTillCallbackRemainder >= CALLBACKS_PER_SECOND) {
- _samplesTillCallback++;
- _samplesTillCallbackRemainder -= CALLBACKS_PER_SECOND;
- }
- }
-
- int32 render = MIN<int>(samplesLeft, _samplesTillCallback);
- samplesLeft -= render;
- _samplesTillCallback -= render;
-
- _opl->readBuffer(buffer, render);
- buffer += render;
- }
- return numSamples;
+ SoundManager::sfUpdateCallback(NULL);
+ flush();
}
/*--------------------------------------------------------------------------*/
diff --git a/engines/tsage/sound.h b/engines/tsage/sound.h
index 49558b4bca..68755a48c8 100644
--- a/engines/tsage/sound.h
+++ b/engines/tsage/sound.h
@@ -27,12 +27,15 @@
#include "common/mutex.h"
#include "common/queue.h"
#include "audio/audiostream.h"
-#include "audio/fmopl.h"
#include "audio/mixer.h"
#include "common/list.h"
#include "tsage/saveload.h"
#include "tsage/core.h"
+namespace OPL {
+class OPL;
+}
+
namespace TsAGE {
class Sound;
@@ -446,21 +449,15 @@ public:
#define ADLIB_CHANNEL_COUNT 9
-class AdlibSoundDriver: public SoundDriver, Audio::AudioStream {
+class AdlibSoundDriver: public SoundDriver {
private:
GroupData _groupData;
Audio::Mixer *_mixer;
- FM_OPL *_opl;
- Audio::SoundHandle _soundHandle;
- int _sampleRate;
+ OPL::OPL *_opl;
byte _portContents[256];
const byte *_patchData;
int _masterVolume;
Common::Queue<RegisterValue> _queue;
- int _samplesTillCallback;
- int _samplesTillCallbackRemainder;
- int _samplesPerCallback;
- int _samplesPerCallbackRemainder;
bool _channelVoiced[ADLIB_CHANNEL_COUNT];
int _channelVolume[ADLIB_CHANNEL_COUNT];
@@ -495,13 +492,8 @@ public:
virtual void proc38(int channel, int cmd, int value);
virtual void setPitch(int channel, int pitchBlend);
- // AudioStream interface
- virtual int readBuffer(int16 *buffer, const int numSamples);
- virtual bool isStereo() const { return false; }
- virtual bool endOfData() const { return false; }
- virtual int getRate() const { return _sampleRate; }
-
- void update(int16 *buf, int len);
+private:
+ void onTimer();
};
class SoundBlasterDriver: public SoundDriver {
diff --git a/gui/options.cpp b/gui/options.cpp
index 726b89d437..ba247e5f15 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -445,11 +445,9 @@ void OptionsDialog::close() {
if (_oplPopUp) {
if (_enableAudioSettings) {
- const OPL::Config::EmulatorDescription *ed = OPL::Config::getAvailable();
- while (ed->name && ed->id != (int)_oplPopUp->getSelectedTag())
- ++ed;
+ const OPL::Config::EmulatorDescription *ed = OPL::Config::findDriver(_oplPopUp->getSelectedTag());
- if (ed->name)
+ if (ed)
ConfMan.set("opl_driver", ed->name, _domain);
else
ConfMan.removeKey("opl_driver", _domain);