From dc666016db1c043150f89991b8f3890f5a6f9690 Mon Sep 17 00:00:00 2001 From: MelekTaus Date: Thu, 8 Oct 2026 21:22:59 +0200 Subject: [PATCH] Let solo win over the mute of the same track (#358) A track with both M and S on stayed silent: the mute closed every send before solo was asked. Pressing S on a muted track is meant to hear it. - trackGates in routing.ts opens the sends of a soloed track even while it is muted. Its own items are heard as with solo alone. - A muted track that a soloed one goes through, or that goes into it, stays silent as before. Tests: - Unit song-routing and song: 28 green (1 new), a counter-check red Co-Authored-By: Claude Opus 5.5 --- src/core/music/routing.ts | 7 ++++--- tests/core/song-routing.test.ts | 9 +++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/core/music/routing.ts b/src/core/music/routing.ts index 0ddc5bd9..cac04bc4 100644 --- a/src/core/music/routing.ts +++ b/src/core/music/routing.ts @@ -128,8 +128,9 @@ export interface TrackGate { /** * Mute and solo along the routing. A muted track passes nothing on, whatever comes in and on every - * send. While some are soloed, a soloed track is heard with all that goes into it; the tracks it - * goes through on its way out pass it on, their own items silent; every other track is silent. + * send, unless it is soloed itself. While some are soloed, a soloed track is heard with all that goes + * into it; the tracks it goes through on its way out pass it on, their own items silent; every other + * track is silent. * Only the ways through a soloed track are open: a track that goes into one sends nothing past it. */ export function trackGates( @@ -158,7 +159,7 @@ export function trackGates( for (const track of tracks) gates.set(track.id, { // What a soloed track went through goes on everywhere; the rest only on towards a soloed one. - passes: (to) => !track.mute && (fed.has(track.id) || feeding.has(to)), + passes: (to) => (track.solo || !track.mute) && (fed.has(track.id) || feeding.has(to)), own: feeding.has(track.id), }); return gates; diff --git a/tests/core/song-routing.test.ts b/tests/core/song-routing.test.ts index 4ea132de..b57f2ca4 100644 --- a/tests/core/song-routing.test.ts +++ b/tests/core/song-routing.test.ts @@ -248,6 +248,15 @@ describe('what the buses of a routed song are set to (#350)', () => { ); }); + it('hears a soloed track even while it is muted', () => { + expect(heard(([a, ...rest]) => [{ ...a!, solo: true, mute: true }, ...rest])).toEqual({ + a: ['1', 1], + b: ['1', 0], + c: ['1', 1], + d: ['0', 0], + }); + }); + it('reads the sends of a song made before #350 as every track into the output', () => { const tracks = [{ ...newTrack(1), id: 'a' }]; expect(songRoutes({ tracks })).toEqual([{ from: 'a', to: '', volume: 0, tap: 'post' }]);