diff options
author | JP Cimalando <jpcima@users.noreply.github.com> | 2018-06-07 07:21:29 +0200 |
---|---|---|
committer | JP Cimalando <jpcima@users.noreply.github.com> | 2018-06-08 00:24:39 +0200 |
commit | 7cfe4dbcef738681b5445aa14b35fc1a6f8ff001 (patch) | |
tree | 2a1bfd77d9a5759f566bed4834ce6721a301844d /src/chips/opl_chip_base.tcc | |
parent | d8142ef298fa4ce54a8dbf8977709b9209c148e6 (diff) | |
download | libADLMIDI-7cfe4dbcef738681b5445aa14b35fc1a6f8ff001.tar.gz libADLMIDI-7cfe4dbcef738681b5445aa14b35fc1a6f8ff001.tar.bz2 libADLMIDI-7cfe4dbcef738681b5445aa14b35fc1a6f8ff001.zip |
chips: create a common method set for generation and resampling
Diffstat (limited to 'src/chips/opl_chip_base.tcc')
-rw-r--r-- | src/chips/opl_chip_base.tcc | 214 |
1 files changed, 214 insertions, 0 deletions
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; +} |