diff options
author | Wohlstand <admin@wohlnet.ru> | 2025-03-29 00:44:52 +0300 |
---|---|---|
committer | Wohlstand <admin@wohlnet.ru> | 2025-03-29 00:44:52 +0300 |
commit | e92a4d7285197ab2868aa36f975d73ceee915bea (patch) | |
tree | b5e3af6e6c58145a62ec6394a40e9e65d26a5fcf /src | |
parent | 7afda0483ab0af9db624052321b42c3d2a245e75 (diff) | |
download | libADLMIDI-e92a4d7285197ab2868aa36f975d73ceee915bea.tar.gz libADLMIDI-e92a4d7285197ab2868aa36f975d73ceee915bea.tar.bz2 libADLMIDI-e92a4d7285197ab2868aa36f975d73ceee915bea.zip |
Refactored DOS support
Diffstat (limited to 'src')
-rw-r--r-- | src/adlmidi.cpp | 39 | ||||
-rw-r--r-- | src/adlmidi_midiplay.cpp | 4 | ||||
-rw-r--r-- | src/adlmidi_opl3.cpp | 127 | ||||
-rw-r--r-- | src/adlmidi_opl3.hpp | 49 | ||||
-rw-r--r-- | src/adlmidi_private.hpp | 11 | ||||
-rw-r--r-- | src/chips/dos_hw_opl.cpp | 163 | ||||
-rw-r--r-- | src/chips/dos_hw_opl.h | 48 |
7 files changed, 359 insertions, 82 deletions
diff --git a/src/adlmidi.cpp b/src/adlmidi.cpp index 7fbf134..b81a342 100644 --- a/src/adlmidi.cpp +++ b/src/adlmidi.cpp @@ -24,11 +24,12 @@ #include "adlmidi_midiplay.hpp" #include "adlmidi_opl3.hpp" #include "adlmidi_private.hpp" -#ifndef ADLMIDI_HW_OPL #include "chips/opl_chip_base.h" -#endif #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER -#include "midi_sequencer.hpp" +# include "midi_sequencer.hpp" +#endif +#ifdef ENABLE_HW_OPL_DOS +# include "chips/dos_hw_opl.h" #endif #if defined(_MSC_VER) && _MSC_VER < 1900 @@ -138,8 +139,7 @@ ADLMIDI_EXPORT int adl_setNumChips(ADL_MIDIPlayer *device, int numChips) #endif #ifdef ADLMIDI_HW_OPL - ADL_UNUSED(numChips); - play->m_setup.numChips = 1; + play->m_setup.numChips = numChips > 2 ? 1 : static_cast<unsigned int>(numChips); #else play->m_setup.numChips = static_cast<unsigned int>(numChips); #endif @@ -835,15 +835,11 @@ ADLMIDI_EXPORT const char *adl_chipEmulatorName(struct ADL_MIDIPlayer *device) { if(device) { -#ifndef ADLMIDI_HW_OPL MidiPlayer *play = GET_MIDI_PLAYER(device); assert(play); Synth &synth = *play->m_synth; if(!synth.m_chips.empty()) return synth.m_chips[0]->emulatorName(); -#else - return "Hardware OPL3 chip on 0x330"; -#endif } return "Unknown"; } @@ -910,6 +906,31 @@ ADLMIDI_EXPORT int adl_switchSerialHW(struct ADL_MIDIPlayer *device, return -1; } +int adl_switchDOSHW(int chipType, ADL_UInt16 baseAddress) +{ +#ifdef ENABLE_HW_OPL_DOS + if(baseAddress > 0) + DOS_HW_OPL::setOplAddress(baseAddress); + + switch(chipType) + { + case ADLMIDI_DOS_ChipAuto: + break; + + case ADLMIDI_DOS_ChipOPL2: + DOS_HW_OPL::setChipType(OPLChipBase::CHIPTYPE_OPL2); + break; + case ADLMIDI_DOS_ChipOPL3: + DOS_HW_OPL::setChipType(OPLChipBase::CHIPTYPE_OPL3); + break; + } +#else + (void)chipType; + (void)baseAddress; +#endif + return -1; +} + ADLMIDI_EXPORT const char *adl_linkedLibraryVersion() { #if !defined(ADLMIDI_ENABLE_HQ_RESAMPLER) diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp index 0bc0191..9db4b67 100644 --- a/src/adlmidi_midiplay.cpp +++ b/src/adlmidi_midiplay.cpp @@ -89,7 +89,11 @@ MIDIplay::MIDIplay(unsigned long sampleRate): m_setup.bankId = 0; m_setup.numFourOps = -1; +#ifdef ADLMIDI_ENABLE_HW_DOS + m_setup.numChips = 1; +#else m_setup.numChips = 2; +#endif m_setup.deepTremoloMode = -1; m_setup.deepVibratoMode = -1; m_setup.rhythmMode = -1; diff --git a/src/adlmidi_opl3.cpp b/src/adlmidi_opl3.cpp index c612637..97760cf 100644 --- a/src/adlmidi_opl3.cpp +++ b/src/adlmidi_opl3.cpp @@ -26,12 +26,9 @@ #include <stdlib.h> #include <cassert> -#ifndef DISABLE_EMBEDDED_BANKS -#include "wopl/wopl_file.h" -#endif -#ifdef ADLMIDI_HW_OPL -static const unsigned OPLBase = 0x388; +#ifdef ENABLE_HW_OPL_DOS +# include "chips/dos_hw_opl.h" #else # if defined(ADLMIDI_DISABLE_NUKED_EMULATOR) && \ defined(ADLMIDI_DISABLE_DOSBOX_EMULATOR) && \ @@ -84,7 +81,7 @@ static const unsigned OPLBase = 0x388; #endif static const unsigned adl_emulatorSupport = 0 -#ifndef ADLMIDI_HW_OPL +#ifndef ENABLE_HW_OPL_DOS # ifndef ADLMIDI_DISABLE_NUKED_EMULATOR | (1u << ADLMIDI_EMU_NUKED) | (1u << ADLMIDI_EMU_NUKED_174) # endif @@ -936,7 +933,9 @@ OPL3::OPL3() : OPL3::~OPL3() { -#ifdef ADLMIDI_HW_OPL + m_curState.clear(); + +#ifdef ENABLE_HW_OPL_DOS silenceAll(); writeRegI(0, 0x0BD, 0); writeRegI(0, 0x104, 0); @@ -1004,48 +1003,17 @@ void OPL3::setEmbeddedBank(uint32_t bank) void OPL3::writeReg(size_t chip, uint16_t address, uint8_t value) { -#ifdef ADLMIDI_HW_OPL - ADL_UNUSED(chip); - unsigned o = address >> 8; - unsigned port = OPLBase + o * 2; - -# ifdef __DJGPP__ - outportb(port, address); - for(unsigned c = 0; c < 6; ++c) inportb(port); - outportb(port + 1, value); - for(unsigned c = 0; c < 35; ++c) inportb(port); -# endif - -# ifdef __WATCOMC__ - outp(port, address); - for(uint16_t c = 0; c < 6; ++c) inp(port); - outp(port + 1, value); - for(uint16_t c = 0; c < 35; ++c) inp(port); -# endif//__WATCOMC__ - -#else//ADLMIDI_HW_OPL m_chips[chip]->writeReg(address, value); -#endif } void OPL3::writeRegI(size_t chip, uint32_t address, uint32_t value) { -#ifdef ADLMIDI_HW_OPL - writeReg(chip, static_cast<uint16_t>(address), static_cast<uint8_t>(value)); -#else//ADLMIDI_HW_OPL m_chips[chip]->writeReg(static_cast<uint16_t>(address), static_cast<uint8_t>(value)); -#endif } void OPL3::writePan(size_t chip, uint32_t address, uint32_t value) { -#ifndef ADLMIDI_HW_OPL m_chips[chip]->writePan(static_cast<uint16_t>(address), static_cast<uint8_t>(value)); -#else - ADL_UNUSED(chip); - ADL_UNUSED(address); - ADL_UNUSED(value); -#endif } @@ -1579,7 +1547,7 @@ void OPL3::setPan(size_t c, uint8_t value) if(g_channelsMapPan[cc] != 0xFFF) { -#ifndef ADLMIDI_HW_OPL +#ifndef ENABLE_HW_OPL_DOS if (m_softPanningSup && m_softPanning) { writePan(chip, g_channelsMapPan[cc], value); @@ -1595,7 +1563,7 @@ void OPL3::setPan(size_t c, uint8_t value) m_regC0[c] = panning; writePan(chip, g_channelsMapPan[cc], 64); writeRegI(chip, 0xC0 + g_channelsMapPan[cc], m_insCache[c].feedconn | panning); -#ifndef ADLMIDI_HW_OPL +#ifndef ENABLE_HW_OPL_DOS } #endif } @@ -1795,48 +1763,72 @@ ADLMIDI_VolumeModels OPL3::getVolumeScaleModel() } } -#ifndef ADLMIDI_HW_OPL void OPL3::clearChips() { for(size_t i = 0; i < m_chips.size(); i++) m_chips[i].reset(NULL); m_chips.clear(); } -#endif void OPL3::reset(int emulator, unsigned long PCM_RATE, void *audioTickHandler) { -#ifndef ADLMIDI_HW_OPL - clearChips(); -#else - (void)emulator; - (void)PCM_RATE; -#endif + bool rebuild_needed = m_curState.cmp(emulator, m_numChips); + + if(rebuild_needed) + clearChips(); + #if !defined(ADLMIDI_AUDIO_TICK_HANDLER) (void)audioTickHandler; #endif - m_insCache.clear(); - m_keyBlockFNumCache.clear(); - m_regBD.clear(); -#ifndef ADLMIDI_HW_OPL - m_chips.resize(m_numChips, AdlMIDI_SPtr<OPLChipBase>()); -#endif + const struct OplTimbre defaultInsCache = { 0x1557403,0x005B381, 0x49,0x80, 0x4, +0 }; + + if(rebuild_needed) + { + m_insCache.clear(); + m_keyBlockFNumCache.clear(); + m_regBD.clear(); + m_regC0.clear(); + m_channelCategory.clear(); + m_chips.resize(m_numChips, AdlMIDI_SPtr<OPLChipBase>()); + } + else + { + adl_fill_vector<OplTimbre>(m_insCache, defaultInsCache); + adl_fill_vector<uint32_t>(m_channelCategory, 0); + adl_fill_vector<uint32_t>(m_keyBlockFNumCache, 0); + adl_fill_vector<uint32_t>(m_regBD, 0); + adl_fill_vector<uint8_t>(m_regC0, OPL_PANNING_BOTH); + } #ifdef ADLMIDI_ENABLE_HW_SERIAL if(emulator >= 0) // If less than zero - it's hardware synth! m_serial = false; #endif - const struct OplTimbre defaultInsCache = { 0x1557403,0x005B381, 0x49,0x80, 0x4, +0 }; - m_numChannels = m_numChips * NUM_OF_CHANNELS; - m_insCache.resize(m_numChannels, defaultInsCache); - m_keyBlockFNumCache.resize(m_numChannels, 0); - m_regBD.resize(m_numChips, 0); - m_regC0.resize(m_numChips * m_numChannels, OPL_PANNING_BOTH); - m_channelCategory.resize(m_numChannels, 0); + if(rebuild_needed) + { + m_numChannels = m_numChips * NUM_OF_CHANNELS; + m_insCache.resize(m_numChannels, defaultInsCache); + m_channelCategory.resize(m_numChannels, 0); + m_keyBlockFNumCache.resize(m_numChannels, 0); + m_regBD.resize(m_numChips, 0); + m_regC0.resize(m_numChips * m_numChannels, OPL_PANNING_BOTH); + } - for(size_t i = 0; i < m_numChips; ++i) + if(!rebuild_needed) + { + bool newRate = m_curState.cmp_rate(PCM_RATE); + + for(size_t i = 0; i < m_numChips; ++i) + { + if(newRate) + m_chips[i]->setRate(PCM_RATE); + + initChip(i); + } + } + else for(size_t i = 0; i < m_numChips; ++i) { #ifdef ADLMIDI_ENABLE_HW_SERIAL if(emulator < 0) @@ -1849,8 +1841,11 @@ void OPL3::reset(int emulator, unsigned long PCM_RATE, void *audioTickHandler) } #endif -#ifndef ADLMIDI_HW_OPL OPLChipBase *chip; +#ifdef ENABLE_HW_OPL_DOS + chip = new DOS_HW_OPL(); + +#else // ENABLE_HW_OPL_DOS switch(emulator) { default: @@ -1898,18 +1893,20 @@ void OPL3::reset(int emulator, unsigned long PCM_RATE, void *audioTickHandler) break; #endif } +#endif // ENABLE_HW_OPL_DOS m_chips[i].reset(chip); chip->setChipId((uint32_t)i); chip->setRate((uint32_t)PCM_RATE); +#ifndef ENABLE_HW_OPL_DOS if(m_runAtPcmRate) chip->setRunningAtPcmRate(true); +#endif -# if defined(ADLMIDI_AUDIO_TICK_HANDLER) +# if defined(ADLMIDI_AUDIO_TICK_HANDLER) && !defined(ENABLE_HW_OPL_DOS) chip->setAudioTickHandlerInstance(audioTickHandler); # endif -#endif // ADLMIDI_HW_OPL initChip(i); } diff --git a/src/adlmidi_opl3.hpp b/src/adlmidi_opl3.hpp index 362b301..aee049f 100644 --- a/src/adlmidi_opl3.hpp +++ b/src/adlmidi_opl3.hpp @@ -60,10 +60,8 @@ public: uint32_t m_numChannels; //! Just a padding. Reserved. char _padding[4]; -#ifndef ADLMIDI_HW_OPL //! Running chip emulators std::vector<AdlMIDI_SPtr<OPLChipBase > > m_chips; -#endif private: //! Cached patch data, needed by Touch() @@ -90,6 +88,51 @@ private: //! Number channels per chip size_t m_perChipChannels; + /*! + * \brief Current state of the synth (if values matched to setup, chips and arrays won't be fully re-created) + */ + struct State + { + int emulator; + uint32_t numChips; + unsigned long pcm_rate; + + State() + { + clear(); + } + + void clear() + { + emulator = -2; + numChips = 0; + pcm_rate = 0; + } + + bool cmp_rate(unsigned long rate) + { + bool ret = pcm_rate != rate; + + if(ret) + pcm_rate = rate; + + return ret; + } + + bool cmp(int emu, uint32_t chips) + { + bool ret = emu != emulator || chips != numChips; + + if(ret) + { + emulator = emu; + numChips = chips; + } + + return ret; + } + } m_curState; + public: /** * @brief MIDI bank entry @@ -339,12 +382,10 @@ public: */ ADLMIDI_VolumeModels getVolumeScaleModel(); -#ifndef ADLMIDI_HW_OPL /** * @brief Clean up all running emulated chip instances */ void clearChips(); -#endif /** * @brief Reset chip properties and initialize them diff --git a/src/adlmidi_private.hpp b/src/adlmidi_private.hpp index 0b1e92f..dcd0d03 100644 --- a/src/adlmidi_private.hpp +++ b/src/adlmidi_private.hpp @@ -60,9 +60,6 @@ typedef int32_t ssize_t; #endif #if defined(__DJGPP__) || (defined(__WATCOMC__) && (defined(__DOS__) || defined(__DOS4G__) || defined(__DOS4GNZ__))) -# ifndef ADLMIDI_HW_OPL -# define ADLMIDI_HW_OPL -# endif # include <conio.h> # ifdef __DJGPP__ # include <pc.h> @@ -157,7 +154,7 @@ class MIDIplay; #define ADL_UNUSED(x) (void)x -#ifdef ADLMIDI_HW_OPL +#ifdef ENABLE_HW_OPL_DOS #define ADL_MAX_CHIPS 1 #define ADL_MAX_CHIPS_STR "1" //Why not just "#MaxCards" ? Watcom fails to pass this with "syntax error" :-P #else @@ -214,6 +211,12 @@ inline int32_t adl_cvtU32(int32_t x) return (uint32_t)adl_cvtS32(x) - (uint32_t)INT32_MIN; } +template<typename T> +void adl_fill_vector(std::vector<T > &v, const T &value) +{ + for(typename std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) + *it = value; +} #if defined(ADLMIDI_AUDIO_TICK_HANDLER) extern void adl_audioTickHandler(void *instance, uint32_t chipId, uint32_t rate); diff --git a/src/chips/dos_hw_opl.cpp b/src/chips/dos_hw_opl.cpp new file mode 100644 index 0000000..a9f4765 --- /dev/null +++ b/src/chips/dos_hw_opl.cpp @@ -0,0 +1,163 @@ +/* + * Interfaces over Yamaha OPL3 (YMF262) chip emulators + * + * Copyright (c) 2017-2025 Vitaly Novichkov (Wohlstand) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#ifdef __DJGPP__ +# include <pc.h> +#endif + +#include "dos_hw_opl.h" + +static uint16_t s_OPLBase[2] = {0x388, 0x38A}; +static char s_devName[80] = {0}; +static OPLChipBase::ChipType s_type = OPLChipBase::CHIPTYPE_OPL3; +static bool s_detected = false; + +static void s_updateDevName() +{ + const char *oplName = (s_type == OPLChipBase::CHIPTYPE_OPL3) ? "OPL3" : "OPL2"; + memset(s_devName, 0, sizeof(s_devName)); + snprintf(s_devName, 80, "%s at 0x%03X", oplName, s_OPLBase[0]); +} + +static void s_detect() +{ + if(s_detected) + return; + + const char *blaster = getenv("BLASTER"); + if(blaster) + { + size_t len = strlen(blaster); + for(size_t i = 0; i < len - 1; ++i) + { + if(blaster[i] == 'T') + { + switch(blaster[i + 1]) + { + case '1': + case '2': + s_type = OPLChipBase::CHIPTYPE_OPL2; + break; + case '3': + case '4': + case '6': + s_type = OPLChipBase::CHIPTYPE_OPL3; + break; + default: + s_type = OPLChipBase::CHIPTYPE_OPL2; + break; + } + + // printf("-- Detected BLASTER T%c\n", blaster[i + 1]); + + break; + } + } + } + else + s_type = OPLChipBase::CHIPTYPE_OPL2; + + s_detected = true; +} + +DOS_HW_OPL::DOS_HW_OPL() +{ + s_detect(); + s_updateDevName(); +} + +void DOS_HW_OPL::setOplAddress(uint16_t address) +{ + s_OPLBase[0] = address; + s_OPLBase[1] = address + 2; + s_updateDevName(); +} + +void DOS_HW_OPL::setChipType(ChipType type) +{ + s_type = type; + s_detected = true; // Assignd manually, no need to detect +} + +DOS_HW_OPL::~DOS_HW_OPL() +{ + DOS_HW_OPL::writeReg(0x0BD, 0); + if(s_type == CHIPTYPE_OPL3) + { + DOS_HW_OPL::writeReg(0x104, 0); + DOS_HW_OPL::writeReg(0x105, 0); + } +} + +void DOS_HW_OPL::writeReg(uint16_t addr, uint8_t data) +{ + assert(m_id <= 1); + unsigned o = addr >> 8; + unsigned port = s_OPLBase[m_id] + o * 2; + +# ifdef __DJGPP__ + outportb(port, addr); + + for(unsigned c = 0; c < 6; ++c) + inportb(port); + + outportb(port + 1, data); + + for(unsigned c = 0; c < 35; ++c) + inportb(port); +# endif + +# ifdef __WATCOMC__ + outp(port, addr); + + for(uint16_t c = 0; c < 6; ++c) + inp(port); + + outp(port + 1, data); + + for(uint16_t c = 0; c < 35; ++c) + inp(port); +# endif//__WATCOMC__ +} + +void DOS_HW_OPL::nativeGenerate(int16_t *frame) +{ + frame[0] = 0; + frame[1] = 0; +} + +const char *DOS_HW_OPL::emulatorName() +{ + return s_devName; +} + +bool DOS_HW_OPL::hasFullPanning() +{ + return false; +} + +OPLChipBase::ChipType DOS_HW_OPL::chipType() +{ + return s_type; +} diff --git a/src/chips/dos_hw_opl.h b/src/chips/dos_hw_opl.h new file mode 100644 index 0000000..5e3750b --- /dev/null +++ b/src/chips/dos_hw_opl.h @@ -0,0 +1,48 @@ +/* + * Interfaces over Yamaha OPL3 (YMF262) chip emulators + * + * Copyright (c) 2017-2025 Vitaly Novichkov (Wohlstand) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#ifndef DOS_HW_OPL_H +#define DOS_HW_OPL_H + +#include "opl_chip_base.h" + +class DOS_HW_OPL : public OPLChipBaseT<DOS_HW_OPL> +{ +public: + DOS_HW_OPL(); + virtual ~DOS_HW_OPL() override; + + static void setChipType(ChipType type); + static void setOplAddress(uint16_t address); + + bool canRunAtPcmRate() const override { return false; } + void setRate(uint32_t /*rate*/) override {} + void reset() override {} + void writeReg(uint16_t addr, uint8_t data) override; + void nativePreGenerate() override {} + void nativePostGenerate() override {} + void nativeGenerate(int16_t *frame) override; + const char *emulatorName() override; + ChipType chipType() override; + bool hasFullPanning() override; +}; + +#endif // DOS_HW_OPL_H |