SaleSpringtime sale!$29$926 days leftGet Deal

Documentation

Tutorial #

A tutorial over the basics of oooo

Introduction #

oooo is a tool for creating and manipulating digital tape loops. These loops can be synchronous or asynchronous, linked or unlinked from the daw host (Ableton, FL Studio, Logic, Reaper, Bitwig, etc.), and can be manipulated in level, panning, and rate in addition to being played polyphonically like a mellotron with MIDI or with a grid. Each loop has its own effect sends, filters, and simple EQ. Each loop can record continouously or as a one shot, and can be routed to any other loop.

Grid Tutorials

Use these guided tours for layout, manipulation, mode rows, mode-specific gestures, and gesture recording.

Keybindings #

Control Action
Htoggle help
Ncreate new loop
CLICK INSIDE Oselect loop (nearest center)
DRAG Omove selected loop (pan/volume)
CLICK PERIMETER Ojump cut on selected loop
DBL-CLICK OUTSIDE Oclear loop selection
CLICK+DRAG OUTSIDE Oadjust selected parameter
LEFT / RIGHTselect parameter
UP / DOWNadjust value (or LFO period)
Pglobal play/stop all loops
SPACE / Ptoggle selected loop playback
Rtoggle selected loop recording
Ztap: load preset, hold 1s: save slot
I / Ohold 1s: load / save session archive (.zip)
C / Vcopy selected loop / paste duplicate
DELETE / BACKSPACEhold 1s: delete selected loop
Xhold 1s: clear selected loop audio
F1..F12select loop 1..12
0..7cut: 0/8..7/8 (selected/all)
Ttoggle dark/light theme
Ltoggle LFO on selected parameter
Q / Aincrease / decrease LFO min (x)
W / Sincrease / decrease LFO max (y)

Tape Controls #

The tape controls provide another way to control the loops when hotkeys are not an option.

Press Play () to play a loop (when selected) or all loops (when not). Press Stop () to stop all loops, or the selected loop if it is the only one playing. When stopped, press Stop () again or key 0 to jump to the start of the loop(s).

Press Forward () or Reverse () to step the playback rate up or down, respectively. Press Play () twice to return to normal speed.

Press Record () to toggle recording on the selected loop. In Continuous Mode, user-stop truncation behavior is controlled by the global Record Truncation parameter.

Loop Parameters #

Loop parameters are accessible by clicking a loop. Use ← / → to scroll through parameters and ↑ / ↓ to change values.

Values can also be adjusted at any time by clicking a non-loop area of the screen and dragging the mouse up and down.

Additionally, values can be set to change via an LFO by pressing L and then using hotkeys: Q/A increases/decreases LFO min (x) and W/S increases/decreases LFO max (y).

Mix #

Volume sets loop output level and Pan places the loop in the stereo field.

Window #

Loop Start and Loop Length define the active playback window within the loop allocation.

Playback #

Rate changes playback speed/pitch, Fade Time controls loop boundary crossfade and also sets post-roll duration when using Record Mode = Once, and DAW Sync links loop timing behavior to host transport sync state.

Periodic Reset #

Reset Every sets an interval for periodic jump-cuts while playback is running (0 disables). In unquantized mode it is edited in seconds; in quantized mode it is edited in beats and snapped by Quantize Resolution at Quantize BPM.

Reset To sets the jump target as a percentage of the active loop window (0% start, 50% middle, 100% end boundary).

Record Path #

Record New controls incoming write level, Record Keep controls retained buffer level during overdub, Record Mode selects Continuous (default) or Once, and Reverb sets loop send amount to the reverb bus.

In Record Mode = Once, recording automatically disarms after one loop span and applies post-roll equal to the current Fade Time.

Record Keep Freq sets a low-pass filter cutoff on the retained buffer signal during overdub. When set to All (default), the existing loop content is kept unfiltered. When set to a frequency value, highs are rolled off from the kept material on each record pass — lower values cause faster high-frequency loss over successive overdubs. (added in v1.4.0)

Input Routing #

Input Live sets the percentage of the main audio input fed into this loop during recording (0–100%). At 100% (default) the full live input signal is passed to the loop; at 0% the main input is cut entirely, which is useful when the loop receives its signal exclusively from loop-to-loop routing. (added in v1.4.0)

Tape #

Tape Bias and Tape Gain shape tape drive behavior; Bass Freq, Bass Boost, and Bass Q tune the low-frequency tape contour.

Filters #

Post LPF/Post LPF Q and Post HPF/Post HPF Q control post-stage low-pass and high-pass filter cutoff and resonance.

Note Envelope #

Note Attack, Note Decay, Note Sustain, and Note Release define the per-note ADSR envelope for note-triggered loop playback.

Note Trigger/MIDI #

Note Start % randomizes note start offset, MIDI CH sets MIDI channel filtering per loop, and Note Mode chooses the note playback start behavior.

Global Parameters #

Global parameters are reached by double-clicking anywhere that is not a loop to open the global parameters menu. Navigate with ← / →, change values with ↑ / ↓, or click-drag in a non-loop area to adjust values directly.

Length/Tempo #

Quantize Resolution controls loop-length/beat quantization behavior, and Quantize BPM sets the tempo used for beat-based calculations.

Record Chain #

Record Chain is great for recording a series of loops in order. When enabled, starting recording on one loop can hand off recording to the next loop when the current loop reaches its boundary, continuing through the remaining loop order.

To use it, select the loop you want to start from and toggle recording with R (or the loop record gesture). Turning Record Chain off cancels future automatic handoffs; manually stopping the currently chained loop also stops the rest of the chain.

Record Truncation #

Record Truncation controls whether manually stopping recording resizes the loop window to the latest capture span.

Default is OFF. When OFF, stopping recording does not edit loop boundaries.

When ON, manual stop truncates to record start → punch-out only when that span is contiguous (no wrap crossing). If recording crossed the loop boundary (including full-loop captures), truncation is skipped.

Mix: Input, Dry, Wet #

Input sets global input trim, while Dry and Wet control global dry/wet output balance.

Reverb #

These parameters shape the global reverb path: Predelay, input level, LPF, HPF, damping, mod frequency and mod depth.

Reverb Shimmer adds a global parallel shimmer return fed by the same per-loop Reverb sends. At 0% (default) it is off; values up to 200% increase the shimmer layer without replacing the main reverb.

MIDI #

Using oooo with a MIDI keyboard lets you play the loops as if it were a Mellotron - each note will change the rate scaling of the playing loop based around middle C. MIDI note input is handled per loop through MIDI CH and Note Mode: channel mode decides which incoming channels are accepted, note mode decides where playback starts on note-on, and note-off (including note-on with velocity 0) releases active note heads while Note Attack, Note Decay, Note Sustain, Note Release, and Note Start % shape the loop’s note response.

Grid #

A monome grid is automatically detected in oooo. When a monome grid is detected, an icon () appears automatically in the top-right corner. Each 8x8 section of the grid (a "tile") controls one loop. Column 1 is the tile menu and columns 2-8 are the active area.

Note: if serialosc is running, oooo will connect through serialosc automatically. If serialosc is not running, oooo falls back to its direct grid driver.

Each tile has four modes: Isomorphic (col1,row1), Slice (col1,row2), Volume/Pan (col1,row3), and Rate (col1,row4). In Slice mode, playhead and loop span are shown across columns 2-8 in recorded-normalized space.

Isomorphic Tile Reference (8x8)

Column 1 is the tile menu. Columns 2-8 show note names sent in Isomorphic mode (note + octave). C notes are dimly highlighted. Example below: held D4 is bright, matching D4 pads are ghost-highlighted.

ISO
C3
F3
B3
E4
A4
D5
G5
SLICE
B2
E3
A3
D4
G4
C5
F5
VOL/PAN
A2
D3
G3
C4
F4
B4
E5
RATE
G2
C3
F3
B3
E4
A4
D5
PAT REC
F2
B2
E3
A3
D4
G4
C5
PAT PLAY
E2
A2
D3
G3
C4
F4
B4
REC
D2
G2
C3
F3
B3
E4
A4
PLAY
C2
F2
B2
E3
A3
D4
G4

Anchor used by current runtime mapping: local tile row=8, col=2 is C2 (MIDI 36).

Live Coding #

Open Live Coding by clicking the terminal icon () in the top-right app bar. This opens the browser-based Lua editor at http://127.0.0.1:17321/ by default.

Run the whole file or selected lines to create loops, shape playback, and control engine globals from Lua.

Common commands include o.create, o.duplicate, o.set(loop_id, ...), o.get(), o.record, and o.play.

Example 1: Create, Record, and Play

-- create and start a 4 second loop
loop_id, err = o.create({ seconds = 4.0, fade = 0.15 })
assert(loop_id, err)
o.record(loop_id, true)
o.play(loop_id, true)

Example 2: Update, Query, and Jump

o.set(loop_id, {
  pan = -0.25,
  db = -6.0,
  pan_slew = 0.3,
  db_slew = 0.3,
})

state = o.get(loop_id)
print('seconds', state.seconds, 'playing', state.playing)
o.jumpn(loop_id, 0.5)

Example 3: Set and Read Engine Globals

o.set({
  in_db = -3,
  wet_db = -6,
  rv_predelay = 12,
  rv_mod_depth = 2,
})

engine = o.get()
print('input', engine.in_db, 'wet', engine.wet_db)

o.* API Reference

This reference reflects the current runtime Lua bindings. Mutating commands return true on success, or nil, err on failure.

Setters / Mutators #

Functions are listed first. Any opts/props object keys are defined in the props tables directly below.

FunctionParametersReturnsNotes
o.create(opts)opts table (optional)loop_id | nil, erropts keys come from Loop Props.
o.duplicate(loop_id)loop_id integerloop_id | nil, errCreates a new loop by duplicating the source loop.
o.set(loop_id, props)loop_id integer, props tabletrue | nil, errprops keys come from Loop Props.
o.set(props)props tabletrue | nil, errprops keys come from Engine Props.
o.record(loop_id, on)loop_id integer, on booleantrue | nil, errStarts/stops recording on one loop.
o.play(loop_id, on)loop_id integer, on booleantrue | nil, errStarts/stops playback on one loop.
o.jump(loop_id, seconds)loop_id integer, seconds numbertrue | nil, errSeeks to loop-relative seconds; values wrap by loop length.
o.jumpn(loop_id, normalized)loop_id integer, normalized numbertrue | nil, errnormalized must be in [0, 1].
o.bpm(value)value numberbpm | nil, errvalue must be > 0.
o.clear(loop_id)loop_id integertrue | nil, errClears loop audio/buffer content.
o.delete(loop_id)loop_id integertrue | nil, errDeletes a loop.

For o.create(opts), length resolution order is: beats (if > 0), then seconds (if > 0), else defaults to 10.0 seconds.

Loop Props (for o.create(opts) and o.set(loop_id, props))
Key (opts/props)MeaningRange / Behavior
beatsLoop length in beats.Number; must be > 0 to apply. Converted using current o.bpm().
secondsLoop length in seconds.Number; must be > 0 to apply.
fadePost-roll / fade time.Clamped to [0, 20] seconds.
preBuffer keep amount.Clamped to [0, 1].
pre_slewSlew time for pre.Seconds; negative values are treated as 0.
recInput write gain.Clamped to [0, 1].
rec_slewSlew time for rec.Seconds; negative values are treated as 0.
dbLoop output level in dB.Upper-clamped by engine to about +12 dB.
db_slewSlew time for db.Seconds; negative values are treated as 0.
panStereo pan position.Clamped to [-1, 1].
pan_slewSlew time for pan.Seconds; negative values are treated as 0.
rv_sendPer-loop reverb send amount.Clamped to [0, 1].
pan_lfo_periodPan LFO period.Seconds; values <= 0 are internally clamped by runtime LFO evaluation.
pan_lfo_minPan LFO minimum.Number; may be lower or higher than pan_lfo_max (runtime normalizes low/high).
pan_lfo_maxPan LFO maximum.Number; may be lower or higher than pan_lfo_min (runtime normalizes low/high).
pan_lfo_activeEnables/disables pan LFO.Boolean.
db_lfo_periodLoop dB LFO period.Seconds; values <= 0 are internally clamped by runtime LFO evaluation.
db_lfo_minLoop dB LFO minimum.Number; may be lower or higher than db_lfo_max (runtime normalizes low/high).
db_lfo_maxLoop dB LFO maximum.Number; may be lower or higher than db_lfo_min (runtime normalizes low/high).
db_lfo_activeEnables/disables loop dB LFO.Boolean.
length_lfo_periodLoop-length LFO period.Seconds; values <= 0 are internally clamped by runtime LFO evaluation.
length_lfo_minLoop-length LFO minimum.Number (seconds); may be lower or higher than length_lfo_max.
length_lfo_maxLoop-length LFO maximum.Number (seconds); may be lower or higher than length_lfo_min.
length_lfo_activeEnables/disables loop-length LFO.Boolean.
start_lfo_periodLoop-start LFO period.Seconds; values <= 0 are internally clamped by runtime LFO evaluation.
start_lfo_minAbsolute loop-start LFO minimum.Number (seconds); may be lower or higher than start_lfo_max; runtime clamps to recorded span constraints.
start_lfo_maxAbsolute loop-start LFO maximum.Number (seconds); may be lower or higher than start_lfo_min; runtime clamps to recorded span constraints.
start_lfo_activeEnables/disables loop-start LFO.Boolean.
rateLoop playback rate.Clamped by engine to [-4, 4].
rate_lfo_periodPlayback-rate LFO period.Seconds; values <= 0 are internally clamped by runtime LFO evaluation.
rate_lfo_minPlayback-rate LFO minimum.Number; may be lower or higher than rate_lfo_max (runtime normalizes low/high).
rate_lfo_maxPlayback-rate LFO maximum.Number; may be lower or higher than rate_lfo_min (runtime normalizes low/high).
rate_lfo_activeEnables/disables playback-rate LFO.Boolean.

Aliases are also accepted for rate LFO keys: lfo_period, lfo_min, lfo_max, lfo_active.

Engine Props (for o.set(props))
ParameterMeaningRange / Behavior
in_dbGlobal input trim (dB).Upper-clamped to +24 dB; supports very low values including -inf.
dry_dbGlobal dry level (dB).Upper-clamped to +24 dB; supports very low values including -inf.
wet_dbGlobal wet level (dB).Upper-clamped to +24 dB; supports very low values including -inf.
in_db_slewSlew time for in_db.Seconds; must be >= 0, negative values return error.
dry_db_slewSlew time for dry_db.Seconds; must be >= 0, negative values return error.
wet_db_slewSlew time for wet_db.Seconds; must be >= 0, negative values return error.
rv_predelayReverb predelay (ms).Clamped to [0, 300] ms.
rv_predelay_slewSlew time for rv_predelay.Seconds; must be >= 0, negative values return error.
rv_inReverb input amount (%).Clamped to [0, 100] %.
rv_in_slewSlew time for rv_in.Seconds; must be >= 0, negative values return error.
rv_lpfReverb input low-pass cutoff (Hz).Clamped to [1, 20000] Hz.
rv_lpf_slewSlew time for rv_lpf.Seconds; must be >= 0, negative values return error.
rv_hpfReverb input high-pass cutoff (Hz).Clamped to [1, 1000] Hz.
rv_hpf_slewSlew time for rv_hpf.Seconds; must be >= 0, negative values return error.
rv_dampReverb damping frequency (Hz).Clamped to [10, 20000] Hz.
rv_damp_slewSlew time for rv_damp.Seconds; must be >= 0, negative values return error.
rv_mod_freqReverb modulator frequency (Hz).Clamped to [0.01, 4.0] Hz.
rv_mod_freq_slewSlew time for rv_mod_freq.Seconds; must be >= 0, negative values return error.
rv_mod_depthReverb modulator depth (ms).Clamped to [0, 10] ms.
rv_mod_depth_slewSlew time for rv_mod_depth.Seconds; must be >= 0, negative values return error.

Getters / Queries #

FunctionParametersReturnsNotes
o.get(loop_id)loop_id integerloop_state | nil, errReturns one loop snapshot table.
o.get()noneengine_state | nil, errReturns global engine snapshot table.
o.list()none{loop_id, ...} | nil, errReturns sorted loop IDs.
o.bpm()nonenumber | nil, errReturns current BPM.
o.get

Form: o.get(loop_id) returns loop_state or nil, err.

FieldMeaningRange / Type
loop_idLoop identifier.Integer.
playingCurrent playback state.Boolean.
recordingCurrent recording state.Boolean.
posCurrent loop-relative position (seconds).Number in [0, seconds).
pos_normCurrent normalized position.Number in [0, 1].
secondsCurrent loop length.Number, expected > 0.
alloc_secondsAllocated loop buffer length.Number, expected > 0.
fadePost-roll / fade time.Number in [0, 20].
preBuffer keep amount.Number in [0, 1].
pre_slewSlew time for pre.Number, >= 0.
recInput write gain.Number in [0, 1].
rec_slewSlew time for rec.Number, >= 0.
dbLoop output dB target.Number, upper-clamped by engine.
db_slewSlew time for db.Number, >= 0.
panStereo pan target.Number in [-1, 1].
pan_slewSlew time for pan.Number, >= 0.
rv_sendPer-loop reverb send amount.Number in [0, 1].
pan_lfo_periodPan LFO period.Number (seconds).
pan_lfo_minPan LFO minimum.Number.
pan_lfo_maxPan LFO maximum.Number.
pan_lfo_activePan LFO enabled.Boolean.
db_lfo_periodLoop dB LFO period.Number (seconds).
db_lfo_minLoop dB LFO minimum.Number.
db_lfo_maxLoop dB LFO maximum.Number.
db_lfo_activeLoop dB LFO enabled.Boolean.
length_lfo_periodLoop-length LFO period.Number (seconds).
length_lfo_minLoop-length LFO minimum.Number.
length_lfo_maxLoop-length LFO maximum.Number.
length_lfo_activeLoop-length LFO enabled.Boolean.
start_lfo_periodLoop-start LFO period.Number (seconds).
start_lfo_minLoop-start LFO minimum (absolute seconds).Number.
start_lfo_maxLoop-start LFO maximum (absolute seconds).Number.
start_lfo_activeLoop-start LFO enabled.Boolean.
rateLoop playback-rate target.Number, engine-clamped to [-4, 4].
rate_lfo_periodPlayback-rate LFO period.Number (seconds).
rate_lfo_minPlayback-rate LFO minimum.Number.
rate_lfo_maxPlayback-rate LFO maximum.Number.
rate_lfo_activePlayback-rate LFO enabled.Boolean.
o.get

Form: o.get() returns engine_state or nil, err.

Engine FieldMeaningRange / Type
in_db / dry_db / wet_dbGlobal mix dB values.Number, upper-clamped to +24 dB.
in_db_slew / dry_db_slew / wet_db_slewLag time for global dB values.Number, >= 0.
rv_predelayReverb predelay.Number in [0, 300] ms.
rv_predelay_slewPredelay lag time.Number, >= 0.
rv_inReverb input amount.Number in [0, 100] %.
rv_in_slewReverb input amount lag.Number, >= 0.
rv_lpf / rv_hpf / rv_dampReverb filter/damping frequencies.rv_lpf: [1, 20000] Hz, rv_hpf: [1, 1000] Hz, rv_damp: [10, 20000] Hz.
rv_lpf_slew / rv_hpf_slew / rv_damp_slewLag time for reverb filter/damping params.Number, >= 0.
rv_mod_freq / rv_mod_depthReverb modulation params.rv_mod_freq: [0.01, 4.0] Hz, rv_mod_depth: [0, 10] ms.
rv_mod_freq_slew / rv_mod_depth_slewLag time for reverb modulation params.Number, >= 0.
bpmCurrent BPM.Number, > 0.

Need setup/download info? Visit Downloads or Buy.