2.5 (a): worker mode in the core — process() on a thread of its own - #29
Merged
Merged
Conversation
Python on a thread of its own, a fixed latency of whole vectors behind the audio thread, which never takes the GIL: a lock-free ring of slots in the core, the existing processor::process() run on the worker, underruns output as silence with the latency kept, @mode and @Latency applied at the next chain compile, and a read-only latency attribute (Max documents no call to report latency to the host). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rVV9SkjkWmiBXFMT4whkz
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rVV9SkjkWmiBXFMT4whkz
@Latency sets it in vectors; the read-only @latencysamples reports it in samples. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rVV9SkjkWmiBXFMT4whkz
worker.h runs a processor's process() on a worker thread a fixed number of vectors behind the audio thread, which only copies vectors through a lock-free ring and never takes the GIL. A vector whose outputs are not ready in time is output as silence; the worker still processes it and catches up, so the latency stays fixed and the class sees every vector in order. A worker a whole ring behind drops new inputs until it catches up. Both are reported once per load from the main thread (the processor gains load_count() for that). The audio thread borrows the ring by taking an atomic pointer, so start() and stop() can run while a host's old signal chain still does. Core battery: the output is the direct output L vectors later, per sample and per vector; channel matching; underruns, drops and their reports; restart and stop; reloads under an audio thread. Clean under ThreadSanitizer. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rVV9SkjkWmiBXFMT4whkz
#25–#28 landed on development/v2 (#28 as a squash of this branch's first three commits), so the plan conflicts: resolved as development/v2's plan with 2.5 (a)'s own change applied. Every file now equals development/v2 plus exactly this PR's commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EaBE7c7xYRveqLrVTQTpQ5
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.
Stacked on #28 (the design). Only the top commit, 65a0694, is new here. Merge #28 first.
Step (a) of plan 2.5, following the decided design.
What changes
core/include/tap/python/worker.hruns a processor'sprocess()on a worker thread, a fixed number of vectors behind the audio thread.processor::process(). Per-sample and per-vector classes work unchanged, with 2.4's channel matching.load_count()so the worker can tell when a load has happened.start()andstop()therefore wait at most one vector, even while a host's old signal chain is still running, and a vector that arrives meanwhile is silence.Tests (
test_worker.cpp, fixturestalls.py)Checked locally (macOS)
Step (b), the Max object (
@mode,@latency,@latencysamples, and a runtime test in Max), is next.🤖 Generated with Claude Code
https://claude.ai/code/session_019rVV9SkjkWmiBXFMT4whkz