Python bindings for ChucK audio programming language
Project description
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
.ckfiles 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
numpyarrays. -
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 — Extend functionality with ChucK chugins for additional instruments and effects.
-
Dynamic Interaction - Bidirectional communication between ChucK and Python through global variables, event triggers, and callbacks.
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.
-
Automatic Versioning — Keeps track of live coding sessions (
file.ck → file-1.ck → file-1-1.ck). -
Command-Line Mode — Run ChucK files directly from the terminal, with support for duration and silent modes.
Installation
Install from pypi
pip install numchuck
or
uv add numchuck
Build from source
# Clone the repository
git clone <repository-url>
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
python -m numchuck edit
# Open specific files in tabs
python -m numchuck edit bass.ck melody.ck
# Enable project versioning
python -m numchuck edit --project mymusic
# Start with audio enabled
python -m numchuck edit --start-audio --project mymusic
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
python -m numchuck repl
# Load files on startup
python -m numchuck repl bass.ck melody.ck
# Enable project versioning
python -m numchuck repl --project mymusic
# Start with audio enabled
python -m numchuck repl --start-audio
# Disable smart Enter mode
python -m numchuck repl --no-smart-enter
# Hide sidebar (can toggle with F2)
python -m numchuck repl --no-sidebar
REPL Commands:
add <file>or+ <file>- Spork a fileremove <id>or- <id>- Remove a shredremove allor- all- Remove all shredsreplace <id> <file>- Replace shred with filestatus- Show VM statustime- Show ChucK time- Type
helpor press F1 for full command reference
3. Command-Line Execution
# Execute ChucK files from command line
python -m numchuck run myfile.ck
# Run multiple files
python -m numchuck run bass.ck melody.ck
# Run for 10 seconds then exit
python -m numchuck run myfile.ck --duration 10
# Silent mode (no audio)
python -m numchuck run myfile.ck --silent
# Custom sample rate
python -m numchuck run myfile.ck --srate 48000
4. Version and Info
# Show version
python -m numchuck version
# Show ChucK and numchuck info
python -m 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,
.ckfiles, 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 windowF2- Toggle shreds table (detailed view with ID, folder/filename, elapsed time)F3- Toggle log window (ChucK VM output)Ctrl+Q- Exit applicationTab- Command and ChucK code completionUp/Down- Navigate command history
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
High-Level API (Recommended)
The Chuck class provides a Pythonic interface with properties and simplified methods:
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.3-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)
# Access low-level API when needed
chuck.raw.set_param(...)
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 ifauto_init=True)compile(code, args="", count=1, immediate=False) -> tuple[bool, list[int]]- Compile ChucK codecompile_file(path, args="", count=1, immediate=False) -> tuple[bool, list[int]]- Compile from filerun(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 bufferreuse=True: uses internal buffer (zero GC without manual management)
advance(num_frames) -> None- Advance VM time without returning audio (for callbacks/events)
Shred Management
remove_shred(shred_id) -> None- Remove a shred by IDreplace_shred(shred_id, code, args="") -> int- Replace running shred with new code, returns new shred IDshred_info(shred_id) -> dict | None- Get shred informationclear()- Remove all shreds from VMreset_id()- Reset shred ID counter
Global Variables
set_int(name, value)- Set global intget_int(name, run_frames=256) -> int- Get global int (synchronous)set_float(name, value)- Set global floatget_float(name, run_frames=256) -> float- Get global float (synchronous)set_string(name, value)- Set global stringget_string(name, run_frames=256) -> str- Get global string (synchronous)get_int_async(name, callback)- Get global int via callbackget_float_async(name, callback)- Get global float via callbackget_string_async(name, callback)- Get global string via callback
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 IDstop_listening_for_event(name, callback_id) -> None- Stop listening for event
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 instanceinit() -> bool- Initialize ChucK with current parametersstart() -> bool- Explicitly start ChucK VM (called implicitly byrun()if needed)
Parameter Configuration
set_param(name: str, value: int) -> int- Set integer parameterset_param_float(name: str, value: float) -> int- Set float parameterset_param_string(name: str, value: str) -> int- Set string parameterset_param_string_list(name: str, value: list[str]) -> int- Set string list parameterget_param_int(name: str) -> int- Get integer parameterget_param_float(name: str) -> float- Get float parameterget_param_string(name: str) -> str- Get string parameterget_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 compileargs: Additional arguments (separated by ':')count: Number of shred instances to sporkimmediate: If True, schedule immediately; if False, queue for next time stepfilepath: 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
- Size must be
output: Output buffer (1D numpy array, dtype=np.float32, C-contiguous)- Size must be
num_frames * output_channels
- Size must be
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 variableset_global_float(name: str, value: float)- Set a global float variableset_global_string(name: str, value: str)- Set a global string variableget_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 arrayset_global_float_array(name: str, values: list[float])- Set a global float arrayset_global_int_array_value(name: str, index: int, value: int)- Set array element by indexset_global_float_array_value(name: str, index: int, value: float)- Set array element by indexset_global_associative_int_array_value(name: str, key: str, value: int)- Set map value by keyset_global_associative_float_array_value(name: str, key: str, value: float)- Set map value by keyget_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 IDstop_listening_for_global_event(name: str, callback_id: int)- Stop listening using listener ID
Shred Management
remove_shred(shred_id: int)- Remove a shred by IDremove_all_shreds()- Remove all running shreds from VMget_all_shred_ids() -> list[int]- Get IDs of all running shredsget_ready_shred_ids() -> list[int]- Get IDs of ready (not blocked) shredsget_blocked_shred_ids() -> list[int]- Get IDs of blocked shredsget_last_shred_id() -> int- Get ID of last sporked shredget_next_shred_id() -> int- Get what the next shred ID will beget_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 VMreset_shred_id()- Reset the shred ID counterreplace_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 initializedvm_running() -> bool- Check if VM is runningnow() -> float- Get current ChucK time in samples
Console Output Control
set_chout_callback(callback: Callable[[str], None]) -> bool- Capture ChucK console outputset_cherr_callback(callback: Callable[[str], None]) -> bool- Capture ChucK error outputtoggle_global_color_textoutput(onOff: bool)- Enable/disable color outputprobe_chugins()- Print info on all loaded chugins
Static Methods
version() -> str- Get ChucK version stringint_size() -> int- Get ChucK integer size in bitsnum_vms() -> int- Get number of active ChucK VMsset_log_level(level: int)- Set global log levelget_log_level() -> int- Get global log levelpoop()- ChucK poop compatibilityset_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 versionPARAM_SAMPLE_RATE- Sample rate (default: 44100)PARAM_INPUT_CHANNELS- Number of input channelsPARAM_OUTPUT_CHANNELS- Number of output channels
VM Configuration
PARAM_VM_ADAPTIVE- Adaptive VM modePARAM_VM_HALT- VM halt on errorsPARAM_OTF_ENABLE- On-the-fly programming enablePARAM_OTF_PORT- On-the-fly programming portPARAM_DUMP_INSTRUCTIONS- Dump VM instructionsPARAM_AUTO_DEPEND- Auto dependency resolutionPARAM_DEPRECATE_LEVEL- Deprecation warning level
Paths
PARAM_WORKING_DIRECTORY- Working directory pathPARAM_CHUGIN_ENABLE- Enable chugins (plugins)PARAM_USER_CHUGINS- User chugin pathsPARAM_IMPORT_PATH_SYSTEM- System import search pathsPARAM_IMPORT_PATH_PACKAGES- Package import search pathsPARAM_IMPORT_PATH_USER- User import search paths
Display & Debugging
PARAM_OTF_PRINT_WARNINGS- Print on-the-fly compiler warningsPARAM_IS_REALTIME_AUDIO_HINT- Hint for real-time audio modePARAM_COMPILER_HIGHLIGHT_ON_ERROR- Syntax highlighting in error messagesPARAM_TTY_COLOR- Enable color output in terminalPARAM_TTY_WIDTH_HINT- Terminal width hint for formatting
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)
import numchuck
chuck = numchuck.ChucK()
chuck.set_param(numchuck.PARAM_SAMPLE_RATE, 44100)
chuck.set_param(numchuck.PARAM_OUTPUT_CHANNELS, 2)
# Enable chugins and set search path
chuck.set_param(numchuck.PARAM_CHUGIN_ENABLE, 1)
chuck.set_param_string(numchuck.PARAM_USER_CHUGINS, "./examples/chugins")
chuck.init()
# 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)
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)
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)
Requirements
- Python 3.8+
- 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
- ChucK: Ge Wang, Perry Cook, and the ChucK team
- nanobind: Wenzel Jakob and contributors
- David Braun: For suggesting the name, numchuck!
- claude-code: Anthropic
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file numchuck-0.1.6.tar.gz.
File metadata
- Download URL: numchuck-0.1.6.tar.gz
- Upload date:
- Size: 34.7 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
04531b4a548724962f94b0719204b6f72a95bc0756cec46e0a26214a1bce9da1
|
|
| MD5 |
9418ccf906aaf4fdf9c6cf65710908a8
|
|
| BLAKE2b-256 |
1e4b823a1673d939be8c66628f2d92c9ff51a9aed0f9903715af5ba8f87f4b5b
|
File details
Details for the file numchuck-0.1.6-cp312-abi3-win_amd64.whl.
File metadata
- Download URL: numchuck-0.1.6-cp312-abi3-win_amd64.whl
- Upload date:
- Size: 1.6 MB
- Tags: CPython 3.12+, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
54c498b7c4701507b7136cfc8db126a85e5cd9a6d08f23f1211ebe9631a05a97
|
|
| MD5 |
46194a4cd9ab99e2a23ecb5c0e2f0474
|
|
| BLAKE2b-256 |
7592430bb1e82caf68273e15e4e2f1e7a5fa94f6170cc35416dfed0790e7b6ff
|
File details
Details for the file numchuck-0.1.6-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: numchuck-0.1.6-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 2.8 MB
- Tags: CPython 3.12+, manylinux: glibc 2.27+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3288a7be271a48447bc9f1d510560b68e19f21ada457f3e8df3e8dfb810c00f7
|
|
| MD5 |
6096968472ba085273ef3148bb6f44b0
|
|
| BLAKE2b-256 |
a2ea1bead760b01d7da0bb1110fccede888db7499f6dd0459c3f97695755db28
|
File details
Details for the file numchuck-0.1.6-cp312-abi3-macosx_11_0_x86_64.whl.
File metadata
- Download URL: numchuck-0.1.6-cp312-abi3-macosx_11_0_x86_64.whl
- Upload date:
- Size: 1.5 MB
- Tags: CPython 3.12+, macOS 11.0+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
95b0a0a78bc8a65bb18afad1e462a201e6bf1155b1999ab27eb6b6903ba58413
|
|
| MD5 |
afc310997f81ddf52ea444e0693771e8
|
|
| BLAKE2b-256 |
349f66af2240fd16e3b7922500ec8355b415f2a5d5a0380dd4e9d6f032ede2c2
|
File details
Details for the file numchuck-0.1.6-cp312-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: numchuck-0.1.6-cp312-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.4 MB
- Tags: CPython 3.12+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d8c22fd8be21bc37b6026d003e18b41c316489d35c151341fcf2f40da745a25b
|
|
| MD5 |
be60d02303c43c3a4d7d40ca42806221
|
|
| BLAKE2b-256 |
a26c2238c80e14c34d7d39e948a4c3ad05a1d870e775e6bf76638208f5951691
|
File details
Details for the file numchuck-0.1.6-cp311-cp311-win_amd64.whl.
File metadata
- Download URL: numchuck-0.1.6-cp311-cp311-win_amd64.whl
- Upload date:
- Size: 1.6 MB
- Tags: CPython 3.11, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bd588e70bb1de56863b519ced2f73ed07abfcb2b4e4ef92ac03972365fefec3f
|
|
| MD5 |
abf18ca5168d2514981ef935eb450c93
|
|
| BLAKE2b-256 |
b674a0cddb9a974f7513f209370c04b4c05af795d4b398bb4b2291dee0305d53
|
File details
Details for the file numchuck-0.1.6-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: numchuck-0.1.6-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 2.8 MB
- Tags: CPython 3.11, manylinux: glibc 2.27+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a574fecec6718a18dc9cf6bf2afeefa4d45a1a623b7f9bb4bb03343ed1060879
|
|
| MD5 |
850732e17b0a20887c2686a4f6e975ef
|
|
| BLAKE2b-256 |
964adacb45ca6576b1acda79a29f507f8980b05db3641070cb1f461c598e8805
|
File details
Details for the file numchuck-0.1.6-cp311-cp311-macosx_11_0_x86_64.whl.
File metadata
- Download URL: numchuck-0.1.6-cp311-cp311-macosx_11_0_x86_64.whl
- Upload date:
- Size: 1.5 MB
- Tags: CPython 3.11, macOS 11.0+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
334c9eece685e1d6bd4f82e7a5c97a318432170f4fba8fd64f7d2c7afa211fb3
|
|
| MD5 |
94cbf8cb6b4c5edb9865be92cbf3ed59
|
|
| BLAKE2b-256 |
bdd46e09bf2b720b46858dc0e1fc0fd5841abaac39e31a5896ce828a602ed689
|
File details
Details for the file numchuck-0.1.6-cp311-cp311-macosx_11_0_arm64.whl.
File metadata
- Download URL: numchuck-0.1.6-cp311-cp311-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.4 MB
- Tags: CPython 3.11, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a02bfc7747ec7a97673783e37aee8a7d6b1c74e0b6ddac34a3b027fb12c39237
|
|
| MD5 |
a4e184cc2dece8a4b5b1924644287ee4
|
|
| BLAKE2b-256 |
831bf14af6f5cc213a2bf82b0109b4aff61f24bc7b2a6ba16dc4eef9c68643d8
|
File details
Details for the file numchuck-0.1.6-cp310-cp310-win_amd64.whl.
File metadata
- Download URL: numchuck-0.1.6-cp310-cp310-win_amd64.whl
- Upload date:
- Size: 1.6 MB
- Tags: CPython 3.10, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8856f76665fcff4fcb6e649838f24c50af40b68aa34a2a2eb84924d215efa334
|
|
| MD5 |
ca57dc6ecd25a0f97e1d02e79b67144e
|
|
| BLAKE2b-256 |
e4f9794c08c0916fc6420a3c99155834ab52d5e256a357a60cdf3b338fc953b8
|
File details
Details for the file numchuck-0.1.6-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: numchuck-0.1.6-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 2.8 MB
- Tags: CPython 3.10, manylinux: glibc 2.27+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b8444215661118e0389192c903b2d491e845597740e8e444701408de34fb6889
|
|
| MD5 |
9bb2bd0aec0487826c603eb20c260c69
|
|
| BLAKE2b-256 |
1a3dcf31df3ce4be953e901884e92042d89a21ec166c2aa638b87b26a08a88ca
|
File details
Details for the file numchuck-0.1.6-cp310-cp310-macosx_11_0_x86_64.whl.
File metadata
- Download URL: numchuck-0.1.6-cp310-cp310-macosx_11_0_x86_64.whl
- Upload date:
- Size: 1.5 MB
- Tags: CPython 3.10, macOS 11.0+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
122e8ce146a348009fbc4f7bc172e0d771e06774465488da579efe18f75d73ab
|
|
| MD5 |
17e2892f12949a93e1ec1c2b2a4c56ca
|
|
| BLAKE2b-256 |
7061c03382fd999cb8c9b18993ed3e04e66b007582f8b5ddbe0d6e0d29eb7c84
|
File details
Details for the file numchuck-0.1.6-cp310-cp310-macosx_11_0_arm64.whl.
File metadata
- Download URL: numchuck-0.1.6-cp310-cp310-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.4 MB
- Tags: CPython 3.10, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9edfdf1ebdf7b725eddb722431babe68bb8b3b7d8605ba53dc182dfc9e59b115
|
|
| MD5 |
3cf65fb0c479eb3d8da53ca2e137996c
|
|
| BLAKE2b-256 |
e1c395a2da5b6bca70de20f1f6c2cf3331b767fb8b3363e4b857aacd5ee9188a
|
File details
Details for the file numchuck-0.1.6-cp39-cp39-win_amd64.whl.
File metadata
- Download URL: numchuck-0.1.6-cp39-cp39-win_amd64.whl
- Upload date:
- Size: 1.6 MB
- Tags: CPython 3.9, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ef5480035a60e036ac7a401bc4eb68f47a2a046a0a1ab677a6a73235296d6d3d
|
|
| MD5 |
555e74ea46e2893a0895edcf39fb43e6
|
|
| BLAKE2b-256 |
e10107257b6f2341b7b61e4950cfb140a690c118af7f5af52bcb1b9281ddef95
|
File details
Details for the file numchuck-0.1.6-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: numchuck-0.1.6-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 2.8 MB
- Tags: CPython 3.9, manylinux: glibc 2.27+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fe9b6acdc33ed217537266a89b69d9c3e975577659cdefb75e68ea985bd5174e
|
|
| MD5 |
a0391a53faa0d1fd49413e973c8f69c0
|
|
| BLAKE2b-256 |
c08a446cc917e464415b59fdcac7ded008dda54a15262cb9db97b17fdb05e4c1
|
File details
Details for the file numchuck-0.1.6-cp39-cp39-macosx_11_0_x86_64.whl.
File metadata
- Download URL: numchuck-0.1.6-cp39-cp39-macosx_11_0_x86_64.whl
- Upload date:
- Size: 1.5 MB
- Tags: CPython 3.9, macOS 11.0+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
382229ffea1a0b4503de1313c5194641780fc50d4a54bff6954c68a6ed6c8dd7
|
|
| MD5 |
add06d905566166cda272826dc9ee665
|
|
| BLAKE2b-256 |
184dcb2c96760392c00c9e514aa3c4bf6f624ba0c512f5e4fe165232be5a1bcb
|
File details
Details for the file numchuck-0.1.6-cp39-cp39-macosx_11_0_arm64.whl.
File metadata
- Download URL: numchuck-0.1.6-cp39-cp39-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.4 MB
- Tags: CPython 3.9, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d86c2be5b3d0ef5533041708d713a5aa578b7250b60778bf576038b54631045a
|
|
| MD5 |
3feb9673ec347409f6c9b385f2f5c25f
|
|
| BLAKE2b-256 |
84d509fd86252d21f2899bce590cec5da41e214b0c9edf32f3fb501b52b3e9cf
|