Repository navigation
Releases: drsamonline/musicgen
Release list
MusicGen v2.5.0
MusicGen v2.5.0 — the song breathes now
Live demo: https://drsamonline.github.io/musicgen/ · Studio: https://drsamonline.github.io/musicgen/app/
Tempo is a map, not a number
Every song now carries a tempo map instead of one BPM:
- sections move — choruses lift (+5%), verses settle (−2%), bridges pull back (−8%), the intro and outro ease in and out
- phrases get rubato — a deterministic nudge every four bars, so a phrase leans into its climax and relaxes after it
- endings ritardando — the last two bars slow down, which is the difference between an ending and a stop
A song at 84 BPM with the default drift now actually runs 77–90 BPM, and the meta line says so.
The dial sets the centre; a new Tempo drift control (0–35%) sets how far it may wander. Set it to 0 for a metronomic loop.
Why this was more than a slider
Everything that converts beats to seconds had to go through the map: note start times, note lengths (a note across a tempo change is not beats × 60/bpm), automation envelopes, loop points, section jumps and the render length. src/core/tempo.js provides secondsAt(), beatAt() and bpmAt(); the engine and the UI read from it and nothing else.
Tests: the map integrates and inverts correctly, a flat map matches the old arithmetic exactly, every scheduled event matches secondsAt(beat) to 1e-6, the render length equals the song duration, and sections really do sit at different tempos.
Also
The browser suite was lightened (16 kHz per-track renders) after it OOM'd under load, and the interaction block now retries once if the frame detaches.
135 tests (39 unit + 96 browser), axe clean, determinism lint, budget check, CI green on 662e421.
COMPOSER_VERSION is 5 — old share links will say the notes changed.
Install
unzip musicgen-v2.5.0.zip && cd musicgen-v2.5.0/app
python3 -m http.server 8080MIT licensed.
MusicGen v2.4.0
MusicGen v2.4.0 — it stops stopping, the static is gone, and it phrases
Live demo: https://drsamonline.github.io/musicgen/ · Studio: https://drsamonline.github.io/musicgen/app/
"Stops midway" — found and fixed
AudioWorkletNode rejects numberOfOutputs: 0. The clock worklet threw, was caught, and the app silently fell back to setInterval — and a throttled tab then simply stopped scheduling notes. That is a song ending in the middle.
Now there is a watchdog: if no tick arrives for 700 ms while playing, the scheduler is kicked back to life. A 3-second continuity test asserts the event cursor keeps advancing, and playback is still running at the end.
"Static, too loud, doesn't mix" — three real causes
- Aliasing. Additive partials, FM sidebands, wavetable frames and pulse harmonics were free to cross Nyquist, and everything above it folds back as noise. Every oscillator now asks
safeHarmonicsFor(sampleRate, freq, …)how many partials it may have; the FM index is clamped so its sidebands stay under the limit. Asserted at 22.05 / 44.1 / 48 kHz. - Hard clipping. The granular worklet clamped with
Math.min/maxand nothing protected the master. Granular now soft-clips throughtanh, and the master has a safety waveshaper — unity at low level, soft knee near full scale — that no preset can bypass. - Resonant, piercing layers. The formant bank ran at Q 6–10 on a saw; the "metallic" hat multiplied its six squares by six. Now Q 3–4.5, and ×3 through a lower band-pass.
Measured result: lofi −16.2 LUFS (target −16), rock −12.8 (−12), peaks around 0.65 with no clipping, and no sample-to-sample jumps above 0.9.
"Read music theory so it sounds more human"
The composer now phrases instead of emitting notes:
- the motif rises through the first half and falls through the second
- articulation mixes short, mid and held notes instead of one flat length
- dynamics arch across each bar
- phrases swell into bar three and breathe with a rest at the end
- section endings are held, not clipped
- repeats vary one note instead of looping exactly
- timing jitter scales with tempo — a slow song can breathe, a 500 BPM one cannot
"Hang"
Export scheduling now yields to the event loop every 250 notes, so a long render no longer freezes the tab, and node cleanup goes through one shared queue instead of a timer per voice.
124 tests (34 unit + 90 browser), axe clean, determinism lint, budget check, CI green on 9115e54.
COMPOSER_VERSION is 4 — old share links will say the notes have changed.
Install
unzip musicgen-v2.4.0.zip && cd musicgen-v2.4.0/app
python3 -m http.server 8080MIT licensed.
MusicGen v2.3.0
MusicGen v2.3.0 — the mix was a bass solo, and now it isn't
Live demo: https://drsamonline.github.io/musicgen/ · Studio: https://drsamonline.github.io/musicgen/app/
What was actually wrong with the sound
I measured instead of guessing. Rendering each track solo and reading its LUFS showed the bass sitting 18 dB above the drums — the app was playing a bass solo with the harmony buried under it. That is the "not proper, glitches" report.
Fixed with:
- a measured per-track trim table (drums ×3.6 with a bus compressor, bass ×0.4, chords/lead ≈×1.5)
- a drum-bus compressor that keeps punch and controls peaks instead of slamming the limiter
- a softer bass attack, and a master gain that leaves headroom
- the physical worklet was double-boosted and hard-clipping — audible as clicks. It now soft-clips through
tanh, has a release tail and gentler damping
Result: every style renders within ~2 LUFS of its target, true peaks between −1 and −4.5 dBTP, no clipping.
And the check that should have caught it now does: the mix-balance test went from "nothing more than 30 dB below the loudest" to "nothing more than 18 dB, and the bass may not sit more than 12 dB over the drums".
Also in this release
- Real wavetable morph — six baked frames (sine → triangle → saw → square → organ → bell) as
PeriodicWaves, crossfaded across the note. - Formant/vowel layer — a saw through three band-pass formants with vowel morphing, now the additive pad.
- Visual regression — the studio screenshotted in dark, light and desktop against committed baselines, comparing luma on a coarse grid so font antialiasing doesn't fail the build.
Backlog, corrected
Three items were wrong about what is possible, so they are now marked as such rather than sitting there as pretend work: a Worker cannot run OfflineAudioContext, typed-array note storage buys nothing below ~10k notes, and a QR encoder I cannot verify with a decoder is a liability, not a feature. A real screen-reader pass remains the most valuable open item, and it cannot be done from here.
117 automated tests (32 unit + 85 browser), axe clean, determinism lint and budget checks green, CI green on 4d84d65.
Install
unzip musicgen-v2.3.0.zip && cd musicgen-v2.3.0/app
python3 -m http.server 8080MIT licensed. Music you make with it is yours.
MusicGen v2.2.0
MusicGen v2.2.0 — AudioWorklets, microtuning, groove editor
Live demo: https://drsamonline.github.io/musicgen/ · Studio: https://drsamonline.github.io/musicgen/app/
The last big synthesis gap
Two real DSP processors, both running on the audio thread:
granular-voice— overlapping Hann-windowed grains with pitch scatter derived from a hash of the note, so it stays deterministic across exports.physical-voice— a fractional-delay waveguide with one-pole damping and a seeded excitation burst.
Both are per-track nodes loaded with addModule, and both fall back to native nodes if anything fails — the app never depends on a worklet. A third worklet, clock-tick, lets the scheduler run off the audio thread instead of setInterval, which is the difference between steady tempo and wobble when the main thread is busy.
Composer
Microtuning (just intonation as cents per pitch class), a 16-step groove editor for kick/snare/hat, polymeter (three against four), automation envelopes drawn from the tension curve, instrument variants (three flavours per tech), drum depth (metallic hats, layered claps, woodier rim), noise beds for ambient and cinematic songs, and per-track FX (delay division and drive, with gain compensation so drive adds colour rather than level).
Bass leaps are now validated in every style, not just jazz.
App
A settings dialog, live recording to WebM via MediaRecorder, a protocol handler (web+musicgen://), a spectral tilt report and a generated CHANGELOG.
Numbers
116 automated tests (32 unit + 84 browser). Master gain was recalibrated after the new drive/EQ stages: every style now renders within 2 LUFS of its target with true peaks below −1 dBTP. axe-core clean in dark, light and desktop; determinism lint and budget check green; CI green on 073d058.
COMPOSER_VERSION is now 3 — the golden seeds were updated deliberately, and old share links will say so.
Install
unzip musicgen-v2.2.0.zip && cd musicgen-v2.2.0/app
python3 -m http.server 8080MIT licensed. Music you make with it is yours.
MusicGen v2.1.0
MusicGen v2.1.0 — honest seeds, better sound, and the checks that keep it honest
Live demo: https://drsamonline.github.io/musicgen/ · Studio: https://drsamonline.github.io/musicgen/app/
Versioned seeds
Every share link, song file and library entry now carries COMPOSER_VERSION. Open a link made by an older composer and the app says so — "this was made with composer v1; you are on v2, so the same seed now produces different notes" — instead of silently playing a different song. Reproducing the old output exactly would mean keeping every historical composer in the build; that is a decision for a later version, not something to fake.
Sound
- Legato glide on adjacent bass and lead notes.
- Per-style EQ — two shelves and a mid band per style, so a lo-fi mix and an EDM mix are shaped differently at the master.
- 4× oversampled true peak (Catmull-Rom), so the −1 dBTP ceiling means what it says rather than measuring sample peaks.
Verification that is now enforced, not claimed
- Mix balance is a test. Every track is rendered solo and checked for being audible, not buried more than 30 dB, and not letting the drums dominate the melodic tracks by more than 14 dB.
npm run budget— shell size (61 KB gzipped against a 200 KB budget), service-worker precache completeness, and no external URLs anywhere in the app. It runs in CI, so the offline promise cannot rot.- Property tests — 40 random preset/seed pairs checked for determinism, pitch ranges and finite timing, plus voicing range checks.
App
Tap a note in the piano roll to audition it; Random now flashes the dials it changed; a first-run hint says what the three buttons do; prefers-contrast: more is supported; the app can receive a seed from the OS share sheet and be opened with a .json song file; the manifest carries screenshots for a richer install sheet; and the library exports as a zip of song JSON.
Docs
CONTRIBUTING.md (the determinism rule and the five checks a PR must pass), issue templates, and docs/LISTENING.md — the golden-seed log where the automated tests stop and a person listens.
105 automated tests (32 unit + 73 browser), axe-core clean in dark, light and desktop, determinism lint and budget checks in CI.
Install
unzip musicgen-v2.1.0.zip && cd musicgen-v2.1.0/app
python3 -m http.server 8080MIT licensed. Music you make with it is yours.
MusicGen v2.0.0
MusicGen v2.0.0 — audio integrity, 20–500 BPM, and the enhancement sweep
Live demo: https://drsamonline.github.io/musicgen/ · Studio: https://drsamonline.github.io/musicgen/app/
The sound that went missing
Three separate bugs, all fixed:
- The voice counter never decremented. It ran on
setTimeout, which is throttled in a background tab and never fires during an offline render — so the counter hit the cap and stayed there, and from then on every quiet note was silently dropped. It is now a pool pruned by time that steals the quietest voice with a fade instead of discarding the new note. - Feedback loops were never disconnected. Karplus-Strong's delay line rang forever and the noise bed's LFO kept running; over a long session that is a CPU creep that ends in dropouts.
- Late notes were fired in a burst. Anything more than 60 ms late is now skipped rather than dumped into the present, with a 200 ms lookahead.
Tempo: 20–500 BPM
The slider, the clamp, the delay line (dotted eighth at 20 BPM is 2.25 s), the drum subdivision, swing and the scheduler all work at both ends, and both ends are in the test suite.
Composer
Section modulation with per-section keys (the validator follows the new key), section aliasing so A-B-A reuses A's material, a pad counter-line that answers the lead in its rests, contour resolution to a chord tone, drum phrase mutation, chord rhythm variation (whole / push / double), lead doubling, an arrangement fade on the outro, and per-track locks that draw from their own seed stream — lock the drums and they survive a new seed.
Sound
Filter envelope and velocity-to-timbre on every voice, analogue drift, stereo width, mono bass below 120 Hz, sidechain ducking for EDM.
App
Piano-roll zoom / pan / scrub, section looping, A/B against the previous song, install prompt and offline badge, update toast, song JSON export and import, a loudness target for exports, library search / rename / duplicate with full song storage, session restore, a text song summary for screen readers, throttled live-region announcements, keyboard navigation of the timeline, and reset-to-defaults.
Tests and audit
30 unit + 70 browser tests, plus a determinism lint in CI. New coverage: tempo extremes, render integrity (no silent holes, no dropped voices), loudness regression across three styles, a 7/8-at-500-BPM stress run, golden-seed snapshots, and the composer features above. axe-core is clean in dark, light and desktop.
docs/ENHANCEMENTS.md now marks what shipped (55 items done or partial) and what is still open (40), with the reasons.
Install
unzip musicgen-v2.0.0.zip && cd musicgen-v2.0.0/app
python3 -m http.server 8080 # → http://localhost:8080MIT licensed. Music you make with it is yours.
MusicGen v1.2.0
MusicGen v1.2.0 — light theme, gallery, audit and a performance pass
Live demo: https://drsamonline.github.io/musicgen/ · Studio: https://drsamonline.github.io/musicgen/app/
Themes
- An explicit theme switch (◐ button or
T): system → light → dark, remembered across reloads, withtheme-colorfollowing it. - Every surface is a token, and so are the canvas palettes — piano roll, spectrum, waveform and generative art re-theme with the UI instead of staying stuck on a dark background.
Landing page
- New gallery section: dark and light desktop captures, phone, waveform mode and generated cover art, with captions.
- Proper heading structure and named landmarks.
Performance
- Reverb IR is synthesised once per context and cached (it used to be rebuilt on every pause).
- The saturation curve is a shared
Float32Arrayinstead of 1024 floats per note. - Analyser buffers are reused across frames; section intensity is a binary search.
- Pausing fades the master instead of tearing down and rebuilding the audio graph.
Audit
npm run auditruns axe-core (WCAG 2.1 A/AA + best practice) over the studio in dark, light and desktop plus the landing page, and adds app-level checks (duplicate ids, unlabelled controls, canvas names, console errors).- Current result: zero violations, zero app-level issues, zero console errors.
Tests
- 24 unit + 44 browser tests, now including theme switching, persistence across reload, and light-mode rendering. CI runs all of them plus the audit.
Docs
docs/ENHANCEMENTS.md— the full backlog: 12 categories, ~95 items, each with effort and impact, plus the five open product decisions.
Install
unzip musicgen-v1.2.0.zip && cd musicgen-v1.2.0/app
python3 -m http.server 8080 # → http://localhost:8080MIT licensed. Music you make with it is yours.
MusicGen v1.1.0
MusicGen v1.1.0
A pocket generative composer that runs entirely in your browser.
Live demo: https://drsamonline.github.io/musicgen/
Studio: https://drsamonline.github.io/musicgen/app/
What's in this release
- Composer — 11-stage seeded pipeline: harmonic grid (Markov + modal interchange), voice-leading solver, bass, groove/Euclidean drums with fills, motif development, pad, arp, humanise, tension curve. Byte-identical output for the same
(presets, seed). - Presets — 11 styles, 10 moods, 10 themes, 8 song types, 7 synthesis technologies, plus a compatibility table so Random stays musical.
- Synthesis — subtractive, FM, chiptune pulse, additive, wavetable, Karplus-Strong, noise; synthesised drum kit; generated convolution reverb, tempo-synced delay, chorus; glue compressor + limiter; ITU-R BS.1770 loudness.
- Export — WAV (16/24/32-bit, normalised per style under a −1 dBTP ceiling), per-track stems as a zip, Type-1 MIDI, 1024 px cover art, seed share links.
- Platform — installable offline PWA, MediaSession with generated artwork, Wake Lock, four visualisers, keyboard shortcuts, undo/redo of preset changes.
- Tests — 24 unit + 38 in real Chromium with real Web Audio, including a 100-run determinism diff and a 330-case theory-validator matrix.
Install
Download musicgen-v1.1.0.zip, unzip, then:
cd musicgen-v1.1.0/app
python3 -m http.server 8080 # → http://localhost:8080MIT licensed. Music you make with it is yours.