aboutsummaryrefslogtreecommitdiff
path: root/audio/softsynth
diff options
context:
space:
mode:
authorMatthew Hoops2015-07-07 20:41:30 -0400
committerMatthew Hoops2015-07-07 20:41:30 -0400
commitbb8132beb82a4f5d5a3f8db0fb9dec08b2965b72 (patch)
treebadd5f30d4940d49d57adaf5f3b1503d64a73380 /audio/softsynth
parentfde8abf8ccea92efec16a83dc4fa6b872f9cc6d2 (diff)
downloadscummvm-rg350-bb8132beb82a4f5d5a3f8db0fb9dec08b2965b72.tar.gz
scummvm-rg350-bb8132beb82a4f5d5a3f8db0fb9dec08b2965b72.tar.bz2
scummvm-rg350-bb8132beb82a4f5d5a3f8db0fb9dec08b2965b72.zip
AUDIO: Move ALSA OPL 'driver' out of softsynth
Might eventually be worth moving to backends/
Diffstat (limited to 'audio/softsynth')
-rw-r--r--audio/softsynth/opl/alsa.cpp349
1 files changed, 0 insertions, 349 deletions
diff --git a/audio/softsynth/opl/alsa.cpp b/audio/softsynth/opl/alsa.cpp
deleted file mode 100644
index 6b9e48e987..0000000000
--- a/audio/softsynth/opl/alsa.cpp
+++ /dev/null
@@ -1,349 +0,0 @@
-/* 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