aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt8
-rw-r--r--libADLMIDI-test.pro2
-rw-r--r--src/chips/dosbox_opl3.cpp88
-rw-r--r--src/chips/dosbox_opl3.h21
-rw-r--r--src/chips/nuked_opl3.cpp141
-rw-r--r--src/chips/nuked_opl3.h32
-rw-r--r--src/chips/nuked_opl3_v174.cpp141
-rw-r--r--src/chips/nuked_opl3_v174.h32
-rw-r--r--src/chips/opl_chip_base.cpp52
-rw-r--r--src/chips/opl_chip_base.h81
-rw-r--r--src/chips/opl_chip_base.tcc214
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;
+}