gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

commit 937cfec4796bb566c42ca88b4b3bbe6bf0e66b3c
parent 4ff7f306532f62cfc61ae786587cc44bab59edae
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date:   Thu, 25 Jul 2024 21:55:01 +0200

new synchronization attempt WIP

Diffstat:
Msource/hardwareLib/CMakeLists.txt | 2++
Asource/hardwareLib/haltDSP.cpp | 34++++++++++++++++++++++++++++++++++
Asource/hardwareLib/haltDSP.h | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asource/hardwareLib/syncUCtoDSP.h | 99+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asource/nord/n2x/n2xLib/n2xsync.cpp | 0
Asource/nord/n2x/n2xLib/n2xsync.h | 16++++++++++++++++
Msource/nord/n2x/n2xLib/n2xtypes.h | 1+
7 files changed, 216 insertions(+), 0 deletions(-)

diff --git a/source/hardwareLib/CMakeLists.txt b/source/hardwareLib/CMakeLists.txt @@ -5,9 +5,11 @@ add_library(hardwareLib STATIC) set(SOURCES am29f.cpp am29f.h + haltDSP.cpp haltDSP.h i2c.cpp i2c.h i2cFlash.cpp i2cFlash.h sciMidi.cpp sciMidi.h + syncUCtoDSP.h ) target_sources(hardwareLib PRIVATE ${SOURCES}) diff --git a/source/hardwareLib/haltDSP.cpp b/source/hardwareLib/haltDSP.cpp @@ -0,0 +1,34 @@ +#include "haltDSP.h" + +#include "dsp56kEmu/dsp.h" + +namespace hwLib +{ + HaltDSP::HaltDSP(dsp56k::DSP& _dsp) + : m_dsp(_dsp) + , m_irq(_dsp.registerInterruptFunc([this] { onInterrupt(); })) + { + } + + void HaltDSP::haltDSP() + { + if(m_halted) + return; + if(++m_halted == 1) + m_dsp.injectExternalInterrupt(m_irq); + } + + bool HaltDSP::resumeDSP() + { + if(!m_halted) + return false; + if(--m_halted == 0) + m_semaphore.notify(); + return true; + } + + void HaltDSP::onInterrupt() + { + m_semaphore.wait(); + } +} diff --git a/source/hardwareLib/haltDSP.h b/source/hardwareLib/haltDSP.h @@ -0,0 +1,64 @@ +#pragma once + +#include <cstdint> + +#include "baseLib/semaphore.h" + +namespace dsp56k +{ + class DSP; +} + +namespace hwLib +{ + class HaltDSP + { + public: + explicit HaltDSP(dsp56k::DSP& _dsp); + + void haltDSP(); + bool resumeDSP(); + + private: + void onInterrupt(); + + dsp56k::DSP& m_dsp; + + uint32_t m_halted = 0; + uint32_t m_irq; + baseLib::Semaphore m_semaphore; + }; + + class ScopedResumeDSP + { + public: + explicit ScopedResumeDSP(HaltDSP& _haltDSP) : m_haltDSP(_haltDSP), m_resumed(_haltDSP.resumeDSP()) + { + } + + ~ScopedResumeDSP() + { + if(m_resumed) + m_haltDSP.haltDSP(); + } + private: + HaltDSP& m_haltDSP; + bool m_resumed; + }; + + class ScopedHaltDSP + { + public: + explicit ScopedHaltDSP(HaltDSP& _haltDSP) : m_haltDSP(_haltDSP) + { + _haltDSP.haltDSP(); + } + + ~ScopedHaltDSP() + { + m_haltDSP.resumeDSP(); + } + private: + HaltDSP& m_haltDSP; + }; +} diff --git a/source/hardwareLib/syncUCtoDSP.h b/source/hardwareLib/syncUCtoDSP.h @@ -0,0 +1,99 @@ +#pragma once + +#include <cstdint> + +#include "haltDSP.h" + +namespace hwLib +{ + template<uint32_t UcFreqHz, uint32_t Samplerate, uint32_t SamplesThreshold> + class SyncUCtoDSP + { + public: + static constexpr double SamplerateInv = 1.0 / static_cast<double>(Samplerate); + static constexpr double UcCyclesPerSample = static_cast<double>(UcFreqHz) / Samplerate; + static constexpr double UcCyclesThreshold = UcCyclesPerSample * SamplesThreshold; + + explicit SyncUCtoDSP(dsp56k::DSP& _dsp) : m_haltDSP(_dsp) + { + } + + virtual ~SyncUCtoDSP() = default; + + void advanceDspSample() + { + m_targetUcCycles += UcCyclesPerSample; + ++m_totalSampleCount; + + if((m_totalSampleCount & (SamplesThreshold-1)) == 0) + m_cvSampleAdded.notify_one(); + } + + void advanceUcCycles(const uint32_t _cycles) + { + m_totalUcCycles += static_cast<double>(_cycles); + + evaluate(); + } + + auto& getHaltDSP() { return m_haltDSP; } + + protected: + void evaluate() + { + if(!m_totalSampleCount) + return; + + const auto diff = m_totalUcCycles - m_targetUcCycles; + + if(diff > UcCyclesThreshold) + { + // UC is too fast, slow down + resumeDSP(); + haltUC(); + } + else if(diff < -UcCyclesThreshold) + { + haltDSP(); + resumeUC(); + } + else + { + resumeDSP(); + resumeUC(); + } + } + + void haltUC() + { + const auto lastCount = m_totalSampleCount; + std::unique_lock lock(m_lockSampleAdded); + m_cvSampleAdded.wait(lock, [&] + { + return m_totalSampleCount > lastCount; + }); + } + + virtual void resumeUC() + { + } + + void haltDSP() + { + m_haltDSP.haltDSP(); + } + + void resumeDSP() + { + m_haltDSP.resumeDSP(); + } + + private: + HaltDSP m_haltDSP; + double m_targetUcCycles = 0.0; + double m_totalUcCycles = 0.0; + uint32_t m_totalSampleCount = 0; + std::condition_variable m_cvSampleAdded; + std::mutex m_lockSampleAdded; + }; +} diff --git a/source/nord/n2x/n2xLib/n2xsync.cpp b/source/nord/n2x/n2xLib/n2xsync.cpp diff --git a/source/nord/n2x/n2xLib/n2xsync.h b/source/nord/n2x/n2xLib/n2xsync.h @@ -0,0 +1,16 @@ +#pragma once + +#include "n2xtypes.h" + +#include "hardwareLib/syncUCtoDSP.h" + +namespace n2x +{ + class Sync : public hwLib::SyncUCtoDSP<g_ucFreqHz, g_samplerate, 16> + { + public: + Sync(dsp56k::DSP& _dsp) : SyncUCtoDSP(_dsp) + { + } + }; +} diff --git a/source/nord/n2x/n2xLib/n2xtypes.h b/source/nord/n2x/n2xLib/n2xtypes.h @@ -40,6 +40,7 @@ namespace n2x static constexpr uint32_t g_keyboardSize = 0x800; static constexpr uint32_t g_samplerate = 98200; + static constexpr uint32_t g_ucFreqHz = 25165824; // Fext=32768Hz, SYNCR=$d700, W=1, X=1, Y=17 enum class ButtonType {