A sound could only be cut to one stretch, set on the asset itself. To
play two parts of one file, the file had to be imported twice. Now a
sound is always the whole file, and its clips are the stretches of it,
each with a name and a cut of its own.
- A clip is { id, name, props } on SoundAsset.clips. Its id shares the
generator with asset ids, so a sound field holds a sound or a clip,
as a texture field holds a texture or a frame.
- props are the cut: start, end, the fades and their curves, reverse.
Volume, loop, sound FX and bus stay on the sound for all its clips.
The cut rows left the sound's schema for CLIP_ROWS.
- findSound resolves either id. Play sound, the Sample of an
instrument, a Reverb impulse, song items, the scheduler and the test
sound of the Sound FX tab all go through it.
- Every sound field offers each sound followed by its clips, "Kick",
"Kick / Clip 1". A clip that is gone reads as "<id>?".
- The Sound tab has a strip under the ruler with the clips as bands.
A drag there makes a clip, a click picks one, beside the bands the
sound. Only the picked clip has handles. Reverse, fades and curves
in the header work on it and are greyed out without one.
- Whole file is gone from the header, as the user asked.
- Picking a clip is a selection of its own, like a frame. The
inspector shows its name, its cut rows and Delete clip. Delete
takes it away without asking, as with a frame. Ctrl+Z brings it
back.
- Copies get fresh clip ids: Duplicate, Embed a copy, a song
duplicated with its takes, and the copy a split or paste makes of
an embedded take. An item on a clip plays the same clip of its copy.
- A double-click on a song item playing a clip opens its sound with
the clip picked. The Sound row of an item on an embedded take
offers the take and its clips, which no list shows.
- A new take stays the whole sound. Clips are made by hand, as the
user decided.
- No migration in the code, as the user decided. The one project
with cut sounds was changed over by hand.
Deviation from the issue: deleting a used clip does not warn. A frame
does not warn either, and the issue had promised "like a frame".
Tests:
- Unit sound-clips (new): 11 green, 7 counter-checks each red
- Unit sounds, embedded: adjusted to clips, green
- e2e 34 (melektaus-atx): ALL PASSED, 90 checks (3 new, 12 rewritten)
- Counter-check in the browser: clips left out of the sound fields,
the picker check fails
- Gate (melektaus-atx): CHECK EXIT 0, 271 files, 4194 tests
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A sound FX for one place in a song had to be a project asset, which
then stood in every picker. Now every pick of a sound FX in a song
can make one the song keeps for that place alone, on top of the
embedded assets of the first two parts.
- Create sound FX sits at the end of the Sound FX row of the song,
a track and an item, and of the menu of a track's FX button. It
makes "Sound FX 1", 2, … per song with the Input wired to the
Output, picks it and opens it. That is one undo step.
- Embed a copy, while the place names a project FX, gives the place
a copy under the same name.
- While the place names its own, the menu shows it with the mark and
offers Edit sound FX and Make project asset.
- Picking anything else lets it go in the same undo step. For a
track or an item `settleEmbedded` did that already. For the song's
own row `AssetPropertyCommand` now settles the song after `fx`.
- The mark `•` moved to the core. `assetRefLabel` puts it in front of
an embedded asset, so the inspector rows show it like the timeline.
- `FieldHandlers.moreChoices` lets a caller end a reference menu
with entries of its own. `embeddedPatternName` is `embeddedName`
with a base now.
Tests:
- Unit own-fx (new): 6 green, 6 counter-checks each red
- Unit embedded and 80 neighbouring files: 1434 green
- e2e 65 (melektaus-atx): ALL PASSED, 51 checks (2 new)
- Gate (melektaus-atx): CHECK EXIT 0, 270 files, 4178 tests
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A pattern for one song had to be made in the Assets panel first and
dragged in, and then stood in every picker of the project. Now a
right-click on an empty spot of a track makes one the song keeps to
itself, on top of the embedded assets of the first part.
- Create pattern lays an item from the grid line before the spot,
a bar long, and opens the pattern in its tab. Pattern, item and
name are one undo step. The name is "Pattern 1", 2, … per song.
- It plays the instrument of the track's pattern item that starts
last before the spot, else of the first one after it. An item's
own pick counts before its pattern's.
- An embedded pattern runs on the song's clock. It takes the tempo
and the meter of the song, and a change on the song moves it along
in the same undo step (`AssetPropertyCommand`).
- Its rows Tempo, Beats per bar, Beat and Bus are hidden, as the
song decides them. Length, grid, instrument and sound FX stay.
- A copy that comes to a song (Embed a copy, a paste from another
song) takes that song's clock. Made a project asset, it keeps the
values it had.
- `CreateAssetCommand` takes an owner. `embeddedCopy` takes the song
now, not its id.
- The cleanup of e2e 65 also takes what the song keeps.
Tests:
- Unit embedded: 18 green (5 new), 6 counter-checks each red
- Unit take, song, pattern and the asset commands: green
- e2e 65 (melektaus-atx): ALL PASSED, 49 checks (2 new)
- Gate (melektaus-atx): CHECK EXIT 0, 269 files, 4172 tests
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A take used to land in the Assets panel as "Song – Take N", next to
every other sound of the project. Now a song can keep a sound, a
pattern or a sound FX to itself: an ordinary asset whose new field
`owner` names the song. Everything that finds an asset by its id
finds it, so playing, the tabs and the game need no change. Only
the places that list assets leave it out.
- `core/music/embedded.ts` holds the rules: which types can be
embedded, `listedAssets`, the title "Song › Take 1", and the
rows an embedded sound hides (Loop, Bus).
- One user per embedded asset. `SetSongCommand` settles the song
after every edit: a place naming an asset an earlier place
claimed, or one of another song, gets a copy, and what nothing
names any more goes in the same undo step. The outcome is worked
out once, so a redo brings back the same copies.
- A split, Ctrl+D and a paste get that for free. The clipboard
keeps the embedded assets of the copied items, so a paste after a
delete brings the take back.
- Deleting a song deletes what it keeps. Duplicating it copies
that and points the copy at the copies. A duplicate of an
embedded asset is a project asset.
- The item menu has Open, Make project asset and Embed a copy.
- An embedded item carries a bullet in front of its name. The
first pick was a diamond, which the gate's font test refused:
the UI font has no glyph for it.
- A take is "Take 1", 2, … numbered per song. With the song gone
while it uploads, it becomes a project sound under a free name.
- Left out of: the Assets panel, every asset picker, the sound FX
menu of a track, the test sound of the Sound FX tab and the
naming of new assets. Delete on an embedded asset only says
where it lives. A ping lights up its song.
- Loading drops an `owner` whose song is gone, the asset stays as
a project asset. No migration: older projects have no owner.
Tests:
- Unit embedded (new): 13 green, 6 counter-checks each red
- Unit take, song, song-edit, asset-fx, asset-ref, serialize and
neighbours: 116 green
- e2e 65 (melektaus-atx): ALL PASSED, 47 checks (1 new)
- Counter-check e2e 65 (asset panel unfiltered): exactly that
check red
- Gate (melektaus-atx): CHECK EXIT 0, 269 files, 4167 tests
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>