Take one sound at the Output of an instrument, mixed by a Mix #331
The Output summed any number of edges as layers. That made it the only sound input of its kind, and it read as if a note could be several voices. A note was always one voice, but the graph did not say so. Now the Output takes one sound like every other sound input, and several are put together with a Mix in front of it (decided by the user after #331). - The Output's input is no longer `many`. A second edge replaces the first, as at any data input. - With only one drum sounding for a note, a Mix is its other side. A drum kit keeps the volume of each drum. - An instrument saved with several edges into the Output keeps them but does not compile. The Output says "Takes one sound: put a Mix in front of it to play several". No saved project has one: the only instrument there (cbbf160bb7e8) has a single edge. - An Output with nothing in it is a problem now, not silence. - The compiler gathers only triggers from several edges. The player still takes a list of layers, which an instrument fills with one. Tests: - instrument.test.ts: drum kit through a Mix, a second edge replacing the first, an old Output with two edges, an empty Output (33 tests) - Counter-check: `many` back on the Output turns 15 tests red, the new one about the second edge among them - e2e 34 on melektaus-atx: ALL PASSED, 47 checks - Gate on melektaus-atx: CHECK EXIT 0, 244 test files, 3789 tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
23bdc3f775
commit
076c564415
3 files changed
+61
-20
No files matched your search
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* An instrument (#331) is a graph that makes a note a sound: Notes nodes bring the note in, Samples
|
||||
* play sounds for it, the effects of a sound FX shape them and the Output sums them. It is compiled
|
||||
* play sounds for it, the effects of a sound FX shape and mix them, and the Output takes one. It is compiled
|
||||
* once per note; a trigger is on only for the notes it stands for.
|
||||
*/
|
||||
import { describe, expect, it } from 'vitest';
|
||||
@@ -183,7 +183,7 @@ describe('compiling a note', () => {
|
||||
expect(way(compile(f, 67).layers[0])?.pitch).toEqual([]);
|
||||
});
|
||||
|
||||
it('a drum kit: one Notes node with single notes, a Sample on each, both into the Output', () => {
|
||||
it('a drum kit: one Notes node with single notes, a Sample on each, mixed into the Output', () => {
|
||||
const f = emptyInstrument();
|
||||
const notes = f.edit.addNode('InstrumentNotes', {
|
||||
from: '36',
|
||||
@@ -193,13 +193,16 @@ describe('compiling a note', () => {
|
||||
});
|
||||
const kick = f.edit.addNode('InstrumentSample', { sound: f.sound('Kick', KICK).id, followNote: false });
|
||||
const snare = f.edit.addNode('InstrumentSample', { sound: f.sound('Snare', SNARE).id, play: 'oneshot' });
|
||||
const mix = f.edit.addNode('SoundFxMix', { mix: 0.5 });
|
||||
const output = f.edit.addNode('InstrumentOutput');
|
||||
f.edit.connect(notes, 'n36', kick, 'trigger');
|
||||
f.edit.connect(notes, 'n38', snare, 'trigger');
|
||||
f.edit.connect(kick, 'out', output, 'in');
|
||||
f.edit.connect(snare, 'out', output, 'in');
|
||||
// The Output takes both: a second edge into it does not replace the first.
|
||||
expect(f.instrument.graph.edges.filter((e) => e.to.node === output.id)).toHaveLength(2);
|
||||
f.edit.wire([
|
||||
[notes, 'n36', kick, 'trigger'],
|
||||
[notes, 'n38', snare, 'trigger'],
|
||||
[kick, 'out', mix, 'a'],
|
||||
[snare, 'out', mix, 'b'],
|
||||
[mix, 'out', output, 'in'],
|
||||
]);
|
||||
// Only one drum sounds for a note, so the Mix is the other side and plays it at its own volume.
|
||||
const files = (note: number) => compile(f, note).layers.map((plan) => way(plan)?.source?.file);
|
||||
expect(files(36)).toEqual([KICK]);
|
||||
expect(files(38)).toEqual([SNARE]);
|
||||
@@ -219,6 +222,43 @@ describe('compiling a note', () => {
|
||||
expect(def.outputs).toHaveLength(4 + 12);
|
||||
});
|
||||
|
||||
it('takes one sound at the Output: a second edge replaces the first', () => {
|
||||
const f = emptyInstrument();
|
||||
const notes = f.edit.addNode('InstrumentNotes');
|
||||
const a = f.edit.addNode('InstrumentSample', { sound: f.sound('A', KICK).id });
|
||||
const b = f.edit.addNode('InstrumentSample', { sound: f.sound('B', SNARE).id });
|
||||
const output = f.edit.addNode('InstrumentOutput');
|
||||
f.edit.wire([
|
||||
[notes, 'any', a, 'trigger'],
|
||||
[notes, 'any', b, 'trigger'],
|
||||
[a, 'out', output, 'in'],
|
||||
[b, 'out', output, 'in'],
|
||||
]);
|
||||
const into = f.instrument.graph.edges.filter((e) => e.to.node === output.id);
|
||||
expect(into.map((e) => e.from.node)).toEqual([b.id]);
|
||||
expect(compile(f, 60).layers.map((plan) => way(plan)?.source?.file)).toEqual([SNARE]);
|
||||
});
|
||||
|
||||
it('says so of an Output saved with more than one sound, which it played together then', () => {
|
||||
const f = makeInstrument();
|
||||
const sample = nodeOf(f, 'InstrumentSample');
|
||||
sample.params.sound = f.sound('A', KICK).id;
|
||||
const output = nodeOf(f, 'InstrumentOutput');
|
||||
const edge = f.instrument.graph.edges.find((e) => e.to.node === output.id)!;
|
||||
f.instrument.graph.edges.push({ ...edge, id: 'second' });
|
||||
expect(compile(f, 60)).toMatchObject({
|
||||
layers: [],
|
||||
problems: { [output.id]: 'Takes one sound: put a Mix in front of it to play several' },
|
||||
});
|
||||
});
|
||||
|
||||
it('an Output with nothing in it says so', () => {
|
||||
const f = makeInstrument();
|
||||
const output = nodeOf(f, 'InstrumentOutput');
|
||||
f.instrument.graph.edges = f.instrument.graph.edges.filter((e) => e.to.node !== output.id);
|
||||
expect(compile(f, 60)).toMatchObject({ layers: [], reason: 'Nothing comes in: connect it to a Sample' });
|
||||
});
|
||||
|
||||
it('two Notes nodes over one Sample: a trigger takes more than one edge, either one plays it', () => {
|
||||
const f = emptyInstrument();
|
||||
const low = f.edit.addNode('InstrumentNotes', { from: '48', to: '52' });
|
||||
|
||||
Reference in new issue
Block a user