diff options
-rw-r--r-- | CMakeLists.txt | 8 | ||||
-rw-r--r-- | libADLMIDI-test.pro | 2 | ||||
-rw-r--r-- | src/chips/dosbox_opl3.cpp | 88 | ||||
-rw-r--r-- | src/chips/dosbox_opl3.h | 21 | ||||
-rw-r--r-- | src/chips/nuked_opl3.cpp | 141 | ||||
-rw-r--r-- | src/chips/nuked_opl3.h | 32 | ||||
-rw-r--r-- | src/chips/nuked_opl3_v174.cpp | 141 | ||||
-rw-r--r-- | src/chips/nuked_opl3_v174.h | 32 | ||||
-rw-r--r-- | src/chips/opl_chip_base.cpp | 52 | ||||
-rw-r--r-- | src/chips/opl_chip_base.h | 81 | ||||
-rw-r--r-- | src/chips/opl_chip_base.tcc | 214 |
11 files changed, 349 insertions, 463 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 156e8c0..92ecb7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,10 +113,6 @@ if(WITH_EMBEDDED_BANKS) ${libADLMIDI_SOURCE_DIR}/utils/gen_adldata/ini/ini_processing.cpp ) - list(APPEND GEN_ADLDATA_SRC - ${libADLMIDI_SOURCE_DIR}/src/chips/opl_chip_base.cpp - ) - if(USE_DOSBOX_EMULATOR) set(HAS_EMULATOR TRUE) list(APPEND GEN_ADLDATA_SRC @@ -203,10 +199,6 @@ else() endif() if(NOT DJGPP AND NOT MSDOS) - list(APPEND libADLMIDI_SOURCES - ${libADLMIDI_SOURCE_DIR}/src/chips/opl_chip_base.cpp - ) - if(USE_DOSBOX_EMULATOR) set(HAS_EMULATOR TRUE) list(APPEND libADLMIDI_SOURCES diff --git a/libADLMIDI-test.pro b/libADLMIDI-test.pro index bf11c1a..982a9a2 100644 --- a/libADLMIDI-test.pro +++ b/libADLMIDI-test.pro @@ -37,6 +37,7 @@ HEADERS += \ src/chips/nuked_opl3.h \ src/chips/nuked_opl3_v174.h \ src/chips/opl_chip_base.h \ + src/chips/opl_chip_base.tcc \ src/fraction.hpp \ src/midiplay/wave_writer.h @@ -57,7 +58,6 @@ SOURCES += \ src/chips/nuked/nukedopl3.c \ src/chips/nuked_opl3.cpp \ src/chips/nuked_opl3_v174.cpp \ - src/chips/opl_chip_base.cpp \ utils/midiplay/adlmidiplay.cpp \ utils/midiplay/wave_writer.c diff --git a/src/chips/dosbox_opl3.cpp b/src/chips/dosbox_opl3.cpp index f1fcce4..af4cb08 100644 --- a/src/chips/dosbox_opl3.cpp +++ b/src/chips/dosbox_opl3.cpp @@ -1,22 +1,16 @@ #include "dosbox_opl3.h" #include "dosbox/dbopl.h" +#include <new> #include <cstdlib> #include <assert.h> DosBoxOPL3::DosBoxOPL3() : - OPLChipBase(), - m_chip(NULL) + OPLChipBaseBufferedT(), + m_chip(new DBOPL::Handler) { reset(); } -DosBoxOPL3::DosBoxOPL3(const DosBoxOPL3 &c) : - OPLChipBase(c), - m_chip(NULL) -{ - setRate(c.m_rate); -} - DosBoxOPL3::~DosBoxOPL3() { DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip); @@ -25,23 +19,20 @@ DosBoxOPL3::~DosBoxOPL3() void DosBoxOPL3::setRate(uint32_t rate) { - OPLChipBase::setRate(rate); - reset(); + OPLChipBaseBufferedT::setRate(rate); + DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip); + chip_r->~Handler(); + new(chip_r) DBOPL::Handler; + chip_r->Init(49716); } void DosBoxOPL3::reset() { + OPLChipBaseBufferedT::reset(); DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip); - if(m_chip && chip_r) - delete chip_r; - m_chip = new DBOPL::Handler; - chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip); - chip_r->Init(m_rate); -} - -void DosBoxOPL3::reset(uint32_t rate) -{ - setRate(rate); + chip_r->~Handler(); + new(chip_r) DBOPL::Handler; + chip_r->Init(49716); } void DosBoxOPL3::writeReg(uint16_t addr, uint8_t data) @@ -50,60 +41,11 @@ void DosBoxOPL3::writeReg(uint16_t addr, uint8_t data) chip_r->WriteReg(static_cast<Bit32u>(addr), data); } -int DosBoxOPL3::generate(int16_t *output, size_t frames) -{ - DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip); - Bitu left = (Bitu)frames; - while(left > 0) - { - Bitu frames_i = left; - chip_r->GenerateArr(output, &frames_i); - output += (frames_i * 2); - left -= frames_i; - } - return (int)frames; -} - -int DosBoxOPL3::generateAndMix(int16_t *output, size_t frames) -{ - DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip); - Bitu left = (Bitu)frames; - while(left > 0) - { - Bitu frames_i = left; - chip_r->GenerateArrMix(output, &frames_i); - output += (frames_i * 2); - left -= frames_i; - } - return (int)frames; -} - -int DosBoxOPL3::generate32(int32_t *output, size_t frames) -{ - DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip); - Bitu left = (Bitu)frames; - while(left > 0) - { - Bitu frames_i = left; - chip_r->GenerateArr(output, &frames_i); - output += (frames_i * 2); - left -= frames_i; - } - return (int)frames; -} - -int DosBoxOPL3::generateAndMix32(int32_t *output, size_t frames) +void DosBoxOPL3::nativeGenerateN(int16_t *output, size_t frames) { DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip); - Bitu left = (Bitu)frames; - while(left > 0) - { - Bitu frames_i = left; - chip_r->GenerateArrMix(output, &frames_i); - output += (frames_i * 2); - left -= frames_i; - } - return (int)frames; + Bitu frames_i = frames; + chip_r->GenerateArr(output, &frames_i); } const char *DosBoxOPL3::emulatorName() diff --git a/src/chips/dosbox_opl3.h b/src/chips/dosbox_opl3.h index 422e2d1..f4c68da 100644 --- a/src/chips/dosbox_opl3.h +++ b/src/chips/dosbox_opl3.h @@ -3,23 +3,20 @@ #include "opl_chip_base.h" -class DosBoxOPL3 final : public OPLChipBase +class DosBoxOPL3 final : public OPLChipBaseBufferedT<DosBoxOPL3> { void *m_chip; public: DosBoxOPL3(); - DosBoxOPL3(const DosBoxOPL3 &c); - virtual ~DosBoxOPL3() override; + ~DosBoxOPL3() override; - virtual void setRate(uint32_t rate) override; - virtual void reset() override; - virtual void reset(uint32_t rate) override; - virtual void writeReg(uint16_t addr, uint8_t data) override; - virtual int generate(int16_t *output, size_t frames) override; - virtual int generateAndMix(int16_t *output, size_t frames) override; - virtual int generate32(int32_t *output, size_t frames) override; - virtual int generateAndMix32(int32_t *output, size_t frames) override; - virtual const char *emulatorName() override; + 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 nativeGenerateN(int16_t *output, size_t frames) override; + const char *emulatorName() override; }; #endif // DOSBOX_OPL3_H diff --git a/src/chips/nuked_opl3.cpp b/src/chips/nuked_opl3.cpp index 6490f7f..48e5c17 100644 --- a/src/chips/nuked_opl3.cpp +++ b/src/chips/nuked_opl3.cpp @@ -1,50 +1,34 @@ #include "nuked_opl3.h" #include "nuked/nukedopl3.h" #include <cstring> -#include <cmath> - -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) -#include <zita-resampler/vresampler.h> -#endif NukedOPL3::NukedOPL3() : - OPLChipBase() + OPLChipBaseT() { m_chip = new opl3_chip; -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) - m_resampler = new VResampler; -#endif - reset(m_rate); + setRate(m_rate); } NukedOPL3::~NukedOPL3() { opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip); delete chip_r; -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) - delete m_resampler; -#endif } void NukedOPL3::setRate(uint32_t rate) { - OPLChipBase::setRate(rate); + OPLChipBaseT::setRate(rate); opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip); std::memset(chip_r, 0, sizeof(opl3_chip)); OPL3_Reset(chip_r, rate); -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) - m_resampler->setup(rate * (1.0 / 49716), 2, 48); -#endif } void NukedOPL3::reset() { - setRate(m_rate); -} - -void NukedOPL3::reset(uint32_t rate) -{ - setRate(rate); + OPLChipBaseT::reset(); + opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip); + std::memset(chip_r, 0, sizeof(opl3_chip)); + OPL3_Reset(chip_r, m_rate); } void NukedOPL3::writeReg(uint16_t addr, uint8_t data) @@ -53,118 +37,11 @@ void NukedOPL3::writeReg(uint16_t addr, uint8_t data) OPL3_WriteRegBuffered(chip_r, addr, data); } -int NukedOPL3::generate(int16_t *output, size_t frames) -{ -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) - for(size_t i = 0; i < frames; ++i) - { - generateResampledHq(output); - output += 2; - } -#else - opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip); - OPL3_GenerateStream(chip_r, output, (Bit32u)frames); -#endif - return (int)frames; -} - -int NukedOPL3::generateAndMix(int16_t *output, size_t frames) -{ -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) - for(size_t i = 0; i < frames; ++i) - { - int32_t frame[2]; - generateResampledHq32(frame); - for (unsigned c = 0; c < 2; ++c) { - int32_t temp = (int32_t)output[c] + frame[c]; - temp = (temp > -32768) ? temp : -32768; - temp = (temp < 32767) ? temp : 32767; - output[c] = temp; - } - output += 2; - } -#else - opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip); - OPL3_GenerateStreamMix(chip_r, output, (Bit32u)frames); -#endif - return (int)frames; -} - -int NukedOPL3::generate32(int32_t *output, size_t frames) -{ - opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip); - for(size_t i = 0; i < frames; ++i) { -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) - (void)chip_r; - generateResampledHq32(output); -#else - int16_t frame[2]; - OPL3_GenerateResampled(chip_r, frame); - output[0] = (int32_t)frame[0]; - output[1] = (int32_t)frame[1]; -#endif - output += 2; - } - return (int)frames; -} - -int NukedOPL3::generateAndMix32(int32_t *output, size_t frames) -{ - opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip); - for(size_t i = 0; i < frames; ++i) { -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) - (void)chip_r; - int32_t frame[2]; - generateResampledHq32(frame); -#else - int16_t frame[2]; - OPL3_GenerateResampled(chip_r, frame); -#endif - output[0] += (int32_t)frame[0]; - output[1] += (int32_t)frame[1]; - output += 2; - } - return (int)frames; -} - -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) -void NukedOPL3::generateResampledHq(int16_t *out) -{ - int32_t temps[2]; - generateResampledHq32(temps); - for(unsigned i = 0; i < 2; ++i) - { - int32_t temp = temps[i]; - temp = (temp > -32768) ? temp : -32768; - temp = (temp < 32767) ? temp : 32767; - out[i] = temp; - } -} - -void NukedOPL3::generateResampledHq32(int32_t *out) +void NukedOPL3::nativeGenerate(int16_t *frame) { opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip); - VResampler *rsm = m_resampler; - float f_in[2]; - float f_out[2]; - rsm->inp_count = 0; - rsm->inp_data = f_in; - rsm->out_count = 1; - rsm->out_data = f_out; - while(rsm->process(), rsm->out_count != 0) - { - int16_t in[2]; - OPL3_Generate(chip_r, in); - f_in[0] = (float)in[0], f_in[1] = (float)in[1]; - rsm->inp_count = 1; - rsm->inp_data = f_in; - rsm->out_count = 1; - rsm->out_data = f_out; - } - out[0] = std::lround(f_out[0]); - out[1] = std::lround(f_out[1]); + OPL3_Generate(chip_r, frame); } -#endif const char *NukedOPL3::emulatorName() { diff --git a/src/chips/nuked_opl3.h b/src/chips/nuked_opl3.h index 765a451..25d9ed5 100644 --- a/src/chips/nuked_opl3.h +++ b/src/chips/nuked_opl3.h @@ -3,34 +3,20 @@ #include "opl_chip_base.h" -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) -class VResampler; -#endif - -class NukedOPL3 final : public OPLChipBase +class NukedOPL3 final : public OPLChipBaseT<NukedOPL3> { void *m_chip; -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) - VResampler *m_resampler; -#endif public: NukedOPL3(); - virtual ~NukedOPL3() override; + ~NukedOPL3() override; - virtual void setRate(uint32_t rate) override; - virtual void reset() override; - virtual void reset(uint32_t rate) override; - virtual void writeReg(uint16_t addr, uint8_t data) override; - virtual int generate(int16_t *output, size_t frames) override; - virtual int generateAndMix(int16_t *output, size_t frames) override; - virtual int generate32(int32_t *output, size_t frames) override; - virtual int generateAndMix32(int32_t *output, size_t frames) override; - virtual const char *emulatorName() override; -private: -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) - void generateResampledHq(int16_t *out); - void generateResampledHq32(int32_t *out); -#endif + 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; }; #endif // NUKED_OPL3_H diff --git a/src/chips/nuked_opl3_v174.cpp b/src/chips/nuked_opl3_v174.cpp index d8e8ef8..e24b2e7 100644 --- a/src/chips/nuked_opl3_v174.cpp +++ b/src/chips/nuked_opl3_v174.cpp @@ -1,50 +1,34 @@ #include "nuked_opl3_v174.h" #include "nuked/nukedopl3_174.h" #include <cstring> -#include <cmath> - -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) -#include <zita-resampler/vresampler.h> -#endif NukedOPL3v174::NukedOPL3v174() : - OPLChipBase() + OPLChipBaseT() { m_chip = new opl3_chip; -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) - m_resampler = new VResampler; -#endif - reset(m_rate); + setRate(m_rate); } NukedOPL3v174::~NukedOPL3v174() { opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip); delete chip_r; -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) - delete m_resampler; -#endif } void NukedOPL3v174::setRate(uint32_t rate) { - OPLChipBase::setRate(rate); + OPLChipBaseT::setRate(rate); opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip); std::memset(chip_r, 0, sizeof(opl3_chip)); OPL3v17_Reset(chip_r, rate); -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) - m_resampler->setup(rate * (1.0 / 49716), 2, 48); -#endif } void NukedOPL3v174::reset() { - setRate(m_rate); -} - -void NukedOPL3v174::reset(uint32_t rate) -{ - setRate(rate); + OPLChipBaseT::reset(); + opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip); + std::memset(chip_r, 0, sizeof(opl3_chip)); + OPL3v17_Reset(chip_r, m_rate); } void NukedOPL3v174::writeReg(uint16_t addr, uint8_t data) @@ -53,118 +37,11 @@ void NukedOPL3v174::writeReg(uint16_t addr, uint8_t data) OPL3v17_WriteReg(chip_r, addr, data); } -int NukedOPL3v174::generate(int16_t *output, size_t frames) -{ -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) - for(size_t i = 0; i < frames; ++i) - { - generateResampledHq(output); - output += 2; - } -#else - opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip); - OPL3v17_GenerateStream(chip_r, output, (Bit32u)frames); -#endif - return (int)frames; -} - -int NukedOPL3v174::generateAndMix(int16_t *output, size_t frames) -{ -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) - for(size_t i = 0; i < frames; ++i) - { - int32_t frame[2]; - generateResampledHq32(frame); - for (unsigned c = 0; c < 2; ++c) { - int32_t temp = (int32_t)output[c] + frame[c]; - temp = (temp > -32768) ? temp : -32768; - temp = (temp < 32767) ? temp : 32767; - output[c] = temp; - } - output += 2; - } -#else - opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip); - OPL3v17_GenerateStreamMix(chip_r, output, (Bit32u)frames); -#endif - return (int)frames; -} - -int NukedOPL3v174::generate32(int32_t *output, size_t frames) -{ - opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip); - for(size_t i = 0; i < frames; ++i) { -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) - (void)chip_r; - generateResampledHq32(output); -#else - int16_t frame[2]; - OPL3v17_GenerateResampled(chip_r, frame); - output[0] = (int32_t)frame[0]; - output[1] = (int32_t)frame[1]; -#endif - output += 2; - } - return (int)frames; -} - -int NukedOPL3v174::generateAndMix32(int32_t *output, size_t frames) -{ - opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip); - for(size_t i = 0; i < frames; ++i) { -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) - (void)chip_r; - int32_t frame[2]; - generateResampledHq32(frame); -#else - int16_t frame[2]; - OPL3v17_GenerateResampled(chip_r, frame); -#endif - output[0] += (int32_t)frame[0]; - output[1] += (int32_t)frame[1]; - output += 2; - } - return (int)frames; -} - -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) -void NukedOPL3v174::generateResampledHq(int16_t *out) -{ - int32_t temps[2]; - generateResampledHq32(temps); - for(unsigned i = 0; i < 2; ++i) - { - int32_t temp = temps[i]; - temp = (temp > -32768) ? temp : -32768; - temp = (temp < 32767) ? temp : 32767; - out[i] = temp; - } -} - -void NukedOPL3v174::generateResampledHq32(int32_t *out) +void NukedOPL3v174::nativeGenerate(int16_t *frame) { opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip); - VResampler *rsm = m_resampler; - float f_in[2]; - float f_out[2]; - rsm->inp_count = 0; - rsm->inp_data = f_in; - rsm->out_count = 1; - rsm->out_data = f_out; - while(rsm->process(), rsm->out_count != 0) - { - int16_t in[2]; - OPL3v17_Generate(chip_r, in); - f_in[0] = (float)in[0], f_in[1] = (float)in[1]; - rsm->inp_count = 1; - rsm->inp_data = f_in; - rsm->out_count = 1; - rsm->out_data = f_out; - } - out[0] = std::lround(f_out[0]); - out[1] = std::lround(f_out[1]); + OPL3v17_Generate(chip_r, frame); } -#endif const char *NukedOPL3v174::emulatorName() { diff --git a/src/chips/nuked_opl3_v174.h b/src/chips/nuked_opl3_v174.h index efe65ba..b9c5ba6 100644 --- a/src/chips/nuked_opl3_v174.h +++ b/src/chips/nuked_opl3_v174.h @@ -3,34 +3,20 @@ #include "opl_chip_base.h" -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) -class VResampler; -#endif - -class NukedOPL3v174 final : public OPLChipBase +class NukedOPL3v174 final : public OPLChipBaseT<NukedOPL3v174> { void *m_chip; -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) - VResampler *m_resampler; -#endif public: NukedOPL3v174(); - virtual ~NukedOPL3v174() override; + ~NukedOPL3v174() override; - virtual void setRate(uint32_t rate) override; - virtual void reset() override; - virtual void reset(uint32_t rate) override; - virtual void writeReg(uint16_t addr, uint8_t data) override; - virtual int generate(int16_t *output, size_t frames) override; - virtual int generateAndMix(int16_t *output, size_t frames) override; - virtual int generate32(int32_t *output, size_t frames) override; - virtual int generateAndMix32(int32_t *output, size_t frames) override; - virtual const char *emulatorName() override; -private: -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) - void generateResampledHq(int16_t *out); - void generateResampledHq32(int32_t *out); -#endif + 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; }; #endif // NUKED_OPL3174_H diff --git a/src/chips/opl_chip_base.cpp b/src/chips/opl_chip_base.cpp deleted file mode 100644 index 670a998..0000000 --- a/src/chips/opl_chip_base.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "opl_chip_base.h" - -OPLChipBase::OPLChipBase() : - m_rate(44100) -{} - -OPLChipBase::OPLChipBase(const OPLChipBase &c): - m_rate(c.m_rate) -{} - -OPLChipBase::~OPLChipBase() -{} - -void OPLChipBase::setRate(uint32_t rate) -{ - m_rate = rate; -} - -void OPLChipBase::reset(uint32_t rate) -{ - setRate(rate); -} - -int OPLChipBase::generate32(int32_t *output, size_t frames) -{ - enum { maxFramesAtOnce = 256 }; - int16_t temp[2 * maxFramesAtOnce]; - for(size_t left = frames; left > 0;) { - size_t count = (left < static_cast<size_t>(maxFramesAtOnce)) ? left : static_cast<size_t>(maxFramesAtOnce); - generate(temp, count); - for(size_t i = 0; i < 2 * count; ++i) - output[i] = temp[i]; - left -= count; - output += 2 * count; - } - return (int)frames; -} - -int OPLChipBase::generateAndMix32(int32_t *output, size_t frames) -{ - enum { maxFramesAtOnce = 256 }; - int16_t temp[2 * maxFramesAtOnce]; - for(size_t left = frames; left > 0;) { - size_t count = (left < static_cast<size_t>(maxFramesAtOnce)) ? left : static_cast<size_t>(maxFramesAtOnce); - generate(temp, count); - for(size_t i = 0; i < 2 * count; ++i) - output[i] += temp[i]; - left -= count; - output += 2 * count; - } - return (int)frames; -} diff --git a/src/chips/opl_chip_base.h b/src/chips/opl_chip_base.h index fb9b9e9..5721a81 100644 --- a/src/chips/opl_chip_base.h +++ b/src/chips/opl_chip_base.h @@ -9,24 +9,91 @@ #define override #endif +#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) +class VResampler; +#endif + class OPLChipBase { protected: uint32_t m_rate; public: OPLChipBase(); - OPLChipBase(const OPLChipBase &c); virtual ~OPLChipBase(); - virtual void setRate(uint32_t rate); + virtual void setRate(uint32_t rate) = 0; virtual void reset() = 0; - virtual void reset(uint32_t rate); virtual void writeReg(uint16_t addr, uint8_t data) = 0; - virtual int generate(int16_t *output, size_t frames) = 0; - virtual int generateAndMix(int16_t *output, size_t frames) = 0; - virtual int generate32(int32_t *output, size_t frames); - virtual int generateAndMix32(int32_t *output, size_t frames); + + virtual void nativePreGenerate() = 0; + virtual void nativePostGenerate() = 0; + virtual void nativeGenerate(int16_t *frame) = 0; + + virtual void generate(int16_t *output, size_t frames) = 0; + virtual void generateAndMix(int16_t *output, size_t frames) = 0; + virtual void generate32(int32_t *output, size_t frames) = 0; + virtual void generateAndMix32(int32_t *output, size_t frames) = 0; + virtual const char* emulatorName() = 0; +private: + OPLChipBase(const OPLChipBase &c); + OPLChipBase &operator=(const OPLChipBase &c); +}; + +// A base class providing F-bounded generic and efficient implementations, +// supporting resampling of chip outputs +template <class T> +class OPLChipBaseT : public OPLChipBase +{ +public: + OPLChipBaseT(); + virtual ~OPLChipBaseT(); + + virtual void setRate(uint32_t rate) override; + virtual void reset() override; + void generate(int16_t *output, size_t frames) override; + void generateAndMix(int16_t *output, size_t frames) override; + void generate32(int32_t *output, size_t frames) override; + void generateAndMix32(int32_t *output, size_t frames) override; +private: + void setupResampler(uint32_t rate); + void resetResampler(); + void resampledGenerate(int32_t *output); +#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) + VResampler *m_resampler; +#else + int32_t m_oldsamples[2]; + int32_t m_samples[2]; + int32_t m_samplecnt; + int32_t m_rateratio; + enum { rsm_frac = 10 }; +#endif + // amplitude scale factors in and out of resampler, varying for chips; + // values are OK to "redefine", the static polymorphism will accept it. + enum { resamplerPreAmplify = 1, resamplerPostAttenuate = 1 }; +}; + +// A base class which provides frame-by-frame interfaces on emulations which +// don't have a routine for it. It produces outputs in fixed size buffers. +// Fast register updates will suffer some latency because of buffering. +template <class T, unsigned Buffer = 256> +class OPLChipBaseBufferedT : public OPLChipBaseT<T> +{ +public: + OPLChipBaseBufferedT() + : OPLChipBaseT<T>(), m_bufferIndex(0) {} + virtual ~OPLChipBaseBufferedT() + {} +public: + void reset() override; + void nativeGenerate(int16_t *frame) override; +protected: + virtual void nativeGenerateN(int16_t *output, size_t frames) = 0; +private: + unsigned m_bufferIndex; + int16_t m_buffer[2 * Buffer]; }; +#include "opl_chip_base.tcc" + #endif // ONP_CHIP_BASE_H diff --git a/src/chips/opl_chip_base.tcc b/src/chips/opl_chip_base.tcc new file mode 100644 index 0000000..42cfc13 --- /dev/null +++ b/src/chips/opl_chip_base.tcc @@ -0,0 +1,214 @@ +#include "opl_chip_base.h" +#include <cmath> + +#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) +#include <zita-resampler/vresampler.h> +#endif + +/* OPLChipBase */ + +inline OPLChipBase::OPLChipBase() : + m_rate(44100) +{ +} + +inline OPLChipBase::~OPLChipBase() +{ +} + +/* OPLChipBaseT */ + +template <class T> +OPLChipBaseT<T>::OPLChipBaseT() + : OPLChipBase() +{ +#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) + m_resampler = new VResampler; +#endif + setupResampler(m_rate); +} + +template <class T> +OPLChipBaseT<T>::~OPLChipBaseT() +{ +#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) + delete m_resampler; +#endif +} + +template <class T> +void OPLChipBaseT<T>::setRate(uint32_t rate) +{ + uint32_t oldRate = m_rate; + m_rate = rate; + if(rate != oldRate) + setupResampler(rate); + else + resetResampler(); +} + +template <class T> +void OPLChipBaseT<T>::reset() +{ + resetResampler(); +} + +template <class T> +void OPLChipBaseT<T>::generate(int16_t *output, size_t frames) +{ + static_cast<T *>(this)->nativePreGenerate(); + for(size_t i = 0; i < frames; ++i) + { + int32_t frame[2]; + static_cast<T *>(this)->resampledGenerate(frame); + for (unsigned c = 0; c < 2; ++c) { + int32_t temp = frame[c]; + temp = (temp > -32768) ? temp : -32768; + temp = (temp < 32767) ? temp : 32767; + output[c] = temp; + } + } + static_cast<T *>(this)->nativePostGenerate(); +} + +template <class T> +void OPLChipBaseT<T>::generateAndMix(int16_t *output, size_t frames) +{ + static_cast<T *>(this)->nativePreGenerate(); + for(size_t i = 0; i < frames; ++i) + { + int32_t frame[2]; + static_cast<T *>(this)->resampledGenerate(frame); + for (unsigned c = 0; c < 2; ++c) { + int32_t temp = (int32_t)output[c] + frame[c]; + temp = (temp > -32768) ? temp : -32768; + temp = (temp < 32767) ? temp : 32767; + output[c] = temp; + } + } + static_cast<T *>(this)->nativePostGenerate(); +} + +template <class T> +void OPLChipBaseT<T>::generate32(int32_t *output, size_t frames) +{ + static_cast<T *>(this)->nativePreGenerate(); + for(size_t i = 0; i < frames; ++i) + { + static_cast<T *>(this)->resampledGenerate(output); + output += 2; + } + static_cast<T *>(this)->nativePostGenerate(); +} + +template <class T> +void OPLChipBaseT<T>::generateAndMix32(int32_t *output, size_t frames) +{ + static_cast<T *>(this)->nativePreGenerate(); + for(size_t i = 0; i < frames; ++i) + { + int32_t frame[2]; + static_cast<T *>(this)->resampledGenerate(frame); + output[0] += frame[0]; + output[1] += frame[1]; + output += 2; + } + static_cast<T *>(this)->nativePostGenerate(); +} + +template <class T> +void OPLChipBaseT<T>::setupResampler(uint32_t rate) +{ +#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) + m_resampler->setup(rate * (1.0 / 49716), 2, 48); +#else + m_oldsamples[0] = m_oldsamples[1] = 0; + m_samples[0] = m_samples[1] = 0; + m_samplecnt = 0; + m_rateratio = (int32_t)((rate << rsm_frac) / 49716); +#endif +} + +template <class T> +void OPLChipBaseT<T>::resetResampler() +{ +#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) + m_resampler->reset(); +#else + m_oldsamples[0] = m_oldsamples[1] = 0; + m_samples[0] = m_samples[1] = 0; + m_samplecnt = 0; +#endif +} + +#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) +template <class T> +void OPLChipBaseT<T>::resampledGenerate(int32_t *output) +{ + VResampler *rsm = m_resampler; + float scale = (float)T::resamplerPreAmplify / + (float)T::resamplerPostAttenuate; + float f_in[2]; + float f_out[2]; + rsm->inp_count = 0; + rsm->inp_data = f_in; + rsm->out_count = 1; + rsm->out_data = f_out; + while(rsm->process(), rsm->out_count != 0) + { + int16_t in[2]; + static_cast<T *>(this)->nativeGenerate(in); + f_in[0] = scale * (float)in[0]; + f_in[1] = scale * (float)in[1]; + rsm->inp_count = 1; + rsm->inp_data = f_in; + rsm->out_count = 1; + rsm->out_data = f_out; + } + output[0] = std::lround(f_out[0]); + output[1] = std::lround(f_out[1]); +} +#else +template <class T> +void OPLChipBaseT<T>::resampledGenerate(int32_t *output) +{ + int32_t samplecnt = m_samplecnt; + const int32_t rateratio = m_rateratio; + while(samplecnt >= rateratio) + { + m_oldsamples[0] = m_samples[0]; + m_oldsamples[1] = m_samples[1]; + int16_t buffer[2]; + static_cast<T *>(this)->nativeGenerate(buffer); + m_samples[0] = buffer[0] * T::resamplerPreAmplify; + m_samples[1] = buffer[1] * T::resamplerPreAmplify; + samplecnt -= rateratio; + } + output[0] = (int32_t)(((m_oldsamples[0] * (rateratio - samplecnt) + + m_samples[0] * samplecnt) / rateratio)/T::resamplerPostAttenuate); + output[1] = (int32_t)(((m_oldsamples[1] * (rateratio - samplecnt) + + m_samples[1] * samplecnt) / rateratio)/T::resamplerPostAttenuate); + m_samplecnt = samplecnt + (1 << rsm_frac); +} +#endif + +/* OPLChipBaseBufferedT */ + +template <class T, unsigned Buffer> +void OPLChipBaseBufferedT<T, Buffer>::reset() +{ + OPLChipBaseT<T>::reset(); + m_bufferIndex = 0; +} + +template <class T, unsigned Buffer> +void OPLChipBaseBufferedT<T, Buffer>::nativeGenerate(int16_t *frame) +{ + unsigned bufferIndex = m_bufferIndex; + if(bufferIndex == 0) + static_cast<T *>(this)->nativeGenerateN(m_buffer, Buffer); + frame[0] = m_buffer[2 * bufferIndex]; + frame[1] = m_buffer[2 * bufferIndex + 1]; + bufferIndex = (bufferIndex + 1 < Buffer) ? (bufferIndex + 1) : 0; + m_bufferIndex = bufferIndex; +} |