Skip to content

Releases: stoatworks-labs/pattern

v0.1.1

Choose a tag to compare

@github-actions github-actions released this 25 Sep 14:43

v0.1.1 fixes the Detected tempo source. In v0.1.0 it locked to half the real tempo on programme material: it read 62 for the release video's 125 BPM groove (and 100 on a syncopated cut), while its metronome check passed. Nothing else in the plugin changed; the controls, the picture and the other tempo sources are as they were.

What was wrong

v0.1.0 summed every bin's spectral flux into one onset envelope and took the best autocorrelation lag, preferring half of it when it scored 70 % as well. On a real mix the kick's flux dwarfs the clap's, so the envelope repeats at the half note (kick to kick) and the half-lag test never fires; where the hats dominate it repeats at the eighth instead. It read 160 for a backbeat at 80 BPM and 200 for one at 100. The error also depended on the host's frame rate (the video's groove read 124.84 at 60 fps and 62.06 at 30, the video's rate), and every earlier check had run at 60 fps on a metronome, which has no metre to get wrong.

What it does now

  • The envelope is kept in three registers — low (below 400 Hz), mid (400 Hz to 5 kHz) and high — each smoothed by 20 ms, standardised so a quiet clap counts as much as a loud kick, and weighted by how periodic it is on its own. The registers are fixed: Channels and Band Split no longer change what the tempo detector hears.
  • A period is scored with its grouping and its subdivision, S(T) = 0.5 R(T/2) + R(T) + R(2T). A prior around 120 BPM picks the family of related periods; within it the beat is the fastest level scoring at least 0.70 of the best, with no prior, so the beat wins over the half note and over the eighths.
  • A reading is published only when the one before agrees within 2 %: the first tempo appears at 4 s (was 3 s), and a single stray reading can no longer re-anchor the row clock.

What is verified

By tools/verify.sh on an Apple M4 Max, macOS 26.4, 2026-09-25, all green, and CI on the release commit:

  • pntest --groove (new): drum grooves rendered as audio and read through the harness's FFT — a backbeat (kick on 1 and 3, clap on 2 and 4, hats on the eighths), the same with the clap 12 dB and the hats 20 dB down, a syncopated kick, and a syncopated pluck over a backbeat, each at 80, 90, 100, 110, 125, 140, 150, 160 and 170 BPM; the release video's house groove at 115–135; four frame rates. 45 of 45 within ±1 BPM at the right metrical level by 4.00 s, holding to 16 s, worst error 0.26 BPM. The true beat scores at least 0.737 of its family's best and the double-time impostor at most 0.672, either side of the 0.70 ratio.
  • Negative control: v0.1.0's detector, kept in the harness, fails 15 of the 45 (160.4 for 80, 180.5 for 90, 200.2 for 100, 62.1 for the video's groove at 30 fps).
  • The release video's own soundtrack (48 s, 125 BPM): 44 of 44 readings from 4 s within ±1 BPM, 124.5–125.0, at 30 and 60 fps. v0.1.0 read 62, 100 and 125 by turns at 30 fps.
  • The metronome check (--detected): 120, 100 and 150 BPM at 24–60 fps within ±1 BPM by 4.00 s, holding for twelve; a lag scaled by 1.1 still fails it.
  • The row clock follows the detected tempo over a host saying 77, and the header reads BPM 125*.
  • Every other check as in v0.1.0 (clock, onsets, frame one, pitch, ring, grid at 640×360 and 320×180, 17 live controls, the pipe, oxbow); --grid now also runs on Apple's software renderer.
  • The browser demo's JavaScript port of the detector matches the C++ to six decimals on eight shared fixtures, and the demo is redeployed with it.

What is not

  • A breakbeat with ghost snares and sixteenth hats still reads at the wrong level (double at 80, half from 140 to 170), and so does a four-on-the-floor with an off-beat bass at 80 and 90 BPM (its eighths are a real pulse at twice the tempo). The harness prints both and does not assert them. Use Host or Manual for such material.
  • No real audio has reached it in a host, and nothing has been measured through Resolume's own FFT: the fixtures are synthesised audio through the harness's FFT. It has still never been loaded into Resolume on macOS.
  • Windows: the DLL is built by CI from this source. It was not re-gated in Arena for this release: the change is in the CPU-side tempo detector, and the win-lab box has no sound device to drive it. v0.1.0's build passed the fleet gate 9/9.
  • The macOS builds are signed and notarised by the release pipeline after publication.

Full account, with every number and the traps: AGENTS.md · User guide · Browser demo

Pattern v0.1.0

Choose a tag to compare

@github-actions github-actions released this 24 Sep 15:47

A tracker's pattern editor written by the music as it plays, as an FFGL source for Resolume Arena and Avenue, shown as SW Pattern. A tracker plays a pattern of 64 rows at a rate set by Speed (ticks a row) and BPM (a tick is 2.5 / BPM seconds), four rows a beat at the default Speed of 6. FFGL gives a plugin no audio output, only the spectrum of what is playing, so this runs the tracker backwards: the row cursor runs on the real tracker clock, rate-locked to the host's tempo, and each channel owns a band of the host's 64-bin spectrum. An onset in that band writes a note into the channel on the current row — its pitch from the band's peak bin, its volume as a Cxx effect from the onset's strength, its sample number from the channel. After row 3F the cursor wraps and the next pass overwrites the last, each row cleared as the cursor enters it.

Nothing is animated. The cursor steps on the beat because it runs on a clock; a busy passage fills every row and a sparse one leaves dots because nothing is written that was not heard; an arrangement change shows as the old notes being replaced. Tempo Source (Host, Detected, Manual), Speed 1–31, Swing, 64 or 32 rows, Keep Notes; four or eight channels, Bin Law (Linear / Log) and Bin Value (Magnitude / Power) for the host's unmeasured spectrum, Sensitivity, Band Split, Fold Octaves; three themes named by colour, 3–33 rows visible, VU bars, an effects column, and whole-pixel scaling. It is not a MOD player; it draws no logos and no tracker's name.

What is verified

By tools/verify.sh on an Apple M4 Max, macOS 26.4, on 2026-09-24, eight of nine check groups with no GL context at all:

  • The row cursor sits on floor(t / T) mod 64 on every one of 36,000 frames of a ten-minute run at 60 fps (30,000 at 50, 18,000 at 30) from a host clock at 499,000,000 ms, with a quarter-row swing and across a 125 → 90 → 180 BPM change with no row jump. A phase kept in float fails on 2,400 frames.
  • A burst in band k writes exactly one note, in channel k, on the row current at that frame, at four and eight channels under both bin laws; a burst held across a row boundary writes once.
  • Loud stationary audio already playing when the clip starts, at 40 s and at 499,000,000 ms, writes no false note in the first second, and a real onset at 1.5 s is still heard.
  • All 64 bins give the predicted note or --- under Linear and Log, folded and unfolded; a 96 kHz sample rate moves the notes as predicted.
  • The next pass clears, keeps (Keep Notes) and overwrites rows exactly; a jump of 520 rows clears the pattern.
  • A metronome at 120, 100 and 150 BPM, at 24–60 fps, is detected within ±1 BPM by 3.00 s and held for twelve; the row clock follows it over a host saying 77.
  • At 640×360 and 320×180, Scale 1–4 and Auto, four and eight channels: every s×s block is one colour, every pixel outside the screen is the background, every probed glyph matches the font table bit for bit.
  • Seven negative controls each fail their check; a one-row shift in the shipped shader fails 36 assertions. All 17 controls change the picture at both rasters. oxbow probes it as SW Pattern / PN01 / source.
  • Render cost at the defaults: 0.041 ms/frame at 720p, 0.054 at 1080p, 0.128 at 4K (macOS figures only).
  • CI (ci.yml) green on the release commit, macOS and Windows.
  • Windows, in Resolume Arena 7.27.1 (win-lab, Mesa llvmpipe, no GPU, 2026-09-24): a CI build of this source loads from Extra Effects, registers as SW Pattern / PN01 / source, all 23 host controls match the declaration, it renders, the five visual controls move the picture and Arena's log stays clean: 9 of the fleet gate's 9 checks. The box has no sound device, so the 12 audio-driven controls were not exercised there; the Manual BPM changes three header digits on a still and read inconclusive. Software rendering says nothing about a GPU or about speed.

Found filming the release video

The video was rendered by the harness from a synthesised 125 BPM track through the plugin's real audio input (pntest --pipe --wav), so the harness's FFT and normalisation, not Resolume's. Three facts, all in the user guide:

  • A quiet band hears the leading edge of any sharp transient: the first frame holding an onset carries only its first milliseconds, which are broadband, so a hard-attack kick writes every channel until each band's floor has learned the leak (about a second).
  • A band holding a sustained instrument adapts its floor to it and can miss a kick that a quieter neighbouring band writes from the leak.
  • The Detected tempo source read the bar, not the beat, on this groove: 62 for 125 in three takes. The --detected metronome checks still hold; the video uses the Host and Manual sources.

What is not

  • Never loaded into Resolume on macOS, and no real audio has reached it in a host. The layout, value law and sample rate of Resolume's 64 bins are assumptions with switches; the onset thresholds were set on synthetic spectra.
  • Rate lock only, no lock to the host's downbeat (barPhase unused).
  • No OpenFX port and no presets. There is a user guide at https://stoatworks-labs.com/software/pattern/guide/ and a browser demo at https://pattern-demo.stoatworks-labs.com/, which is a port rather than the plugin.

The macOS build is Developer ID-signed and notarised by the release pipeline after publication; if macOS refuses a download, it predates the signing, so download it again. The Windows build is unsigned, so SmartScreen warns once.