aboutsummaryrefslogtreecommitdiff
path: root/src/chips
diff options
context:
space:
mode:
Diffstat (limited to 'src/chips')
-rw-r--r--src/chips/dosbox_opl3.cpp4
-rw-r--r--src/chips/dosbox_opl3.h1
-rw-r--r--src/chips/nuked_opl3.h1
-rw-r--r--src/chips/nuked_opl3_v174.h1
-rw-r--r--src/chips/opl_chip_base.h30
-rw-r--r--src/chips/opl_chip_base.tcc84
6 files changed, 116 insertions, 5 deletions
diff --git a/src/chips/dosbox_opl3.cpp b/src/chips/dosbox_opl3.cpp
index af4cb08..30fa38e 100644
--- a/src/chips/dosbox_opl3.cpp
+++ b/src/chips/dosbox_opl3.cpp
@@ -23,7 +23,7 @@ void DosBoxOPL3::setRate(uint32_t rate)
DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip);
chip_r->~Handler();
new(chip_r) DBOPL::Handler;
- chip_r->Init(49716);
+ chip_r->Init(effectiveRate());
}
void DosBoxOPL3::reset()
@@ -32,7 +32,7 @@ void DosBoxOPL3::reset()
DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip);
chip_r->~Handler();
new(chip_r) DBOPL::Handler;
- chip_r->Init(49716);
+ chip_r->Init(effectiveRate());
}
void DosBoxOPL3::writeReg(uint16_t addr, uint8_t data)
diff --git a/src/chips/dosbox_opl3.h b/src/chips/dosbox_opl3.h
index f4c68da..1928026 100644
--- a/src/chips/dosbox_opl3.h
+++ b/src/chips/dosbox_opl3.h
@@ -10,6 +10,7 @@ public:
DosBoxOPL3();
~DosBoxOPL3() override;
+ bool canRunAtPcmRate() const override { return true; }
void setRate(uint32_t rate) override;
void reset() override;
void writeReg(uint16_t addr, uint8_t data) override;
diff --git a/src/chips/nuked_opl3.h b/src/chips/nuked_opl3.h
index 25d9ed5..1b34e9a 100644
--- a/src/chips/nuked_opl3.h
+++ b/src/chips/nuked_opl3.h
@@ -10,6 +10,7 @@ public:
NukedOPL3();
~NukedOPL3() override;
+ bool canRunAtPcmRate() const override { return false; }
void setRate(uint32_t rate) override;
void reset() override;
void writeReg(uint16_t addr, uint8_t data) override;
diff --git a/src/chips/nuked_opl3_v174.h b/src/chips/nuked_opl3_v174.h
index b9c5ba6..f14221f 100644
--- a/src/chips/nuked_opl3_v174.h
+++ b/src/chips/nuked_opl3_v174.h
@@ -10,6 +10,7 @@ public:
NukedOPL3v174();
~NukedOPL3v174() override;
+ bool canRunAtPcmRate() const override { return false; }
void setRate(uint32_t rate) override;
void reset() override;
void writeReg(uint16_t addr, uint8_t data) override;
diff --git a/src/chips/opl_chip_base.h b/src/chips/opl_chip_base.h
index 5721a81..879d6da 100644
--- a/src/chips/opl_chip_base.h
+++ b/src/chips/opl_chip_base.h
@@ -13,15 +13,33 @@
class VResampler;
#endif
+#if defined(ADLMIDI_AUDIO_TICK_HANDLER)
+extern void adl_audioTickHandler(void *instance, uint32_t chipId, uint32_t rate);
+#endif
+
class OPLChipBase
{
+public:
+ enum { nativeRate = 49716 };
protected:
+ uint32_t m_id;
uint32_t m_rate;
public:
OPLChipBase();
virtual ~OPLChipBase();
+ uint32_t chipId() const { return m_id; }
+ void setChipId(uint32_t id) { m_id = id; }
+
+ virtual bool canRunAtPcmRate() const = 0;
+ virtual bool isRunningAtPcmRate() const = 0;
+ virtual bool setRunningAtPcmRate(bool r) = 0;
+#if defined(ADLMIDI_AUDIO_TICK_HANDLER)
+ virtual void setAudioTickHandlerInstance(void *instance) = 0;
+#endif
+
virtual void setRate(uint32_t rate) = 0;
+ virtual uint32_t effectiveRate() const = 0;
virtual void reset() = 0;
virtual void writeReg(uint16_t addr, uint8_t data) = 0;
@@ -49,13 +67,25 @@ public:
OPLChipBaseT();
virtual ~OPLChipBaseT();
+ bool isRunningAtPcmRate() const override;
+ bool setRunningAtPcmRate(bool r) override;
+#if defined(ADLMIDI_AUDIO_TICK_HANDLER)
+ void setAudioTickHandlerInstance(void *instance);
+#endif
+
virtual void setRate(uint32_t rate) override;
+ uint32_t effectiveRate() const 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:
+ bool m_runningAtPcmRate;
+#if defined(ADLMIDI_AUDIO_TICK_HANDLER)
+ void *m_audioTickHandlerInstance;
+#endif
+ void nativeTick(int16_t *frame);
void setupResampler(uint32_t rate);
void resetResampler();
void resampledGenerate(int32_t *output);
diff --git a/src/chips/opl_chip_base.tcc b/src/chips/opl_chip_base.tcc
index 58145bc..48ad103 100644
--- a/src/chips/opl_chip_base.tcc
+++ b/src/chips/opl_chip_base.tcc
@@ -5,9 +5,22 @@
#include <zita-resampler/vresampler.h>
#endif
+#if !defined(LIKELY) && defined(__GNUC__)
+#define LIKELY(x) __builtin_expect((x), 1)
+#elif !defined(LIKELY)
+#define LIKELY(x) (x)
+#endif
+
+#if !defined(UNLIKELY) && defined(__GNUC__)
+#define UNLIKELY(x) __builtin_expect((x), 0)
+#elif !defined(UNLIKELY)
+#define UNLIKELY(x) (x)
+#endif
+
/* OPLChipBase */
inline OPLChipBase::OPLChipBase() :
+ m_id(0),
m_rate(44100)
{
}
@@ -20,7 +33,12 @@ inline OPLChipBase::~OPLChipBase()
template <class T>
OPLChipBaseT<T>::OPLChipBaseT()
- : OPLChipBase()
+ : OPLChipBase(),
+ m_runningAtPcmRate(false)
+#if defined(ADLMIDI_AUDIO_TICK_HANDLER)
+ ,
+ m_audioTickHandlerInstance(NULL)
+#endif
{
#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER)
m_resampler = new VResampler;
@@ -37,6 +55,33 @@ OPLChipBaseT<T>::~OPLChipBaseT()
}
template <class T>
+bool OPLChipBaseT<T>::isRunningAtPcmRate() const
+{
+ return m_runningAtPcmRate;
+}
+
+template <class T>
+bool OPLChipBaseT<T>::setRunningAtPcmRate(bool r)
+{
+ if(r != m_runningAtPcmRate)
+ {
+ if(r && !static_cast<T *>(this)->canRunAtPcmRate())
+ return false;
+ m_runningAtPcmRate = r;
+ static_cast<T *>(this)->setRate(m_rate);
+ }
+ return true;
+}
+
+#if defined(ADLMIDI_AUDIO_TICK_HANDLER)
+template <class T>
+void OPLChipBaseT<T>::setAudioTickHandlerInstance(void *instance)
+{
+ m_audioTickHandlerInstance = instance;
+}
+#endif
+
+template <class T>
void OPLChipBaseT<T>::setRate(uint32_t rate)
{
uint32_t oldRate = m_rate;
@@ -48,6 +93,12 @@ void OPLChipBaseT<T>::setRate(uint32_t rate)
}
template <class T>
+uint32_t OPLChipBaseT<T>::effectiveRate() const
+{
+ return m_runningAtPcmRate ? m_rate : (uint32_t)nativeRate;
+}
+
+template <class T>
void OPLChipBaseT<T>::reset()
{
resetResampler();
@@ -119,6 +170,15 @@ void OPLChipBaseT<T>::generateAndMix32(int32_t *output, size_t frames)
}
template <class T>
+void OPLChipBaseT<T>::nativeTick(int16_t *frame)
+{
+#if defined(ADLMIDI_AUDIO_TICK_HANDLER)
+ adl_audioTickHandler(m_audioTickHandlerInstance, m_id, effectiveRate());
+#endif
+ static_cast<T *>(this)->nativeGenerate(frame);
+}
+
+template <class T>
void OPLChipBaseT<T>::setupResampler(uint32_t rate)
{
#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER)
@@ -147,6 +207,15 @@ void OPLChipBaseT<T>::resetResampler()
template <class T>
void OPLChipBaseT<T>::resampledGenerate(int32_t *output)
{
+ if(UNLIKELY(m_runningAtPcmRate))
+ {
+ int16_t in[2];
+ static_cast<T *>(this)->nativeTick(in);
+ output[0] = (int32_t)in[0] * T::resamplerPreAmplify / T::resamplerPostAttenuate;
+ output[1] = (int32_t)in[1] * T::resamplerPreAmplify / T::resamplerPostAttenuate;
+ return;
+ }
+
VResampler *rsm = m_resampler;
float scale = (float)T::resamplerPreAmplify /
(float)T::resamplerPostAttenuate;
@@ -159,7 +228,7 @@ void OPLChipBaseT<T>::resampledGenerate(int32_t *output)
while(rsm->process(), rsm->out_count != 0)
{
int16_t in[2];
- static_cast<T *>(this)->nativeGenerate(in);
+ static_cast<T *>(this)->nativeTick(in);
f_in[0] = scale * (float)in[0];
f_in[1] = scale * (float)in[1];
rsm->inp_count = 1;
@@ -174,6 +243,15 @@ void OPLChipBaseT<T>::resampledGenerate(int32_t *output)
template <class T>
void OPLChipBaseT<T>::resampledGenerate(int32_t *output)
{
+ if(UNLIKELY(m_runningAtPcmRate))
+ {
+ int16_t in[2];
+ static_cast<T *>(this)->nativeTick(in);
+ output[0] = (int32_t)in[0] * T::resamplerPreAmplify / T::resamplerPostAttenuate;
+ output[1] = (int32_t)in[1] * T::resamplerPreAmplify / T::resamplerPostAttenuate;
+ return;
+ }
+
int32_t samplecnt = m_samplecnt;
const int32_t rateratio = m_rateratio;
while(samplecnt >= rateratio)
@@ -181,7 +259,7 @@ void OPLChipBaseT<T>::resampledGenerate(int32_t *output)
m_oldsamples[0] = m_samples[0];
m_oldsamples[1] = m_samples[1];
int16_t buffer[2];
- static_cast<T *>(this)->nativeGenerate(buffer);
+ static_cast<T *>(this)->nativeTick(buffer);
m_samples[0] = buffer[0] * T::resamplerPreAmplify;
m_samples[1] = buffer[1] * T::resamplerPreAmplify;
samplecnt -= rateratio;