Repository navigation
Releases: iltempe/openband
Releases · iltempe/openband
Release list
OpenBand v0.6.34
G6c1 · Publishing, with your own accounts and your click (SPEC v0.6 G6)
- Publish in the Release tab, or
publish. Tick the platforms (Publish in CC ticks the ones the licence allows) and press Publish…. The release is checked again, then a confirmation in the studio lists each platform with what it means: the Archive is public and permanent, Commons is public and free to reuse, and Creative Commons can't be withdrawn. Nothing goes out without that click. When the AI callspublish, the same confirmation opens and the tool waits for it. A cancel, or no answer within 5 minutes, is an error. - Internet Archive, through its S3-like API with the user's own keys:
- an item in Community Audio (
opensource_audio) holding the master as 24-bit FLAC (tags and cover inside), the cover, the LRC, LICENSE.txt and CREDITS.txt; - metadata in
x-archive-meta-*headers: title, creator, date, description with the licence and the AI-use statement,licenseurl, the tags assubject; values areuri()-encoded, so accents survive; - a busy Archive (503 SlowDown) is retried with backoff.
Without a Creative Commons licence it is blocked, with the reason.
- an item in Community Audio (
- Wikimedia Commons:
- Sign-in is OAuth 2.0 with PKCE through meta.wikimedia.org, with the local OpenBand as the redirect target. The token is renewed when it expires (refresh tokens are single-use), and once more if the wiki refuses it early. The access token of an owner-only consumer can be pasted instead.
- The master is sent with the chunked upload (4 MB chunks to the stash). A failed chunk is sent again from its offset.
- The file is then published with the description page the studio writes:
{{Information}}(description with the AI-use statement, date,{{own}}, author, software), and{{cc-zero}},{{cc-by-4.0}}or{{cc-by-sa-4.0}}. Free text is kept in<nowiki>, so a title can't break the template. - NC and ND licences are refused, and so is a file name that already exists (change the title).
- The keys never reach the web page. They stay in the local OpenBand (
npx openbandor the desktop app) in~/.openband/publish.json, readable only by the user (0600). The page only learns which accounts are set up; the AI never sees keys.- Files reach the local server over HTTP, accepted only from loopback, from a local origin (
openband://appor 127.0.0.1) and with a token the server gives the studio over the bridge. - Everything else goes over the bridge. A paired public site (the online demo) can't publish.
- Files reach the local server over HTTP, accepted only from loopback, from a local origin (
- Publications are kept in the song (
Project.publications, not an undo step), each with its platform, id, URL, date and the hash of the master that went out. They show as Published in the tab and inget_publications. - Tools (169 in all):
list_publish_targets(every platform: whether OpenBand publishes there yet, the account, what blocks it),publish,get_publications. - Guide: docs/PUBLISHING.md (IT: PUBLISHING.it.md), with how to get the Archive keys and a Wikimedia consumer.
- Fix: a sample marked All rights reserved in the licence select (stored as
all-rights-reserved) was not seen as a conflict with a Creative Commons song. Now it is. - Different from the spec:
- The adapters are in the local server (
server/publish/), not insrc/publish/adapters/, because they are where the keys are. - The Archive doesn't publish from the browser alone, so a local OpenBand is always needed.
- Keys are kept in a 0600 file, not yet encrypted with the system keychain in the desktop app.
privacyother than public is refused for the Archive and Commons, which have no private uploads.
- The adapters are in the local server (
- Not yet: SoundCloud, YouTube and Mixcloud (G6c2), Funkwhale and Audius (G6c3).
- Tests:
- Against a mock of both platforms (
server/fixtures/fake-platforms.mjs;server/publish.test.ts, 10 tests): files need the token and a local origin; the page never gets a secret, and the key file is 0600; the item is created with decoded metadata after one 503, its files are added, and its status is live; wrong keys give a clear error; Wikimedia sign-in completes the full PKCE round trip, and a forged verifier fails; a 9 MB upload in 3 chunks survives a failed chunk and an expired token (one refresh) and keeps its page text; a duplicate name is refused; signed out, it asks to sign in; a pasted owner-only token works. - In Chrome (
npm run e2e, publish, 15 checks, the real server against the mock): the page never sees the secret;list_publish_targets; Commons before sign-in is refused; publish without the click → error, nothing uploaded; the Archive without CC and Commons with NC are blocked with the reason; an all-rights-reserved sample blocks it by name; the Wikimedia sign-in window returns through the local OpenBand; the confirmation shows the warnings; both uploads arrive (FLAC, cover, LICENSE, CREDITS with the metadata; the page with{{Information}}and{{cc-by-4.0}}); the publications are kept with their master; no secret, S3 header or token endpoint in the web bundle. - Unit tests: the Archive identifier and metadata, CC required; the Commons page and templates, NC and ND refused, free text escaped, file names.
- Against a mock of both platforms (
OpenBand v0.6.33
G6b · A video from the song, made in the browser (SPEC v0.6 G6)
- Make the video in the Release tab, or
render_video. Each video shows:- the cover, on a glow of its palette's accent;
- the title and artist;
- the spectrum moving with the music: 48 log bands from 40 Hz to 12 kHz, fast attack and slow fall;
- a progress line;
- the lyric line being sung, from the aligned lyrics, with the next one dimmer.
Syllable hyphens are removed, as in the LRC. A preview plays in the panel and the MP4 is saved.
- Two formats:
- 16:9, 1920×1080: the whole song.
- 9:16, 1080×1920: a Short of 15–60 s. It shows the first chorus by default (a chorus shorter than 15 s takes what follows), or
section_id, at mostmax_seconds. It fades in over 0.3 s and out over 1.5 s.
- Encoding: WebCodecs in a worker, at 30 fps and 6 Mbit/s for H.264 High and 192 kbit/s for AAC. Chrome on Linux has no AAC encoder, so there the audio is Opus; VP9 is the fallback where H.264 isn't available. The file is an MP4 with its index at the front, muxed by
mp4-muxer5.2.2 (MIT). That library is finished but deprecated in favour of Mediabunny, which is MPL-2.0. Nothing is uploaded. - Not yet: publishing to the platforms (G6c).
- Acceptance. The spec asks for a video that opens in standard players, with the audio and lyrics in sync within ±50 ms.
- In Chrome (
npm run e2e, video, 12 checks), ffprobe reads both files as H.264 + AAC at 1920×1080 and 1080×1920, with audio and video the same length (27.07 / 27.00 s, and 15.08 / 15.00 s for the Short). - Both streams start at 0.000 s.
- The Short is the chorus (from 12 s, 15 s long).
- ffmpeg's decoded frames show the first lyric line absent 50 ms before it is sung (contrast 5.0) and present 50 ms after (68.3). Every line appears on its own frame (0 ms late).
- 27 s of 1080p were made in 5.2 s.
- Unit tests: the Short's excerpt (chorus, short chorus, limit, end of song, no sections, unknown section), the lyric cues within an excerpt, and a line on the first frame at or after it.
- In Chrome (
- CI installs ffmpeg for the e2e job if it's missing.
- CI's e2e job had failed since v0.6.30: the sound-alike's "under 10 s" check took up to 18.9 s on GitHub's shared runners, about 2.2× slower than a computer. There the bound is now 25 s, as a guard against regressions. The 10 s bar still applies, and is met, on a computer (slowest 8.7 s on an M-series Mac).
OpenBand v0.6.32
G6a · Getting a song ready to release: metadata, licence, what it contains, cover, Release Kit (SPEC v0.6 G6)
- The Release tab (bottom panel): the song's metadata — title, artist, genre, tags, date, contact, description — saved with the song (
Project.release). - A licence in three answers: may others use it commercially? may they change it? must changed versions keep the licence? — or give it to the public domain. The answers pick one of CC0, CC BY, BY-SA, BY-NC, BY-ND, BY-NC-SA, BY-NC-ND, or all rights reserved, explained in plain words (EN and IT) with a link to the deed. Two warnings come with a Creative Commons choice: it cannot be withdrawn for copies already shared, and it may clash with a collecting society (SIAE, PRS, ASCAP…).
- What the song contains, from its regions and the ledger: imported samples (a licence select each,
sample_licenses), library loops (CC0), parts made by AI engines (their weights' licence), your own recordings. Each is checked against the song's licence. NC material can't go in a song that allows commercial use, ND can't be mixed in, SA must match, unknown or all-rights-reserved material can't go under Creative Commons, and BY material can't go in CC0. A conflict is named by sample, here and in Problems (lint rulerelease-license). - Where it can go, only platforms with an open upload API: SoundCloud, YouTube, Mixcloud, Audius, Internet Archive, Funkwhale, Wikimedia Commons. Each shows ready or what stops it:
- the Archive needs Creative Commons, and an upload there is permanent;
- Commons takes only CC0, BY and BY-SA;
- YouTube takes only its standard licence or CC BY;
- Mixcloud takes at most 5 tags;
- a cover is required for YouTube.
With a CC licence, the list of platforms it can go to.
- A generated cover in four styles and a set of palettes, deterministic by seed (Another one changes the seed). Your own image can be used instead (
cover.kind: image). - The AI-use statement is written from the song's ledger (which engines made which parts) and can be edited.
- The Release Kit is one zip:
- the master as 24-bit FLAC at 48 kHz, with Vorbis comments (TITLE, ARTIST, GENRE, DATE, DESCRIPTION, CONTACT, COPYRIGHT, LICENSE, COMMENT with the AI use) and the cover as its PICTURE block;
cover.pngat 3000 px;LICENSE.txt;CREDITS.txt, with the AI use;lyrics.txt;- an LRC synchronised from the lyrics' alignment.
The FLAC encoder is our own (fixed predictors, Rice coding) and decodes bit-exact with the referenceflac(unit test).
- MCP tools (new toolset
release, 165 tools in all):get_release,set_release,check_release,generate_cover,export_release_kit. - Not yet: publishing to the platforms (G6c, with mock servers and a confirmation in the studio for every upload) and the YouTube video (G6b).
- Tests: unit tests for licences, conflicts, platform checks and the FLAC round trip. In Chrome (
npm run e2e, release), 13 checks:- a CC BY-NC sample in a CC BY song is named, in
check_releaseand in Problems; - the Internet Archive refuses all rights reserved;
- "not commercial, may change it" picks CC BY-NC, which Commons refuses and SoundCloud accepts;
- the kit holds a FLAC whose tags carry the title and licence, the PNG cover, LICENSE.txt, CREDITS.txt with the AI use, and an LRC with the line at 00:02.00 (bar 2 at 120 BPM);
- the tab shows the seven platforms.
- a CC BY-NC sample in a CC BY song is named, in
- Docs: the MCP tool count was out of date in README, FEATURES and AI-MODELS (149): it is 165.
OpenBand v0.6.31
E4 · Ensemble and taste: blind tests between engines, preferences, the GPU scheduler (SPEC v0.6 §6, §7)
- Ensemble variants as takes: variants from different engines arrive as takes of one region — now audio ones too, when each fills the bars in one piece (before, each went on a muted track of its own) — ready for a blind test, every take in the ledger with its engine.
- Blind tests of audio takes (they compared MIDI takes only): the region's clip switches with the letter, for listening only.
- Taste: every blind ranking becomes pairwise comparisons between the engines that made the takes (found through the ledger), per capability and style (funk, lo-fi, jazz… from the request), kept in this browser and never sent. A Bradley–Terry model (MM iterations, a weak prior of one win and one loss against an average engine, so two listens can't decide) gives each engine a score 0..1 with an interval; per style once a style has 5 comparisons of its own. The router weighs the score more as comparisons add up (0.25 → up to 0.6), so after about ten it changes its choice — and only then.
- Your engines in Ensemble: the ranking per capability, with comparisons, wins and the interval; Forget my preferences.
list_enginesshows the same taste and its routes now use it, likecreatedoes. - The GPU scheduler (
server/scheduler.mjs): engines on this computer that declare a GPU and a VRAM need (manifestruntime.device,vram_gb) take turns — one heavy model at a time per device, the studio's (interactive) requests before batch jobs, the least recently used engine unloaded (its process stopped) when another needs the room; the budget fromengines.json("gpu": { "vram_gb": 12 }, or per device), one loaded at a time without it. Their state (loaded, running, waiting) shows in Ensemble andlist_engines, and the router prefers an engine already loaded. Engines elsewhere (url) aren't scheduled. - Tests (the spec's acceptance: after 10 comparisons the router changes its choice coherently, with simulated preferences): with OpenBand's Drummer and another drum engine, 2 rankings for the other don't change the choice, 10 do; 10 split ones don't; funk and pop preferences each apply to their style; Bradley–Terry scores and intervals. Scheduler: one at a time per device, interactive before batch, devices in parallel, LRU unloading within the budget (6 + 6 GB over 10 → the older goes; the least recently used of two goes), one loaded without a budget, a failed job doesn't block the queue, which engines are scheduled. In Chrome (
npm run e2e, taste) with the OMEP mock engine installed: the Drummer plays first; ten variant pairs ranked for the other engine reach the router; then make drums asks it (80 % ± 19 against 20 %).
OpenBand v0.6.30
G5 · Parametric instruments, sounds from words, sounds from a sample, tone match (SPEC v0.6 G5)
- Parametric synths: the twelve synthesized presets are now data (which Tone synth plays them, with what options), and each exposes its parameters with range, scale (linear, log, integer, choice) and the preset's own value as default: amplitude envelope (attack, decay, sustain, release); filter cutoff and resonance — on the mono synths (basses, lead) the per-voice filter with its envelope amount and attack/decay/sustain, on the others a polyphony-safe filter after the voices, wide open by default; FM index, ratio and modulation decay/sustain on the electric piano and the bells; the wave (sine, triangle, sawtooth, square) where the preset has one; unison voices and detune on the pad and strings; level.
Track.synthParamskeeps only what differs from the preset, is saved with the song and exported, changes live without rebuilding the instrument (PolySynth.set), and is cleared when the preset changes. - Sound under Smart Controls: the parameters as knobs by group (log parameters turn on a log scale), Back to the preset, and Describe it.
- Sounds from words (
sound_from_words, Italian and English, inflections included): the words pick the family and the preset (bass, pad, pluck, lead, keys, bells, organ, strings; acid → Acid Line, wide → Aurora Pad, metallic → the bells, round → Sub Bass, 8-bit → the chip) and push its parameters — warm/caldo lower cutoff and little resonance, dark/scuro, bright/brillante, plucky no attack, short decay, no sustain, soft/morbido, aggressive, acid, wide/largo unison and detune, metallic FM, slow/lento about half a second of attack, long, short, round, retro — combinable, with what each word did. A starting point, no optimisation (that comes with matching a sample). - Tools:
set_synth_params(values, reset; without values the parameters with ranges and current values; unknown ones refused with the list),sound_from_words,apply_patch(on an instrument track, or a new one). One undo step each. - Tests (the spec's acceptance for words): "basso caldo plucky" → a bass with a 1 ms attack, no sustain and a cutoff below its preset's; "bright wide pad", "campane metalliche", "acid bass, aggressive", "archi morbidi e lenti"; every preset's defaults round-trip through the knobs' scale; parameters reach the voice; only changes are kept. In Chrome (
npm run e2e, synth): "pad brillante e largo" → Aurora Pad with 6 voices on a new track; cutoff 500 Hz darkens the rendered note (spectral centroid 1743 → 737 Hz); one undo step; an unknown parameter refused. - Sound-alike (
match_sound; Like this sample → Find the sound under Sound): one note in — a sample, an audio region or a stretch of the reference track — and the three closest patches of OpenBand's synths out, with a similarity, each with an A/B against the original at the same loudness (each at its own sample rate) and Use. In the browser, nothing uploaded. How: the note's pitch (YIN, median of the voiced frames), how long it sounds and how long it is held (where the envelope leaves its sustain); features on 10 ms frames — 64-band log-mel, 13 MFCCs, centroid, flatness, the RMS envelope with attack (10→70 % of the peak, so beating unison voices don't fool it), decay and sustain; a distance of log-mel frame by frame from the onset, the envelopes aligned with a light DTW, the mean MFCCs, the envelope's shape and brightness over time, levels matched first. The search: every compatible preset probed at its defaults, at the target's own envelope and at five cutoffs, and at each wave; the three best start a coarse coordinate sweep each (the held time first, then cutoff and ADSR), so they compete fairly; the winner gets a second coarse sweep, finer ones, and CMA-ES (a small implementation of our own: rank-one and rank-μ updates, step-size adaptation, ask/tell, seeded) with the filter's and FM's shape too. Candidates render in their own short offline contexts, all at once (Chrome renders them on their own threads): 300 renders in 4–8.5 s.familyandwordsnarrow it; WAM plugins as targets: not yet. - Tone match (
tone_match; Tone like on audio tracks): the long-term spectrum in third-octaves against a reference's, six peaking bands (100 Hz – 10 kHz, ±12 dB) fitted to the difference, and the amp's drive tried from 0 to 0.8 by rendering the track; applied as one undo step, with how far apart they were before and after. - Acceptance, measured honestly (
npm run e2e, soundmatch: 20 seeded cases, a preset rendered with random known cutoff and ADSR, then searched blind): the first candidate's similarity is ≥ 0.9 in 18 of 20 (the spec asks all), its main parameters within 15 % of their range in 12 of 20 (the spec asks ≥ 80 %), every search under 10 s. What misses is mostly what can barely be heard — decay under a high sustain, release traded for a shorter note, lookalike presets (a triangle sub bass and the lead on a triangle) — and the plucked unison. The test guards these levels; the gap to the spec stays open. - Fixes found on the way: (1) exports could be out of tune: Tone.js shares its PeriodicWaves across audio contexts, so a preset with custom partials or unison voices that had played live at 48 kHz rendered 1.5 semitones flat in a 44.1 kHz export; each wave now keeps to its own context (
src/audio/toneFix.ts; e2e tuning: felt piano, finger bass and aurora pad exported in tune after playing live); (2) the synths' filters are kept under Nyquist at low sample rates; (3) the pitch tracker and the new features read fractional sample indices at some sample rates (16 / 22.05 kHz) and found nothing there.
OpenBand v0.6.29
G4 · Talking to the studio with the instrument in your hands, and sessions that pick the best take (SPEC v0.6 G4)
- Voice commands in Italian and English, the spec's list: registra / record (one-bar count-in, from the bar you're on), stop, ancora / again (records again from the same bar after a take, plays again otherwise), riascolta / play back, dal ritornello / from the chorus (and dalla seconda strofa, from verse two), dalla battuta nove / from bar nine, loop sul ritornello / loop the chorus, loop via, punch dalla nove alla dodici (said inclusive), segna errore / mark error, buona questa / good one, tieni questa / keep this one (makes the last take active and marks it good), cancella l'ultima take / delete the last take, metronomo più forte / più piano / via, più lento / più veloce, tempo novanta, più me in cuffia / more me (input monitoring level), meno basi / less track (playback level in the headphones — both listening only, never exported), annulla / undo. Each runs as the user's own action.
- A small fixed grammar (
src/voice/grammar.ts): the command words, numbers 1–299 as they are said (ventuno, centoventi, one hundred twenty; Italian compounds glued or spaced), section words and the song's own section names. It is robust to what a small model really hears: punch (English) dropped by the Italian model, dal swallowed, to heard as two. - Recognition in the browser with Vosk (vosk-browser, Apache-2.0; WebAssembly, loaded only when used and kept out of the offline precache), offline and private. The small Italian and English models (49.7 / 41.2 MB, Apache-2.0) are downloaded once with the user's OK from Hugging Face mirrors pinned to a commit and checked against the SHA-256 of the official files (the official host sends no CORS headers); the page repacks the zip as the tar.gz vosk-browser reads (a small ustar writer) and keeps it in Cache Storage. The browser's Web Speech API is the alternative, with the warning that some browsers send the audio online. CSP:
connect-srcallowsblob:(the recognizer's worker loads the model the page checked). - Push-to-talk: hold `, or a MIDI pedal learnt with Learn (a pedal taken for talking no longer marks flubs). A level meter on the voice button while listening. Wake word: not yet.
- Spoken answers (speechSynthesis, can be turned off, never while recording): "Dalla battuta 9", "Take registrata". A phrase that isn't a command goes to a listening AI as an
askevent (context.voice), and the user gets the list of commands. Every command is avoice_commandevent. set_voice_control(recording toolset): on/off, engine, language, the pedal's CC, spoken answers. The voice button and its panel in the toolbar.- Acceptance: 120 of 120 test phrases recognized (100 %; the spec asks ≥ 95 %) — the spec's 20 commands, in each language, said by three macOS voices (
say), through the studio's own grammar and model loader with the official models (node scripts/voice-accuracy/run.mjs <models folder>, local). In Chrome (npm run e2e, voice): what each spoken command does to the song — the playhead to the chorus and bar 9, the chorus looped, a flub, 90 → 85 BPM, the click louder then off, the backing −3 dB in the headphones, undo, the AI fallback, English; withOPENBAND_VOSK_DIRalso for real: a fake microphone says "dalla battuta nove" while ` is held, Vosk in the studio hears it and the playhead moves to bar 9. Not done: the 10 real (human) recordings of the acceptance set. - A command said during a take is silenced in it (10 ms fades, 50 ms margin) — the push-to-talk window mapped from the browser's clock onto the recording's — so "segna errore" never ends up in the mix.
- Session mode (Session in the microphone menu,
start_session, or "sessione sul ritornello, cinque passaggi" / "session on the chorus, five passes"): the section loops with a count-in, every pass becomes a take, flubs (voice, pedal, key) attach to the take being recorded; then each take is scored bar by bar — pitch against the guide melody (the lyrics' melody, or a lead part; YIN, cents with octave errors forgiven), onset timing against the sixteenths, clipping; MIDI takes by timing and notes out of the key — and the score shows beside each take. The comp takes, for each bar, the best take without a mistake there (a flub costs 60 points, a good mark gives 8) and joins them with equal-power 10 ms crossfades into a Session comp take, made active, to compare with the best single take (start_ab_test). "Basta così" / "that's enough" (stop_session) stops it: the passes so far are kept and comped.get_session; eventssession_take,session_done. - Fixes: cycle recording with no armed or chosen track now makes its takes (it made one long clip); the pitch tracker read a fractional index at some sample rates (16 kHz among them) and found no pitch there.
- Session acceptance, in Chrome (
npm run e2e, session): three passes through the (fake) microphone → three scored takes; five sung takes of a guide melody with simulated flubs (take 3, the most in tune, slips in bar 2; take 5 in bar 4) → the comp is take 3 · 5 · 3 · 3, never a take where it slipped, and it is the active take. Unit tests: pitch against the guide (in tune vs 70 cents sharp), timing (on the grid vs 40 ms late), clipping, silence, MIDI out of the key, the comp choice, the crossfaded audio comp, and a span silenced in a buffer with its fades.
OpenBand v0.6.28
E3 (part 5) · omep-diffsinger, locally and on a GPU machine (SPEC v0.6 §10)
omep-diffsinger("builtin": "omep-diffsinger"withrepo,exp,python): DiffSinger (openvpi, Apache-2.0) with the user's own install and voicebank as avoice.singengine. The song context becomes a DiffSinger.ds— phrases split at rests (gaps under 0.12 s are sung legato), each opening with a short rest that carries the first onset; per note its vowel and coda plus the next syllable's onset consonants (DiffSinger puts the vowel on the note's start), soph_numgroups and every group'sph_duradds up to its note;note_seq/note_dur/note_slur; anf0_seqevery 5 ms with 40 ms glides — and the acoustic model runs (scripts/infer.py acoustic … --exp --out --title --seed [--spk --lang]), no variance model needed. A 0.3 s pre-roll gives the first consonants room; the answer is cut to the scope.- Phonemes: OpenBand's (Italian by rule, from v0.6.27) mapped to the voicebank's with
phonemes,lang_prefixfor multilingual banks. No Italian DiffSinger voicebank was found published, so none is suggested. - The voicebank's licence is in the manifest (
weights,commercial, a CC-BY attribution made from its name when none is given) and in the ledger of every part it sings. The router puts DiffSinger before OpenBand's guide voice. - On a GPU machine: the adapter serves MCP over Streamable HTTP (
--http <port>, bearerOMEP_TOKEN, required beyond this computer), returning the voice inline;deploy/diffsinger/has a Dockerfile (DiffSinger pinned, the adapter with exactly its packages) and a guide in EN/IT for RunPod, Modal, a Space or a server, reached from OpenBand as aurlengine. - Tests: the
.dsagainst DiffSinger's own sample format (rests, onsets, groups summing to notes, f0 length and the first note at 220 Hz); against a stand-in forscripts/infer.pythat checks the file as DiffSinger reads it and sings its f0 as a sine: the engine over MCP gives a valid contribution with the voicebank's licence, exactly the scope's length with the pre-roll cut (the first note at 220 Hz), the syllables' timing, a missing voicebank said plainly; over HTTP the token is required and the voice comes back inline — run also with exactly the packages the image installs. In Chrome (npm run e2e, diffsinger) throughengines.jsonand the real engine host: Sing it is sung by DiffSinger, not the guide voice; it getsn o t t e a t r a s t e v e r e; the ledger has the voicebank's CC-BY-4.0 with its attribution. - Not done here: building the Docker image (no Docker daemon on this machine) and singing with a real voicebank.
OpenBand v0.6.27
E3 (part 4) · voice.sing, sing, and the song context speaking Italian (SPEC v0.6 §8.1, §10)
- Italian G2P by rule (
src/lyrics/g2p.it.ts): every syllable's phonemes in a small X-SAMPA-like set — soft and hard c/g (the i of cia/gio only softens), ch/gh, gn → J, gli → L, sc(i) → S, qu → k w, silent h, s voiced between vowels and before voiced consonants, z → dz at the start of a word and ts elsewhere, doubled affricates holding their stop (piz-za → t | ts), glides j/w, open E/O where the spelling marks them (è, ò). Synalepha syllables carry both vowels (te‿a → t e a). - The Song Context Package now gives every aligned syllable its beat (
start_beat, from the scope, like notes) and duration (dur, held through a melisma), and in Italian its phonemes — so a singing engine needs no language of its own (as §10 asks of DiffSinger). sing(capability tool and MCP task; Sing it in the Lyrics panel): a voice sings the melody track (by default the lyrics' melody) on the lyrics, on a new vocal track, one undo step, through the router (voice.sing) and conformance like any part. Without lyrics the melody is sung on "a", and the answer says how to add words.- OpenBand Guide voice (builtin,
voice.sing, MIT): a small formant synthesizer — a glottal pulse at the note's pitch with portamento and vibrato, three resonances per vowel gliding between them, noise for fricatives, stop and burst for plosives, a murmur for nasals and liquids. Instant and offline; a guide vocal to hear the topline with its words, not a finished voice. Its contribution carries the syllables' timing (alignment.syllables). It stands in: the router puts any singing engine the user installed before it. - Docs:
separate(added in v0.6.25) andsingin the tools list. - Tests: the G2P on the tricky words (chiesa, figlio, sciare, quando, sbaglio, zero, pizza, faccia, oggi, caffè, però, piede, uomo) and a whole line; the guide voice sings the note's pitch (A3 within 8 Hz), an /a/ and an /i/ have their formants where they belong, syllables land on their notes, a melisma keeps its vowel, no words → "a". In Chrome (
npm run e2e, sing): notte a Trastevere on a melody — the context givesn o t | t e a | t r a | s t e | v e | r eon beats 0–5, the guide voice sings it on a vocal track at 220.5 Hz for the A3 it starts on, in the ledger. - Next (E3 part 5): DiffSinger as a singing engine (the user's own install and voicebank; no Italian DiffSinger voicebank was found published).
OpenBand v0.6.26
E3 (part 3) · omep-ace-step: songs, layers, repaints and restyles from a local ACE-Step 1.5 (SPEC v0.6 §10)
omep-ace-step("builtin": "omep-ace-step"in~/.openband/engines.json): ACE-Step 1.5 (MIT code and weights, commercial use allowed, under 4 GB of VRAM, CUDA/MPS/ROCm/CPU) as an OMEP engine, through the REST server ACE-Step ships (uv run acestep-api) — the user installs and starts it; OpenBand installs no Python and downloads no weights.music.song→text2music(words, lyrics as the song's lines or[Instrumental], tempo, key as "A minor", meter, length, seed);music.add_layer→legowith ACE-Step's track for the instrument named (strings, guitar, keys…; base models only, so the manifest offers it only with"model": "acestep-v15-base");music.repaint→repaintof the bars;music.restyle→cover. Each is an MCP task; the answer is cut to the scope. If the server isn't running, the error says how to start it.- The song's audio for engines that listen (any engine whose manifest asks for
context_audio, local or online):createandtransformnow render it once per request and send it — the mix of the bars for a layer; for a repaint the part being changed with two bars around it; for a restyle that part — exactly those bars, without the render's reverb tail. - Tests: the mapping onto ACE-Step's tasks; against a mock of its REST API, written from its server code (
release_taskwith thesrc_audioupload,query_result's JSON-string results with status 0/1/2,/v1/audio?path=, Bearer key): submit, follow, download, a failed run and a wrong key said plainly, the repaint window inside the context audio, the answer trimmed to the scope; the engine over MCP gives valid OMEP contributions and offersadd_layeronly on a base model. In Chrome (npm run e2e, acestep) throughengines.jsonand the real engine host in front of a fake ACE-Step server: a layer goes as alegotask with exactly the 8 s of mix of its 4 bars, a restyle as acoverof that track alone, both placed and in the ledger. - Not run here against the real ACE-Step weights (it would need running ACE-Step's own code on this machine). Next (E3 part 4): Italian phonemes in the song context,
voice.sing,singand DiffSinger.
OpenBand v0.6.25
E3 (part 2) · Demucs in the browser, the separate tool, and isolating a new layer (SPEC v0.6 §7 step 5, §10)
openband-demucs, a builtin OMEP engine foraudio.separate: HT-Demucs v4 (Meta, MIT) runs in the browser with onnxruntime-web on WebAssembly, in a Worker — free, private (the audio never leaves the computer) and offline. The song is cut into the model's 7.8-second segments overlapping by a quarter, crossfaded and summed back (the song's own first and last samples are not faded, unlike the reference script). Runs on one thread unless the page is cross-origin isolated: about 2.7 × the audio's length on this Mac (10 s in 34 s, the model's load included). The runtime (13.5 MB) is bundled but fetched only when someone separates, and kept out of the offline precache.- The model (166 MB, StemSplit's single-file ONNX export with fp16 weights, MIT) is never bundled and never downloaded without the user's OK: from Hugging Face, pinned to a commit, checked against its SHA-256 (a file that doesn't match is not used), kept in the browser's Cache Storage. Ensemble → Stem separation shows it, downloads it with progress, removes it. An AI that asks for a separation without the model is told to ask the user and retry with
confirm_download: true; the studio never falls back to an online separator for that. The CSP allowshuggingface.coand*.hf.co. separate(capability tool, also an MCP task; Separate stems in an audio region's editor): the region becomes drums, bass, other and vocals on their own tracks right under the original, which is muted, not removed — one undo step; silent stems are left out (a song without vocals gets no vocals track);stemspicks some. Stretch, pitch and gain carry over. Routed like every engine (Demucs on fal only when online engines are allowed, with its quote and budget); each stem is in the ledger with engine, model hash and licence.- Conformance step 5, isolation: when an engine asked for a layer (
add_layer,repaint) answers the full mix, OpenBand separates the answer and the same bars of the song, keeps the stems where the answer has energy the song doesn't (spectral difference per stem; the role asked for keeps its stem), subtracts what is still the song (a soft spectral mask) and places the new part alone, saying which stems it kept. Without the model it places the answer as it came and says why. - Tests (the spec's acceptance): the overlap-add rebuilds every stem exactly where the model is exact — seams and edges included — and stops when cancelled; isolation keeps the new keys over a context bass (correlation > 0.98 with the keys) and finds nothing new in an answer that is just the context; the model is not fetched without consent, is checked, kept (no second download) and removed. In Chrome (
npm run e2e, separate) with the shipped runtime and worker and a 211-byte stand-in model of the same shape (scripts/e2e/fixtures/): asked before the download, four stems in the ledger with the source muted, every stem exactly its share of 10 s of stereo across two segments, one undo, downloaded once. WithOPENBAND_DEMUCS_MODEL=<the real model>the same test runs the real HT-Demucs: the low note lands in bass, the chord in other, drums near silence, no vocals track. - Not yet (E3 part 3): local ACE-Step and DiffSinger with Italian phonemes, and
sing. separateis the 32nd tool an AI sees first (core + capability, as §8.1 lists it); 150 tools in all.