Wednesday, 12 September 2012

ASIO Recording in NAudio

It’s been a long time coming, but I’ve finally checked in support for ASIO recording in NAudio. It’s not actually too difficult to implement, but the main problem has been finding the time for it, and how best to present the feature within the NAudio API. I decided in the end to just do the simplest thing that works. This means simply extending the AsioOut class to allow you to optionally record at the same time as playing with NAudio.

To initiate ASIO Recording, there is a new InitRecordAndPlayback method, which allows you to specify how many channels to record. If you are only recording, and not playing back as well, then you need to tell it what sample rate you would prefer in a third parameter (leaving the input IWaveProvider null).

this.asioOut.InitRecordAndPlayback(null, recordChannelCount, 44100);

I’ve also added an InputChannelOffset property, which means you can skip over some of the input channels to select just the input you want. Obviously in the future it would be better to let you pick explicitly which inputs you want to record from.

To start recording (and playback), you simply call the Play method, and you must explicitly stop recording yourself. You are alerted of new audio available via the AudioAvailable event. This gives you an AudioAvailableEventArgs which gives you direct access to the ASIO driver’s record buffers for maximum performance, along with AsioSampleType which tells you what format the audio is in:

public class AsioAudioAvailableEventArgs : EventArgs

    /// <summary>
    /// Pointer to a buffer per input channel
    /// </summary>
    public IntPtr[] InputBuffers { get; private set; }

    /// <summary>
    /// Number of samples in each buffer
    /// </summary>
    public int SamplesPerBuffer { get; private set; }

    /// <summary>
    /// Audio format within each buffer
    /// Most commonly this will be one of, Int32LSB, Int16LSB, Int24LSB or Float32LSB
    /// </summary>
    public AsioSampleType AsioSampleType { get; private set; }

    /// <summary>
    /// Converts all the recorded audio into a buffer of 32 bit floating point samples, interleaved by channel
    /// </summary>
    /// <returns>The samples as 32 bit floating point, interleaved</returns>
    public float[] GetAsInterleavedSamples() ...

The GetAsInterleavedSamples is a helper method to make working with the recorded audio easier. It creates a float array, and reads the recorded samples into that, converting from 16 or 24 bit if necessary (only the most common ASIO sample types are supported). This saves you from having to write your own unsafe C# code if you are not comfortable with that. Remember that this callback is happening from within the ASIO driver itself, so you must return as quickly as possible. If you crash while in this callback you could find your ASIO driver fails and you may need to reboot your computer to recover the audio device.

I’ve updated the NAudioDemo application to include a simple demonstration of ASIO recording in action, so if you can, test it out with your soundcard and let me know how you get on. I am aware that the public interface for this feature is a bit of a hack, but time does not permit me at the moment to polish it further. Hopefully a future version of NAudio will feature an improved ASIO API, but for NAudio 1.6 there will at least be a way to do recording with ASIO.

Post a Comment