Skip to content

Releases: MrityunjayBhardwaj/SonicWeb

v1.5.0-beta.4

Choose a tag to compare

@MrityunjayBhardwaj MrityunjayBhardwaj released this 23 Jun 07:22
14bf035

Prerelease. First release under the new name @mjayb/sonicweb (formerly @mjayb/sonicpijs). The project is now Sonic Web, live at sonicweb.cc. Bundles all work merged since beta.3. Install: npm install @mjayb/sonicweb.

Rebrand

  • Sonic Pi Web → Sonic Web. npm @mjayb/sonicpijs → @mjayb/sonicweb, repo SonicPiWeb → SonicWeb, domain sonicpi.cc → sonicweb.cc (308 redirect, old paths preserved). Upstream Sonic Pi attribution and the audio-critical sonic-pi-* synthdef/OSC identifiers are unchanged. (#610, #611, #614)

Engine

  • Self-sufficient by default (#604) — the engine auto-loads SuperSonic (the GPL scsynth WASM core, from CDN), the tree-sitter transpiler, and its PRNG table itself. A bare consumer needs zero runtime wiring.
  • Hash#length / #size / #count transpile correctly via a runtime __spSize helper (#603) — fixes loops over Hash literals silently dropping layers.
  • spread(hits, total) matches Desktop Sonic Pi's redistribute placement byte-for-byte for all (hits, total) (#597, #598).
  • Parity fixes: dynamic / non-literal use_synth, inline-loop RNG continuity, cross-loop get/set time-frame alignment, and bang-only mixer/volume linting (#585, #586, #588#593, #595, #596).

Docs & tooling

  • Parity dashboards and every docs code snippet are now playable (Run/Stop) with an "open in sonicweb.cc" link; dashboards published to Vercel + Cloudflare R2.
  • Fixed the "Engine not ready" race when Run is pressed during engine init.
  • CI: actions/checkout / actions/setup-node bumped to v6/v7 (#607).

v1.5.0-beta.3 — engine hardening + beta-ready docs

Choose a tag to compare

@MrityunjayBhardwaj MrityunjayBhardwaj released this 11 May 11:23

v1.5.0-beta.3 — engine hardening + beta-ready docs

First public-beta cut since v1.5.0-beta.2 (Apr 10). ~30 PRs of engine
fixes, ~50 new DSL fns, full parity-comparator tooling, and the
operational docs to triage incoming beta bugs.

TL;DR — what's in this release

Engine fixes (the 2026-05 audit pass)

  • SP72: use_bpm / use_synth no longer leak from in_thread into
    nested live_loop registration (#280) — months of FX-comparator
    numbers were running web at half tempo
  • SP78–81: four hot-swap state-hygiene bugs caught by Playwright +
    WAV reproducers (#283) — empty-cycle Updates, FX-scope inversion,
    stop-tail queue drain, per-loop state leakage
  • SP70: lossless capture pipeline — Recorder.ts swapped MediaRecorder
    • opus codec for raw float32 → WAV, removing the codec damage that
      had been masquerading as "filter family broken" for weeks
  • Per-loop audio isolation via private loopBus + monitor synth (#178)
    — first Sonic Pi implementation to ship this
  • #199: nested live_loop hot-swap routes through scheduler.hotSwap()
    directly (#261)
  • Sonic Tau mixer baseline: pre_amp=0.3, amp=0.8 — calibrated for
    browser-WASM headroom, not Desktop SP driver levels

DSL coverage: ~87% of upstream (148/170 user-facing fns)

  • Tier A: 17 critical fns — recording, kill, current_*, define
    persistence (#213)
  • Tier B: 27 fns across 3 PRs — ring/spread, tuplets, defonce,
    sync_bpm, dynamic eval (run_code/eval_file/run_file),
    live_audio control, load_example (#230, #234, #238)
  • Tier C: 23 fns across 3 PRs — state wrappers
    (with_synth_defaults, with_sample_defaults, use_arg_checks
    family), sample/buffer registry, mixer + introspection helpers
    (#252, #254, #256)
  • Help panel + autocomplete entries shipped for every new fn

Parity tooling

  • A/B comparator rig (tools/capture-desktop.ts + spectrogram
    compare) — captures both engines, renders 3-panel mel-spectrograms,
    reports L2 + MFCC + per-beat metrics (#264)
  • FX A/B inspector: npm run inspect opens a single-file viewer with
    desktop ↔ web <audio> players, sync-play, MFCC sidebar, verdict
    tiers HIGH/MID/LOW/INCONCLUSIVE (#277)
  • WAV-verify sweep across 40 wired FX (#275) — current scores:
    4 HIGH / 26 MID / 8 LOW / 2 INCONCLUSIVE (composite ~89.5%)
  • Capture tool: --batch <dir> for fixture-folder runs (#224),
    engine hooks for puts/cues instead of DOM slicing (#222)

UI / app

  • Welcome buffer drop + Cm9 finale (#220)
  • Preloader pulls forward CDN deps before App mount (#284)
  • Live Mixer Pre-Amp / Amp sliders in Prefs push to scsynth on drag
  • MIDI toolbar button hidden until Tier D ships (Web MIDI input via
    the engine API still works)
  • README rebranded to "Sonic Pi Web"

Beta operational infrastructure

  • KNOWN_ISSUES.md + TRIAGE.md + bug-template gates so triage
    isn't ambiguous when users report problems
  • 8 Plausible custom events wired for beta-visibility analytics
  • SuperSonic CDN version pinned end-to-end (v0.57.0)

Numbers

  • 929 unit tests pass (was 805 at beta.2)
  • 62/66 synths working end-to-end (3 upstream WASM LOAD-FAIL)
  • 197/197 samples
  • 42/42 FX wired, 40/42 WAV-classified
  • ~148/170 DSL fns (~87%)
  • 49 community forum compositions verified end-to-end in Chromium

Compatibility notes

  • Mixer behaviour change: web output is ~0.19× Desktop SP's
    driver-attenuated level by default. Comparators should RMS-normalise
    before A/B. Override via Prefs → Audio → Mixer Amp.
  • MIDI: Web MIDI continues to work via the engine API. Only the
    toolbar dropdown UI is gated until Tier D (midi_pc, midi_raw,
    midi_sysex, device picker).
  • DSL: net additive — no upstream-compatible code that worked in
    beta.2 should break in beta.3.

Install

npm install @mjayb/sonicpijs        # latest tag now points here
npm install @mjayb/sonicpijs@beta   # beta tag — same version

Browser: https://sonicpi.cc

See KNOWN_ISSUES.md
for current beta blockers.

v1.5.0-beta.2 — transpiler consolidation + P2 credibility

Choose a tag to compare

@MrityunjayBhardwaj MrityunjayBhardwaj released this 10 Apr 09:04

Prerelease. Two PRs since v1.5.0-beta.0 — transpiler stability work (#165) and four new features from the Desktop Sonic Pi tutorial (#166). Installed via npm install @mjayb/sonicpijs@beta.

New features

  • use_real_time (tutorial Ch 11.1) — disable the schedule-ahead buffer for the current thread. Use inside a MIDI-triggered live_loop to drop perceived latency to near-zero.
  • MIDI input cue paths (tutorial Ch 11) — sync "/midi:*:1/note_on" (Desktop format) and sync "/midi/note_on" (short format) both match a single incoming MIDI message. Either form from the tutorial now works unchanged.
  • Wildcard sync / cue matching (tutorial Ch 10.3) — sync "/osc*/trigger" and sync "/foo/?ar/tick" support * and ? glob patterns. Exact-match is still the fast path when no glob characters are present.
  • synth :sound_in / synth :sound_in_stereo (tutorial Ch 13.1) — capture microphone input into the live composition. The browser prompts for mic permission on first use, then routes the mic through scsynth so you can gate, filter, FX, or record it like any other synth. Stereo input devices go through sound_in_stereo.

Transpiler consolidation (#165)

  • synth :NAME idiomsynth :prophet, note: :c4, release: 0.5 now dispatches the named synth. Previously every such call silently fell back to :beep because the transpiler emitted play(opts) instead of play(note, opts).
  • Top-level use_synth orderinguse_synth :saw; play :c4; use_synth :tri; play :e4 now plays the right synth for each note. Previously the use_synth calls were hoisted together and only the last one took effect.
  • Single transpiler path — the legacy regex-based transpiler has been removed. TreeSitter is now the sole Ruby → JS path, eliminating a class of inconsistencies where one transpiler handled a construct and the other didn't.
  • Ruby array helpers: .zip and .each_with_index now transpile correctly.

Bug fixes

  • get[:key] bracket formif get[:flag] ... end branches now read the stored value. Previously the bracket form silently returned undefined for every key, so any composition that gated loops on shared state (set/get) appeared inert — no error, no warning, just nothing happening. get(:key) function-call form was unaffected.
  • synth :sound_in connect error — every dispatch used to print Mic input failed: Failed to execute 'connect' on 'AudioNode': Overload resolution failed to the log. Fixed in initial review.
  • synth :sound_in mic lifecycle — three sharp edges fixed during review testing:
    • Stop now releases the mic track so the browser's recording indicator clears and nothing keeps feeding scsynth's input channel.
    • Rapid re-dispatch inside a live_loop (e.g., synth :sound_in; sleep 0.1) no longer re-acquires the microphone ten times per second. The mic connects once and stays connected.
    • Hot-swap (edit code to remove sound_in, press Run again) cleanly releases the mic without needing an explicit Stop first.
  • MIDI dual-fire drop — the new /midi:*:ch/type + /midi/type dual dispatch was silently dropping every event because the scheduler's fireCue early-returned when called with a synthetic taskId. MIDI input now actually wakes sync waiters.

Verified compatibility

The 56 real-world compositions from the beta.0 regression set still pass end-to-end. New automated E2E coverage (tests/p2-credibility.spec.ts) exercises the four new features in headed Chromium with mocked MIDI input and a mocked microphone stream.

Known gaps (follow-up)

  • use_real_time latency reduction is wired through the scheduler but hasn't been measured against real MIDI hardware — perceptual verification is still owed.
  • synth :sound_in has been verified to reach scsynth end-to-end and real mic passthrough works in manual testing, but an automated fidelity test (known tone in → known tone out with FFT verification) is still owed.

Bug reports welcome on GitHub issues. The in-app Report Bug button pre-fills the version, browser, and current code.


v1.5.0-beta.0

v1.5.0-beta.0 Pre-release
Pre-release

Choose a tag to compare

@MrityunjayBhardwaj MrityunjayBhardwaj released this 08 Apr 22:28
e2e6d14

Prerelease. This is the first public beta of v1.5.0. Installed via npm install @mjayb/sonicpijs@beta; the default latest tag still points to v1.4.0. Bug reports welcome on GitHub issues — the in-app Report Bug button pre-fills the version, browser, and current code.

Engine audit — 33 bugs fixed

Found during a multi-round audit against MagPi book chapters, official Sonic Pi wizard/sorcerer/magician examples, and community forum compositions. Per-bug rationale in the engine audit PR (#155) and synth alias cleanup (#157).

Critical engine:

  • randomSuffix() was const f = (): string => f() — infinite recursion on top-level in_thread/at
  • ProgramBuilder children (in_thread/with_fx/at) not inheriting _transpose, _synthDefaults, _sampleDefaults
  • wrapBareCode didn't track loop do/.times do/.each douse_synth hoisted out of loops
  • normalizeSampleParams missing expandSlideParamsample :x, slide: silently ignored
  • normalizeFxParams resolved symbols AFTER injecting defaults (wrong order)
  • with_bpm didn't restore previous BPM
  • resumeTick() race condition on rapid pause/resume

Bridge / runtime:

  • in_thread inside with_fx not inheriting outBus — thread audio bypassed FX entirely
  • Sample/SynthDef lazy-load race conditions (buffer leaks, duplicate loads)
  • freeBus() allowed duplicate frees — bus collision
  • fetchSampleDuration silently swallowed errors, breaking beat_stretch

DSL / tutorial parity:

  • use_sample_bpm — wrapper around use_bpm(60 / sample_duration(name))
  • midi shorthand — midi 60, sustain: 0.5 (note_on + auto note_off)
  • use_osc / osc shorthand — state variable for default host/port
  • with_fx reps: — FX body now loops N times within same FX instance
  • with_synth_defaults / with_sample_defaults — scoped variants
  • use_density — permanent density setter
  • use_debug — exposed in sandbox as no-op (was causing crashes)
  • .take(n) — transpiler was emitting .slice() but Ring uses .take()
  • Ring.line(steps=1) returned [NaN] (division by zero) — now returns [start]

Public API additions:

  • Exported: hzToMidi, chord_degree, degree, knit, range, line

Sandbox fixes:

  • get() was defined as a new Proxy(...) not a function — get(:key) crashed
  • with_random_seed, with_octave, with_density, with_synth_defaults, with_sample_defaults weren't in transpileWithBlock handler — blocks transpiled without callback wrapper
  • TOP_LEVEL_SETTINGS missing use_arg_bpm_scaling

Architectural fix — b shadowing:

  • User variable b shadowed ProgramBuilder callback parameter via Proxy set trap. Renamed internal parameter from b to __b across all transpiler output sites (callback params, method prefixes, __checkBudget, stop, lastRef, density, define funcs, at callbacks). Documented in KNOWN_LIMITATIONS.

wrapBareCode regex expansion:

  • Regex only matched /^\s*(play|sleep|sample)\s/ — missed play_chord, play_pattern_timed, use_synth_defaults, synth, control, cue, sync, etc. Expanded to cover all bare DSL callables that need __b scope.

Synth aliases:

  • Removed dark_sea_horn and singer from SYNTH_NAMES — no corresponding .scsyndef on the SuperSonic CDN (silent failure trap).

Verified compatibility

56 real-world compositions run end-to-end in Chromium capture:

  • 18 E2E tests (covering 122 DSL functions)
  • 7 MagPi Essentials chapter examples
  • 15 official Sonic Pi examples (wizard/sorcerer/magician tiers from etc/examples/)
  • 13 community forum compositions from in-thread.sonic-pi.net
  • 3 edge cases

Test coverage

  • 703 unit tests pass
  • Zero TypeScript errors

UI

  • Version label in the menu bar displays v1.5.0-beta.0 (top-right, muted). Click to copy the full SonicPi.js v1.5.0-beta.0 string to clipboard. Pre-filled into the Report Bug URL so every bug report is tagged to a specific build.

Release engineering

  • This is the first release following the new release-cycle criteria: single version string across all surfaces, npm --tag beta to protect latest, UI footer as the load-bearing signal for the prerelease channel, explicit beta → RC → stable gate criteria documented in the release runbook.

Known limitations

See KNOWN_LIMITATIONS.md for the current list. The limitations file is the single source of truth; it is intentionally NOT duplicated per-release in this changelog. Noteworthy feasible-but-not-built items tracked for post-beta work: external sample upload (#159), OSC receive via WebSocket bridge (#150), synth :sound_in via getUserMedia (#152), use_real_time MIDI latency bypass (#149), .zip/.each_with_index Array methods (#154).


v1.4.0 — UI/UX overhaul + error handling

Choose a tag to compare

@MrityunjayBhardwaj MrityunjayBhardwaj released this 06 Apr 17:14

What's new

Help Panel

  • Fixed cursor word detection (CodeMirror ESM wordAt() bug)
  • Resizable with draggable splitter (height persists)
  • 311 help entries — 33 functions + 37 synths + 34 FX + 207 samples

View Menu

  • All 5 panel toggles now work: scope, log, cue log, buttons, tabs
  • Scope visualization stays within its panel (overflow fixed)

Cue Log

  • Wired to live cue/sync events from the scheduler
  • Resizable with splitter between log and cue log

Error Handling

  • Syntax errors block execution with clear "your code could not be parsed" message
  • live_loop, define, with_fx, in_thread, at, time_warp, density all validate do...end blocks
  • Runtime errors now highlight the error line in the editor
  • Hot-swap reEvaluate() rolls back on failure

UI Polish

  • Autocomplete tooltip dark-themed
  • Report Bug button (pre-filled GitHub issue, no OAuth)
  • New hero image

Infrastructure

  • CI workflow on PRs
  • GitHub Actions v6, TypeScript 6.0.2
  • Dependabot configured
  • Blade Runner x Techno in advanced examples

Milestone

5 issues closed, 4 PRs merged

Full Changelog: v1.3.0...v1.4.0