Flow

Musical Context

Musical context blocks set tempo, time signature, key, swing, dynamics, pan, gain, reverb time, voice pool size, sustain pedal state, tuning, and tempo ramps for the code inside them. They use a push/pop scoping model — inner blocks inherit from outer blocks and can override specific settings; exiting a block restores the previous state.

The full set of context-block keywords is:

tempo, timesig, key, swing, dynamics, pan, gain, reverbTime, rit, accel, voicePool, sustainPedal, tuning

These are all reserved — they can’t be redefined as proc or variable names.

Tempo

Sets the beats per minute (BPM):

use "@std"

tempo 120 {
    (print "120 BPM context")
}
Open in playground

Default when not set: 120 BPM.

Time Signature

Sets the meter as numerator/denominator:

timesig 4/4 {
    Sequence fourFour = | C4 D4 E4 F4 |
}

timesig 3/4 {
    Sequence waltz = | C4 E4 G4 |
}

timesig 6/8 {
    Sequence compound = | C4 D4 E4 F4 G4 A4 |
}
Open in playground

Default: 4/4.

Common-Time Shorthand

The capital C is shorthand for 4/4 — it lowers to 4/4 at parse time so the renderer, MIDI export, and musical-context stack all see identical data to the explicit form:

timesig C {
    Sequence sameAs44 = | C4 D4 E4 F4 |
}
Open in playground

Key

Sets the musical key for roman numeral resolution and scale operations:

key Cmajor {
    Sequence prog = | I IV V I |
}

key Aminor {
    Sequence prog = | i iv V i |
}
Open in playground

Valid Keys

All 12 major keys — Cmajor, Csharpmajor / Dbmajor, Dmajor, Dsharpmajor / Ebmajor, Emajor, Fmajor, Fsharpmajor / Gbmajor, Gmajor, Gsharpmajor / Abmajor, Amajor, Asharpmajor / Bbmajor, Bmajor.

All 12 minor keys — same pattern with minor (e.g., Aminor, Fsharpminor).

Swing

Adds swing feel to rhythms. Value accepts decimals or percentages (0.5 = straight, ~0.67 / 66% = triplet swing):

swing 55% {
    Note: subtle swing
}

swing 0.6 {
    Note: moderate swing
}
Open in playground

The N% form divides by 100 at parse time — swing 55% and swing 0.55 are equivalent through the rest of the pipeline.

Dynamics

Sets a default velocity for notes in scope:

dynamics f {
    Sequence loud = | C4 D4 E4 F4 |

    dynamics pp {
        Sequence soft = | C4 D4 E4 F4 |
    }
}
Open in playground
MarkingVelocity
ppp0.125
pp0.25
p0.375
mp0.5
mf0.625
f0.75
ff0.875
fff1.0

Pan

Sets stereo placement for audio rendered inside the block. Range is -1.0 (hard left) to +1.0 (hard right):

use "@audio"

pan -0.5 {
    Note: section will be panned left
    section leftChannel {
        Sequence mel = | C4 E4 G4 |
    }
}

pan 0.5 {
    Note: section will be panned right
    section rightChannel {
        Sequence mel = | G4 B4 D5 |
    }
}
Open in playground

pan is also a buffer-level effect for applying panning to a single Buffer.

Gain

Applies a gain factor to audio rendered inside the block (values in the 0.0 - 1.0 range):

use "@audio"

gain 0.3 {
    section quietPart {
        Sequence mel = | C4q E4q G4q C5q |
    }
}
Open in playground

gain is also available as a buffer-level effect using decibel values.

Reverb Time

Wraps audio rendered inside the block with a global reverb tail of the given RT60 (in seconds):

use "@audio"

reverbTime 2.5 {
    section cathedral {
        Sequence chant = | C4w E4w G4w C5w |
    }
}
Open in playground

Must be non-negative. Use 0 to disable.

Voice Pool

Sets the maximum number of simultaneously active voices for the block. When the voice count exceeds the pool, Flow truncates the active voice with the earliest onset (steal-oldest policy) with a 5 ms fade to avoid clicks:

voicePool 16 {
    Note: rendering inside this block uses at most 16 simultaneous voices
    section denseTexture {
        Sequence layered = | [C3 E3 G3 C4 E4 G4 C5 E5 G5]w |
    }
}
Open in playground

The default pool size is 32; the range is [1, 256]. The policy is fully deterministic (tiebreaker is the original input index), so two-run output stays byte-identical.

Sustain Pedal

Extends every note’s rendered buffer by a 2.0 s sustain tail — the digital equivalent of holding down a piano damper pedal:

use "@audio"

sustainPedal {
    section dreamy {
        Sequence arp = | C4q E4q G4q B4q C5q E5q G5q B5q |
    }
}
Open in playground

Pair with the release= named arg on renderSong for finer-grained control over the decay tail length:

Buffer buf = (renderSong song "piano" release=3.0s)
Open in playground

Tuning

Applies a non-12-TET tuning to its body — Scala .scl files load into a Tuning value, then a tuning { ... } block scopes that tuning to the contained code. Three composer-facing surface forms:

use "@std"
use "@audio"

Note: 1. identifier-bound variable
Tuning partch = (loadScala "partch43.scl")
tuning partch {
    section microtonal { Sequence mel = | C4 D4 E4 F4 | }
}

Note: 2. inline call
tuning (loadScala "carlos_alpha.scl") {
    section nonOctave { Sequence climb = | C4 D4 E4 F4 G4 A4 B4 C5 | }
}

Note: 3. string-literal sugar (desugars to form 2 at parse time)
tuning "bohlen_pierce.scl" {
    section thirteenStep { Sequence mel = | C4 D4 E4 F4 | }
}
Open in playground

Tuning blocks compose last-wins with the file-scope enable justIntonation; / pythagorean; / equalTemperament; pragmas. Non-octave-repeating scales (Carlos Alpha, Bohlen-Pierce) auto-adopt the loaded scale’s period.

Ritardando / Accelerando

Wrap a passage in a rit block to interpolate tempo downward to a target BPM, or accel to speed up:

tempo 120 {
    rit 60 {
        Note: tempo ramps from 120 down to 60 inside this block
        Sequence ending = | C4h G3h |
    }
}

tempo 80 {
    accel 140 {
        Note: tempo ramps from 80 up to 140 inside this block
        Sequence intro = | C4q D4q E4q F4q |
    }
}
Open in playground

See also the tempoRamp transform which produces a rendered buffer directly.

Nesting and Inheritance

Context blocks nest naturally. Inner blocks inherit from outer blocks and can override specific settings:

tempo 120 {
    timesig 4/4 {
        key Cmajor {
            Note: 120 BPM, 4/4, C major
            Sequence mel = | C4 D4 E4 F4 |

            key Aminor {
                Note: still 120 BPM, 4/4, but now A minor
                Sequence mel2 = | A4 B4 C5 D5 |
            }
        }
    }
}
Open in playground

Typical Pattern

Most musical code wraps everything in tempotimesigkey:

tempo 120 {
    timesig 4/4 {
        key Cmajor {
            Sequence melody = | C4 E4 G4 C5 |
        }
    }
}
Open in playground

Deeply Nested Example

tempo 100 {
    timesig 6/8 {
        key Aminor {
            swing 55% {
                dynamics mf {
                    Sequence mel = | A4 C5 E5 A5 C6 E6 |
                }
            }
        }
    }
}
Open in playground

Scoping Rules

  • Musical context is push/pop scoped: entering a block pushes new settings, exiting pops them.
  • Unspecified fields inherit from the parent scope.
  • Code outside any context block uses defaults (120 BPM, 4/4, no key, no swing).
  • Note streams require a timesig context to determine bar duration.

When to Use Each Block

BlockWhen Required
timesigWhen using note streams (determines beat count per bar)
tempoWhen rendering audio (determines actual playback speed)
keyWhen using roman numerals, progressions, or scaleNotes
swingWhen you want swing feel applied to rhythms
dynamicsWhen you want a default velocity for all notes in scope
panWhen you want a section positioned in the stereo field
gainWhen you want a passage rendered quieter/louder
reverbTimeWhen you want a global reverb tail (RT60 seconds)
voicePoolWhen you need to cap simultaneous-voice count for dense textures
sustainPedalWhen you want piano-pedal-style 2 s sustain tails
tuningWhen using a non-12-TET tuning (Scala .scl file)
rit, accelWhen you want tempo interpolation inside the block

See Also