Search code examples
c++audioasiosteinberg-asio

C++ ASIO, accessing buffers


I have no experience in audio programming and C++ is quite low level language so I have a little problems with it. I work with ASIO SDK 2.3 downloaded from http://www.steinberg.net/en/company/developers.html.

I am writing my own host based on example inside SDK.

For now I've managed to go through the whole sample and it looks like it's working. I have external sound card connected to my PC. I've successfully loaded driver for this device, configured it, handled callbacks, casting data from analog to digital etc. common stuff.

And part where I am stuck now: When I play some track via my device I can see bars moving in the mixer (device's software). So device is connected in right way. In my code I've picked the inputs and outputs with the names of the bars that are moving in mixer. I've also used ASIOCreateBuffers() to create buffer for each input/output.

  1. Now correct me if I am wrong: When ASIOStart() is called and driver is in running state, when I input the sound signal to my external device I believe the buffers get filled with data, right?

  2. I am reading the documentation but I am a bit lost - how can I access the data being sent by device to application, stored in INPUT buffers? Or signal? I need it for signal analysis or maybe recording in future.

EDIT: If I had made it to complicated then in a nutshell my question is: how can I access input stream data from code? I don't see any objects/callbacks letting me to do so in documentation.


Solution

  • The hostsample in the ASIO SDK is pretty close to what you need. In the bufferSwitchTimeInfo callback there is some code like this:

    for (int i = 0; i < asioDriverInfo.inputBuffers + asioDriverInfo.outputBuffers; i++)
    {
        int ch = asioDriverInfo.bufferInfos[i].channelNum;
        if (asioDriverInfo.bufferInfos[i].isInput == ASIOTrue)
        {
            char* buf = asioDriver.bufferInfos[i].buffers[index];
            ....
    

    Inside of that if block asioDriver.bufferInfos[i].buffers[index] is a pointer to the raw audio data (index is a parameter to the method).

    The format of the buffer is dependent upon the driver and that can be discovered by testing asioDriverInfo.channelInfos[i].type. The types of formats will be 32bit int LSB first, 32bit int MSB first, and so on. You can find the list of values in the ASIOSampleType enum in asio.h. At this point you'll want to convert the samples to some common format for downstream signal processing code. If you're doing signal processing you'll probably want convert to double. The file host\asioconvertsample.cpp will give you some idea of what's involved in the conversion. The most common format you're going to encounter is probably INT32 MSB. Here is how you'd convert it to double.

    for (int i = 0; i < asioDriverInfo.inputBuffers + asioDriverInfo.outputBuffers; i++)
    {
        int ch = asioDriverInfo.bufferInfos[i].channelNum;
        if (asioDriverInfo.bufferInfos[i].isInput == ASIOTrue)
        {
            switch (asioDriverInfo.channelInfos[i].type)
            {
                case ASIOInt32LSB:
                {
                    double* pDoubleBuf = new double[_bufferSize];
                    for (int i = 0 ; i < _bufferSize ; ++i)
                    {
                        pDoubleBuf[i] = *(int*)asioDriverInfo.bufferInfos.buffers[index] / (double)0x7fffffff;
                    }
                    // now pDoubleBuf contains one channels worth of samples in the range of -1.0 to 1.0.
                    break;
                }
                // and so on...