a speech-operated terminal looper for synthetic sound studies.
Current release: 0.4.0.
"We seem to have tuned circuits within us" — Daphne Oram, An Individual Note of Music, Sound and Electronics
ORAM is a local-first sound workstation for recording, looping, sampling, listening, and generating sound material. It is built from the idea that sound is never at rest.
Every recorded layer becomes a flowing circuit: a small river of frequencies, tensions, residues and resonances that can be listened to, transformed, summoned and returned. The user does not simply control the system. They tune with it.
record → resonate → listen → transform → generate → return
Named after Daphne Oram — pioneer of electronic music, inventor of the Oramics machine, and composer who built instruments to hear what did not yet exist.
ORAM started as a speech-operated terminal looper for synthetic sound studies. The current app has several surfaces around the same core idea:
- Python CLI/TUI instrument
- localhost dashboard and daemon
- native macOS SwiftUI app
- early JUCE DAW plugin target for Audio Unit, VST3, and Standalone builds
ORAM is not a DAW replacement, not a chatbot, and not a hosted prompt-to-song service. It is a small instrument where local audio, structured commands, and optional BYOK providers become constrained audio actions.
ORAM 0.4.0 is the stack's performance instrument. Its direct stack
integration is GERM 0.2.0: ORAM can use the local GERM-compatible generation
surface for constrained sound generation and transformation.
ORAM does not currently embed the AKOÚŌ v0.7 listening contract or write
Earworm 0.4.0 / akousma v1.3 records itself. Recordings and exports can enter
the Listening Stack through OÍDA 0.6.0 or GERM, then be navigated in
Akousmata 0.4.0 and evaluated by Algophony 0.5.0. This boundary is
intentional: ORAM remains usable as a standalone local instrument.
Not stable objects, but flowing resonant states. Not notes, but unstable entities. Not fixed frequencies, but living circuits of relation.
layers = circuits
loops = resonant fields
prompts = tuning gestures
generation = summoning
analysis = listening back
effects = tension-shaping
archive = trace of a state
ORAM is in alpha. The CLI/TUI, dashboard, daemon, and macOS app are working
development surfaces. The AU/VST3 plugin now builds, installs, validates with
Apple's auval on macOS, and has a native realtime layer core, but it still
needs DAW-by-DAW validation before it should be treated as a reliable production
plugin.
Expect API changes, rough edges, unsigned builds, and platform-specific audio behavior while the app stabilizes.
Current known alpha gaps:
- AU validation passes locally with
auval, but Logic, Ableton, Reaper, and other host scans still need explicit smoke tests. - VST3 build generation works, including JUCE module-info generation, but DAW host smoke tests are still required.
- The plugin imports generated audio, serializes native layer state, and applies a useful subset of ORAM structured actions; full DSP parity with the Python engine is not complete. As of v0.4 the plugin's native filter is a zero-phase Butterworth biquad and its reverb is a Schroeder comb/allpass network, with per-block gain smoothing on the mix bus.
- Granular effects and audio-to-audio generation remain app/core-first rather than fully native in the plugin.
- Release plugin packages are ad-hoc signed by default; Developer ID signing and notarization require local Apple credentials.
| Format | Path | State |
|---|---|---|
| Python CLI/TUI | src/oram |
Working development instrument |
| Browser dashboard | oram dashboard |
Working local test/control surface |
| Local daemon | oram daemon |
Working localhost API for app/plugin control |
| macOS app | apps/macos |
Working SwiftUI shell around the Python daemon |
| Audio Unit | plugins/oram-plugin |
Alpha build; installs and passes auval |
| VST3 | plugins/oram-plugin |
Alpha build with JUCE module-info generation |
| Standalone plugin app | plugins/oram-plugin |
Alpha debug/release build |
The performer records sound. The sound loops. The performer speaks or types. The agent listens to the speech, parses intent, and translates it into a constrained audio action. The sound changes. The performer listens again. The process repeats as a cycle of recording, transformation, and listening.
ORAM does not only generate sound. It listens for states of tension. Every loop is treated as a resonant body: unstable, mutable, recursive, alive. The user is not outside the circuit. The listener, the microphone, the machine, the model, and the sound form one tuned system.
recorder → looper → sampler → engine router → local archive
- Records host or microphone audio into layered circuits (up to four layers).
- Loops, overdubs, mutes, solos, clears, pans, and volumes layers.
- Parses typed or spoken commands into structured ORAM actions.
- Applies offline DSP tension-shaping: reverse, pitch, speed, filter, reverb, chorus, delay, flanger, phaser, distortion, bitcrush, stutter, granular, normalize, trim, fades, and spatial transforms.
- Listens back — spectral analysis of pitch, BPM, key, harmonics, and frequency character through local FFT, LLM-based interpretation, or hybrid routes.
- Generates sound through local audio routing by default when the local service is available, or summons textures through BYOK providers (ElevenLabs, Stability AI, fal Stable Audio).
- Writes generated sounds into
~/Music/ORAM Library. - Archives sessions as traces of a state: mix/stem WAVs, command logs, metadata, waveform text, and listening reports.
| Effect | Description |
|---|---|
reverse |
full buffer reverse |
pitch |
phase-vocoder pitch shift ±12 semitones, duration preserved (loops stay in time) |
speed |
anti-aliased varispeed (tape-style: pitch follows speed) |
lowpass / highpass |
4th-order Butterworth, or resonant biquad when a q is given |
bandpass |
resonant band around a center frequency |
reverb |
Freeverb-style 8-comb + 4-allpass network, loop-aware tail |
chorus |
three detuned modulated voices |
delay |
damped feedback echo, ping-pong option, tail folded into the loop |
flanger |
swept short-delay comb |
phaser |
swept 6-stage allpass ladder |
distortion |
oversampled waveshaper: soft / warm / fuzz |
bitcrush |
bit-depth + sample-rate reduction |
stutter |
slice-repeat glitch, in time |
granular |
granular cloud with local grain spray |
normalize |
peak or RMS loudness normalization |
trim |
silence trimming |
fade |
fade in / out curves |
spatial |
spatial positioning: near, far, wide |
ORAM treats listening as an active circuit, not passive reception. The body is also a resonator, a filter, a modulation system — a circuit that becomes activated by external vibrations.
Three listening routes:
| Route | Engine | Description |
|---|---|---|
spectral |
local FFT | frequency content, waveform statistics, amplitude dynamics |
llm |
BYOK provider | spectral data sent to an LLM for natural language interpretation |
hybrid |
both | combines spectral and LLM analysis into a unified listening report |
Listening produces listening_report.md files with layer-by-layer analysis,
frequency content, amplitude/dynamics statistics, waveform visualization, and
optional natural language interpretation.
Generation is always non-vocal — ORAM produces sound textures, effects, and music, never speech. Available engines:
| Engine | Type | Description |
|---|---|---|
mock |
local | test tones, noise, or silence for development |
elevenlabs |
BYOK | sound generation via ElevenLabs API |
stability |
BYOK | audio generation via Stability AI API |
fal |
BYOK | Stable Audio generation via fal |
Prompt types: generate [prompt], generate bed [prompt],
generate texture [prompt], generate hit [prompt], regenerate.
Each session archives as a complete trace:
session_name/
├── session.json # metadata, timestamps, engine config
├── commands.log # chronological command log
├── mix.wav # stereo mixdown
├── stems/
│ ├── layer_1.wav
│ ├── layer_2.wav
│ ├── layer_3.wav
│ └── layer_4.wav
├── generated/ # generated audio files
├── listening_report.md # analysis report
└── waveform.txt # ASCII waveform visualization
All interaction flows through structured commands — tuning gestures that resolve to bounded audio actions. Poetic language is accepted as input but must resolve to validated operations.
record [layer N] # capture into layer
overdub [layer N] # layer new audio over existing
stop # stop recording / transport
play / pause # transport controls
arm / disarm # arm layer for recording
mute layer N # mute a circuit
solo layer N # isolate a circuit
clear layer N # erase layer audio
set layer N volume 0.8 # set amplitude
set layer N pan -0.5 # set stereo position
reverse layer N # reverse audio buffer
set speed N ratio # time-stretch / speed
filter layer N lowpass 800 # filter with frequency
reverb layer N # reverb wash
chorus / delay / flanger / phaser
distortion / bitcrush # saturation / reduction
stutter / granular # glitch / granular synthesis
trim / fade in / fade out
normalize
spatial:far / spatial:near / spatial:wide
generate [prompt] # summon a texture
generate bed [prompt] # summon a bed layer
generate texture [prompt] # summon a texture
generate hit [prompt] # summon a percussive hit
regenerate # re-summon with last prompt
listen # analyze current state
listen layer N # listen to a specific circuit
listen mix # listen to the full mix
describe # describe what's sounding
listen --route hybrid|spectral|llm
save / export / archive # persist the trace
name [session_name] # name the session
load session [name] # recall a previous state
credentials set|status|test [provider]
mode [mode_name] / status / help / quit
The macOS app About view describes ORAM as a "Local-first BYOK sound workstation." That is the intended boundary:
- No ORAM cloud account is required.
- The app talks to a localhost daemon.
- Provider keys are stored in macOS Keychain for the packaged app.
- Local audio generation is the default local path; Local Mock remains available only as an explicit fallback.
- Telemetry is off by default.
- Generated sounds and archives stay in the local ORAM Library.
- Daemon mutation routes use a local bearer token when auth is enabled.
Requires Python 3.11+.
cd oram
pip install -e ".[dev]"For Whisper STT support:
pip install -e ".[dev,stt]"For the optional dashboard and daemon:
pip install -e ".[dev,web]"The development workflow also supports uv:
uv sync --extra dev --extra web
uv run pytestoram # start with defaults
oram run # equivalent explicit subcommand
oram --list-devices # show audio devices
oram --mock-audio # run without audio hardware
oram --input-device 2 # select input device
oram --session-name grey_chapel # name this session
oram --session-dir ./sessions # choose archive directory
oram --no-stt # keyboard only, no voice
oram dashboard # browser dashboard with real audio by default
oram dashboard --mock-audio # browser dashboard without audio hardware
oram daemon --mock-audio # local app/plugin daemon on 127.0.0.1
oram export ./oram_sessions/oram_0001space push-to-talk
r record selected layer
o overdub selected layer
1-4 select layer
m mute selected layer
M solo selected layer
x clear selected layer (repeat to confirm)
s save session
e export mix
l generate listening report
k hard-silence audio
i toggle prompt/audio input mode
tab cycle mode
q quit
The browser dashboard (click the oram title to open the About modal) provides
a visual control surface with:
⏺ record from mic into selected layer
⊕ overdub onto selected layer
fx open DSP transforms (grouped: motion / tone / space / character)
✦ summon — listen to what's sounding and generate a new layer
● record the master bus to a timed WAV
◉ export mix — bounce all layers to a WAV
⊘ nuke/reset — stop all audio and clear every layer (undoable)
+ add layer
The fx panel now offers the full effect set as one-click chips: reverse,
slower, faster, stretch, stutter, darker, thinner, pitch up/down, reverb,
delay, near, far, wide, distort, fuzz, bitcrush, chorus, flanger, phaser,
granulate, and normalize.
Layer corners: top-left select/mute (right-click: solo), top-right export, bottom-left generate, bottom-right clear. Waveform drag sets loop region. Volume strip supports drag, scroll, double-click for unity.
Keyboard shortcuts in the dashboard:
1-4 select layer
r record
o overdub
k nuke/reset all audio
g generate
l listen (analyze selected layer)
⇧A toggle auto mode
m mute
u unmute all
⌘E export mix
⌘Z / ⇧⌘Z undo / redo
⌘K command palette
/ focus prompt
esc close
The native app in apps/macos is a SwiftUI shell around the local Python ORAM
daemon. It launches or discovers oram daemon, stores provider keys in macOS
Keychain, controls recording/generation/listening/library workflows, and writes
generated sounds to the ORAM Library.
Views: Record, Generate, Listen, Library, Settings, About.
Build and run locally:
apps/macos/script/build_and_run.sh --no-open
open apps/macos/dist/ORAM.appRefresh the unsigned development DMG:
apps/macos/script/package_unsigned.shThe app bundle, DMG, and checksums are generated locally under:
apps/macos/dist/
The plugin lives in plugins/oram-plugin. It is a JUCE CMake project with a
native realtime layer engine. The plugin uses the ORAM daemon only for
control-plane work: parsing commands, generation, provider discovery, and
library access.
Supported build targets:
- Audio Unit:
ORAM.component - VST3:
ORAM.vst3 - Standalone debug app:
ORAM.app
Current plugin features:
- mono-in/mono-out and stereo-in/stereo-out effect layouts
- four native layers with record, overdub, mute, solo, clear, volume, and pan
- loop regions and host-input monitoring
- typed ORAM command parsing through the daemon
- generation through local audio, ElevenLabs, or Stability routing, then WAV import into native plugin layers
- native state serialization for parameters and layer audio
- basic plugin-side DSP actions including reverse, speed/pitch-ratio, filters, reverb/spatial-far, fades, and trim
Build:
plugins/oram-plugin/scripts/build.shInstall debug AU/VST3 into the current user's macOS plugin folders:
plugins/oram-plugin/scripts/install_debug_macos.shValidate the installed debug plugin on macOS:
plugins/oram-plugin/scripts/validate_macos.shCreate ad-hoc signed release zips and checksums:
plugins/oram-plugin/scripts/package_macos.shSet ORAM_PLUGIN_SIGN_IDENTITY and ORAM_PLUGIN_NOTARY_PROFILE to use
Developer ID signing and Apple notarization.
The plugin discovers the daemon through:
~/Library/Application Support/ORAM/oram-daemon.json
Plugin architecture notes: docs/architecture/daw-plugin-architecture.md.
Packaged app usage stores keys in Keychain:
service: com.sonicfieldlabs.oram
account: provider:elevenlabs
account: provider:stability
Terminal setup:
oram credentials set elevenlabs
oram credentials set stability
oram credentials status
oram credentials test elevenlabs
oram credentials test stabilityMock mode remains the default. ElevenLabs and Stability AI are optional. See:
Environment variables:
ORAM_SAMPLE_RATE=48000
ORAM_BLOCK_SIZE=512
ORAM_INPUT_DEVICE=
ORAM_OUTPUT_DEVICE=
ORAM_SESSION_DIR=./oram_sessions
ORAM_STT_BACKEND=mock
ORAM_GENERATOR_BACKEND=mock
ORAM_LLM_BACKEND=none
ORAM_AUTO_LISTEN=false
ORAM_DEFAULT_LISTENING_ROUTE=hybrid
ORAM_DEFAULT_ENGINE=auto
ORAM_DASHBOARD_TOKEN=
ELEVENLABS_API_KEY=
STABILITY_API_KEY=
Precedence: CLI args > env vars > config file > defaults.
Safe defaults: generator_backend=mock, llm_backend=none,
auto_listen=false. Cloud credentials are never required for the core looper.
See .env.example for a complete template.
ORAM is local-first: no hosted ORAM server is required, no telemetry is enabled by default, and provider credentials are never exposed in local state responses.
The dashboard and daemon bind to 127.0.0.1 by default.
To expose the dashboard on the local network:
export ORAM_DASHBOARD_TOKEN=<local-token>
oram dashboard --allow-lan- Token authentication: when
ORAM_DASHBOARD_TOKENis set, all POST endpoints requireAuthorization: Bearer <token>. - WebSocket auth: when a token is set, WebSocket connections must include
?token=<token>in the URL. - Origin checking: WebSocket connections from non-localhost origins are rejected
unless
--allow-lanis used. - No secrets in state:
/api/stateand daemon/statedo not expose provider keys.
Run:
oram doctor --privacyPrivacy notes: docs/security/local-first-privacy.md.
record → resonate → listen → transform → generate → return
Core architecture:
- architecture.md
- docs/architecture/local-engine-boundary.md
- docs/architecture/daw-plugin-architecture.md
Command grammar:
Session archive format:
Design principles:
Constrained vocabulary: commands map to bounded actions. Poetic language is accepted as input but must resolve to structured, validated operations.
Offline transforms: expensive DSP happens outside the realtime audio callback. The callback only does bounded, predictable work.
Graceful degradation: if STT fails, keyboard controls remain. If the LLM is unavailable, the deterministic parser handles commands. If generation fails, existing loops continue.
Minimal identity: the interface is monochrome-first, lowercase, austere. The complexity lives inside the loop, not in the chrome.
Sound as material: ORAM treats sound not as notation or signal, but as a changing field of tensions. Not stable objects, but flowing resonant states. Not notes, but unstable entities. Not fixed frequencies, but living circuits of relation.
uv run ruff check src/oram_daemon/server.py tests/test_daemon_api.py
uv run pytest
plugins/oram-plugin/scripts/build.sh
plugins/oram-plugin/scripts/validate_macos.sh
plugins/oram-plugin/scripts/package_macos.shThe current debug plugin artifacts are produced under:
plugins/oram-plugin/build/ORAMPlugin_artefacts/Debug/
oram --list-devicesoram --mock-audiooramwith a microphone- Press
r, make sound, stop recording - Confirm loop playback
- Press
2, record a second layer - Mute layer 1
- Reverse layer 2
- Generate a mock bed
- Export session
- Open exported WAV
- Inspect
session.json,commands.log, andlistening_report.md
No audio devices found: check system audio permissions. On macOS, grant terminal or ORAM access in System Settings > Privacy & Security > Microphone.
Audio dropouts: try increasing block size with --block-size 1024.
STT not working: run with --no-stt for keyboard-only mode. Check that Whisper
is installed with pip install -e ".[stt]".
Plugin does not see the daemon: start oram daemon --mock-audio and confirm
~/Library/Application Support/ORAM/oram-daemon.json exists.
Audio Unit discovery issues: run plugins/oram-plugin/scripts/validate_macos.sh,
restart the DAW or AudioComponent registrar, then retry host/plugin scanning.
Import errors: ensure you installed from the project root.