Repository navigation
numchuck
Python bindings for the ChucK audio programming language using nanobind.
The numchuck library provides interactive control over ChucK, enabling live coding workflows, bidirectional Python/ChucK communication, and comprehensive VM introspection—all while maintaining the existing real-time and offline audio capabilities.
Changes since the last Release
Added
-
OTF shred tracking (
session.py,common.py,repl.py,editor.py): Shreds added or removed via on-the-fly programming (chuck --add,chuck --remove) are now automatically tracked in the REPL and editor. A newsync_shreds()method onChuckSessiondiffssession.shredsagainstchuck.get_all_shred_ids()and reconciles: externally-added shreds appear in the topbar,?/shreds table, and status bar count; finished or externally-removed shreds are pruned. Sync runs on each render tick (via the bottom toolbar callback in the REPL, status bar callback in the editor), guarded by_otf_enableso there is zero cost when OTF is off. OTF-discovered shreds are tagged withshred_type="otf". -
OTF CLI flags (
cli/main.py,tui/tui.py,tui/repl.py,tui/editor.py,tui/common.py): Added--otfand--otf-portflags to thereplandeditsubcommands.--otfenables the ChucK OTF listener (default port 8888), allowing externalchuckcommands to add/remove shreds. The OTF port is shown in the REPL status bar when enabled. -
REPL real-time stereo level meters (
repl.py,waveform.py): Thewavecommand now displays live L/R peak meters below the shreds panel. Uses a background daemon thread pollingget_audio_meters()at 100ms intervals withApplication(refresh_interval=0.1)for redraws. Meters appear/disappear viaConditionalContainertied tosession.show_waveform. Styled green-on-dark-green (class:waveform-area). -
REPL word aliases for symbol commands (
parser.py,lang/constants.py): Every terse symbol command now has a readable word equivalent. New aliases:shreds(?),shred <id>(? <id>),globals(?g),audio(?a),start(>),stop(||),shutdown(X),compile <file>(: <file>),exec "code"(! "code"),shell <cmd>($ <cmd>),snippet <name>(@<name>),get <var>(<var>?),set <var> <val>(<var>::<val>),signal <ev>(<ev>!),broadcast <ev>(<ev>!!). All word aliases are tab-completable. -
REPL command cheatsheet (
docs/repl-commands.md): Standalone reference documenting every REPL command organized by category, showing both symbol and word forms. -
Wheel RECORD Validation (
scripts/check_wheel_record.py,scripts/repair_wheel.py):- New standalone script validates wheel RECORD files against actual ZIP contents -- checks for smuggled files, dangling entries, hash mismatches, and size mismatches
- Addresses wheel archive confusion attacks
- Integrated into
repair_wheel.pyas a post-repair validation step for both chugin and non-chugin wheels - Added RECORD validation steps to CI wheels workflow (per-platform and combined artifact stages)
make checknow runs RECORD validation alongsidetwine check
-
CLAP, PdPatch, and VST3 Chugins (
thirdparty/chugins/{CLAP,PdPatch,VST3}/):- Added three new chugins from my-chugins: CLAP (host CLAP plugins), PdPatch (embed Pure Data patches), and VST3 (host VST3 plugins)
- All three are enabled by default via
option(CM_CLAP/CM_PDPATCH/CM_VST3 ... ON)and bundled in release wheels - External dependencies (clap SDK 1.2.6, libpd, VST3 SDK v3.8.0) fetched automatically via CMake
FetchContent - Can be individually disabled with
-DCM_CLAP=OFF,-DCM_PDPATCH=OFF, or-DCM_VST3=OFF - macOS and Linux only -- all three depend on POSIX APIs (
dlfcn.h,dirent.h, pthreads) not available on Windows - Fixed VST3 SDK option names (
SMTG_ENABLE_VST3_PLUGIN_EXAMPLES/SMTG_ENABLE_VST3_HOSTING_EXAMPLES) to correctly disable SDK samples that requiregtk+-3.0on Linux - The numchuck package now includes:
- AbletonLink.chug
- ABSaturator.chug
- AmbPan.chug
- AudioUnit.chug
- Binaural.chug
- Bitcrusher.chug
- CLAP.chug
- ConvRev.chug
- Elliptic.chug
- ExpDelay.chug
- ExpEnv.chug
- FIR.chug
- FoldbackSaturator.chug
- GVerb.chug
- KasFilter.chug
- Ladspa.chug
- Line.chug
- MagicSine.chug
- Mesh2D.chug
- MIAP.chug
- Multicomb.chug
- NHHall.chug
- Overdrive.chug
- PanN.chug
- Patch.chug
- PdPatch.chug
- Perlin.chug
- PitchTrack.chug
- PowerADSR.chug
- Random.chug
- Range.chug
- RegEx.chug
- Sigmund.chug
- Spectacle.chug
- VST3.chug
- Wavetable.chug
- WinFuncEnv.chug
- WPDiodeLadder.chug
- WPKorg35.chug
- XML.chug
Fixed
-
Wheels workflow collect job (
.github/workflows/wheels.yml):- Reordered
collectjob steps to runcheckoutbefore artifact downloads --actions/checkout@v4cleans the working directory by default, which was wiping the downloadeddist/directory
- Reordered
-
FetchContent install leaking into wheels (
thirdparty/chugins/{CLAP,PdPatch}/CMakeLists.txt):- Added
EXCLUDE_FROM_ALLtoFetchContent_Declarefor CLAP and PdPatch to prevent their SDKinstall()rules from polluting the wheel with headers, pkgconfig, and cmake config files (reduced wheel from 186 to 100 files)
- Added
-
REPL ghost line on shred removal (
common.py): Fixed terminal rendering corruption (ghost line at bottom of screen) when removing shreds while level meters were visible. Root cause: ChucK's VM writes[chuck]: (VM) removing shred: ...directly to stdout viaCK_FPRINTF_STDOUT, bypassing prompt_toolkit's full-screen renderer. Fix:setup_output_capture()now also sets the global/staticChucK.set_stdout_callback()andChucK.set_stderr_callback()to route all VM system messages through the TUI log system. Seedocs/architecture.mdfor the two-tier callback architecture. -
REPL exception handling (
repl.py):_submit_input(TUI) andprocess_line(stdin) now catch exceptions fromexecutor.execute()andspork_code(), displaying graceful error messages instead of crashing with tracebacks. -
REPL shutdown crash (
repl.py): Fixed malloc double-free / segfault on exit. Removed staticset_stdout_callback/set_stderr_callback(which outlived the Python objects they referenced) in favor of instance-level callbacks cleaned up bychuck.shutdown(). Reordered cleanup to break all reference cycles before destroying C++ objects. -
nanobind ref leak on shutdown (
common.py): Fixed "leaked 1 instances" / "leaked 1 types" nanobind warnings on exit. Root cause:setup_output_capture()registers alog_callbackclosure (capturingself) as static class-level callbacks viaChucK.set_stdout_callback()/ChucK.set_stderr_callback(). These outlived the instance and pinned the entireChuckApplication -> ChucKobject graph, preventing C++ destructor from running. Fix:cleanup()now clears static callbacks toNonebefore breaking instance references. -
Shell command execution (
commands.py):$ <cmd>now captures stdout/stderr (routed through_log()), enforces a 30-second timeout, reports nonzero exit codes, and catchesTimeoutExpired/OSErrorinstead of running unsanitized with no output capture or error handling. -
ConvRev segfault on ARM64 macOS CI (
test_examples.py): Fixed segfault intest_chugin_convrev_exampleon macos-14 (ARM64). Root cause:_check_chugin_available()created up to 2 ChucK instances without callingshutdown(), leaving ConvRev's backgroundstd::threadactive. When the test then created a new instance, concurrent ConvRev destructor/thread cleanup races caused a segfault (ARM64's stricter memory ordering exposed this). Fix: all ChucK instances intest_examples.pynow callremove_all_shreds()+shutdown()before going out of scope. -
Windows CI test failures (
test_waveform.py): Fixed 3TestREPLMeterInfrastructuretests failing on Windows CI withNoConsoleScreenBufferError. These tests instantiateChuckREPL()which creates aprompt_toolkit.Applicationrequiring a real TTY. Fix: skip the test class when stdout is not a TTY.
Changed
-
REPL help panel (
repl.py): F1 help text now showsword / symbolforms side by side for all commands that have both. -
REPL inline transcript (
repl.py): Replaced split input/output layout with a single-buffer Python/Jupyter-style transcript. Input and output are interleaved in one scrollable area -- commands echo as[=>] ..., output is indented, errors show inline with[!]prefix. Removed separate log window (F3 toggle), error bar, and transcript TextArea. Input prompt sits at the bottom of the transcript buffer.