A nonoha-engine plugin for audio playback and streaming, providing audio device control and file streaming capabilities within the nonoha-engine visual programming environment.
This plugin provides specialized nodes for audio playback using sounddevice and soundfile libraries. It enables real-time audio streaming, file playback with preloading, and audio device management.
-
AudioQueryDevice: Queries available audio devices
- Logs all detected audio devices with details
- Dispatches the device list as named parallel arrays (
devicesoutput, one element per device): index, name, hostapi, max_input_channels, max_output_channels, default low/high input/output latencies, default_samplerate — a complete mirror of PortAudio's per-device info. Output devices are the entries withmax_output_channels > 0 - Dispatches the default output and input devices (
default_output/default_inputoutputs: name, index, hostapi) - Useful for finding device IDs / name queries for other audio nodes
-
AudioDevicePlayFile: Plays audio from a file with ring buffer
- Automatic file preloading for low-latency playback
- Background file reading with ring buffer (30 second buffer by default)
- Gapless loop playback (
loopproperty) - Underrun-tolerant playback (transient buffer starvation pads with silence and is counted, instead of terminating playback)
- Configurable device ID selection
- Play/Stop control via input ports
-
AudioDevicePlayStream: Real-time streaming audio playback
- Accepts streaming audio frames via input port
- Thread-safe ring buffer for smooth playback
- Buffer low notification output for flow control
- Configurable sample rate, channels, and buffer duration
- Play/Stop control via input ports (play is idempotent and may be level-driven; play from the error state recreates the stream)
- Error messages (device not found, rate mismatch, ...) are dispatched
on the
last_erroroutput
-
AudioFileStream: Streams audio data from a file
- On-demand frame reading with configurable readout count
- Gapless loop playback (
loopproperty): wraps to the file start on EOF - Seek support for random access
- EOF detection output (dispatched once at EOF when loop is disabled)
- Audio info output (channels, sample rate, total frames)
- Loading status output (NOT_LOADED, LOADING, LOADED)
- Buffer reuse optimization for efficient memory usage
-
AudioGain: Gain stage with constant-slew glide (no clicks)
gaininput port sets a target; the node glides toward it per sampleramp_secondsproperty sets the slew rate (seconds per gain difference of 1.0): short (default 0.05) = smoothed volume control, long (e.g. 3.0) = fade in/out from a single target change- Gain starts at 0.0, so playback always fades in from silence
- Chain two instances for independent fade and volume stages:
AudioFileStream → AudioGain(fade) → AudioGain(volume) → AudioDevicePlayStream
pip install git+https://github.com/viestyle-dev/audio-nodes.gitRequires Python 3.11+. nonoha-core is provided by the host runtime (the
nonoha engine), so it is not a runtime dependency of this package.
- Add
audio-nodesto your workspace'spyproject.toml:
[project]
dependencies = [
"audio-nodes",
# other dependencies...
]
[tool.uv.sources]
audio-nodes = { path = "./plugins/audio-nodes", editable = false }- Install dependencies using uv:
uv syncTo include audio-nodes as a built-in plugin in your nonoha-engine instance:
- Import the plugin in your
src/main.py:
import audio_nodes- Add to RuntimeConfig:
from nonoha_engine.runtime_config import RuntimeConfig
config = RuntimeConfig(
builtin_plugins=[
audio_nodes,
# other built-in plugins...
]
)Once installed, the audio nodes will appear in the nonoha-engine node palette. You can:
- Drag and drop audio nodes into your visual programming workspace
- Configure node properties (file path, device ID, sample rate, channels)
- Connect data flows between audio nodes and other processing nodes
- Run the graph to enable audio playback
- Add an
AudioDevicePlayFilenode - Set the
file_pathproperty to your audio file (relative to graph data directory) - Connect a trigger to the
playinput port - Audio will be preloaded automatically and play with minimal latency
- Add an
AudioFileStreamnode to read audio data - Add an
AudioDevicePlayStreamnode for playback - Connect the
framesoutput to theframesinput - Use
buffer_lowoutput to trigger more frame reads
Insert AudioGain nodes between them for volume control and fades. Note
that gain applied upstream of the output buffer becomes audible only after
the buffered audio drains (≈ buffer_duration seconds of latency).
The device_id property of the playback nodes accepts, mirroring
sounddevice's device parameter:
- empty string: system default output device
- a number: PortAudio device index (not stable across reboots or device changes — prefer name queries for permanent installations)
- anything else: a sounddevice name query — space-separated substrings
matched case-insensitively, in order, against
"<device name>, <host API name>"
Platform notes:
- Windows: every physical device is enumerated once per host API
(MME / DirectSound / WASAPI / WDM-KS), so a bare device name often matches
multiple entries. Append the host API to disambiguate, e.g.
"Speakers wasapi". MME truncates device names to ~31 characters. - macOS: Core Audio only; names are stable and unique.
- Linux / Raspberry Pi: ALSA enumerates real and virtual devices;
"default"is usually what you want.
Use AudioQueryDevice to list the available devices and their host APIs.
All playback nodes open their own PortAudio output stream in shared mode (the OS mixes multiple streams), so any number of audio nodes — in one graph or across graphs in the same engine process — can output to the same device concurrently without conflicts. Exclusive-mode (WASAPI exclusive) and ASIO single-client setups are not supported.
Stream creation is slow on Windows (~12 s per stream) and is serialized
process-wide, so expect roughly 12 s × (number of playback nodes) of
startup time before all nodes reach the stopped state.
- Python >= 3.11
- nonoha-core (nonoha-engine core library)
- sounddevice (audio I/O)
- soundfile (audio file reading)
- numpy (array processing)
Linux (including Raspberry Pi):
On Linux systems, you need to install PortAudio before using the audio nodes:
sudo apt install libportaudio2This provides the necessary audio backend for sounddevice to function properly.
To contribute or modify the plugin:
uv sync # also installs the dev dependency group (pytest, nonoha-core)
uv run pytestOn Windows, run pytest through the venv's Python instead of uv run:
.\.venv\Scripts\python.exe -m pytesthttps://python-sounddevice.readthedocs.io/
https://python-soundfile.readthedocs.io/
Contributions are welcome — see CONTRIBUTING.md. Pull requests require signing the nonoha CLA (a one-time comment on your first PR, shared across the nonoha repositories).
See SECURITY.md for how to report vulnerabilities.