Search code examples
naudioasio

NAudio - ASIO Playback to device (static only)


I'm trying to route ASIO audio to my playback devices, however, all I hear is static.

ASIO Setup

BIT_PER_SAMPLE = 24

SAMPLE_RATE = 48000

Currently, trying with 1 channel into 1 playback device called "Line 1" for testing. The playback of the sound is static.

EDIT: The code below has been updated. It will take 64 channels of ASIO input and route them one at a time into Waveout devices (I'm using Virtual Audio Cable to create them)

    private static AsioOut asioOut;
    private static AsioInputPatcher inputPatcher;
    private static readonly int BIT_PER_SAMPLE = 16;
    private static readonly int SAMPLE_RATE = 48000;
    private static readonly int NUMBER_OF_CHANNELS = 64;

    private static BufferedWaveProvider[] bufferedWaveProviders = new BufferedWaveProvider[NUMBER_OF_CHANNELS];
    private static WaveOut[] waveouts = new WaveOut[NUMBER_OF_CHANNELS];

    [STAThread]
    static void Main(string[] args)
    {
        InitDevices();
        Record();
        while (true)
        {
            Console.WriteLine("Recording...press any key to Exit.");

            Console.ReadKey(true);
            break;
        }

        asioOut.Stop();
        asioOut.Dispose();
        asioOut = null;
    }

    private static void Record()
    {
        inputPatcher = new AsioInputPatcher(SAMPLE_RATE, NUMBER_OF_CHANNELS, NUMBER_OF_CHANNELS);

        asioOut = new AsioOut(AsioOut.GetDriverNames()[0]);
        asioOut.InitRecordAndPlayback(new SampleToWaveProvider(inputPatcher),
            NUMBER_OF_CHANNELS, 0);
        asioOut.AudioAvailable += OnAsioOutAudioAvailable;
        asioOut.Play();
    }

    private static void InitDevices()
    {
        for (int n = -1; n < WaveOut.DeviceCount; n++)
        {
            WaveOutCapabilities caps = WaveOut.GetCapabilities(n);
            if (caps.ProductName.StartsWith("Line"))
            {
                int _number = int.Parse(caps.ProductName.Split(' ')[1]);

                if (_number <= NUMBER_OF_CHANNELS)
                {
                    waveouts[_number - 1] = new WaveOut() { DeviceNumber = n };
                    bufferedWaveProviders[_number - 1] = new BufferedWaveProvider(new WaveFormat(SAMPLE_RATE, BIT_PER_SAMPLE, 2));
                    waveouts[_number - 1].Init(bufferedWaveProviders[_number - 1]);
                    waveouts[_number - 1].Play();
                }
            }
        }
    }
    static void OnAsioOutAudioAvailable(object sender, AsioAudioAvailableEventArgs e)
    {
        inputPatcher.ProcessBuffer(e.InputBuffers, e.OutputBuffers,
            e.SamplesPerBuffer, e.AsioSampleType);

        for (int outputChannel = 0; outputChannel < e.OutputBuffers.Length; outputChannel++)
        {
            byte[] buf = new byte[e.SamplesPerBuffer * (BIT_PER_SAMPLE / 8)];
            Marshal.Copy(e.OutputBuffers[outputChannel], buf, 0, e.SamplesPerBuffer * (BIT_PER_SAMPLE / 8));

            bufferedWaveProviders[outputChannel].AddSamples(buf, 0, buf.Length);
        }

        e.WrittenToOutputBuffers = true;
    }

Solution

  • There are two main problems with your code. First, InputBuffers is one per channel, not sample. Second, when you set e.WrittenToOutputBuffers = true you are saying that you have written to e.OutputBuffers which you haven't. So they will just contain uninitialized data.

    If you want to see an example of low-level manipulation of ASIO buffers, then check out my ASIO patch bay sample project.