Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set asio buffer size #914

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
98 changes: 86 additions & 12 deletions NAudio.Asio/ASIODriverExt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ public class AsioDriverExt
private int numberOfOutputChannels;
private int numberOfInputChannels;
private AsioFillBufferCallback fillBufferCallback;
private int bufferSize;
private int outputChannelOffset;
private int inputChannelOffset;
public Action ResetRequestCallback;
Expand Down Expand Up @@ -169,10 +168,12 @@ public AsioFillBufferCallback FillBufferCallback
/// <summary>
/// Creates the buffers for playing.
/// </summary>
/// <param name="numberOfOutputChannels">The number of outputs channels.</param>
/// <param name="numberOfInputChannels">The number of input channel.</param>
/// <param name="useMaxBufferSize">if set to <c>true</c> [use max buffer size] else use Prefered size</param>
public int CreateBuffers(int numberOfOutputChannels, int numberOfInputChannels, bool useMaxBufferSize)
/// <param name="numberOfOutputChannels"></param>
/// <param name="numberOfInputChannels"></param>
/// <param name="bufferSize"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
public int CreateBuffers(int numberOfOutputChannels, int numberOfInputChannels, int bufferSize = -1)
{
if (numberOfOutputChannels < 0 || numberOfOutputChannels > capability.NbOutputChannels)
{
Expand Down Expand Up @@ -213,17 +214,30 @@ public int CreateBuffers(int numberOfOutputChannels, int numberOfInputChannels,
bufferInfos[totalIndex].pBuffer1 = IntPtr.Zero;
}

if (useMaxBufferSize)
bool bufferSizeWentWrong = false;
try
{
// use the drivers maximum buffer size
bufferSize = capability.BufferMaxSize;
bufferSize = EnsureBufferSize(bufferSize);
CreateAsioBuffer(nbTotalChannels, bufferSize);
}
else
catch
{
bufferSizeWentWrong = true;
}

if (bufferSizeWentWrong)
{
// use the drivers preferred buffer size
bufferSize = capability.BufferPreferredSize;
CreateAsioBuffer(nbTotalChannels, bufferSize);
}

// Check if outputReady is supported
isOutputReadySupported = (driver.OutputReady() == AsioError.ASE_OK);
return bufferSize;
}

private void CreateAsioBuffer(int nbTotalChannels, int bufferSize)
{
unsafe
{
fixed (AsioBufferInfo* infos = &bufferInfos[0])
Expand All @@ -234,9 +248,57 @@ public int CreateBuffers(int numberOfOutputChannels, int numberOfInputChannels,
driver.CreateBuffers(pOutputBufferInfos, nbTotalChannels, bufferSize, ref callbacks);
}
}
}

// Check if outputReady is supported
isOutputReadySupported = (driver.OutputReady() == AsioError.ASE_OK);
private int EnsureBufferSize(int bufferSize)
{
// If a preference was not submitted than go for the preferred size
if (bufferSize == -1)
bufferSize = capability.BufferPreferredSize;
else if (bufferSize < capability.BufferMinSize)
bufferSize = capability.BufferMinSize;
else if (bufferSize > capability.BufferMaxSize)
bufferSize = capability.BufferMaxSize;
else
{
/* BUFFER GRANULARITY
* Calculating a supported buffer size can be made by starting from the minimum supported
* size (capability.BufferMinSize) and adding each time the value of granularity (capability.BufferGranularity).
* With a minimum of 8 and a granularity of 16 we got this possible values:
* 8, 24, 40, 56, 72, 88, 104, etc.. until max size is reached (capability.BufferMaxSize)
*/

// If the requested buffer size is not supported by granularity we choose the closest value supported
if ((bufferSize - capability.BufferMinSize) % capability.BufferGranularity != 0)
{
int prevBS = -1,
nextBs = -1;
for (int bs = capability.BufferMinSize; bs < capability.BufferMaxSize; bs += capability.BufferGranularity)
if (bs > bufferSize)
{
nextBs = bs;
prevBS = bs - capability.BufferGranularity;
break;
}
if (prevBS == -1 && nextBs == -1)
bufferSize = capability.BufferPreferredSize;
else if (prevBS == -1 && nextBs > 0)
bufferSize = nextBs;
else if (prevBS > 0 && nextBs == -1)
bufferSize = prevBS;
else
{
int diffPrev = bufferSize - prevBS,
diffNext = nextBs - bufferSize;
if (diffPrev == diffNext)
bufferSize = nextBs;
else if (diffPrev < diffNext)
bufferSize = diffPrev;
else if (diffPrev > diffNext)
bufferSize = diffNext;
}
}
}
return bufferSize;
}

Expand Down Expand Up @@ -284,6 +346,18 @@ private void BuildCapabilities()
driver.GetBufferSize(out capability.BufferMinSize, out capability.BufferMaxSize, out capability.BufferPreferredSize, out capability.BufferGranularity);
}

/// <summary>
/// Gets the size of the buffer.
/// </summary>
/// <param name="minSize">Size of the min.</param>
/// <param name="maxSize">Size of the max.</param>
/// <param name="preferredSize">Size of the preferred.</param>
/// <param name="granularity">The granularity.</param>
public void GetBufferSize(out int minSize, out int maxSize, out int preferredSize, out int granularity)
{
driver.GetBufferSize(out minSize, out maxSize, out preferredSize, out granularity);
}

/// <summary>
/// Callback called by the AsioDriver on fill buffer demand. Redirect call to external callback.
/// </summary>
Expand Down
25 changes: 20 additions & 5 deletions NAudio.Asio/AsioOut.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ public class AsioOut : IWavePlayer
private readonly SynchronizationContext syncContext;
private bool isInitialized;

public int PreferredBufferSize { get { return driver is null ? -1 : driver.Capabilities.BufferPreferredSize; } }

/// <summary>
/// Playback Stopped
/// </summary>
Expand Down Expand Up @@ -234,10 +236,14 @@ public void Init(IWaveProvider waveProvider)
/// <summary>
/// Initialises to play, with optional recording
/// </summary>
/// <param name="waveProvider">Source wave provider - set to null for record only</param>
/// <param name="recordChannels">Number of channels to record</param>
/// <param name="recordOnlySampleRate">Specify sample rate here if only recording, ignored otherwise</param>
public void InitRecordAndPlayback(IWaveProvider waveProvider, int recordChannels, int recordOnlySampleRate)
/// <param name="waveProvider"></param>
/// <param name="recordChannels"></param>
/// <param name="recordOnlySampleRate"></param>
/// <param name="bufferSize"></param>
/// <exception cref="InvalidOperationException"></exception>
/// <exception cref="NotSupportedException"></exception>
/// <exception cref="ArgumentException"></exception>
public void InitRecordAndPlayback(IWaveProvider waveProvider, int recordChannels, int recordOnlySampleRate, int bufferSize = -1)
{
if (isInitialized)
{
Expand Down Expand Up @@ -293,8 +299,12 @@ public void InitRecordAndPlayback(IWaveProvider waveProvider, int recordChannels
driver.FillBufferCallback = driver_BufferUpdate;

this.NumberOfInputChannels = recordChannels;
UpdateBufferSize(waveProvider, bufferSize);
}
public void UpdateBufferSize(IWaveProvider waveProvider, int bufferSize = -1)
{
// Used Prefered size of ASIO Buffer
nbSamples = driver.CreateBuffers(NumberOfOutputChannels, NumberOfInputChannels, false);
nbSamples = driver.CreateBuffers(NumberOfOutputChannels, NumberOfInputChannels, bufferSize);
driver.SetChannelOffset(ChannelOffset, InputChannelOffset); // will throw an exception if channel offset is too high

if (waveProvider != null)
Expand Down Expand Up @@ -410,6 +420,11 @@ public int PlaybackLatency
/// </summary>
public int DriverOutputChannelCount => driver.Capabilities.NbOutputChannels;

public void GetBufferSize(out int minSize, out int maxSize, out int preferredSize, out int granularity)
{
driver.GetBufferSize(out minSize, out maxSize, out preferredSize, out granularity);
}

/// <summary>
/// The number of samples per channel, per buffer.
/// </summary>
Expand Down