Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
<PackageVersion Include="Microsoft.Extensions.ObjectPool" Version="10.0.11" />
<PackageVersion Include="ModelContextProtocol" Version="2.2.0" />
<PackageVersion Include="ModelContextProtocol.AspNetCore" Version="2.2.0" />
<PackageVersion Include="NAudio.Core" Version="2.3.0" />
<PackageVersion Include="NAudio.Core" Version="3.0.1" />
Comment thread
yuto-trd marked this conversation as resolved.
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.9.0" />
<PackageVersion Include="Nito.AsyncEx" Version="5.1.2" />
<PackageVersion Include="NuGet.Packaging" Version="7.9.0" />
Expand Down
10 changes: 5 additions & 5 deletions src/Beutl.Engine/Audio/Graph/Nodes/ResampleNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ public AudioBuffer Read(int sampleCount)
try
{
var buffer = new float[sampleCount * _channelCount];
int samplesRead = _wdlResampler!.Read(buffer, 0, buffer.Length);
int samplesRead = _wdlResampler!.Read(buffer.AsSpan());

// Copy interleaved samples back to AudioBuffer
for (int ch = 0; ch < _channelCount; ch++)
Expand Down Expand Up @@ -320,13 +320,13 @@ public void Append(AudioBuffer buffer)
_inputBuffers.Enqueue(buffer);
}

public int Read(float[] buffer, int offset, int count)
public int Read(Span<float> buffer)
{
if (_disposed)
return 0;

int total = 0;
while (total < count)
while (total < buffer.Length)
{
if (_currentBuffer is null)
{
Expand All @@ -337,7 +337,7 @@ public int Read(float[] buffer, int offset, int count)
_position = 0;
}

int samplesPerChannel = (count - total) / ChannelCount;
int samplesPerChannel = (buffer.Length - total) / ChannelCount;
int availableSamples = _currentBuffer.SampleCount - _position;
int samplesToRead = Math.Min(samplesPerChannel, availableSamples);
if (samplesToRead <= 0)
Expand All @@ -351,7 +351,7 @@ public int Read(float[] buffer, int offset, int count)
{
for (int ch = 0; ch < ChannelCount; ch++)
{
buffer[offset + total + i * ChannelCount + ch]
buffer[total + i * ChannelCount + ch]
= _currentBuffer.GetChannelData(ch)[_position + i];
}
}
Expand Down
41 changes: 25 additions & 16 deletions src/Beutl.Engine/Audio/Graph/Nodes/SpeedNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -443,13 +443,11 @@ private bool BeginStream(double outputStartSeconds, double sourceStartSeconds, b
// stream never jumps between chunks. Advances the cursor by what was actually produced (short
// only at end-of-source) and returns that count.
private int Read(
float[] buffer,
int interleavedOffset,
int count,
Span<float> buffer,
AudioProcessContext context,
bool draining)
{
if (count <= 0)
if (buffer.IsEmpty)
return 0;

// Derive each sub-range from the exact sample cursor to avoid repeated samples at fractional rates.
Expand All @@ -465,7 +463,7 @@ private int Read(
TimeSpan sourceStart = TimeSpan.FromTicks(sourceStartTicks);
var range = new TimeRange(
sourceStart,
AudioProcessContext.GetDurationForSampleCount(count, _sampleRate));
AudioProcessContext.GetDurationForSampleCount(buffer.Length / _channels, _sampleRate));
var subContext = new AudioProcessContext(
range,
_sampleRate,
Expand All @@ -480,15 +478,15 @@ private int Read(
: _speedNode.Inputs[0].Process(subContext);
var leftData = result.GetChannelData(0);
var rightData = result.GetChannelData(1);
int samplesToRead = Math.Min(count, result.SampleCount);
int samplesToRead = Math.Min(buffer.Length / _channels, result.SampleCount);
for (int i = 0; i < samplesToRead; i++)
{
buffer[interleavedOffset + i * _channels] = leftData[i];
buffer[interleavedOffset + i * _channels + 1] = rightData[i];
buffer[i * _channels] = leftData[i];
buffer[i * _channels + 1] = rightData[i];
}

_srcReadPos += samplesToRead;
return samplesToRead;
return samplesToRead * _channels;
}

public AudioBuffer ProcessBuffer(
Expand Down Expand Up @@ -529,10 +527,17 @@ public AudioBuffer ProcessBuffer(
int framesDone = 0;
while (framesDone < expectedOut)
{
int want = _rs.ResamplePrepare(expectedOut - framesDone, _channels, out float[] inBuf, out int inOff);
int got = Read(inBuf, inOff, want, context, draining);

int made = _rs.ResampleOut(dst, framesDone * _channels, got, expectedOut - framesDone, _channels);
int want = _rs.ResamplePrepare(
expectedOut - framesDone,
_channels,
out Span<float> inBuf);
int got = Read(inBuf[..(want * _channels)], context, draining) / _channels;

int made = _rs.ResampleOut(
dst.AsSpan(framesDone * _channels, (expectedOut - framesDone) * _channels),
got,
expectedOut - framesDone,
_channels);

// No output and no input means the source is exhausted; the tail-fill below pads the
// rest. (got > 0 with made == 0 just means the resampler needs more lookahead.)
Expand Down Expand Up @@ -590,10 +595,14 @@ public AudioBuffer ProcessBufferWithVariableSpeed(
double vAvg = sumSpeed / framesThis;
ConfigureVariableResampling(vAvg);

int want = _rs.ResamplePrepare(framesThis, _channels, out float[] inBuf, out int inOff);
int got = Read(inBuf, inOff, want, context, draining);
int want = _rs.ResamplePrepare(framesThis, _channels, out Span<float> inBuf);
int got = Read(inBuf[..(want * _channels)], context, draining) / _channels;

int made = _rs.ResampleOut(dst, framesDone * _channels, got, framesThis, _channels);
int made = _rs.ResampleOut(
dst.AsSpan(framesDone * _channels, framesThis * _channels),
got,
framesThis,
_channels);

if (made == 0 && got == 0)
break;
Expand Down
2 changes: 1 addition & 1 deletion src/Beutl.Engine/Media/Decoding/SampleProviderReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public static Ref<IPcm> ReadStereo(ISampleProvider provider, int sampleRate, int

// ToStereo() yields 2 floats per frame, so the provider's element count maps to frames via /2.
float[] buffer = new float[length * 2];
int frames = provider.Read(buffer, 0, buffer.Length) / 2;
int frames = provider.Read(buffer.AsSpan()) / 2;
if (frames <= 0)
return Ref<IPcm>.Create(new Pcm<Stereo32BitFloat>(sampleRate, 0));

Expand Down
1 change: 1 addition & 0 deletions src/Beutl.ProjectSystem/Beutl.ProjectSystem.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<PackageReference Include="Microsoft.Extensions.FileSystemGlobbing" />
<PackageReference Include="Microsoft.Extensions.Logging" />
<PackageReference Include="Microsoft.Extensions.ObjectPool" />
<PackageReference Include="NAudio.Core" />
<PackageReference Include="ReactiveProperty" />
<PackageReference Include="SkiaSharp" />
<PackageReference Include="SkiaSharp.HarfBuzz" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ public FakeSampleProvider(int totalFrames, int maxReturnFrames = int.MaxValue)

public WaveFormat WaveFormat { get; }

public int Read(float[] buffer, int offset, int count)
public int Read(Span<float> buffer)
{
int available = Math.Max(0, _totalFrames - _position);
int frames = Math.Min(Math.Min(count / 2, available), _maxReturnFrames);
int frames = Math.Min(Math.Min(buffer.Length / 2, available), _maxReturnFrames);
for (int i = 0; i < frames; i++)
{
int idx = _position + i;
buffer[offset + i * 2] = idx;
buffer[offset + i * 2 + 1] = -idx;
buffer[i * 2] = idx;
buffer[i * 2 + 1] = -idx;
}
_position += frames;
return frames * 2;
Expand All @@ -52,11 +52,11 @@ private sealed class OddFloatProvider : ISampleProvider
{
public WaveFormat WaveFormat { get; } = WaveFormat.CreateIeeeFloatWaveFormat(SampleRate, 2);

public int Read(float[] buffer, int offset, int count)
public int Read(Span<float> buffer)
{
int floats = Math.Min(count, 3); // always 3 floats = 1.5 frames
int floats = Math.Min(buffer.Length, 3); // always 3 floats = 1.5 frames
for (int i = 0; i < floats; i++)
buffer[offset + i] = i;
buffer[i] = i;
return floats;
}
}
Expand Down
Loading