aboutsummaryrefslogtreecommitdiff
path: root/src/chips/opl_chip_base.tcc
diff options
context:
space:
mode:
Diffstat (limited to 'src/chips/opl_chip_base.tcc')
-rw-r--r--src/chips/opl_chip_base.tcc214
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;
+}