diff options
author | JP Cimalando <jpcima@users.noreply.github.com> | 2018-06-03 14:50:53 +0200 |
---|---|---|
committer | JP Cimalando <jpcima@users.noreply.github.com> | 2018-06-03 15:45:44 +0200 |
commit | e3cad2f46925ac0b9ae303bea68a5fe508e78bc9 (patch) | |
tree | b72c940f22221f55c582115a71a4dd12259b94a7 | |
parent | 9ed43c5b909b1a0aafe16bbd431d6a90af3c9920 (diff) | |
download | libADLMIDI-e3cad2f46925ac0b9ae303bea68a5fe508e78bc9.tar.gz libADLMIDI-e3cad2f46925ac0b9ae303bea68a5fe508e78bc9.tar.bz2 libADLMIDI-e3cad2f46925ac0b9ae303bea68a5fe508e78bc9.zip |
optional high-quality resampling
-rw-r--r-- | CMakeLists.txt | 13 | ||||
-rw-r--r-- | src/chips/nuked_opl3.cpp | 91 | ||||
-rw-r--r-- | src/chips/nuked_opl3.h | 13 | ||||
-rw-r--r-- | src/chips/nuked_opl3_v174.cpp | 91 | ||||
-rw-r--r-- | src/chips/nuked_opl3_v174.h | 13 |
5 files changed, 203 insertions, 18 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index ce162a0..0bf7719 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,6 +70,7 @@ option(WITH_CPP_EXTRAS "Build with support for C++ extras (features are can option(WITH_MIDI_SEQUENCER "Build with embedded MIDI sequencer. Disable this if you want use library in real-time MIDI drivers or plugins.)" ON) option(WITH_MUS_SUPPORT "Build with support for DMX MUS files)" ON) option(WITH_XMI_SUPPORT "Build with support for AIL XMI files)" ON) +option(WITH_HQ_RESAMPLER "Build with support for high quality resampling" OFF) option(libADLMIDI_STATIC "Build static library of libADLMIDI" ON) option(libADLMIDI_SHARED "Build shared library of libADLMIDI" OFF) @@ -480,6 +481,17 @@ if(WITH_VLC_PLUGIN) endif() +if(WITH_HQ_RESAMPLER) + find_library(ZITA_RESAMPLER_LIBRARY "zita-resampler" REQUIRED) + add_definitions(-DADLMIDI_ENABLE_HQ_RESAMPLER) + if(libADLMIDI_SHARED) + target_link_libraries(ADLMIDI_shared PUBLIC "${ZITA_RESAMPLER_LIBRARY}") + endif() + if(libADLMIDI_STATIC) + target_link_libraries(ADLMIDI_static PUBLIC "${ZITA_RESAMPLER_LIBRARY}") + endif() +endif() + install(TARGETS ${libADLMIDI_INSTALLS} RUNTIME DESTINATION "bin" LIBRARY DESTINATION "lib" @@ -512,6 +524,7 @@ message("WITH_MIDI_SEQUENCER = ${WITH_MIDI_SEQUENCER}") message("WITH_CPP_EXTRAS = ${WITH_CPP_EXTRAS}") message("WITH_MUS_SUPPORT = ${WITH_MUS_SUPPORT}") message("WITH_XMI_SUPPORT = ${WITH_XMI_SUPPORT}") +message("WITH_HQ_RESAMPLER = ${WITH_HQ_RESAMPLER}") message("libADLMIDI_STATIC = ${libADLMIDI_STATIC}") message("libADLMIDI_SHARED = ${libADLMIDI_SHARED}") message("EXAMPLE_SDL2_AUDIO = ${EXAMPLE_SDL2_AUDIO}") diff --git a/src/chips/nuked_opl3.cpp b/src/chips/nuked_opl3.cpp index 70fc525..fc6363d 100644 --- a/src/chips/nuked_opl3.cpp +++ b/src/chips/nuked_opl3.cpp @@ -1,26 +1,29 @@ #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() { m_chip = new opl3_chip; +#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) + m_resampler = new VResampler; +#endif reset(m_rate); } -NukedOPL3::NukedOPL3(const NukedOPL3 &c): - OPLChipBase(c) -{ - m_chip = new opl3_chip; - std::memset(m_chip, 0, sizeof(opl3_chip)); - reset(c.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) @@ -29,6 +32,9 @@ void NukedOPL3::setRate(uint32_t 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() @@ -49,15 +55,34 @@ void NukedOPL3::writeReg(uint16_t addr, uint8_t 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) + { + int16_t frame[2]; + generateResampledHq(frame); + output[0] += (int32_t)frame[0]; + output[1] += (int32_t)frame[1]; + output += 2; + } +#else opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip); OPL3_GenerateStreamMix(chip_r, output, (Bit32u)frames); +#endif return (int)frames; } @@ -65,10 +90,15 @@ 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; @@ -78,8 +108,14 @@ 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; @@ -87,6 +123,45 @@ int NukedOPL3::generateAndMix32(int32_t *output, size_t frames) 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) +{ + 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]); +} +#endif + const char *NukedOPL3::emulatorName() { return "Nuked OPL3 (v 1.8)"; diff --git a/src/chips/nuked_opl3.h b/src/chips/nuked_opl3.h index ceb1dfd..765a451 100644 --- a/src/chips/nuked_opl3.h +++ b/src/chips/nuked_opl3.h @@ -3,12 +3,18 @@ #include "opl_chip_base.h" +#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) +class VResampler; +#endif + class NukedOPL3 final : public OPLChipBase { void *m_chip; +#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) + VResampler *m_resampler; +#endif public: NukedOPL3(); - NukedOPL3(const NukedOPL3 &c); virtual ~NukedOPL3() override; virtual void setRate(uint32_t rate) override; @@ -20,6 +26,11 @@ public: 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 }; #endif // NUKED_OPL3_H diff --git a/src/chips/nuked_opl3_v174.cpp b/src/chips/nuked_opl3_v174.cpp index 0dcf925..675e104 100644 --- a/src/chips/nuked_opl3_v174.cpp +++ b/src/chips/nuked_opl3_v174.cpp @@ -1,26 +1,29 @@ #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() { m_chip = new opl3_chip; +#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) + m_resampler = new VResampler; +#endif reset(m_rate); } -NukedOPL3v174::NukedOPL3v174(const NukedOPL3v174 &c): - OPLChipBase(c) -{ - m_chip = new opl3_chip; - std::memset(m_chip, 0, sizeof(opl3_chip)); - reset(c.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) @@ -29,6 +32,9 @@ void NukedOPL3v174::setRate(uint32_t 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() @@ -49,15 +55,34 @@ void NukedOPL3v174::writeReg(uint16_t addr, uint8_t 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) + { + int16_t frame[2]; + generateResampledHq(frame); + output[0] += (int32_t)frame[0]; + output[1] += (int32_t)frame[1]; + output += 2; + } +#else opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip); OPL3v17_GenerateStreamMix(chip_r, output, (Bit32u)frames); +#endif return (int)frames; } @@ -65,10 +90,15 @@ 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; @@ -78,8 +108,14 @@ 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; @@ -87,6 +123,45 @@ int NukedOPL3v174::generateAndMix32(int32_t *output, size_t frames) 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) +{ + 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]); +} +#endif + const char *NukedOPL3v174::emulatorName() { return "Nuked OPL3 (v 1.7.4)"; diff --git a/src/chips/nuked_opl3_v174.h b/src/chips/nuked_opl3_v174.h index acbdcca..efe65ba 100644 --- a/src/chips/nuked_opl3_v174.h +++ b/src/chips/nuked_opl3_v174.h @@ -3,12 +3,18 @@ #include "opl_chip_base.h" +#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) +class VResampler; +#endif + class NukedOPL3v174 final : public OPLChipBase { void *m_chip; +#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) + VResampler *m_resampler; +#endif public: NukedOPL3v174(); - NukedOPL3v174(const NukedOPL3v174 &c); virtual ~NukedOPL3v174() override; virtual void setRate(uint32_t rate) override; @@ -20,6 +26,11 @@ public: 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 }; #endif // NUKED_OPL3174_H |