Fixed mono stems mixing

This commit is contained in:
Alexander Shabarshov 2026-07-25 11:02:03 +01:00
parent d14c07f457
commit 72b4a16378
5 changed files with 50 additions and 42 deletions

View File

@ -194,49 +194,33 @@
Margin="0,0,6,0"/> Margin="0,0,6,0"/>
<Button Command="{Binding SetPointACommand}" <Button Command="{Binding SetPointACommand}"
Width="60" Width="40"
Height="32" Height="40"
Grid.Column="1" Grid.Column="1"
Margin="0,0,6,0"> Margin="0,0,6,0">
<Grid> <Grid>
<Path Fill="#0080ff" <Path Fill="#0080ff"
Data="M 30 6 L 46 18 L 38 18 L 38 26 L 22 26 L 22 18 L 14 18 Z"/> Data="M 26 8
<Path Stroke="#e0e0e0" L 26 32
StrokeThickness="2" L 14 32
Fill="Transparent" L 24 20
Data="M 20 5 L 34 35 H 28 L 25 25 H 15 L 12 35 H 6 Z M 20 13 L 17 21 H 23 Z"/> L 14 8
L 26 8" />
</Grid> </Grid>
</Button> </Button>
<Button Command="{Binding SetPointBCommand}" <Button Command="{Binding SetPointBCommand}"
Width="60" Width="40"
Height="32" Height="40"
Grid.Column="2"> Grid.Column="2">
<Grid> <Grid>
<Path Fill="#0080ff" <Path Fill="#0080ff"
Data="M 30 26 L 46 14 L 38 14 L 38 6 L 22 6 L 22 14 L 14 14 Z"/> Data="M 14 8
<Path Stroke="#e0e0e0" L 14 32
StrokeThickness="2" L 26 32
Fill="Transparent" L 16 20
Data=" L 26 8
M 10 2.44 L 18.4 2.44 L 14 8"/>
A 6 6 0 0 1 24.4 8.44
A 6 6 0 0 1 18.4 14.44
L 22 14.44
A 5.4 5.4 0 0 1 27.4 19.84
A 5.4 5.4 0 0 1 22 25.24
L 10 25.24 Z
M 19 7.24 L 19 10.44
L 25 10.44
A 1.2 1.2 0 0 0 26.2 9.24
A 1.2 1.2 0 0 0 25 7.24 Z
M 19 14.44 L 19 19.04
L 25 19.04
A 1.8 1.8 0 0 0 26.8 17.24
A 1.8 1.8 0 0 0 25 14.44 Z
"/>
</Grid> </Grid>
</Button> </Button>
</Grid> </Grid>

View File

@ -50,18 +50,34 @@ public sealed class AudioMixer : IAudioMixer
for (var i = 0; i < frames; i++) for (var i = 0; i < frames; i++)
{ {
if (i * inChannels + 1 >= inSpan.Length) var baseIndex = i * inChannels;
// If there are no samples for this frame, skip
if (baseIndex >= inSpan.Length)
{ {
outSpan[i * 2 + 0] = 0f; outSpan[i * 2 + 0] = 0f;
outSpan[i * 2 + 1] = 0f; outSpan[i * 2 + 1] = 0f;
continue; continue;
} }
var l = inChannels > 1 ? inSpan[i * inChannels + 0] : inSpan[i]; if (inChannels == 1)
var r = inChannels > 1 ? inSpan[i * inChannels + 1] : inSpan[i]; {
var inp = inSpan[baseIndex];
outSpan[i * 2 + 0] += inp * leftGain;
outSpan[i * 2 + 1] += inp * rightGain;
}
else
{
// ensure both left and right samples exist for multi-channel input
if (baseIndex + 1 >= inSpan.Length)
continue; // or treat missing right as 0, depending on desired behavior
outSpan[i * 2 + 0] += l * leftGain; var l = inSpan[baseIndex + 0];
outSpan[i * 2 + 1] += r * rightGain; var r = inSpan[baseIndex + 1];
outSpan[i * 2 + 0] += l * leftGain;
outSpan[i * 2 + 1] += r * rightGain;
}
} }
} }

View File

@ -343,9 +343,17 @@ public sealed class StemPlaybackEngine : IStemPlaybackEngine, IDisposable
if (loopEnabled && loopEnd > loopStart && nextPosition >= loopEnd) if (loopEnabled && loopEnd > loopStart && nextPosition >= loopEnd)
{ {
// Rewind decoders to the loop start and continue decoding so playback loops
foreach (var d in decodersSnapshot)
{
try { d.Seek(loopStart); } catch { }
}
lock (_stateLock) lock (_stateLock)
_decodedFramePosition = loopEnd; _decodedFramePosition = loopStart;
break;
// continue decoding from the loop start
continue;
} }
lock (_stateLock) lock (_stateLock)

View File

@ -147,7 +147,7 @@ public sealed class AudioMixer_Tests
[TestMethod] [TestMethod]
[TestCategory("ProductionBugSuspected")] [TestCategory("ProductionBugSuspected")]
[Ignore("ProductionBugSuspected")] //[Ignore("ProductionBugSuspected")]
public void Mixer_Handles_Mono_Stem() public void Mixer_Handles_Mono_Stem()
{ {
// mono block // mono block

View File

@ -302,7 +302,7 @@ public sealed class StemPlaybackEngine_Tests
public async Task LoopRegion_SeeksBackOnBoundary() public async Task LoopRegion_SeeksBackOnBoundary()
{ {
var pool = new AudioBufferPool(); var pool = new AudioBufferPool();
var decoderFactory = new MockDecoderFactory(pool, 1024, 5); var decoderFactory = new MockDecoderFactory(pool, 44100, 5);
var output = new MockOutput(); var output = new MockOutput();
var mixer = new MockMixer(pool); var mixer = new MockMixer(pool);
var stretch = new MockTimeStretch(); var stretch = new MockTimeStretch();
@ -320,7 +320,7 @@ public sealed class StemPlaybackEngine_Tests
await engine.LoadSessionAsync(session, new DummyProgressReporter()); await engine.LoadSessionAsync(session, new DummyProgressReporter());
await engine.PlayAsync(); await engine.PlayAsync();
await Task.Delay(TimeSpan.FromSeconds(3)); await Task.Delay(TimeSpan.FromSeconds(6));
await engine.StopAsync(); await engine.StopAsync();