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"/>
<Button Command="{Binding SetPointACommand}"
Width="60"
Height="32"
Width="40"
Height="40"
Grid.Column="1"
Margin="0,0,6,0">
<Grid>
<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"/>
<Path Stroke="#e0e0e0"
StrokeThickness="2"
Fill="Transparent"
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"/>
Data="M 26 8
L 26 32
L 14 32
L 24 20
L 14 8
L 26 8" />
</Grid>
</Button>
<Button Command="{Binding SetPointBCommand}"
Width="60"
Height="32"
Width="40"
Height="40"
Grid.Column="2">
<Grid>
<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"/>
<Path Stroke="#e0e0e0"
StrokeThickness="2"
Fill="Transparent"
Data="
M 10 2.44 L 18.4 2.44
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
"/>
Data="M 14 8
L 14 32
L 26 32
L 16 20
L 26 8
L 14 8"/>
</Grid>
</Button>
</Grid>

View File

@ -50,20 +50,36 @@ public sealed class AudioMixer : IAudioMixer
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 + 1] = 0f;
continue;
}
var l = inChannels > 1 ? inSpan[i * inChannels + 0] : inSpan[i];
var r = inChannels > 1 ? inSpan[i * inChannels + 1] : inSpan[i];
if (inChannels == 1)
{
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
var l = inSpan[baseIndex + 0];
var r = inSpan[baseIndex + 1];
outSpan[i * 2 + 0] += l * leftGain;
outSpan[i * 2 + 1] += r * rightGain;
}
}
}
return new MixedAudioBlock(outBuf, frames, _outputChannels, sampleRate, position);

View File

@ -343,9 +343,17 @@ public sealed class StemPlaybackEngine : IStemPlaybackEngine, IDisposable
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)
_decodedFramePosition = loopEnd;
break;
_decodedFramePosition = loopStart;
// continue decoding from the loop start
continue;
}
lock (_stateLock)

View File

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

View File

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