Skip to main content

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 .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 — 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 file
  • remove <id> or - <id> - Remove a shred
  • remove all or - all - Remove all shreds
  • replace <id> <file> - Replace shred with file
  • status - Show VM status
  • time - Show ChucK time
  • Type help or 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, .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

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 if auto_init=True)
  • 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)

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

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

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

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

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

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

numchuck-0.1.7.tar.gz (34.7 MB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

numchuck-0.1.7-cp312-abi3-win_amd64.whl (1.6 MB view details)

Uploaded CPython 3.12+Windows x86-64

numchuck-0.1.7-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (2.9 MB view details)

Uploaded CPython 3.12+manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

numchuck-0.1.7-cp312-abi3-macosx_11_0_x86_64.whl (1.5 MB view details)

Uploaded CPython 3.12+macOS 11.0+ x86-64

numchuck-0.1.7-cp312-abi3-macosx_11_0_arm64.whl (1.4 MB view details)

Uploaded CPython 3.12+macOS 11.0+ ARM64

numchuck-0.1.7-cp311-cp311-win_amd64.whl (1.6 MB view details)

Uploaded CPython 3.11Windows x86-64

numchuck-0.1.7-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (2.9 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

numchuck-0.1.7-cp311-cp311-macosx_11_0_x86_64.whl (1.5 MB view details)

Uploaded CPython 3.11macOS 11.0+ x86-64

numchuck-0.1.7-cp311-cp311-macosx_11_0_arm64.whl (1.4 MB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

numchuck-0.1.7-cp310-cp310-win_amd64.whl (1.6 MB view details)

Uploaded CPython 3.10Windows x86-64

numchuck-0.1.7-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (2.9 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

numchuck-0.1.7-cp310-cp310-macosx_11_0_x86_64.whl (1.5 MB view details)

Uploaded CPython 3.10macOS 11.0+ x86-64

numchuck-0.1.7-cp310-cp310-macosx_11_0_arm64.whl (1.4 MB view details)

Uploaded CPython 3.10macOS 11.0+ ARM64

numchuck-0.1.7-cp39-cp39-win_amd64.whl (1.6 MB view details)

Uploaded CPython 3.9Windows x86-64

numchuck-0.1.7-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (2.9 MB view details)

Uploaded CPython 3.9manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

numchuck-0.1.7-cp39-cp39-macosx_11_0_x86_64.whl (1.5 MB view details)

Uploaded CPython 3.9macOS 11.0+ x86-64

numchuck-0.1.7-cp39-cp39-macosx_11_0_arm64.whl (1.4 MB view details)

Uploaded CPython 3.9macOS 11.0+ ARM64

File details

Details for the file numchuck-0.1.7.tar.gz.

File metadata

  • Download URL: numchuck-0.1.7.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

Hashes for numchuck-0.1.7.tar.gz
Algorithm Hash digest
SHA256 42d9b1fd9b896742450e27fe3c1893004460c5af97356678b38f920ec1009155
MD5 2b033d3a8c227efff15875bc8fc221d3
BLAKE2b-256 c97054a5a715301d5cb4c1c2d6138200d09ecdde306d9f44c0761e19e6d67adc

See more details on using hashes here.

File details

Details for the file numchuck-0.1.7-cp312-abi3-win_amd64.whl.

File metadata

  • Download URL: numchuck-0.1.7-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

Hashes for numchuck-0.1.7-cp312-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 340ccf3c9ccae9229772b4bae799c7f0b73c53a8c44138269b4f5b1b015da4ee
MD5 d8e29018dde466cf4417c4eff7962383
BLAKE2b-256 d36c33f5ab9335d817913638f9c8ffd3f9ddf4b5717eb301dda8ad3086f3308a

See more details on using hashes here.

File details

Details for the file numchuck-0.1.7-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for numchuck-0.1.7-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 edfd1c8cec41178d552d3a94ac081f3a9f312d0252f534e948fa69467382b23c
MD5 f656680f20748d6d0b3cc3eb2a1bda4d
BLAKE2b-256 222e03089c2ae5b43e51942da3f42ee6ad5a488ad0ca697145a00358d7f4ce56

See more details on using hashes here.

File details

Details for the file numchuck-0.1.7-cp312-abi3-macosx_11_0_x86_64.whl.

File metadata

File hashes

Hashes for numchuck-0.1.7-cp312-abi3-macosx_11_0_x86_64.whl
Algorithm Hash digest
SHA256 d4e8169f9eb6775ac03f2a135398d29be23a2429d6896ec419c224cc6e435c21
MD5 fed8ffac8d443ada881b6d026d3d60a0
BLAKE2b-256 46334ef259f36f7267cea526437933f04a91f9e42b7caa0d3924ddb0e6c69dff

See more details on using hashes here.

File details

Details for the file numchuck-0.1.7-cp312-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for numchuck-0.1.7-cp312-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 8b9976445324301b6cecd1d6dc8756ce371de12b643c023f41f765302dddbf48
MD5 89655f99621488b4d5cf18b56c380aea
BLAKE2b-256 efc2928f0d5a55aebf28acc58bae88ab30da05dae4e078a47b6c2f3cdf81da13

See more details on using hashes here.

File details

Details for the file numchuck-0.1.7-cp311-cp311-win_amd64.whl.

File metadata

  • Download URL: numchuck-0.1.7-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

Hashes for numchuck-0.1.7-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 f9731bea75997d00caccbf754f05c8c4238c8b0917d1072a3551cb1a2d5c9b76
MD5 80b970399444ee0881d3a49a138d953c
BLAKE2b-256 86ee9e2f1fb666b314812bd811d72f482a6198656ddd2847b03de3775a0d035a

See more details on using hashes here.

File details

Details for the file numchuck-0.1.7-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for numchuck-0.1.7-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 f35984f367fd12087ab935d719dfd4726cce0c5605d5a7b55b3707fe3391d15a
MD5 f8c47d25fb9b8d693be72f3811f45227
BLAKE2b-256 fb4dbe73141c23e210d3118edf18cf25b746991f3598e2c7dd1bd873b99a8eb8

See more details on using hashes here.

File details

Details for the file numchuck-0.1.7-cp311-cp311-macosx_11_0_x86_64.whl.

File metadata

File hashes

Hashes for numchuck-0.1.7-cp311-cp311-macosx_11_0_x86_64.whl
Algorithm Hash digest
SHA256 9233b08e5332b46d6dff2ddd90434aa3f62ef711a2516068eea75d4090ab2199
MD5 d2ebd258d23f3739e9b03b408d4fc70a
BLAKE2b-256 a8f14e4e75238f194c0a96f54df2de7c174521a6bbf329e87edd7a1492054c9f

See more details on using hashes here.

File details

Details for the file numchuck-0.1.7-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for numchuck-0.1.7-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 63622b7b3f4287edf355ed59b219b9f7347b0d299059c1a37b714fbb8b2c3e8c
MD5 ce6f012509ecbfda19759ec65ab9a98e
BLAKE2b-256 4909023bf8e0fc9a4bd38f9508cd33af071fe400110f59c0f22617a24ec10f10

See more details on using hashes here.

File details

Details for the file numchuck-0.1.7-cp310-cp310-win_amd64.whl.

File metadata

  • Download URL: numchuck-0.1.7-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

Hashes for numchuck-0.1.7-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 9a4d8beb32b5f00893970ab88b396466a3bbe1b3cb48e290bb8bad4351c25b51
MD5 1bd1a1101cb888ba476bb4450b18c515
BLAKE2b-256 0c053061dd74aa5c460322a4103323238d7f4179e7389750a06af2bbf9f4dd21

See more details on using hashes here.

File details

Details for the file numchuck-0.1.7-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for numchuck-0.1.7-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 07c706106712e011910efc12457a85e568ef286a6f2ae4dc3d375ec8202ec14b
MD5 cbeffd4eecc279d51b6f3a9fdd2ddc17
BLAKE2b-256 58a1fbbcf39fa060c54b292b8e18256aceee96c66bc5fa592f8713ff3b60f5b8

See more details on using hashes here.

File details

Details for the file numchuck-0.1.7-cp310-cp310-macosx_11_0_x86_64.whl.

File metadata

File hashes

Hashes for numchuck-0.1.7-cp310-cp310-macosx_11_0_x86_64.whl
Algorithm Hash digest
SHA256 a4bf3bc0fbe8390f4ec03634b10a22b356acd7600d3ef5663d013ebad97ae7bf
MD5 f0c46f48cb884d64e6bd7e13aece8d3a
BLAKE2b-256 9142e59efbf677b54dffdb2c27232864256675b3d49bbbf75c2afc619a6fa877

See more details on using hashes here.

File details

Details for the file numchuck-0.1.7-cp310-cp310-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for numchuck-0.1.7-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 6330382a20cec62b82085cc06107aef95f126a2b7d1b2791b27dca8b5ec7995f
MD5 ea570f52ac42784f6fcf427367a1135b
BLAKE2b-256 4b2630cb8ff51777fae03d1337c6c9d1388c04d9986e88e59313e23afd266294

See more details on using hashes here.

File details

Details for the file numchuck-0.1.7-cp39-cp39-win_amd64.whl.

File metadata

  • Download URL: numchuck-0.1.7-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

Hashes for numchuck-0.1.7-cp39-cp39-win_amd64.whl
Algorithm Hash digest
SHA256 bc66c6c5b7eefd1021ffbda90ae8a7f5fbe619881a4a35f66f8be949b1d05507
MD5 87905bec3e44a2e0ebda755ebb15b736
BLAKE2b-256 7d871c03a6c8e2cd40aa23a1173a70ea9919426ac2d9d616842d48c77d487c41

See more details on using hashes here.

File details

Details for the file numchuck-0.1.7-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for numchuck-0.1.7-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 a38b1e719353f395b47b7a9544dc460d0e1e2a02ef795b9d22bbeab68647efc4
MD5 cd7a5361134fb8894e4ac69b8662edd6
BLAKE2b-256 f0803a500173d71ba6d215463ffb46ecdd4710e0f974155efc929f11bab342c0

See more details on using hashes here.

File details

Details for the file numchuck-0.1.7-cp39-cp39-macosx_11_0_x86_64.whl.

File metadata

File hashes

Hashes for numchuck-0.1.7-cp39-cp39-macosx_11_0_x86_64.whl
Algorithm Hash digest
SHA256 41aca9f774e83b5693be97d9a30650f5fdd5129d71d226eaa75fa620ca6ed564
MD5 ed03b79d7248c0f3f821140613a08e75
BLAKE2b-256 5c1f3838457a057a63ca44e1aafe0fd68e89d9d69652ea915afd77239d18be06

See more details on using hashes here.

File details

Details for the file numchuck-0.1.7-cp39-cp39-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for numchuck-0.1.7-cp39-cp39-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 3b2e7e397edd58294ba161a646232f54abf90a8b6194d462bdf7aa0ef23ccaa2
MD5 e96991f05c6addf79a7ac6e3b4b5ab5d
BLAKE2b-256 72ba8d00cf689dc6d222a20637b837b135c742448c3d7435d0cf4f5fd0659be6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page