Skip to content

Regions, takes and notes

Region { id, name, start, length, muted, color, content, loop_end, takes, params, pattern }. Times are in samples at the project rate.

  • content is Audio { clip, offset, gain_db, fade_in, fade_out, fade_shape } or Midi { notes, cc }. offset is the clip frame at the region’s start; fades are frame lengths (their curves and types are in fade_shape, see Fades and crossfades); region gain is clamped to -96..+30 dB.
  • Loops: loop_end is the timeline sample where a looping region stops repeating; the region’s own start..start+length is what repeats. Region::end() clamps it (at most MAX_LOOP_PASSES = 4096 repetitions), passes() lists every pass, and move_to takes the loop end along. real_copies implements Convert Loops to Real Copies.
  • Take folders: takes: Some(TakeFolder) makes the region play a comp. See below.
  • Order matters: within a track, a region later in regions is newer and wins where audio overlaps. Moving a region pushes it to the end of the list.
  • Playback parameters: params: RegionParams (region_params.rs, session side in session/region_params.rs) holds the Region inspector’s Quantize, Q-Swing, Transpose, Velocity, Dynamics, Gate Time and Delay; the defaults change nothing and aren’t saved. They are applied when regions_dsp builds the playback list, so the audio thread does nothing new: a MIDI region with parameters becomes one RegionDsp::Midi per pass with transformed notes and a window widened (lead, tail) to cover notes a negative delay or quantize moved before its start and the end a positive delay moved later (region_params::pass); an audio region’s delay moves it (bake). Quantize and tick delays read the tempo map, so sync_globals rebuilds the lists of tracks whose parameters follow it (push_tempo_regions). bake writes the parameters into a region so it plays the same (Apply Region Parameters, Join, MIDI file export), and bounds gives render ranges (Bounce in Place, Export Region, Freeze, the project end). The snapshot’s played list carries the notes as they play for the Tracks area; the Piano Roll edits the stored notes.
  • Pattern regions (the Step Sequencer): pattern: Some(Pattern) on a MIDI region (pattern.rs, session side in session/patterns.rs). A Pattern has a length in steps, a step rate, swing, a loop switch and PatternRows (pitch, mute, solo, an optional rate and length of its own, and Steps: on, velocity, gate, tie; off steps with default values save as {}). regions_dsp turns each pattern region into the plain MIDI region it plays (pattern::realize, through the tempo map from the region’s start) before anything else, so playback parameters, loops, chase and every render work unchanged; bake realizes first, so Join and MIDI export do too, and push_tempo_regions rebuilds pattern tracks on tempo changes. The region’s stored notes stay empty. The Step Sequencer sends the whole edited pattern with set_pattern (keyed per drag, so a painted run is one undo step).

TakeFolder { takes, comp, comps, current, offset } (types in model/take_folder.rs, logic in takes.rs, session edits in session/takes.rs; the folder menu’s labels in src/comps.ts):

  • Everything inside a folder is in take time: frames from the start of the recorded passes. The folder region’s content is still Audio, but its offset is the take time at the region’s start (so moving, trimming and splitting work as for any audio region), its clip is the newest take’s file, and its gain and fades apply to the whole comp.
  • Each Take has its own clip and offset (clip frame at take time 0) and the take-time range it has audio for. takes is oldest first.
  • comp is a sorted, non-overlapping list of CompSegment { start, end, take }. Gaps are silent. default_comp starts with the newest take, older ones filling in where it has no audio.
  • Several comps: comps holds every Comp { name, comp } and current the one heard; comp is the one being heard and edited, and store_comp copies it back into comps[current] after every edit, so playback and the swipe edits only touch comp. An empty comps is the single “Comp 1”, so older projects load unchanged. create_comp, duplicate_comp, switch_comp, rename_comp and delete_comp are the menu’s commands.
  • Playback expands the comp into CompPieces (pass_pieces_edged), crossfading over Settings › Editing › Crossfade Time (EditingPrefs::crossfade_ms, 20 ms by default) with the Crossfade Curve, centred on each boundary. A folder crossfades with its neighbours like any audio region (PassEdges carries the crossfades at its ends into the pieces).
  • MIDI take folders: a folder on a MIDI region. Each Take keeps its own notes and cc in take time, and offset is the take time at the region’s start. A MIDI folder plays one whole take (midi_take), and the region’s content always holds that take’s notes inside the region (load_midi_take; edits are written back with save_midi_take before anything reads the takes), so the playback list, the Piano Roll and every render treat it as a plain MIDI region. MidiOverlap::TakeFolders (Settings › Recording) makes MIDI cycle passes into takes, split at the PASS_MARKs the engine puts in the recorded stream (midi_passes).
  • Recording: RecPlan (takes.rs) describes how a cycle or Autopunch recording is cut into takes; Session::record_plan builds it before recording, and shape_take applies it to each finished file.
  • Note { start, length, pitch, velocity, muted }, start relative to the region.
  • CcEvent { start, kind, value } with CcKind::Controller(n), PitchBend (0..16383, 8192 centred) or Aftertouch. cc is kept sorted by start. CcKind::index gives a dense index (0..130) used for per-kind tables on the audio thread.
  • crates/engine/src/midi.rs has the pure helpers for split, trim and join that keep controllers consistent: the later part of a split starts with the values in effect at the cut.
  • The Piano Roll edits content wholesale: it sends set_midi_content with the region’s new notes and controllers (and new bounds when the region grew), as one undo step.