Skip to main content

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.

Overview

numchuck is a high-performance Python wrapper for ChucK that provides:

Library

  • Python Programmatic Access to ChucK API — Load, compile, and concurrently execute .ck files and ChucK code into audio processing or generated shreds. Manage the VM using python code: configure parameters, monitor timing, and control shred lifecycles.

  • Flexible Execution — Choose between real-time audio playback and recording using asynchronous RtAudio or offline input from and rendering to numpy arrays.

  • Advanced Audio Processing — Harness ChucK's complete synthesis, filtering, and DSP capabilities.

  • Live Coding — Hot-swap code, replace active shreds, and inspect VM state in real time.

  • Plugin Support — 40 ChucK chugins bundled in the wheel for additional instruments and effects (see Bundled Chugins). Works out of the box with pip install.

  • Dynamic Interaction - Bidirectional communication between ChucK and Python through global variables, event triggers, and callbacks.

  • Host Classes — Host, HostBuffer and HostBufPlay are bound into every VM. Host.msg and Host.send* call Python callbacks at the shred's logical time; HostBuffer and HostBufPlay read, write and play a numpy array in place. chuck-max and pd-chuck bind the same names, so one .ck file runs in all three hosts (see Host Classes).

User Interface

  • Multi-Tab Editor — Full-screen ChucK editor with syntax highlighting; use F5 to spork and F6 to replace.

  • Interactive REPL — Terminal-style interface supporting ChucK commands and code completion.

  • Command-Line Mode — Run ChucK files directly from the terminal, with support for duration and silent modes.

  • Automatic Versioning — Keeps track of live coding sessions (file.ck → file-1.ck → file-1-1.ck).

  • Web IDE — Browser-based editor and REPL with real-time audio meters, globals panel, and WebSocket updates. Binds loopback by default; see Web IDE for the trust model.

Installation

Install from pypi

pip install numchuck

or

uv add numchuck

Build from source

# Clone the repository
git clone https://github.com/shakfu/numchuck.git
cd numchuck

# Build the extension
make build

# Run tests
make test

Quick Start

Command-Line Interface

numchuck provides three modes of operation:

1. Multi-Tab Editor (for livecoding)

# Launch the editor
numchuck edit

# Open specific files in tabs
numchuck edit bass.ck melody.ck

# Enable project versioning
numchuck edit --project mymusic

# Start with audio enabled
numchuck edit --start-audio --project mymusic

# Enable on-the-fly programming
numchuck edit --otf

Editor Features:

  • Multi-tab editing with ChucK syntax highlighting
  • F5 or Ctrl-R to spork (compile and run current buffer)
  • F6 to replace running shred with current buffer
  • Ctrl-O to open files with interactive dialog (Tab for path completion)
  • Ctrl-S to save files
  • Ctrl-T for new tab, Ctrl-W to close tab
  • Ctrl-N/Ctrl-P (or Ctrl-PageDown/PageUp) to navigate tabs
  • Tab names show shred IDs after sporking (e.g., bass-1.ck)
  • Project versioning: file.ck → file-1.ck → file-1-1.ck
  • F1/F2/F3 for help/shreds/log windows
  • Ctrl-Q to exit

2. Interactive REPL

# Launch the REPL
numchuck repl

# Load files on startup
numchuck repl bass.ck melody.ck

# Enable project versioning
numchuck repl --project mymusic

# Start with audio enabled
numchuck repl --start-audio

# Disable smart Enter mode
numchuck repl --no-smart-enter

# Hide sidebar (can toggle with F2)
numchuck repl --no-sidebar

# Enable on-the-fly programming (listen for chuck --add/--remove)
numchuck repl --otf

# OTF on custom port
numchuck repl --otf --otf-port 9999

REPL Commands:

  • add <file> or + <file> - Spork a file
  • remove <id> or - <id> - Remove a shred
  • remove all or - all - Remove all shreds
  • abort.shred <id> or abort <id> - Abort a shred (ChucK-native)
  • replace <id> <file> or = <id> <file> - Replace shred with file
  • status or ^ - Show VM status
  • time or . - Show ChucK time
  • exit or quit - Exit the REPL
  • @<name> - Load a snippet (e.g., @sine, @drum)
  • watch <file> - Auto-reload file on changes
  • record start [name] - Start recording session
  • record stop - Stop recording and save
  • play <name> [speed] - Replay recorded session
  • midi learn <var> <cc> [channel] [min max] - Map MIDI CC to global variable
  • osc start [port] - Start OSC server
  • wave - Toggle waveform display
  • Type help or press F1 for full command reference
Recording

Record and replay REPL sessions. Recordings are saved as JSON to ~/.numchuck/recordings/.

Command Description
record start [name] Start recording. Default name is session.
record stop Stop recording and auto-save to disk.
record save <name> Stop recording and save under a specific name.
record discard Discard the current recording without saving.
record status Show whether recording is active, elapsed time, and action count.

All commands except recording meta-commands (record *, exit) are captured with timestamps during recording.

Playback
Command Description
play <name> [speed] Load a recording and start playback. Speed defaults to 1.0 (real-time); use 2.0 for double speed.
play pause Pause playback.
play resume Resume paused playback.
play stop Stop playback.
recordings List all saved recordings.
MIDI

Map MIDI CC messages to ChucK global variables. Uses ChucK's native MidiIn -- a ChucK shred is sporked to listen for MIDI and update globals in real time.

Typical workflow: run midi monitor to see CC values from your controller, then midi learn freq 74 to map CC 74 to the freq global.

Command Description
midi learn <var> <cc> [channel] [min max] Create a mapping from MIDI CC to a global variable. Channel defaults to 0, range defaults to [0.0, 1.0].
midi list Show all MIDI mappings (channel, CC, global name, range).
midi remove <var> Remove the mapping for a global variable. If the listener is running, it is automatically re-sporked.
midi start Spork the MIDI listener shred with all current mappings.
midi stop Remove the MIDI listener shred.
midi status Show mapping count and whether the listener is running.
midi monitor Spork a monitor shred that prints all incoming MIDI CC messages (channel, CC number, value).
OSC

Start an OSC server for remote control. External applications can send OSC messages to control ChucK globals, spork code, remove shreds, signal events, and more.

Command Description
osc start [port] Start OSC server. Port defaults to 9000.
osc stop Stop OSC server.
osc status Show server state, port, and handler count.

Standard OSC addresses: /numchuck/set/<var>, /numchuck/get/<var>, /numchuck/event/<name>, /numchuck/broadcast/<name>, /numchuck/spork, /numchuck/remove, /numchuck/clear.

Waveform Display
Command Description
wave Toggle waveform display on/off.
wave on Enable waveform display.
wave off Disable waveform display.

Toggles real-time stereo L/R peak meters below the shreds panel. A background thread polls get_audio_meters() at 100ms intervals; meters animate while audio is running and disappear when toggled off.

3. Command-Line Execution

# Execute ChucK files from command line
numchuck run myfile.ck

# Run multiple files
numchuck run bass.ck melody.ck

# Run for 10 seconds then exit
numchuck run myfile.ck --duration 10

# Silent mode (no audio)
numchuck run myfile.ck --silent

# Custom sample rate
numchuck run myfile.ck --srate 48000

4. Snippet Management

# List all available snippets
numchuck snippets list

# Show snippet content
numchuck snippets show sine

# Show snippets directory path
numchuck snippets path

5. File Watch Mode

# Watch files and auto-reload on changes
numchuck watch bass.ck melody.ck

6. WAV Export

# Export ChucK files to WAV
numchuck export output.wav --files sine.ck --duration 10

7. Web IDE (Browser-Based)

# Launch browser-based ChucK IDE (binds 127.0.0.1)
numchuck web

# Specify port
numchuck web --port 9000

# Load files on startup with audio enabled
numchuck web --start-audio bass.ck melody.ck

# Don't auto-open browser
numchuck web --no-browser

# Reachable from another machine (issues an auth token automatically)
numchuck web --host 0.0.0.0

Security: the IDE compiles ChucK, and ChucK can read and write files, so anyone who can reach the server can run code as you. It binds 127.0.0.1 by default for that reason, and always issues an auth token.

  • Every run gets a random token, included in the URL numchuck prints and opens. Every API request and the WebSocket handshake require it. Loopback is no exception: it keeps other sites out via the origin check below, but any other process or user on the machine can reach 127.0.0.1 directly, and a non-browser client sends no Origin to check. Supply your own token with --token, or --token "" to turn auth off deliberately.
  • --host widens the bind beyond loopback, and warns when you do.
  • Requests whose Origin disagrees with their Host are refused, so a page on another site cannot drive the IDE over a WebSocket even while it is running on your own machine.
  • Commands that would start a process on the host (shell, the external editor) or that only end at a terminal (watch) are refused in the browser.

Web IDE Features:

  • Browser-based code editor with syntax highlighting
  • Interactive REPL terminal (toggle between Editor and REPL views)
  • Multi-file tabs with local storage persistence (files saved automatically)
  • Open files from disk and download/save-as to disk
  • Examples dropdown with built-in ChucK examples (click to load)
  • Globals panel with auto-discovery of ChucK global variables
    • Interactive sliders for int/float globals with real-time control
    • Real-time sync via WebSocket (updates pushed, not polled)
    • Event buttons to signal/broadcast global events
  • Shred management panel:
    • View all running shreds with elapsed time
    • Replace shred with current editor code
    • Preview shred source code
    • Remove individual shreds
  • Real-time audio level meters:
    • RMS and peak levels for left/right channels
    • Visual meter bars updated in real-time
    • Calculated in C++ audio callback for accuracy
  • Theme toggle (dark/light mode) with system preference detection
  • Real-time console output via WebSocket
  • Audio start/stop controls
  • Keyboard shortcuts (Editor mode):
    • Ctrl+Enter: Spork code
    • Ctrl+S: Save to local storage
    • Ctrl+O: Open file from disk
    • Ctrl+Shift+S: Download/Save As
    • Ctrl+N: New tab
  • Keyboard shortcuts (REPL mode):
    • Ctrl+C: Copy selection or cancel input
    • Ctrl+X: Cut selection
    • Ctrl+V: Paste from clipboard
    • Ctrl+L: Clear terminal
    • Up/Down: Navigate command history

REPL Commands (ChucK-compatible):

  • + file.ck / + "code" - Spork a file or code
  • - <id> / - all - Remove shred(s)
  • = <id> file.ck / = <id> "code" - Replace shred
  • status / ^ - Show VM status
  • ? / ?<id> - List shreds / shred info
  • ?g - List global variables
  • ?a - Audio info
  • name::value - Set global variable
  • name? - Get global value
  • name! / name!! - Signal/broadcast event
  • > - Start audio, || - Stop audio
  • clear - Clear VM, reset - Reset shred ID
  • Or enter ChucK code directly

REST API Endpoints:

Endpoint Method Description
/api/status GET Get VM status, shreds, audio state
/api/compile POST Compile and spork code
/api/shred/:id DELETE Remove a shred
/api/shred/:id/replace POST Replace shred with new code
/api/shred/:id/code GET Get shred source code
/api/globals GET List all global variables with types
/api/clear POST Clear all shreds
/api/audio/start POST Start real-time audio
/api/audio/stop POST Stop real-time audio
/ws WebSocket Real-time console and status updates

8. Version and Info

# Show version
numchuck version

# Show ChucK and numchuck info
numchuck info

Interface Features:

  • Full-screen layout: Professional terminal UI with multiple display areas
  • Live topbar: Minimal display showing shred IDs [1] [2] [3]
  • Shreds table: Detailed shred information table (F2) with ID, name (folder/file), and elapsed time since spork
  • Error display bar: Red error bar shows command errors without disrupting layout
  • Help window: Built-in command reference (toggle with F1)
  • Log window: Scrollable ChucK VM output capture (toggle with Ctrl+L)
  • Mouse support: Scroll through log output with mouse wheel
  • Scrollable input: Main input area with scrollbar for long code

Editing Features:

  • Smart Enter mode: Enter submits commands immediately, but allows multiline ChucK code editing
  • ChucK syntax highlighting: Full Pygments lexer for ChucK language with color themes
  • ChucK code completion: Tab completion for keywords, types, UGens, and standard library
  • Intelligent code detection: Automatically compiles multiline ChucK code
  • Tab completion: Commands, .ck files, and ChucK language elements
  • Command history: Persistent history with Ctrl+R search
  • Colored prompt: [=>] matches ChucK logo styling

Common Keyboard Shortcuts (Editor & REPL):

  • F1 - Toggle help window
  • F2 - Toggle shreds table (detailed view with ID, folder/filename, elapsed time)
  • F3 - Toggle log window (ChucK VM output)
  • Ctrl+Q - Exit application
  • Tab - Command and ChucK code completion
  • Up/Down - Navigate command history

User Directory (.numchuck)

numchuck uses a .numchuck directory for user configuration, snippets, and customization.

Search Order:

  1. Global: ~/.numchuck (home directory) — always used
  2. Local: ./.numchuck (current working directory) — only with --local

A project-local .numchuck takes precedence over the global one, which allows project-specific settings. It is opt-in because the directory can supply chugins, and chugins are native shared libraries loaded into the process: honouring it automatically would mean that running numchuck inside a checked-out repository executes whatever native code that repository shipped.

# Use ./.numchuck for this run
numchuck repl --local

# Or for the whole shell session
export NUMCHUCK_LOCAL=1

Directory Structure:

.numchuck/
  snippets/     # Code snippets loaded with @<name>
  themes/       # Color theme configurations (.toml)
  keybindings/  # Custom key binding configurations (.toml)
  examples/     # Example ChucK files
  chugins/      # User chugins (.chug plugins)
  config.toml   # Main configuration file

Template Directory:

The _numchuck/ directory in the repository contains a template with examples:

_numchuck/
  snippets/
    sine.ck     # Simple sine wave oscillator
    fm.ck       # FM synthesis with modulation
    drum.ck     # Basic drum machine pattern
    noise.ck    # Noise generator with filter
    delay.ck    # Delay effect with feedback
  themes/
    dark.toml   # Dark theme colors
    light.toml  # Light theme colors
  keybindings/
    default.toml  # Default key bindings
  examples/
    hello.ck    # Hello world sine wave
    arpeggio.ck # Simple arpeggiator
    lfo.ck      # LFO modulation example
  chugins/
    README.md   # Chugins installation guide

Copy to your home directory to use globally:

cp -r _numchuck ~/.numchuck

Or copy to a project directory for project-specific settings:

cp -r _numchuck .numchuck

Snippets

Snippets are reusable ChucK code files that can be loaded with @<name> in the REPL.

Usage in REPL:

[=>] @sine        # Loads snippets/sine.ck
[=>] @drum        # Loads snippets/drum.ck
[=>] @<TAB>       # Tab completion for available snippets

Snippets are searched in .numchuck/snippets/ (local first, then global).

Project Versioning

When using --project <name>, numchuck automatically versions your files as you livecode:

~/.numchuck/projects/mymusic/
  bass.ck           # Original file
  bass-1.ck         # After first spork (shred ID 1)
  bass-1-1.ck       # After first replace of shred 1
  bass-1-2.ck       # After second replace of shred 1
  melody-2.ck       # Second file sporked (shred ID 2)
  melody-2-1.ck     # After replace of shred 2

This creates a complete history of your livecoding session, making it easy to:

  • Review your creative process
  • Recover previous versions
  • Replay session timeline
  • Share reproducible livecoding performances

Offline Rendering API

numchuck provides a simple API for rendering ChucK code to audio files or numpy arrays:

from numchuck import render, render_file, to_wav

# Render code to numpy array
audio = render("SinOsc s => dac; 1::second => now;", duration=1.0)
print(audio.shape)  # (88200,) - 1 second of stereo audio

# Render files to numpy array
audio = render_file(["bass.ck", "melody.ck"], duration=5.0)

# Export directly to WAV file
to_wav("output.wav", code="SinOsc s => dac; 2::second => now;", duration=2.0)
to_wav("output.wav", files=["sine.ck"], duration=10.0, sample_rate=48000)

Rendering Functions

Function Description
render(code, duration, sample_rate, channels, dtype) Render ChucK code string to numpy array
render_file(files, duration, sample_rate, channels, dtype) Render ChucK files to numpy array
to_wav(output, code, files, duration, ...) Export to WAV file (provide either code or files)

All functions support:

  • duration - Seconds to render (default: 10.0)
  • sample_rate - Sample rate in Hz (default: 44100)
  • channels - Output channels (default: 2)
  • dtype - Output type: np.float32 or np.int16 (default: float32)

The Chuck class provides a Pythonic interface with properties and simplified methods:

import numpy as np
from numchuck import Chuck

# Create with parameters (auto-initializes)
chuck = Chuck(sample_rate=48000, output_channels=2)

# Properties instead of get_param/set_param
print(chuck.sample_rate)   # 48000
print(chuck.version)       # "1.5.5.9-dev (chai)"

# Compile and run
success, shreds = chuck.compile("SinOsc s => dac; 1::second => now;")
output = chuck.run(44100)  # Returns numpy array

# Shred management
print(chuck.shreds)        # [1]
chuck.remove_shred(1)
chuck.clear()

# Synchronous global variables
chuck.compile("global int tempo;")
chuck.run(100)
chuck.set_int("tempo", 120)
val = chuck.get_int("tempo")  # 120

# Events
chuck.signal_event("trigger")
chuck.on_event("response", my_callback)

# Host classes: ChucK calls Python, and both sides share an array
chuck.on_msg(lambda name, value: print(name, value))   # Host.msg("freq", 440)
chuck.on_receive("tick", lambda value: print("tick"))  # Host.sendBang("tick")
chuck.set_buffer("rec", np.zeros(48000, dtype=np.float32))  # HostBuffer b; b.name("rec")

# Access low-level API when needed
chuck.raw.set_param(...)

Context Manager Support

The Chuck class supports the context manager protocol for automatic cleanup:

from numchuck import Chuck

# Automatic cleanup on exit (calls close())
with Chuck() as chuck:
    chuck.compile("SinOsc s => dac; 1::second => now;")
    output = chuck.run(44100)
# chuck.close() is called automatically, even on exceptions

Shred Handle Objects

Use Shred objects for more intuitive shred management:

from numchuck import Chuck

chuck = Chuck()

# spork() returns a Shred object
shred = chuck.spork("SinOsc s => dac; 1::second => now;")
print(shred.id)          # 1
print(shred.is_running)  # True

# Methods for shred control
shred.replace("TriOsc t => dac; 1::second => now;")  # Hot-swap code
shred.remove()           # Remove the shred

# Load from file
shred = chuck.spork_file("melody.ck")

# Get detailed info
print(shred.info)  # {'id': 1, 'name': '...', 'is_running': True, ...}

Typed Global Variable Proxies

Property-based access to global variables:

from numchuck import Chuck

chuck = Chuck()
chuck.compile("global int tempo; global float gain; global string mode;")
chuck.run(100)

# Create typed proxies
tempo = chuck.global_int("tempo")
gain = chuck.global_float("gain")
mode = chuck.global_string("mode")

# Property-based access
tempo.value = 120        # Instead of chuck.set_int("tempo", 120)
print(tempo.value)       # 120

gain.value = 0.8
mode.value = "minor"

# Also supports method-style access
tempo.set(140)
print(tempo.get())       # 140

Async/Await API

For integration with asyncio applications:

import asyncio
from numchuck import Chuck

async def main():
    chuck = Chuck()
    chuck.compile("global int counter; 42 => counter;")
    chuck.run(100)

    # Async global variable access
    value = await chuck.get_int_awaitable("counter")
    print(value)  # 42

    # Also available for float and string
    # await chuck.get_float_awaitable("gain")
    # await chuck.get_string_awaitable("mode")

    # Proxies also support async
    counter = chuck.global_int("counter")
    value = await counter.get_async()

asyncio.run(main())

Low-Level API

For fine-grained control, use the low-level API via numchuck._numchuck:

from numchuck._numchuck import ChucK, start_audio, stop_audio

Real-Time Audio

from numchuck._numchuck import (
    ChucK, start_audio, stop_audio, shutdown_audio,
    PARAM_SAMPLE_RATE, PARAM_OUTPUT_CHANNELS
)
import time

# Create and configure ChucK
chuck = ChucK()
chuck.set_param(PARAM_SAMPLE_RATE, 44100)
chuck.set_param(PARAM_OUTPUT_CHANNELS, 2)
chuck.init()

# Compile ChucK code
chuck.compile_code('''
    SinOsc s => dac;
    440 => s.freq;
    while(true) { 1::samp => now; }
''')

# Start real-time audio playback
start_audio(chuck)
time.sleep(2)  # Play for 2 seconds
stop_audio()
shutdown_audio()

Offline Rendering

from numchuck._numchuck import ChucK, PARAM_SAMPLE_RATE, PARAM_OUTPUT_CHANNELS
import numpy as np

# Create ChucK instance
chuck = ChucK()
chuck.set_param(PARAM_SAMPLE_RATE, 44100)
chuck.set_param(PARAM_OUTPUT_CHANNELS, 2)
chuck.init()

# Compile code
chuck.compile_code('''
    SinOsc s => dac;
    440 => s.freq;
    while(true) { 1::samp => now; }
''')

# Render to numpy array
frames = 512
output = np.zeros(frames * 2, dtype=np.float32)
chuck.run(np.zeros(0, dtype=np.float32), output, frames)

API Reference

High-Level API (numchuck.Chuck)

The Chuck class provides a Pythonic wrapper with properties and simplified methods.

from numchuck import Chuck

Constructor

Chuck(
    sample_rate: int = 44100,
    input_channels: int = 2,
    output_channels: int = 2,
    working_directory: str = "",
    chugin_enable: bool = True,
    user_chugins: list[str] | None = None,
    vm_adaptive: bool = False,
    vm_halt: bool = False,
    auto_depend: bool = False,
    deprecate_level: int = 1,
    dump_instructions: bool = False,
    otf_enable: bool = False,
    otf_port: int = 8888,
    tty_color: bool = False,
    tty_width_hint: int = 80,
    auto_init: bool = True,
)

Properties

Property Type Description
sample_rate int Audio sample rate in Hz
input_channels int Number of input channels
output_channels int Number of output channels
working_directory str Working directory for file operations
version str ChucK version string (read-only)
chugin_enable bool Whether chugin loading is enabled
user_chugins list[str] List of user chugin paths
vm_adaptive bool Whether adaptive VM timing is enabled
vm_halt bool Whether VM halts when no shreds remain
auto_depend bool Whether automatic dependency resolution is enabled
deprecate_level int Deprecation warning level (0=none, 1=warn, 2=error)
dump_instructions bool Whether VM instruction dumping is enabled
otf_enable bool Whether on-the-fly programming is enabled
otf_port int Port for on-the-fly programming
tty_color bool Whether colored terminal output is enabled
tty_width_hint int Terminal width hint for formatting
compiler_highlight_on_error bool Syntax highlighting in error messages
is_realtime_audio_hint bool Hint for real-time audio mode
otf_print_warnings bool Whether OTF compiler warnings are printed
shreds list[int] List of all active shred IDs
raw ChucK Access to underlying low-level ChucK instance

Core Methods

  • init() -> bool - Initialize ChucK (called automatically if auto_init=True)
  • close() -> None - Shutdown ChucK instance (important on Windows)
  • __enter__() -> Chuck - Context manager entry (returns self)
  • __exit__(...) -> None - Context manager exit (calls close())
  • compile(code, args="", count=1, immediate=False) -> tuple[bool, list[int]] - Compile ChucK code
  • compile_file(path, args="", count=1, immediate=False) -> tuple[bool, list[int]] - Compile from file
  • run(num_frames, *, output=None, input=None, reuse=False) -> np.ndarray - Run VM and return output audio
    • No args: allocates new buffer each call
    • output=buf: uses provided buffer (zero allocation)
    • input=buf: uses provided input buffer
    • reuse=True: uses internal buffer (zero GC without manual management)
  • advance(num_frames) -> None - Advance VM time without returning audio (for callbacks/events)
  • spork(code, args="") -> Shred - Compile code and return Shred handle
  • spork_file(path, args="") -> Shred - Compile file and return Shred handle

Shred Management

  • remove_shred(shred_id) -> None - Remove a shred by ID
  • replace_shred(shred_id, code, args="") -> int - Replace running shred with new code, returns new shred ID
  • shred_info(shred_id) -> dict | None - Get shred information
  • clear() - Remove all shreds from VM
  • reset_id() - Reset shred ID counter

Global Variables

  • set_int(name, value) - Set global int
  • get_int(name, run_frames=256) -> int - Get global int (synchronous)
  • set_float(name, value) - Set global float
  • get_float(name, run_frames=256) -> float - Get global float (synchronous)
  • set_string(name, value) - Set global string
  • get_string(name, run_frames=256) -> str - Get global string (synchronous)
  • get_int_async(name, callback) - Get global int via callback
  • get_float_async(name, callback) - Get global float via callback
  • get_string_async(name, callback) - Get global string via callback
  • get_int_awaitable(name, run_frames=256) -> Awaitable[int] - Get global int (async/await)
  • get_float_awaitable(name, run_frames=256) -> Awaitable[float] - Get global float (async/await)
  • get_string_awaitable(name, run_frames=256) -> Awaitable[str] - Get global string (async/await)
  • global_int(name) -> GlobalInt - Create typed int proxy
  • global_float(name) -> GlobalFloat - Create typed float proxy
  • global_string(name) -> GlobalString - Create typed string proxy

Events

  • signal_event(name) -> None - Signal event (wakes one shred)
  • broadcast_event(name) -> None - Broadcast event (wakes all shreds)
  • on_event(name, callback, listen_forever=True) -> int - Register event callback, returns callback ID
  • stop_listening_for_event(name, callback_id) -> None - Stop listening for event

Host Classes

Every VM binds Host, HostBuffer and HostBufPlay. Full reference: docs/api/host.md.

  • on_msg(callback) - Call callback(name, value) for each Host.msg(name, ...) in ChucK; value is None, float, str or list[float] by overload. One callback per instance; pass None to clear
  • on_receive(name, callback) -> int - Call callback(value) for each Host.sendBang/sendFloat/sendSymbol/sendList to name, the Python counterpart of [receive name]. Several callbacks may share a name. Returns a callback ID
  • remove_receiver(name, callback_id) -> bool - Remove a callback registered with on_receive
  • set_buffer(name, array, sample_rate=None) - Let HostBuffer and HostBufPlay use array in place. Requires a writable, C-contiguous float32 array of shape (frames,) or (frames, channels); anything that would need a copy raises
  • remove_buffer(name) -> bool - Detach the array; ChucK then reads 0

Callbacks run on whichever thread drives the VM, at the shred's logical time. During real-time audio that is the audio thread, so keep them short. Exceptions go to sys.unraisablehook.

Console Output

  • set_stdout_callback(callback) - Capture ChucK stdout (chout)
  • set_stderr_callback(callback) - Capture ChucK stderr (cherr)

Low-Level API (numchuck._numchuck.ChucK)

The low-level API provides direct access to all ChucK functionality with explicit parameter management.

from numchuck._numchuck import ChucK

Initialization Methods

  • __init__() - Create a new ChucK instance
  • init() -> bool - Initialize ChucK with current parameters
  • start() -> bool - Explicitly start ChucK VM (called implicitly by run() if needed)

Parameter Configuration

  • set_param(name: str, value: int) -> int - Set integer parameter
  • set_param_float(name: str, value: float) -> int - Set float parameter
  • set_param_string(name: str, value: str) -> int - Set string parameter
  • set_param_string_list(name: str, value: list[str]) -> int - Set string list parameter
  • get_param_int(name: str) -> int - Get integer parameter
  • get_param_float(name: str) -> float - Get float parameter
  • get_param_string(name: str) -> str - Get string parameter
  • get_param_string_list(name: str) -> list[str] - Get string list parameter

Compilation Methods

  • compile_code(code: str, args: str = "", count: int = 1, immediate: bool = False, filepath: str = "") -> tuple[bool, list[int]]

    • Compile ChucK code from string
    • Returns: (success, shred_ids)
    • Parameters:
      • code: ChucK code to compile
      • args: Additional arguments (separated by ':')
      • count: Number of shred instances to spork
      • immediate: If True, schedule immediately; if False, queue for next time step
      • filepath: Optional filepath for path-related operations
  • compile_file(path: str, args: str = "", count: int = 1, immediate: bool = False) -> tuple[bool, list[int]]

    • Compile ChucK code from file
    • Returns: (success, shred_ids)

Audio Processing

  • run(input: np.ndarray, output: np.ndarray, num_frames: int)
    • Process audio for specified number of frames (synchronous/offline)
    • input: Input buffer (1D numpy array, dtype=np.float32)
      • Size must be num_frames * input_channels
    • output: Output buffer (1D numpy array, dtype=np.float32, C-contiguous)
      • Size must be num_frames * output_channels
    • num_frames: Number of audio frames to process

Real-Time Audio (RtAudio)

  • start_audio(chuck: ChucK, sample_rate: int = 44100, num_dac_channels: int = 2, num_adc_channels: int = 0, dac_device: int = 0, adc_device: int = 0, buffer_size: int = 512, num_buffers: int = 8) -> bool

    • Start real-time audio playback using RtAudio
    • Audio plays asynchronously in the background
    • Returns: True if successful
  • stop_audio() -> bool

    • Stop real-time audio playback
    • Returns: True if successful
  • shutdown_audio(msWait: int = 0)

    • Shutdown audio system completely
    • msWait: Milliseconds to wait before shutdown
  • audio_info() -> dict

    • Get current audio system information
    • Returns dict with keys: sample_rate, num_channels_out, num_channels_in, buffer_size

Global Variable Management

  • set_global_int(name: str, value: int) - Set a global int variable
  • set_global_float(name: str, value: float) - Set a global float variable
  • set_global_string(name: str, value: str) - Set a global string variable
  • get_global_int(name: str, callback: Callable[[int], None]) - Get a global int (async via callback)
  • get_global_float(name: str, callback: Callable[[float], None]) - Get a global float (async via callback)
  • get_global_string(name: str, callback: Callable[[str], None]) - Get a global string (async via callback)
  • set_global_int_array(name: str, values: list[int]) - Set a global int array
  • set_global_float_array(name: str, values: list[float]) - Set a global float array
  • set_global_int_array_value(name: str, index: int, value: int) - Set array element by index
  • set_global_float_array_value(name: str, index: int, value: float) - Set array element by index
  • set_global_associative_int_array_value(name: str, key: str, value: int) - Set map value by key
  • set_global_associative_float_array_value(name: str, key: str, value: float) - Set map value by key
  • get_global_int_array(name: str, callback: Callable[[list[int]], None]) - Get int array (async)
  • get_global_float_array(name: str, callback: Callable[[list[float]], None]) - Get float array (async)
  • get_all_globals() -> list[tuple[str, str]] - Get list of all globals as (type, name) pairs

Global Event Management

  • signal_global_event(name: str) - Signal a global event (wakes one waiting shred)
  • broadcast_global_event(name: str) - Broadcast a global event (wakes all waiting shreds)
  • listen_for_global_event(name: str, callback: Callable[[], None], listen_forever: bool = True) -> int - Listen for event, returns listener ID
  • stop_listening_for_global_event(name: str, callback_id: int) - Stop listening using listener ID

Host Classes

  • set_host_msg_callback(callback: Callable[[str, None | float | str | list[float]], None] | None) - Callback for Host.msg
  • add_host_receiver(name: str, callback: Callable[[None | float | str | list[float]], None]) -> int - Register a callback for Host.send* to name, returns callback ID
  • remove_host_receiver(name: str, callback_id: int) -> bool - Remove a receiver
  • set_buffer(name: str, array: np.ndarray, sample_rate: float = 0.0) - Register a float32 array for HostBuffer/HostBufPlay; 0.0 means the VM's sample rate
  • remove_buffer(name: str) -> bool - Detach the array

Shred Management

  • remove_shred(shred_id: int) - Remove a shred by ID
  • remove_all_shreds() - Remove all running shreds from VM
  • get_all_shred_ids() -> list[int] - Get IDs of all running shreds
  • get_ready_shred_ids() -> list[int] - Get IDs of ready (not blocked) shreds
  • get_blocked_shred_ids() -> list[int] - Get IDs of blocked shreds
  • get_last_shred_id() -> int - Get ID of last sporked shred
  • get_next_shred_id() -> int - Get what the next shred ID will be
  • get_shred_info(shred_id: int) -> dict - Get shred info (id, name, is_running, is_done)

VM Control

  • clear_vm() - Clear the VM (remove all shreds)
  • clear_globals() - Clear global variables without clearing the VM
  • reset_shred_id() - Reset the shred ID counter
  • replace_shred(shred_id: int, code: str, args: str = "") -> int - Replace running shred with new code

Status and Utility

  • is_init() -> bool - Check if ChucK is initialized
  • vm_running() -> bool - Check if VM is running
  • now() -> float - Get current ChucK time in samples

Console Output Control

  • set_chout_callback(callback: Callable[[str], None]) -> bool - Capture ChucK console output
  • set_cherr_callback(callback: Callable[[str], None]) -> bool - Capture ChucK error output
  • toggle_global_color_textoutput(onOff: bool) - Enable/disable color output
  • probe_chugins() - Print info on all loaded chugins

Static Methods

  • version() -> str - Get ChucK version string
  • int_size() -> int - Get ChucK integer size in bits
  • num_vms() -> int - Get number of active ChucK VMs
  • set_log_level(level: int) - Set global log level
  • get_log_level() -> int - Get global log level
  • poop() - ChucK poop compatibility
  • set_stdout_callback(callback: Callable[[str], None]) -> bool - Set global stdout callback (static)
  • set_stderr_callback(callback: Callable[[str], None]) -> bool - Set global stderr callback (static)
  • global_cleanup() - Global cleanup for all ChucK instances

Parameter Constants

Core Parameters

  • PARAM_VERSION - ChucK version
  • PARAM_SAMPLE_RATE - Sample rate (default: 44100)
  • PARAM_INPUT_CHANNELS - Number of input channels
  • PARAM_OUTPUT_CHANNELS - Number of output channels

VM Configuration

  • PARAM_VM_ADAPTIVE - Adaptive VM mode
  • PARAM_VM_HALT - VM halt on errors
  • PARAM_OTF_ENABLE - On-the-fly programming enable
  • PARAM_OTF_PORT - On-the-fly programming port
  • PARAM_DUMP_INSTRUCTIONS - Dump VM instructions
  • PARAM_AUTO_DEPEND - Auto dependency resolution
  • PARAM_DEPRECATE_LEVEL - Deprecation warning level

Paths

  • PARAM_WORKING_DIRECTORY - Working directory path
  • PARAM_CHUGIN_ENABLE - Enable chugins (plugins)
  • PARAM_USER_CHUGINS - User chugin paths
  • PARAM_IMPORT_PATH_SYSTEM - System import search paths
  • PARAM_IMPORT_PATH_PACKAGES - Package import search paths
  • PARAM_IMPORT_PATH_USER - User import search paths

Display & Debugging

  • PARAM_OTF_PRINT_WARNINGS - Print on-the-fly compiler warnings
  • PARAM_IS_REALTIME_AUDIO_HINT - Hint for real-time audio mode
  • PARAM_COMPILER_HIGHLIGHT_ON_ERROR - Syntax highlighting in error messages
  • PARAM_TTY_COLOR - Enable color output in terminal
  • PARAM_TTY_WIDTH_HINT - Terminal width hint for formatting

Rendering API (numchuck.render)

  • render(code, duration=10.0, sample_rate=44100, channels=2, dtype=np.float32) -> np.ndarray - Render ChucK code to numpy array
  • render_file(files, duration=10.0, sample_rate=44100, channels=2, dtype=np.float32) -> np.ndarray - Render ChucK files to numpy array
  • to_wav(output, code=None, files=None, duration=10.0, sample_rate=44100, channels=2) -> Path - Export to WAV file
  • RenderError - Exception raised for rendering failures

File Watcher (numchuck.watcher)

from numchuck.watcher import FileWatcher, WatchedFile
  • FileWatcher(chuck, session, on_reload=None, on_error=None) - Watch files for changes and auto-reload
  • watch_file(filepath, shred_id=None) -> bool - Start watching a file
  • unwatch_file(filepath) -> bool - Stop watching a file
  • start() -> None - Start the file watcher
  • stop() -> None - Stop the file watcher
  • WatchedFile - Dataclass for watched file info

Web Server (numchuck.web)

from numchuck.web import WebChuckServer, WEB_AVAILABLE
  • WEB_AVAILABLE - Boolean indicating if web module is available
  • is_loopback_host(host) -> bool - Whether a bind address stays off the network
  • WebChuckServer(chuck, port=8080, host="127.0.0.1", auth_token=None, static_dir=None) - Browser-based ChucK IDE server
    • host - Address to bind; defaults to loopback
    • auth_token - Token required on /api/ and /ws. None generates one (loopback included); pass "" to disable auth explicitly, or a string to set your own
    • start() -> None - Start the web server in background thread
    • stop() -> None - Stop the web server
    • broadcast(msg: str) -> None - Broadcast message to all WebSocket clients
    • port - Server port (read-only)
    • url - Server URL, carrying ?token= when auth is on
    • is_running - Check if server is running
    • client_count - Number of connected WebSocket clients
# Example usage
from numchuck import Chuck
from numchuck.web import WebChuckServer

chuck = Chuck()
with WebChuckServer(chuck, port=8080) as server:
    print(f"IDE running at {server.url}")
    input("Press Enter to stop...")

MIDI Support (numchuck.midi)

from numchuck.midi import MIDIMapping, MIDIMappings, generate_midi_listener_code
  • MIDIMapping(channel, cc_number, global_name, min_value=0.0, max_value=1.0) - Map MIDI CC to ChucK global
  • MIDIMappings - Collection of MIDI mappings with add(), remove(), get(), to_dict() methods
  • MIDILearnState - State machine for MIDI learn mode
  • generate_midi_listener_code(mappings) -> str - Generate ChucK code for MIDI control
  • generate_midi_monitor_code() -> str - Generate MIDI monitor code

OSC Support (numchuck.osc)

from numchuck.osc import OSCServer, OSCClient, generate_osc_listener_code
  • OSCServer(port=9000) - UDP server for receiving OSC messages
  • OSCClient(host, port) - UDP client for sending OSC messages
  • OSCController(executor, port=9000) - Map OSC addresses to REPL actions
  • OSCHandler - Dataclass for OSC address handlers
  • generate_osc_listener_code(address, port, global_type, global_name) -> str - Generate ChucK OSC listener
  • generate_osc_sender_code(host, port, address) -> str - Generate ChucK OSC sender

Waveform Display (numchuck.tui.waveform)

from numchuck.tui.waveform import samples_to_waveform, WaveformBuffer
  • samples_to_waveform(samples, width=80, height=8, use_unicode=True) -> str - Convert audio to waveform string
  • WaveformBuffer(size, channels=2) - Circular buffer for real-time waveform display
  • format_waveform_bar(level, width=40, use_unicode=True) -> str - Format a level meter bar
  • format_stereo_meters(left, right, width=20) -> str - Format stereo level meters
  • calculate_rms(samples) -> float - Calculate RMS level
  • calculate_peak(samples) -> float - Calculate peak level
  • db_to_linear(db) -> float / linear_to_db(linear) -> float - Decibel conversions

Session Recording (numchuck.recorder)

from numchuck.recorder import SessionRecorder, SessionPlayer, list_recordings
  • SessionRecorder() - Record REPL sessions with timestamps
    • start(name) -> None - Start recording
    • stop() -> RecordedSession - Stop and return session
    • record_action(action_type, content) -> None - Record an action
  • SessionPlayer(session) - Playback recorded sessions
    • start(speed=1.0) -> None - Start playback
    • tick() -> bool - Advance playback, returns True if still playing
  • RecordedAction(timestamp, action_type, content) - A recorded action
  • RecordedSession(name, actions) - A complete recorded session
  • get_recording_path(name) -> Path - Get path to recording file
  • list_recordings() -> list[str] - List saved recordings

ChucK Language Support (numchuck.lang)

The lang subpackage provides ChucK language constants and syntax highlighting:

from numchuck.lang import ChuckLexer, KEYWORDS, TYPES, UGENS, REPL_COMMANDS

# Check if an identifier is a ChucK keyword
from numchuck.lang import is_keyword, is_ugen, get_category
is_keyword("while")  # True
is_ugen("SinOsc")    # True
get_category("LPF")  # "ugen"

Constants:

  • KEYWORDS - ChucK keywords (if, while, class, fun, etc.)
  • TYPES - ChucK types (int, float, time, dur, etc.)
  • OPERATORS - ChucK operators (=>, +, -, etc.)
  • TIME_UNITS - Time units (samp, ms, second, etc.)
  • UGENS - Unit generators (SinOsc, LPF, ADSR, etc.)
  • STD_CLASSES - Standard library classes (Std, Math, Machine, etc.)
  • REPL_COMMANDS - REPL command prefixes (+, -, ~, etc.)
  • ALL_IDENTIFIERS - All ChucK identifiers combined

Lexer:

  • ChuckLexer - Pygments lexer for ChucK syntax highlighting

Module Functions

  • version() -> str - Get ChucK version (convenience function)

Important Notes

Audio Buffer Types

ChucK uses float (32-bit) for audio samples by default. Always use np.float32 for numpy arrays:

# Correct
output_buffer = np.zeros(num_frames * channels, dtype=np.float32)

# Incorrect - will produce silent output
output_buffer = np.zeros(num_frames * channels, dtype=np.float64)

Buffer Layout

Audio buffers are interleaved:

  • For stereo output: [L0, R0, L1, R1, L2, R2, ...]
  • Buffer size = num_frames * num_channels

Time Advancement

ChucK code must advance time to generate audio:

# Good - infinite loop advances time
code = '''
SinOsc s => dac;
440 => s.freq;
while(true) { 1::samp => now; }
'''

# Bad - shred exits immediately, no audio
code = '''
SinOsc s => dac;
440 => s.freq;
'''

Examples

Real-Time Audio Playback

import numchuck
import time

# Create and initialize ChucK
chuck = numchuck.ChucK()
chuck.set_param(numchuck.PARAM_SAMPLE_RATE, 44100)
chuck.set_param(numchuck.PARAM_OUTPUT_CHANNELS, 2)
chuck.init()

# Compile ChucK code
chuck.compile_code('''
    SinOsc s => dac;
    440 => s.freq;
    0.5 => s.gain;
    while(true) { 1::samp => now; }
''')

# Start real-time audio (plays asynchronously)
numchuck.start_audio(chuck, sample_rate=44100, num_dac_channels=2)

# Audio plays in background
time.sleep(3)  # Play for 3 seconds

# Stop audio
numchuck.stop_audio()
numchuck.shutdown_audio()

Offline Audio Processing

import numchuck
import numpy as np

chuck = numchuck.ChucK()
chuck.set_param(numchuck.PARAM_SAMPLE_RATE, 44100)
chuck.set_param(numchuck.PARAM_OUTPUT_CHANNELS, 2)
chuck.init()

chuck.compile_code('''
    SinOsc s => dac;
    440 => s.freq;
    0.5 => s.gain;
    while(true) { 1::samp => now; }
''')

# Process audio synchronously
frames = 512
output = np.zeros(frames * 2, dtype=np.float32)
chuck.run(np.zeros(0, dtype=np.float32), output, frames)

# output now contains audio samples

Parameter Control

# Get ChucK version
print(f"ChucK version: {numchuck.version()}")

# Configure VM
chuck.set_param(numchuck.PARAM_VM_HALT, 0)
chuck.set_param_string(numchuck.PARAM_WORKING_DIRECTORY, "/path/to/files")

# Check status
print(f"Initialized: {chuck.is_init()}")
print(f"Current time: {chuck.now()} samples")

Multiple Shreds

# Compile the same code 3 times
success, ids = chuck.compile_code(code, count=3)
print(f"Spawned shreds: {ids}")  # [1, 2, 3]

# Remove all shreds
chuck.remove_all_shreds()

Loading ChucK Files

import numchuck

chuck = numchuck.ChucK()
chuck.set_param(numchuck.PARAM_SAMPLE_RATE, 44100)
chuck.set_param(numchuck.PARAM_OUTPUT_CHANNELS, 2)
chuck.init()

# Compile from file
success, shred_ids = chuck.compile_file("examples/basic/blit2.ck")

# Start playback
numchuck.start_audio(chuck)
import time; time.sleep(2)
numchuck.stop_audio()
numchuck.shutdown_audio()

Using Chugins (Plugins)

40 chugins are bundled with numchuck and automatically discovered -- no manual path setup needed. Run numchuck info to see what's available on your system.

Bundled Chugins

Category Chugins
Effects ABSaturator, Bitcrusher, ExpDelay, FoldbackSaturator, GVerb, KasFilter, Multicomb, NHHall, Overdrive, Spectacle
Filters Elliptic, FIR, WPDiodeLadder, WPKorg35
Oscillators / Synthesis MagicSine, Mesh2D, Wavetable
Envelopes ExpEnv, PowerADSR, WinFuncEnv
Spatial AmbPan, Binaural, MIAP, PanN
Analysis PitchTrack, Sigmund
Utility ConvRev, Ladspa, Line, Patch, Perlin, Random, Range, RegEx, XML
Networking AbletonLink
Plugin Hosting CLAP, AudioUnit, VST3
Pure-data PdPatch
from numchuck import Chuck

# Bundled chugins are loaded automatically
chuck = Chuck(sample_rate=44100, output_channels=2)

# Use a chugin in code
code = '''
SinOsc s => Bitcrusher bc => dac;
440 => s.freq;
8 => bc.bits;
while(true) { 1::samp => now; }
'''
chuck.compile_code(code)

To use additional chugins from a custom directory:

chuck = Chuck(user_chugins=["~/my-chugins"])

Global Variables (Python/ChucK Communication)

import numchuck
import numpy as np

chuck = numchuck.ChucK()
chuck.set_param(numchuck.PARAM_SAMPLE_RATE, 44100)
chuck.set_param(numchuck.PARAM_INPUT_CHANNELS, 2)
chuck.set_param(numchuck.PARAM_OUTPUT_CHANNELS, 2)
chuck.init()
chuck.start()

# Define global variables in ChucK
chuck.compile_code('''
    global int tempo;
    global float frequency;
    global string mode;

    SinOsc s => dac;

    while(true) {
        frequency => s.freq;
        1::samp => now;
    }
''')

# Helper to run audio cycles (VM processes messages during audio)
def run_cycles(count=5):
    buf_in = np.zeros(512 * 2, dtype=np.float32)
    buf_out = np.zeros(512 * 2, dtype=np.float32)
    for _ in range(count):
        chuck.run(buf_in, buf_out, 512)

# Set globals from Python
chuck.set_global_int("tempo", 120)
chuck.set_global_float("frequency", 440.0)
chuck.set_global_string("mode", "major")
run_cycles()

# Get globals via callback
result = []
chuck.get_global_float("frequency", lambda val: result.append(val))
run_cycles()
print(f"Current frequency: {result[0]} Hz")

# List all globals
globals_list = chuck.get_all_globals()
print(f"Globals: {globals_list}")

Global Events (Event-Driven Communication)

import numchuck
import numpy as np

chuck = numchuck.ChucK()
chuck.set_param(numchuck.PARAM_SAMPLE_RATE, 44100)
chuck.set_param(numchuck.PARAM_INPUT_CHANNELS, 2)
chuck.set_param(numchuck.PARAM_OUTPUT_CHANNELS, 2)
chuck.init()
chuck.start()

# ChucK code with global events
chuck.compile_code('''
    global Event trigger;
    global Event response;
    global int noteValue;

    SinOsc s => dac;

    fun void player() {
        while(true) {
            trigger => now;
            Std.mtof(noteValue) => s.freq;
            100::ms => now;
            response.broadcast();
        }
    }

    spork ~ player();
''')

def run_cycles(count=5):
    buf_in = np.zeros(512 * 2, dtype=np.float32)
    buf_out = np.zeros(512 * 2, dtype=np.float32)
    for _ in range(count):
        chuck.run(buf_in, buf_out, 512)

# Listen for response from ChucK
response_count = []
def on_response():
    response_count.append(1)
    print(f"Response received! Total: {len(response_count)}")

listener_id = chuck.listen_for_global_event("response", on_response, listen_forever=True)

# Trigger notes from Python
for note in [60, 64, 67, 72]:  # C major chord
    chuck.set_global_int("noteValue", note)
    chuck.signal_global_event("trigger")
    run_cycles(10)

# Stop listening
chuck.stop_listening_for_global_event("response", listener_id)

Host Classes (Messages and Shared Buffers)

Host.msg sends a value to Python without declaring a global, an event and a getter. The callback runs at the shred's logical time.

from numchuck import Chuck

with Chuck(input_channels=0) as chuck:
    chuck.on_msg(lambda name, value: print(name, value))
    chuck.compile('''
        while (true) {
            Math.random2f(200, 800) => float f;
            Host.msg("freq", f);
            250::ms => now;
        }
    ''')
    chuck.run(chuck.sample_rate)   # one second: prints 4 lines

Host.sendBang/sendFloat/sendSymbol/sendList reach the callbacks registered for a name with on_receive, as [send] reaches [receive] in Pd and Max. The callback always takes one argument, so it accepts whatever the .ck file sends.

with Chuck(input_channels=0) as chuck:
    chuck.on_receive("tick", lambda _: print("tick"))
    chuck.on_receive("pair", lambda values: print("pair", values))
    chuck.compile('''
        Host.sendBang("tick");
        Host.sendList("pair", [440.0, 0.2]);
    ''')
    chuck.run(1)

HostBuffer reads and writes a numpy array in place; HostBufPlay is a UGen that plays one.

import numpy as np

with Chuck(input_channels=0) as chuck:
    buf = np.zeros((48000, 2), dtype=np.float32)
    chuck.set_buffer("rec", buf)
    chuck.compile('''
        HostBuffer b;
        b.name("rec");
        for (0 => int i; i < b.frames(); i++) {
            b.poke(i, 0, Math.sin(2 * pi * 440 * i / b.sampleRate()));
        }
    ''')
    chuck.run(1)
    # buf[:, 0] now holds a 440 Hz sine

    chuck.compile('''
        HostBufPlay p => dac;
        p.name("rec");
        1 => p.loop;
        1::day => now;
    ''')
    audio = chuck.run(48000)

set_buffer accepts only a writable, C-contiguous float32 array. A float64 or strided array raises instead of being copied, since ChucK's writes would go to the copy. chuck-max and pd-chuck bind the same class names, so a .ck file that uses only these members runs in each host. See docs/api/host.md for the full member list and limits.

Shred Management & Introspection

import numchuck
import numpy as np

chuck = numchuck.ChucK()
chuck.set_param(numchuck.PARAM_SAMPLE_RATE, 44100)
chuck.set_param(numchuck.PARAM_INPUT_CHANNELS, 2)
chuck.set_param(numchuck.PARAM_OUTPUT_CHANNELS, 2)
chuck.init()
chuck.start()

# Spork multiple shreds
code = "while(true) { 100::ms => now; }"
success1, ids1 = chuck.compile_code(code)
success2, ids2 = chuck.compile_code(code)
success3, ids3 = chuck.compile_code(code)

# Introspect running shreds
all_ids = chuck.get_all_shred_ids()
print(f"Running shreds: {all_ids}")

for shred_id in all_ids:
    info = chuck.get_shred_info(shred_id)
    print(f"Shred {info['id']}: {info['name']}, running={info['is_running']}")

# Remove specific shred
chuck.remove_shred(ids1[0])
print(f"After removal: {chuck.get_all_shred_ids()}")

# Get next shred ID
next_id = chuck.get_next_shred_id()
print(f"Next shred ID will be: {next_id}")

# Clear all
chuck.clear_vm()
print(f"After clear_vm: {chuck.get_all_shred_ids()}")

Live Coding with replace_shred()

import numchuck
import numpy as np

chuck = numchuck.ChucK()
chuck.set_param(numchuck.PARAM_SAMPLE_RATE, 44100)
chuck.set_param(numchuck.PARAM_INPUT_CHANNELS, 2)
chuck.set_param(numchuck.PARAM_OUTPUT_CHANNELS, 2)
chuck.init()
chuck.start()

# Start with one sound
code_v1 = '''
SinOsc s => dac;
440 => s.freq;
while(true) { 1::samp => now; }
'''
success, ids = chuck.compile_code(code_v1)
original_id = ids[0]

# ... play for a while ...

# Hot-swap to different sound
code_v2 = '''
TriOsc t => dac;
330 => t.freq;
0.5 => t.gain;
while(true) { 1::samp => now; }
'''
new_id = chuck.replace_shred(original_id, code_v2)
print(f"Replaced shred {original_id} with {new_id}")

Capturing ChucK Console Output

import numchuck

chuck = numchuck.ChucK()
chuck.init()

# Capture chout (console output)
output_log = []
chuck.set_chout_callback(lambda msg: output_log.append(msg))

# Capture cherr (error output)
error_log = []
chuck.set_cherr_callback(lambda msg: error_log.append(msg))

# Run code that prints
chuck.compile_code('''
    <<< "Hello from ChucK!" >>>;
    <<< "Value:", 42 >>>;
''')

# Check captured output
print("ChucK output:", output_log)

Configuration

numchuck supports user configuration via ~/.numchuck/config.toml:

from numchuck import Config, load_config, save_config, get_config

# Load config (from ~/.numchuck/config.toml or defaults)
config = get_config()

# Access settings
print(config.audio.sample_rate)   # 44100
print(config.repl.smart_enter)    # True

# Modify and save
config.audio.sample_rate = 48000
config.repl.show_sidebar = False
save_config(config)

Example ~/.numchuck/config.toml:

[audio]
sample_rate = 48000
output_channels = 2
input_channels = 0
buffer_size = 512

[repl]
smart_enter = true
show_sidebar = true
start_audio = false
max_log_lines = 100

[editor]
start_audio = false
tab_size = 4
wrap_lines = false

[paths]
working_directory = "~/chuck"
chugin_paths = ["~/.chuck/chugins"]

[chuck]
chugin_enable = true
vm_adaptive = false
deprecate_level = 1

Configuration Classes

Class Description
Config Complete configuration (contains all sections)
AudioConfig Audio settings (sample_rate, channels, buffer_size, etc.)
REPLConfig REPL settings (smart_enter, show_sidebar, max_log_lines)
EditorConfig Editor settings (start_audio, tab_size, wrap_lines)
PathsConfig Path settings (working_directory, chugin_paths)
ChuckConfig ChucK VM settings (chugin_enable, vm_adaptive, etc.)

Requirements

  • Python 3.9+
  • CMake 3.15+
  • C++17 compatible compiler
  • macOS: Xcode with CoreAudio/CoreMIDI frameworks
  • numpy (for audio processing)

Development

# Build
make build

# Run tests
make test

# Clean build artifacts
make clean

What's with the name?

numchuck initially started off as pychuck. When I posted in the Chuck Discord about an earlier iteration of the project, David Braun suggested the name NumChuck, which fits much better with the project’s use of NumPy.

Nonetheless, the inertia of the initial name held until I went to publish the project on PyPI and discovered that there was already a pychuck project whose purpose is to implement (rather than wrap) the Chuck language in Python—-which is, in hindsight, a much stronger claim to the name.

Luckily, the name numchuck was available, allowing this project to narrowly avoid an unnecessary naming showdown.

License

numchuck is licensed under the GNU General Public License v3.0

Credits

Metadata

Release files for numchuck 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for numchuck 0.4.0
File Size Uploaded Provenance Actions
numchuck-0.4.0.tar.gz 35.2 MB Without provenance Details for numchuck-0.4.0.tar.gz

Built distributions (wheels)

Table of built distributions (wheels) for numchuck 0.4.0
File Actions
numchuck-0.4.0-cp312-abi3-win_amd64.whl CPython 3.12 abi3 Windows x86-64 Details for numchuck-0.4.0-cp312-abi3-win_amd64.whl
numchuck-0.4.0-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.12 abi3 Linux glibc 2.28+ x86-64, Linux glibc 2.27+ x86-64 Details for numchuck-0.4.0-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
numchuck-0.4.0-cp312-abi3-macosx_11_0_x86_64.whl CPython 3.12 abi3 macOS 11.0+ x86-64 Details for numchuck-0.4.0-cp312-abi3-macosx_11_0_x86_64.whl
numchuck-0.4.0-cp312-abi3-macosx_11_0_arm64.whl CPython 3.12 abi3 macOS 11.0+ ARM64 Details for numchuck-0.4.0-cp312-abi3-macosx_11_0_arm64.whl
numchuck-0.4.0-cp311-cp311-win_amd64.whl CPython 3.11 CPython 3.11 Windows x86-64 Details for numchuck-0.4.0-cp311-cp311-win_amd64.whl
numchuck-0.4.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.11 CPython 3.11 Linux glibc 2.28+ x86-64, Linux glibc 2.27+ x86-64 Details for numchuck-0.4.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
numchuck-0.4.0-cp311-cp311-macosx_11_0_x86_64.whl CPython 3.11 CPython 3.11 macOS 11.0+ x86-64 Details for numchuck-0.4.0-cp311-cp311-macosx_11_0_x86_64.whl
numchuck-0.4.0-cp311-cp311-macosx_11_0_arm64.whl CPython 3.11 CPython 3.11 macOS 11.0+ ARM64 Details for numchuck-0.4.0-cp311-cp311-macosx_11_0_arm64.whl
numchuck-0.4.0-cp310-cp310-win_amd64.whl CPython 3.10 CPython 3.10 Windows x86-64 Details for numchuck-0.4.0-cp310-cp310-win_amd64.whl
numchuck-0.4.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.10 CPython 3.10 Linux glibc 2.27+ x86-64, Linux glibc 2.28+ x86-64 Details for numchuck-0.4.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
numchuck-0.4.0-cp310-cp310-macosx_11_0_x86_64.whl CPython 3.10 CPython 3.10 macOS 11.0+ x86-64 Details for numchuck-0.4.0-cp310-cp310-macosx_11_0_x86_64.whl
numchuck-0.4.0-cp310-cp310-macosx_11_0_arm64.whl CPython 3.10 CPython 3.10 macOS 11.0+ ARM64 Details for numchuck-0.4.0-cp310-cp310-macosx_11_0_arm64.whl

Total release size: 82.0 MB

Release files / numchuck-0.4.0.tar.gz

Download URL numchuck-0.4.0.tar.gz
Size 35.2 MB
Tags Source
SHA-256 checksum
How to use checksums
6ba8defc17fb109c3b02d4a674cb78b909dcf3a089b079a2568f43d7bb4ff27c
BLAKE2b-256 checksum
How to use checksums
f25d2843579b9def664889186014d23bb7e235a6e2408c96c64243a59ef4e025
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / numchuck-0.4.0-cp312-abi3-win_amd64.whl

Download URL numchuck-0.4.0-cp312-abi3-win_amd64.whl
Size 5.1 MB
Tags CPython 3.12 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
55219b81512652209eaa7cd1555fbb27ba44945adf417ef11c9b881b39859641
BLAKE2b-256 checksum
How to use checksums
3ed17aff52e7f0b1731181a58d58d98fedba92d6d981b08d273d47f5284c849a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / numchuck-0.4.0-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl

Download URL numchuck-0.4.0-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Size 4.8 MB
Tags CPython 3.12 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 abi3
SHA-256 checksum
How to use checksums
69c9b0aabf6940ae7fa52ddf54814433b177d8f1f41a1593e87a05a10398a828
BLAKE2b-256 checksum
How to use checksums
110775eac2db2fe5c2dd9646c107c7e9faf5ed76bdaed33eb31e5900af07e15b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / numchuck-0.4.0-cp312-abi3-macosx_11_0_x86_64.whl

Download URL numchuck-0.4.0-cp312-abi3-macosx_11_0_x86_64.whl
Size 3.0 MB
Tags CPython 3.12 abi3 macOS 11.0+ x86-64
SHA-256 checksum
How to use checksums
9fc9aeb8f8b39b81e2346e9c23207c66a78e37c6b72535edea0444952f1b72ba
BLAKE2b-256 checksum
How to use checksums
33db231cc6e704bcd53d4554e75fe1139ad16760aee6f32a362b1bfeab12877c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / numchuck-0.4.0-cp312-abi3-macosx_11_0_arm64.whl

Download URL numchuck-0.4.0-cp312-abi3-macosx_11_0_arm64.whl
Size 2.7 MB
Tags CPython 3.12 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
7c2230f07a8be8f32a9ac21bb4e887e06c8bca3c4429c1faede994bcc57119a1
BLAKE2b-256 checksum
How to use checksums
3d61b5c1d5a5eb2c3fac1e24ae8ad5909ccbd578fff36a5bbb559dca47c3c018
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / numchuck-0.4.0-cp311-cp311-win_amd64.whl

Download URL numchuck-0.4.0-cp311-cp311-win_amd64.whl
Size 5.1 MB
Tags CPython 3.11 Windows x86-64
SHA-256 checksum
How to use checksums
a64f76488a197a5d81745ceeafe88fc2745a028ff95510c0b83c149d813da85c
BLAKE2b-256 checksum
How to use checksums
ec679bc635966135a6ea9a6b8579f1a8847597ae56b4f15ae6edf25c8ab54dc0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / numchuck-0.4.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl

Download URL numchuck-0.4.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Size 4.8 MB
Tags CPython 3.11 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
816c9468adcaa84d97b4e5b5f6ee8f158062fb31d0a590c343e452cc4cf58de4
BLAKE2b-256 checksum
How to use checksums
821597d2193bfbc7b3f0736da7650a26892da5aba737044c9dbc283c1643a080
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / numchuck-0.4.0-cp311-cp311-macosx_11_0_x86_64.whl

Download URL numchuck-0.4.0-cp311-cp311-macosx_11_0_x86_64.whl
Size 3.0 MB
Tags CPython 3.11 macOS 11.0+ x86-64
SHA-256 checksum
How to use checksums
5ac9ab9d570d524fc2aacbc484a236eba658b697694205a16b6c3ddfcdc1458a
BLAKE2b-256 checksum
How to use checksums
e7a02769649d3d5d6b00c3c678ccd421afe51be52f0e9d80019797a99d2ae892
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / numchuck-0.4.0-cp311-cp311-macosx_11_0_arm64.whl

Download URL numchuck-0.4.0-cp311-cp311-macosx_11_0_arm64.whl
Size 2.7 MB
Tags CPython 3.11 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
03456be33180048c9feeaab98967c606252dc99f6e2f1c929067f731dffd4281
BLAKE2b-256 checksum
How to use checksums
3919a3ea52dde3cc37ea1a473c419149be238a94d5995acb5bf94ac09442d340
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / numchuck-0.4.0-cp310-cp310-win_amd64.whl

Download URL numchuck-0.4.0-cp310-cp310-win_amd64.whl
Size 5.1 MB
Tags CPython 3.10 Windows x86-64
SHA-256 checksum
How to use checksums
d966e8c201505b5651f7b4a42ad9d67c82be54281c2e3304c8e02d61ebc6bb66
BLAKE2b-256 checksum
How to use checksums
99b052112c7d9cf425d721d7040ef1efb3ad17240b91e49a7d31cca7ffb548a8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / numchuck-0.4.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl

Download URL numchuck-0.4.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Size 4.8 MB
Tags CPython 3.10 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
bdf9adeace2f6100534bc165fb97640ddce275e4c0b27b41ed59c1b111923e22
BLAKE2b-256 checksum
How to use checksums
39991f7884f1b61e095f0f245cbcc96e4bdb569f2d8d036f4eadd957ac7c7cda
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / numchuck-0.4.0-cp310-cp310-macosx_11_0_x86_64.whl

Download URL numchuck-0.4.0-cp310-cp310-macosx_11_0_x86_64.whl
Size 3.0 MB
Tags CPython 3.10 macOS 11.0+ x86-64
SHA-256 checksum
How to use checksums
fa268d1abf5ffb5debcc3c90937083ea26d443988a66066b257aa6fe725db4cd
BLAKE2b-256 checksum
How to use checksums
0271c8c126608b1466ac406600531bd8e1d4ac2fac16e4da5760d6c7d87a36bf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / numchuck-0.4.0-cp310-cp310-macosx_11_0_arm64.whl

Download URL numchuck-0.4.0-cp310-cp310-macosx_11_0_arm64.whl
Size 2.7 MB
Tags CPython 3.10 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
c399129c94ed3234e224fa38b5b601f0b4265323bdc572979bb485b566f5024e
BLAKE2b-256 checksum
How to use checksums
c30752975a3dc9bca7489615d9f725f527ebd595b0295fd2009912831793f91c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Security for numchuck 0.4.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page