Python client¶
The gloopy package wraps the gRPC API in idiomatic Python.
Install with pip install ./python. For a guided start, do the
Python quickstart.
from gloopy import Gloopy, note
with Gloopy() as g: # connects to 127.0.0.1:50051
lead = g.add_synth_track("Lead", wave="SAW")
g.add_clip(lead, notes=[note(60, 0, 1), note(64, 1, 1), note(67, 2, 1)])
g.play()
g.render("/tmp/mix.wav", tail_seconds=1.0)
Methods map roughly one-to-one onto the RPCs and return plain Python values.
note(pitch, start_beat, length_beats, velocity=0.8) is a small helper for
building notes; the music-theory helpers below (pitch, dur, scale,
chord, seq, mini) are documented in full under
Describing notes.
Pulled live from the source
The reference below is generated at build time from the docstrings in
python/gloopy/client.py and python/gloopy/music.py (mkdocstrings,
Google-style docstrings) — no pre-generation step, so it never drifts from
the code. If it's blank here, the docs environment doesn't have the gloopy
package importable yet.
gloopy.client
¶
A thin, Pythonic client for Gloopy's gRPC control API.
Mirrors examples/gloopy-grpc.lisp. The DAW listens on 127.0.0.1:50051;
structural edits and queries go over gRPC (live notes/knobs are on OSC 9000).
from gloopy import Gloopy, note, seq, mini, scale, chord
g = Gloopy() # connects to 127.0.0.1:50051
g.set_tempo(128)
tid = g.add_synth_track("lead", wave="SAW")
# Notes are (pitch, start_beat, length_beats). pitch accepts a MIDI int or a
# name; length accepts beats or shorthand ("q", "8t"). See gloopy.music for
# seq() (lay steps end-to-end, with rests), the mini() string DSL, scale()
# and chord().
g.add_clip(tid, notes=[note(60, 0, 1), note("E4", 1, 1), note("G4", 2, 2)])
g.add_clip(tid, notes=seq([("C4","q"), ("E4","e"), (None,"e"), ("G4","h")]))
g.add_clip(tid, notes=mini("c4q d e f g4h a b")) # compact melody DSL
g.play()
...
g.render("/tmp/out.wav", tail_seconds=1.0)
Gloopy
¶
Connection to a running Gloopy instance.
Usable as a context manager (with Gloopy() as g: ...) which closes the
channel on exit. Methods return plain Python values (ints, dicts, lists).
panic()
¶
All-notes-off across every track — clears stuck/hanging notes.
set_swing(amount)
¶
0.5 = straight, up to ~0.75 = triplet feel.
set_metronome(enabled=True)
¶
Toggle the beat-click metronome (a monitor layer; included in a bounce if left on).
set_metronome_level(level=1.0)
¶
Set the metronome click volume (0..1). A session setting (not saved).
start_recording()
¶
Record armed MIDI + armed audio tracks from the playhead.
list_midi_inputs()
¶
MIDI input sources Gloopy is listening to (it auto-opens all + hot-plugs).
arm_track(track_id, armed=True, input=0, channels=2, monitor=False)
¶
Arm an audio track for recording (input = first hardware channel).
set_punch_range(enabled=True, in_beat=0.0, out_beat=0.0, count_in_beats=0.0)
¶
Punch in/out (record only within [in,out)) with an optional count-in lead.
set_record_settings(format=0, latency_offset_seconds=0.0)
¶
Take format (0=WAV, 1=FLAC) and manual latency offset (added to device latency).
promote_take(take_id)
¶
Move a scratch take from raw/ into the recordings dir and repoint its clips.
cleanup_takes()
¶
Delete take files no clip references; returns the count removed.
recover_takes()
¶
Create clips for orphan take files (crash recovery); returns the count.
set_sampler_controls(track_id, start=0.0, end=1.0, reverse=False, root_note=0, fade_in=0.0, fade_out=0.0, loop=False, mono=False, loop_xfade=0.0, interp=0)
¶
Sampler playback controls: window [start,end] as fractions of the sample length, reverse plays the window back-to-front, root_note>0 sets the root (0 leaves it unchanged), fade_in/fade_out are per-voice fades in seconds (0 = off; de-click a mid-waveform trim). loop repeats the window until note-off (fade_out then acts as the release time). mono chokes: a new hit cuts every ringing voice (hi-hat choke / mono 808). loop_xfade (seconds) crossfades the loop seam so it has no discontinuity click. interp selects the resampling interpolation (0 = linear, 1 = cubic — smoother when pitch-shifted). Fails if not a Sampler.
add_sfz_track(path, name='')
¶
Load a native SFZ instrument (samples preloaded) onto a new track.
add_surge_track(patch='', name='')
¶
Add a new track backed by the embedded Surge XT engine (optional .fxp patch).
set_synth_param(track_id, name, value)
¶
Tweak the built-in synth engine on a track. name is one of:
wave osc2wave osc2detune oscmix sub · attack decay sustain release gain ·
ftype cutoff reso fenvamt fattack fdecay fsustain frelease ·
lfotarget lforate lfodepth.
add_macro(track_id, name='Macro')
¶
Add a perceptual macro (an encoder, 0..1) to a track. Returns its index.
set_macro_value(track_id, macro, value)
¶
Turn a macro (0..1); every mapped param sweeps across its authored [lo,hi].
map_macro_synth(track_id, macro, param, lo=0.0, hi=1.0)
¶
Map a macro onto a built-in synth param (see set_synth_param names), swept lo..hi.
map_macro_effect(track_id, macro, insert, slot, param, lo=0.0, hi=1.0)
¶
Map a macro onto a mixer insert-effect param (insert/slot), swept lo..hi.
randomize_macros(track_id)
¶
Roll every macro on the track to a fresh random 0..1 and apply — musical because each mapping stays within its authored [lo,hi] safe range.
rename_macro(track_id, macro, name)
¶
Rename a macro. Empty/whitespace names are rejected.
clear_macro_mappings(track_id, macro)
¶
Remove all of a macro's param mappings (the macro itself stays).
remove_macro(track_id, macro)
¶
Delete a macro from the track (later macros shift down by one index).
rename_track(track_id, name)
¶
Rename an existing track. Empty/whitespace names are rejected.
duplicate_track(track_id)
¶
Clone a track — its clips, generator/instrument and insert state — as a new
'
set_track_colour(track_id, colour)
¶
Recolour a track. colour is an 8-hex ARGB string (e.g. 'ffef5350'), with or
without a leading '#'.
move_track(track_id, delta)
¶
Reorder a track: delta<0 moves it up (toward the top), delta>0 down. No-op (error) if the track is already at that edge.
set_track_polarity(track_id, invert)
¶
Phase-invert (polarity flip) a track's contribution to the mix — negates its samples so it can cancel a correlated layer.
split_clip(track_id, index, beat)
¶
Split a clip at an absolute beat; returns the new (right-hand) clip index.
split_clip_equal(track_id, index, pieces)
¶
Chop a clip into pieces equal-length clips (a loop chopper); returns the number
of pieces produced.
split_clip_at_marker(track_id, index, marker)
¶
Split a clip at a named timeline location; new (right) clip index, or -1.
slice_at_transients(track_id, index, sensitivity=1.0)
¶
Slice an audio clip at detected onsets; returns the resulting slice count (1 = none).
set_clip_muted(track_id, index, muted=True)
¶
Mute (disable) or enable a clip in the arrangement without deleting it.
rename_clip(track_id, index, name)
¶
Rename a clip (its label). An empty name makes the clip fall back to showing the track's name.
set_clip_colour(track_id, index, colour)
¶
Per-clip colour override (8-hex ARGB, e.g. 'ffef5350'). An empty string clears the override so the clip inherits the track's colour.
set_loop_to_clip(track_id, index)
¶
Set the transport loop to a clip's span and enable looping (audition on repeat).
regenerate_clip(track_id, index, script='', lang='', seed=0, generator='', system='')
¶
Mark a clip as a script clip and generate its notes from the kernel.
A clip's generator is EITHER a source file (script, a project-relative path) OR a
named generator (generator): "pkg.mod:fn" in Python / "pkg:sym" in Lisp, with
system the ASDF system / import root to load. lang is inferred when omitted — from
the script extension (.py -> python, .lisp/.cl -> common-lisp) or the
generator's shape — so Python users needn't spell it out. It still routes to the matching
kernel (SBCL for Lisp; the auto-launched or attached Python kernel for Python).
set_clip_script_live(track_id, index, live=True)
¶
Toggle a script clip's "Live" flag — auto-regenerate ~1 bar before it plays.
get_clip_notes(track_id, index)
¶
Return a clip's notes as dicts: pitch, start_beat, length_beats, velocity.
duplicate_clip(track_id, index, at_beat=-1.0)
¶
Copy a clip to at_beat (default -1 = butt up right after it); returns new index.
repeat_clip(track_id, index, copies)
¶
Tile copies back-to-back duplicates after a clip; returns copies added.
crop_clip(track_id, index, start_beat, end_beat)
¶
Trim a MIDI clip to the absolute beat range [start_beat, end_beat).
consolidate_clip(track_id, index)
¶
Flatten a looped MIDI clip's repetitions into explicit notes and un-loop it.
scale_clip_time(track_id, index, factor=0.5)
¶
Time-scale a MIDI clip: multiply note starts/lengths and the clip's content+slot by factor (0.5 = double-time / twice as fast, 2 = half-time / twice as slow).
bounce_clip(track_id, index)
¶
Freeze a clip to audio on a new track; returns the new track id (-1 on failure).
set_clip_gain(track_id, index, gain_db)
¶
Set an audio clip's playback gain in dB.
normalize_clip(track_id, index, target_dbfs=0.0)
¶
Set an audio clip's gain so its loudest sample sits at target_dbfs (0 = full scale).
set_clip_fades(track_id, index, fade_in_beats=0.0, fade_out_beats=0.0)
¶
Set an audio clip's fade-in / fade-out lengths, in beats.
set_clip_fade_shape(track_id, index, shape=0)
¶
Set an audio clip's fade curve shape: 0 linear, 1 equal-power (constant-power, louder than linear), 2 exponential (slow start). Applies to both fade edges.
set_clip_transpose(track_id, index, semitones)
¶
Non-destructive playback transpose of a MIDI clip (semitones, +/-48). The stored notes are untouched — the offset is applied at render time (unlike transpose_clip).
set_clip_velocity(track_id, index, scale)
¶
Non-destructive playback velocity scale of a MIDI clip (multiplier 0..2). The stored note velocities are untouched — the scale is applied at render time.
set_clip_probability(track_id, index, probability)
¶
Set every note's fire probability in a MIDI clip (0..1). A generative gate: each note (per looped repetition) fires with this chance, deterministically (reproducible renders). Per-note probabilities can also be set via add_clip's Note.probability.
export_notes_json(track_id, index)
¶
A clip's notes as a JSON array string [{pitch,start,length,velocity},...].
import_notes_json(track_id, json_text, start_beat=0.0)
¶
Build a new clip on track_id at start_beat from a JSON note array (the shape export_notes_json emits). Returns the new clip index, or -1 if no usable notes.
quantize_clip(track_id, index, grid=0.25, strength=1.0)
¶
Snap note starts toward a beat grid (0.25 = 16ths). strength 0..1: 1 = full snap, 0.5 = halfway (tighten without robotizing).
strum_clip(track_id, index, step_beats=0.05, down=True)
¶
Fan out chord voices (notes sharing a start beat) by step_beats each; down = high->low.
arpeggiate_clip(track_id, index, step_beats=0.25, mode=0)
¶
Turn each chord into an arpeggio (destructive); mode 0=up, 1=down, 2=up-down.
legato_clip(track_id, index, amount=1.0)
¶
Legato: stretch each note's length so it reaches the next distinct onset, blended by amount (0 = unchanged, 1 = notes exactly touch the next onset). Chords extend together.
ramp_clip_velocity(track_id, index, frm=0.3, to=1.0)
¶
Velocity ramp: interpolate each note's velocity from frm at the first onset to to
at the last onset (crescendo if frm
echo_clip(track_id, index, delay_beats=0.5, repeats=3, feedback=0.6)
¶
MIDI echo: append repeats decaying copies of every note, each delay_beats later,
velocity multiplied by feedback each step (copies fading below ~1% are dropped).
invert_clip(track_id, index)
¶
Melodic inversion: mirror every note's pitch around the earliest note's pitch, so intervals flip direction (ascending <-> descending). Timing/length/velocity kept.
ratchet_clip(track_id, index, subdivisions=2)
¶
Ratchet/roll: subdivide each note into subdivisions equal same-pitch hits filling
its span (a drum roll / stutter). Pitch and velocity kept.
harmonize_clip(track_id, index, semitones)
¶
Harmonize: add a parallel voice semitones from each note (e.g. +7 a fifth, +12
an octave), keeping the originals — a monophonic line becomes parallel harmony.
Voices that fall off the 0..127 keyboard are dropped.
swing_clip(track_id, index, grid_beats=0.5, amount=0.33)
¶
Swing/groove: delay every off-beat note (one sitting on an odd grid_beats line) by
amount of a grid step, baking a shuffle into the clip. amount 0=straight, ~0.33=triplet
feel. On-beat notes stay; length/pitch/velocity preserved.
chordify_clip(track_id, index, chord_type=0)
¶
Chordify: turn every note into a named chord by adding voices above the root. chord_type: 0 major {+4,+7}, 1 minor {+3,+7}, 2 dom7 {+4,+7,+10}, 3 diminished {+3,+6}, 4 sus4 {+5,+7}. Originals kept as roots; off-keyboard voices dropped.
gate_clip(track_id, index, factor=0.5)
¶
Gate/articulation: scale every note's length by factor (keeping its start) —
0.5 = staccato (detached), 1.5 = tenuto (fuller). Rhythm is unchanged.
flatten_clip_velocity(track_id, index, velocity=0.8)
¶
Flatten dynamics: set every note's velocity to a single value (0..1) — make a part mechanically even. Distinct from velocity-scale (multiply) and ramp (gradient).
split_notes_at_beat(track_id, index, beat)
¶
Knife: cut every note spanning beat (clip-relative) into two abutting notes.
set_track_arp(track_id, enabled=True, rate=0.25, octaves=1, gate=0.5, mode=0, swing=0.0, hold=False, probability=1.0)
¶
Live (non-destructive) per-track arpeggiator; mode 0=up 1=down 2=updown 3=random. swing 0..0.9 delays every other step; hold latches the last chord across rests. probability 0..1 is the chance each generated step fires (a deterministic generative gate; each looped repetition rolls independently, renders stay reproducible).
add_chord(track_id, index, root, type='maj', start_beat=0.0, length_beats=1.0, velocity=0.8, inversion=0)
¶
Stamp a chord (maj/min/7/maj7/min7/sus4/... ) into a clip at a beat position.
set_insert_name(index, name)
¶
Rename a mixer strip (insert). Empty/whitespace names are rejected.
add_bus(name='Bus')
¶
Append a bus mixer track (receives sends, sums to master); returns its insert index.
remove_bus(index)
¶
Remove a bus mixer track; sends are re-indexed (drops sends to it, shifts higher).
set_send(insert, bus, level, post_fader=False)
¶
Aux send from an insert to a bus at level (level<=0 removes). post_fader=True makes the send follow the source fader/mute; the default (pre-fader) taps at a fixed level.
define_control_group(name, gain=1.0)
¶
Create/update a control group whose fader scales its member inserts.
set_control_group_solo(name, solo=True)
¶
VCA solo: while any group is soloed, only members of soloed groups are audible.
assign_insert_to_group(insert, group)
¶
Assign an insert to a control group (group='' clears membership).
list_control_groups()
¶
List control groups as (name, gain, mute, solo, members) tuples.
define_mixer_scene(name)
¶
Snapshot the current mixer strip (vol/pan/mute/solo + effect bypass).
list_presets(category)
¶
category = 'synth' | 'effects'.
save_instrument_preset(track_id, name)
¶
Save a track's instrument (synth or SFZ) as a reusable preset.
load_instrument_preset(track_id, name)
¶
Replace a track's instrument with a saved preset (may change its type).
set_parameter_normalized(id, pos01)
¶
Set a parameter from a 0..1 knob position, mapped through its scaling (log/dB/linear).
add_controller_map(source, target, lo=0.0, hi=1.0)
¶
Map a source (cc:
set_controller_bypass(source, target, bypass)
¶
Enable/disable a controller map without removing it.
set_controller(source, value)
¶
Feed a controller source a 0..1 value (MIDI CC and OSC feed the same path).
midi_learn(target)
¶
Arm learn: the next controller fed binds to this ParamModel target ('' cancels).
set_modulation(target, rate, depth, shape=0, center=0.0, sync_beats=0.0, phase=0.0, unipolar=False, slew_ms=0.0)
¶
LFO on a ParamModel target: value = center + depth*unit(phase). shape 0=sine 1=tri 2=saw 3=square 4=random(S&H). Replaces any modulation already on the target (use add_modulation to stack a second source). sync_beats>0 tempo-syncs the LFO (one cycle per sync_beats beats); otherwise rate is in Hz. phase (0..1) offsets the waveform start; unipolar keeps the value on one side (center..center+depth); slew_ms>0 applies a one-pole slew (ms time constant) softening abrupt value changes.
add_modulation(target, rate, depth, shape=0, center=0.0, sync_beats=0.0, phase=0.0, unipolar=False, slew_ms=0.0)
¶
Append an ADDITIONAL modulation source on target. Multiple sources on the same target sum (value = center + sum of depth*unit), so e.g. two LFOs at different rates stack. Same args as set_modulation, which instead replaces any source on the target. shape 4 = random/sample-and-hold. Remove them all with remove_modulation(target).
beats_to_bar_beat(beat)
¶
Absolute beat -> (bar, beat_in_bar), both 1-based.
set_scale(root=0, name='', intervals=())
¶
Set the project scale by built-in name (major/minor/dorian/...) or explicit intervals.
set_tuning(cents12)
¶
Microtuning: 12 per-pitch-class cents offsets from equal temperament (all 0 = 12-TET; applies to the built-in synth). Must be exactly 12 values.
import_scl(path)
¶
Load a Scala .scl tuning file (12-note scales map to the chromatic keys).
add_location(name, kind='marker', start_beat=0.0, end_beat=0.0)
¶
Named marker/range/section on the timeline (upsert by name).
copy_clip_to_session_slot(track_id, clip_index, scene)
¶
Populate a session slot from an existing arrangement clip (grows the grid).
set_session_slot_colour(track_id, scene, colour='')
¶
Colour a session slot's clip (hex ARGB, e.g. 'ffef5350'); '' clears to inherit the track colour.
session_launch_clip(track_id, scene)
¶
Queue a clip launch (fires at the next launch-quantum boundary during playback).
session_launch_scene(scene)
¶
Queue a scene (row) launch — every occupied slot in the row fires.
session_stop_track(track_id)
¶
Queue a stop on one track (back to arrangement playback).
session_set_quantum(beats)
¶
Set the session launch-quantize window in beats (0 = launch immediately, 4 = one bar).
session_state()
¶
Per-track playing/pending slot + scene count + launch quantum.
playing: -1 arrangement / >=0 scene; pending: -2 none / -1 stop / >=0 scene.
define_export_profile(name, target='mix', range_name='', track_id=0, format='wav', tail_seconds=0.0)
¶
target: 'mix' | 'range' (+range_name) | 'track' (+track_id) | 'stems'.
run_export(name, out_dir='')
¶
Render the named profile; returns the list of files written.
set_automation_by_id(param_id, points)
¶
Automate a ParamModel id (the same id a controller/LFO addresses). Empty points clears it.
add_automation_point(param_id, beat, value)
¶
Append/replace one keyframe on an id-addressed automation lane.
set_automation_step(param_id, step=True)
¶
Toggle a param's automation lane between stepped (hold each value until the next point) and linear interpolation. The lane must already exist.
set_automation_curve(param_id, curve)
¶
Ease curve for a param's automation lane: -1 = ease-out (fast start), 0 = linear, +1 = ease-in (slow start). Ignored while the lane is stepped. Lane must exist.
list_templates()
¶
Project templates: built-ins ('Starter Beat', 'Drum Kit', 'Lead + Bass') plus any user templates saved with save_as_template.
new_from_template(name)
¶
Empty the project and seed a template (built-in or a saved user template).
save_as_template(name)
¶
Save the current project as a reusable user template under the templates dir
(
analyzer_data(insert, slot)
¶
A scope/analyzer effect's live snapshot (the captured waveform samples). Non-empty only while audio is flowing through that insert during playback.
list_favorites()
¶
The user's pinned browser items (outside the composition). Each is a dict {kind, ref, label}: kind in {plugin, sample, preset, template} chooses the action, ref is its argument (plugin identifier / file path / patch path / template name).
add_favorite(kind, ref, label='')
¶
Pin a browser item as a favorite (idempotent; deduped by kind+ref).
remove_favorite(kind, ref)
¶
Unpin a favorite (matched by kind+ref).
save_composition(path)
¶
Save the project as a directory 'composition as code' (diff-friendly TOML+notes).
load_composition(path)
¶
Load a composition directory (or its gloopy.toml).
export_midi(path)
¶
Write all instrument tracks to a Type-1 standard MIDI file.
export_loop_region(path)
¶
Bounce the current transport loop window to a WAV/FLAC (the 'export selection' action). Errors if no loop is set or it is empty. Encoder picked from the extension.
export_track(track_id, path)
¶
Bounce a single track (through its own insert chain, soloed) to a WAV/FLAC stem.
export_stems(directory)
¶
Bounce every instrument track to its own stem WAV (directory.
import_midi(path)
¶
Load a standard MIDI file as synth tracks + clips.
import_audio(path)
¶
Load an audio file (wav/aiff/flac) as a new audio track.
set_project_notes(text)
¶
Free-form markdown notes saved with the song (composition notes.md).
git_available()
¶
Whether the system git binary is present, and its version string.
git_status(dir='')
¶
Git status of the project's dir (or dir): branch, ahead/behind, dirty files.
git_init(dir)
¶
Turn a folder into a git repository (git init); creates the folder if needed.
git_add(dir, paths=None)
¶
Stage changes in dir (all of them when paths is omitted).
git_commit(dir, message, amend=False)
¶
Commit staged changes in dir with message (reuses your git identity).
git_log(dir, max=50)
¶
Recent commits in dir (newest first): hash, parents, refs, author, date, subject.
git_branches(dir)
¶
Current branch + all local branches in dir.
git_branch_create(dir, name, start_point='')
¶
Create a branch name (from start_point, or the current HEAD).
git_checkout(dir, ref)
¶
Switch the working tree to a branch, tag, or commit (changes files on disk).
git_merge(dir, name)
¶
Merge branch name into the current branch.
git_branch_delete(dir, name, force=False)
¶
Delete branch name (force=True for -D).
git_branch_rename(dir, name, new_name)
¶
Rename branch name to new_name.
git_tags(dir)
¶
All tags in dir, newest-created first.
git_tag_create(dir, name, message='')
¶
Tag the current commit (annotated when message is given, else lightweight).
git_tag_delete(dir, name)
¶
Delete tag name.
git_diff(dir, pathspec='', rev_a='', rev_b='')
¶
Unified diff. rev_a+rev_b = between two revisions; rev_a only = rev_a..working tree; neither = working tree vs HEAD. Returns {ok, error, diff, files:[{status,path}]}.
git_discard(dir, paths=None)
¶
Discard uncommitted tracked changes (empty paths = all).
git_stash(dir, message='')
¶
Shelve tracked changes onto a stash.
git_stash_pop(dir)
¶
Restore (and drop) the latest stash.
git_stash_list(dir)
¶
List stashes ("stash@{0}: ...").
git_revert(dir, commit)
¶
Create a new commit that undoes commit.
git_reset(dir, mode='mixed', ref='HEAD')
¶
Reset to ref (mode: soft | mixed | hard). Hard discards uncommitted work.
git_add_remote(dir, name, url)
¶
Add a remote (git remote add
git_list_remotes(dir)
¶
List remotes as [{name, url}].
git_fetch(dir, remote='')
¶
Fetch from remote (empty = --all).
git_pull(dir, remote='', branch='')
¶
Pull remote/branch.
git_push(dir, remote='', branch='')
¶
Push remote/branch (explicit; sets upstream).
git_conflicts(dir)
¶
List files with merge conflicts.
git_resolve(dir, path, mode)
¶
Resolve a conflicted file (mode: ours | theirs | both), then stage it.
git_merge_continue(dir)
¶
Finish the merge once all conflicts are resolved.
git_merge_abort(dir)
¶
Abort the in-progress merge.
git_set_identity(dir, name='', email='')
¶
Set the per-project commit identity (local user.name/email).
git_get_identity(dir)
¶
Read the per-project commit identity as {name, email}.
git_set_auto_commit(dir, on)
¶
Enable/disable auto-commit-on-save (gloopy.autocommit in .git/config).
git_get_auto_commit(dir)
¶
Whether auto-commit-on-save is enabled for this repo.
diagnostics()
¶
Engine health: device settings, callback timing, DSP load, dropouts, render speed.
project_status()
¶
Status-bar summary: which project, whether it has unsaved edits, the Gloopy version, and a compact git working-tree summary (branch + uncommitted count).
get_waveform(path, buckets=256)
¶
Cached min/max waveform peaks for an audio file (per-bucket).
analyze_file(path)
¶
Offline loudness of a WAV: peak/true-peak (dBFS/dBTP), RMS (dBFS), integrated LUFS.
render(path, tail_seconds=0.0, start_beat=0.0, end_beat=0.0, track_id=None, range_name='', report=False)
¶
Offline bounce. With report=True, also analyse the output and return its loudness {peak_dbfs, true_peak_dbtp, rms_dbfs, lufs}; otherwise return None.
subscribe(transport=True, meters=False, changes=False, interval_ms=100)
¶
Yield a dict per streamed Event until the caller stops iterating.
note(pitch, start_beat, length_beats, velocity=0.8)
¶
Build a Note for AddClip. Times are in beats, relative to the clip.
pitch accepts a MIDI int or a name ("C#4"); length_beats accepts
a number of beats or duration shorthand ("q", "8t") — see
gloopy.music.
connect(target=None)
¶
Context-manager sugar: with connect() as g: .... target=None
auto-discovers Gloopy's port (see :class:Gloopy).
Music-theory helpers — gloopy.music¶
gloopy.music
¶
Music-theory sugar for building Gloopy clips: note names, durations, scales and chords.
Nothing here talks to the DAW — these are pure helpers that turn musician vocabulary into the ints and beats the wire format wants. A pitch is a MIDI number (C4 = 60, the same middle-C Gloopy uses for a sampler's root_note); a duration is a length in beats (a quarter note = 1 beat).
from gloopy import Gloopy, seq, scale, chord
g = Gloopy()
tid = g.add_synth_track("lead", wave="SAW")
# a melody, note names + duration shorthand, laid end-to-end:
g.add_clip(tid, notes=seq([("C4","q"), ("E4","e"), ("G4","e"),
(None,"q"), ("A4","h")]))
# a C-major run and a Cmaj7 stab:
run = [note(p, i*0.25, 0.25) for i, p in enumerate(scale("C4", "major"))]
stab = [note(p, 0, 2) for p in chord("C4", "maj7")]
The scale names match Gloopy's engine (Source/Scales.cpp) so the desktop
"set scale" control, the Python client and the Common Lisp client all speak
one dialect.
pitch(p)
¶
MIDI number for a note name ("C4", "F#3", "Bb5"); passes ints
through unchanged. Accidentals may repeat ("C##4"); octave is optional
and defaults to 4 (so "C" is middle C).
pitch_name(midi)
¶
Sharp-spelled scientific name for a MIDI number (61 -> "C#4").
dur(d)
¶
Length in beats for a duration shorthand; passes numbers through.
dur("q") == 1.0, dur("8") == 0.5, dur("q.") == 1.5 (dotted),
dur("8t") == 1/3 (triplet). Dots stack: "q.." == 1.75.
scale(root, name='major', octaves=1)
¶
MIDI pitches of a scale, ascending from root over octaves.
scale("C4", "major") -> the seven notes C4..B4. Names match the engine
(major, dorian, pentatonic-minor, blues, ...).
chord(root, quality='maj', inversion=0)
¶
MIDI pitches of a chord. chord("C4", "maj7") -> [60, 64, 67, 71].
inversion raises that many of the lowest notes by an octave (1 = first
inversion). Qualities: maj, min, dim, aug, sus2/4, maj7, min7, 7, 6, 9, ...
seq(steps, start=0.0, velocity=0.8, note_builder=None)
¶
Lay steps end-to-end on the timeline and return a list of Notes.
Each step is (pitch, duration) or (pitch, duration, velocity). A
step's duration advances the clock whether or not it sounds, so rests
(REST/None/"r") just leave a gap. Pitches accept names, durations
accept shorthand::
seq([("C4","q"), ("E4","e"), (REST,"e"), ("G4","h")])
note_builder defaults to gloopy.note; pass your own to build a
different message type (it is called builder(pitch, start, length, vel)).
mini(s, start=0.0, velocity=0.8, note_builder=None)
¶
Parse mini-notation s into a list of Notes for add_clip.
Durations glue onto the pitch with no separator and are sticky (a bare note inherits the previous length; quarter to start)::
mini("c4q d e f") # four quarter notes, C4 D4 E4 F4
mini("c4q d e f g4h a b") # C..F quarter, then G4 A4 B4 half
mini("[c e g]q [f a c5]h") # chords (spaces inside the brackets)
mini("c4e r e f") # a rest inherits the duration too
pitch is anything :func:pitch accepts, the duration anything
:func:dur accepts (q h w e s, dotted "q.", triplet "8t"). There are
no bare duration tokens: to change length, attach the code to the note that
starts the run. note_builder defaults to gloopy.note.