Let the places of a song share what it keeps to itself (#357)
With clips, one take serves many items: four items on the four clips of one take. The rule from #355 gave every further place its own copy of an embedded asset, so a cut made in the Sound tab reached one item only. Now the song, its tracks and its items share a sound, a pattern or a sound FX the song keeps. - settleEmbedded no longer copies within the song. An embedded asset stays as long as one place names it, and goes with the last one. - A paste from another song still gets a copy, but one copy for all the places naming the same asset, with its clip ids mapped. - The picks in a song offer what the song keeps, under a line after the project's assets: the Sound row of an item the song's sounds and their clips, the Pattern row its patterns, every sound FX pick its sound FX. - Make project asset and Embed a copy are unchanged. The project cbbf160bb7e8 was merged by hand afterwards: the items of Song 2 on three copies of Take 1 now play the same clips of the first one, and the copies are gone. Tests: - Unit embedded, sound-clips, own-fx and the song tests: 66 green, 3 counter-checks red as expected - e2e 65 on melektaus-atx: ALL PASSED, 52 checks - Gate on melektaus-atx: CHECK EXIT 0, 271 files, 4198 tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
95edf9959b
commit
e721bba120
6 files changed
+131
-56
No files matched your search
+23
-17
@@ -1,9 +1,9 @@
|
||||
/**
|
||||
* What a song keeps to itself (#355): a sound, a pattern or a sound FX made in a song is an asset like
|
||||
* any other, so everything that finds an asset by its id finds it, but its `owner` names the song.
|
||||
* The lists of assets leave it out, and it has exactly one user in its song: the song itself, a
|
||||
* track or an item. `settleEmbedded` holds a song to that after every edit, so a split, a duplicate
|
||||
* or a paste gets a copy of its own and what nothing uses any more goes.
|
||||
* The lists of assets leave it out. The places of its song may share it (#357): the song itself, its
|
||||
* tracks and its items. `settleEmbedded` holds a song to that after every edit, so a paste from another
|
||||
* song gets a copy of its own and what nothing uses any more goes.
|
||||
*/
|
||||
import type { Graph } from '../graph/Graph';
|
||||
import { SOUND_FX_INPUT, SOUND_FX_OUTPUT } from '../graph/nested';
|
||||
@@ -185,10 +185,11 @@ export interface Settled {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds the song to one user per embedded asset, writing the places in `tracks` and `items` (fresh
|
||||
* lists the caller owns): a place naming an asset of the song that an earlier place claimed, or one of
|
||||
* another song, gets a copy; one naming an asset that is gone but in `spare` – what was copied along
|
||||
* with items – gets that back. The song's own props are only read: they claim, never copy.
|
||||
* Holds the song to what it keeps to itself, writing the places in `tracks` and `items` (fresh lists
|
||||
* the caller owns). The places of the song share its assets (#357), so the clips of one take serve
|
||||
* many items. A place naming an asset of another song gets a copy, one for all places naming it; one
|
||||
* naming an asset that is gone but in `spare` – what was copied along with items – gets that back.
|
||||
* The song's own props are only read: they claim, never copy.
|
||||
*/
|
||||
export function settleEmbedded(
|
||||
project: Project,
|
||||
@@ -199,6 +200,7 @@ export function settleEmbedded(
|
||||
): Settled {
|
||||
const claimed = new Set<string>();
|
||||
const added: Asset[] = [];
|
||||
const copies = new Map<string, Map<string, string>>();
|
||||
const taken = new Set(project.assets.map((a) => a.id));
|
||||
const own = { ...song.props };
|
||||
slotsOf(own, tracks, items).forEach((slot, index) => {
|
||||
@@ -207,20 +209,24 @@ export function settleEmbedded(
|
||||
const found = assetNamedBy(project.assets, slot.id) ?? assetNamedBy(added, slot.id);
|
||||
const source = found ?? assetNamedBy(spare, slot.id);
|
||||
if (!source || !slot.types.includes(source.type) || (found && !isEmbedded(found))) return;
|
||||
if (found?.owner === song.id && !claimed.has(found.id)) {
|
||||
if (found?.owner === song.id) {
|
||||
claimed.add(found.id);
|
||||
return;
|
||||
}
|
||||
if (index === 0) return;
|
||||
const fresh = found !== undefined || taken.has(source.id);
|
||||
const id = fresh ? newId() : source.id;
|
||||
const copy = ownedBy({ ...structuredClone(source), id }, song);
|
||||
const ids = new Map([[source.id, id]]);
|
||||
if (fresh) renewClipIds(copy, ids);
|
||||
taken.add(id);
|
||||
added.push(copy);
|
||||
claimed.add(id);
|
||||
slot.set(ids.get(slot.id) ?? id);
|
||||
let ids = copies.get(source.id);
|
||||
if (!ids) {
|
||||
const fresh = found !== undefined || taken.has(source.id);
|
||||
const id = fresh ? newId() : source.id;
|
||||
const copy = ownedBy({ ...structuredClone(source), id }, song);
|
||||
ids = new Map([[source.id, id]]);
|
||||
if (fresh) renewClipIds(copy, ids);
|
||||
copies.set(source.id, ids);
|
||||
taken.add(id);
|
||||
added.push(copy);
|
||||
claimed.add(id);
|
||||
}
|
||||
slot.set(ids.get(slot.id) ?? ids.get(source.id) ?? slot.id);
|
||||
});
|
||||
const dropped = project.assets.filter((a) => a.owner === song.id && !claimed.has(a.id)).map((a) => a.id);
|
||||
return { added, dropped };
|
||||
|
||||
Reference in new issue
Block a user