Fix/arp clock sync - #266
Open
kartun83 wants to merge 3 commits into
Open
Conversation
build_mac.sh targeted the wrong CMake output directory (temp/cmake instead of temp/cmake_macos) and called cpack as a bare command which is not on PATH when CMake is installed as CMake.app on macOS. Fix both. The SSE flag pairs in juceRmlUi were broken for macOS universal builds: CMake was deduplicating the second -Xarch_x86_64, leaving a bare -msse4.1 that clang rejects when compiling the arm64 slice. Wrap each pair with SHELL: so CMake preserves them as single arguments.
Adds LunaSVG 3.5.0 as a submodule (source/3rdparty/lunasvg, including its plutovg dependency) and enables the RmlUi SVG plugin via RMLUI_SVG_PLUGIN=ON in source/3rdparty/CMakeLists.txt. The fork's RmlUi (dsp56300/RmlUi, rmlui_multiinstance branch) had not been updated for the multi-instance CoreInstance API introduced in EMU-70, causing build failures when the SVG plugin is enabled. The submodule is updated to a commit that brings the SVG plugin in line: - ElementSVG constructor accepts CoreInstance& and forwards it to Element - LoadSource() uses GetSystemInterface(GetCoreInstance()) and GetFileInterface(GetCoreInstance()), which are no longer static - SVGPlugin holds a CoreInstance& reference and registers through core_instance.factory rather than the removed static Factory API - SVG::Initialise() accepts and forwards CoreInstance&; Core.cpp updated The submodule commit also adds two capabilities not present upstream: Inline SVG: when src is absent, LoadSource() reconstructs the full SVG document from the element's attributes and GetInnerRML(), so SVG markup can be embedded directly in RML without an external file. Dynamic updates via inner_rml: OnChildAdd/OnChildRemove set source_dirty without calling DirtyLayout (which caused hangs during document teardown). A subsequent attribute write on the element, e.g. a data-ts cache-buster, triggers DirtyLayout via OnAttributeChange, scheduling a re-rasterize. This lets Lua scripts update SVG content at runtime.
Two bugs in MidiClock::start() and process() caused the arpeggiator to run out of phase with the host tempo (issues dsp56300#205, dsp56300#241). Bug 1: wrong initial clock phase in start() The formula: quarterPos = (ppqPos - floor(ppqPos + 1.0)) m_clockTickPos = quarterPos * 24 produces values in [-24, 0). The tick-generation loop only fires when m_clockTickPos crosses 0, so starting at -24 suppresses all ticks for 24 full tick periods — one entire beat. This is why the ARP was heard as "wrong at the beginning" and appeared to catch up after one or two bars. The fix computes the fractional position within the current clock tick period and keeps m_clockTickPos in [-1, 0): absoluteTicks = ppqPos * 24 fracTick = absoluteTicks - floor(absoluteTicks) m_clockTickPos = fracTick - 1.0 Examples: ppqPos = 0.0 → fracTick = 0.0 → m_clockTickPos = -1.0 (fires after 1 tick period) ppqPos = 0.5 → fracTick = 0.0 → m_clockTickPos = -1.0 (at a tick boundary) ppqPos = 0.52 → fracTick = 0.48 → m_clockTickPos = -0.52 (fires after 0.52 tick period) Bug 2: no loop or backward-seek detection process() only called start() on the false→true transition of _isPlaying. When the DAW looped back to an earlier position, ppqPos jumped backward while m_isPlaying stayed true, so start() was never called and the clock continued at the wrong phase indefinitely. The fix tracks m_lastPpqPos and restarts the clock whenever ppqPos drops by more than 0.5 beats during playback. 0.5 beats is well above any normal per-buffer advance (e.g. 300 BPM / 4096 samples ≈ 0.28 beats max) while reliably catching all loop-back distances.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fix MIDI clock phase and loop re-sync for ARP sync issues
Fixes #205, #241
Two bugs in
synthLib/MidiClockcaused the arpeggiator to play out of phase with the host tempo in all DAWs.Bug 1 — wrong initial clock phase in
start()The formula used to initialise
m_clockTickPoson playback start:produces values in
[-24, 0). The tick-generation loop only fires a tick whenm_clockTickPoscrosses 0, so starting at-24suppresses all ticks for 24 full tick periods — one entire beat at any tempo.This is exactly the symptom reported: "ARP tempo is wrong at the beginning, but catches up after one or two bars." The "catch up" was the clock finally escaping its one-beat head start.
Fix — keep
m_clockTickPosin[-1, 0)by computing the fractional position within the current tick period:This also fixes the issue reported in #205 where starting playback mid-beat caused immediate de-sync: the old formula ignored the sub-beat position entirely, the new one accounts for it precisely.
Bug 2 — loop and backward-seek not detected
process()only calledstart()on thefalse → truetransition of_isPlaying. When the DAW looped back to an earlier bar,ppqPosjumped backward whilem_isPlayingremainedtrue, sostart()was never called and the clock continued accumulating at the wrong phase indefinitely.Fix — track
m_lastPpqPosand restart the clock wheneverppqPosdrops by more than 0.5 beats during playback. The 0.5-beat threshold is safely above any normal per-buffer advance (e.g. 300 BPM with a 4096-sample buffer ≈ 0.28 beats) while reliably detecting all practical loop-back distances.Both fixes are in
source/synthLib/midiClock.cppand affect all synths that use the shared MIDI clock (Osirus, OsTIrus, Vavra, Xenia, etc.), but the ARP sync issue was primarily reported against OsTIrus.