getRecordPosition Always Returns 0 for ASIO Driver when recording

I’m having trouble with ASIO in FMOD. When using WASAPI, everything works fine. However, when I switch the system output to FMOD_OUTPUTTYPE_ASIO, my ASIO driver (Focusrite USB ASIO) is detected without issues. The problem arises when I call system->getRecordPosition(recorddriver, &recordpos). The recordpos variable always returns 0, regardless of the actual position. Any ideas on what might be causing this issue? I’m using FMOD 2.02 for Unreal 5.4 on Visual Studio 2022 and copied the content of FMODStudio (not the Niagara)

The program simply tries to record audio input from ASIO drivers, the code is based on the FMOD examples, with slight modifications to adapt it to my version of FMOD:

/*===============================================================================================
Record to disk example
Copyright (c), Firelight Technologies Pty, Ltd 2004-2015.

This example shows how to do a streaming record to disk.
===============================================================================================*/
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <timeapi.h>

#include <fmod.hpp>
#include <fmod_errors.h>

#include <iostream>
#pragma comment(lib, "winmm.lib")

void ERRCHECK(FMOD_RESULT result)
{
    if (result != FMOD_OK)
    {
        printf("FMOD error! (%d) %s\n", result, FMOD_ErrorString(result));
        exit(-1);
    }
}

#if defined(WIN32) || defined(__WATCOMC__) || defined(_WIN32) || defined(__WIN32__)
#define __PACKED                         /* dummy */
#else
#define __PACKED __attribute__((packed)) /* gcc packed */
#endif


void WriteWavHeader(FILE* fp, FMOD::Sound* sound, int length)
{
    int             channels, bits;
    float           rate;

    if (!sound)
    {
        return;
    }

    fseek(fp, 0, SEEK_SET);

    sound->getFormat(0, 0, &channels, &bits);
    sound->getDefaults(&rate, 0);

    {
#if defined(WIN32) || defined(_WIN64) || defined(__WATCOMC__) || defined(_WIN32) || defined(__WIN32__)
#pragma pack(1)
#endif

        /*
            WAV Structures
        */
        typedef struct
        {
            signed char id[4];
            int         size;
        } RiffChunk;

        struct
        {
            RiffChunk       chunk           __PACKED;
            unsigned short  wFormatTag      __PACKED;    /* format type  */
            unsigned short  nChannels       __PACKED;    /* number of channels (i.e. mono, stereo...)  */
            unsigned int    nSamplesPerSec  __PACKED;    /* sample rate  */
            unsigned int    nAvgBytesPerSec __PACKED;    /* for buffer estimation  */
            unsigned short  nBlockAlign     __PACKED;    /* block size of data  */
            unsigned short  wBitsPerSample  __PACKED;    /* number of bits per sample of mono data */
        } FmtChunk = { {{'f','m','t',' '}, sizeof(FmtChunk) - sizeof(RiffChunk) }, 1, channels, (int)rate, (int)rate * channels * bits / 8, 1 * channels * bits / 8, bits } __PACKED;

        struct
        {
            RiffChunk   chunk;
        } DataChunk = { {{'d','a','t','a'}, length } };

        struct
        {
            RiffChunk   chunk;
            signed char rifftype[4];
        } WavHeader = { {{'R','I','F','F'}, sizeof(FmtChunk) + sizeof(RiffChunk) + length }, {'W','A','V','E'} };

#if defined(WIN32) || defined(_WIN64) || defined(__WATCOMC__) || defined(_WIN32) || defined(__WIN32__)
#pragma pack()
#endif

        /*
            Write out the WAV header.
        */
        fwrite(&WavHeader, sizeof(WavHeader), 1, fp);
        fwrite(&FmtChunk, sizeof(FmtChunk), 1, fp);
        fwrite(&DataChunk, sizeof(DataChunk), 1, fp);
    }
}


int main(int argc, char* argv[])
{
    int systemrate;
    FMOD_SPEAKERMODE speakermode;
    int speakermodechannels;
    FMOD_DRIVER_STATE state;
    FMOD::System* system = 0;
    FMOD::Sound* sound = 0;
    FMOD_RESULT            result;
    FMOD_CREATESOUNDEXINFO exinfo;
    int                    key, recorddriver, numdrivers, numconnected, count;
    unsigned int           version;
    FILE* fp;
    unsigned int           datalength = 0, soundlength;

    /*
        Create a System object and initialize.
    */
    result = FMOD::System_Create(&system);
    ERRCHECK(result);

    unsigned int bufferlength;
    int numbuffers;
    result = system->getDSPBufferSize(&bufferlength, &numbuffers);
    ERRCHECK(result);

    result = system->setDSPBufferSize(512, numbuffers);
    ERRCHECK(result);

    result = system->init(16, FMOD_INIT_NORMAL, 0);
    ERRCHECK(result);

    result = system->getVersion(&version);
    ERRCHECK(result);

    result = system->setOutput(FMOD_OUTPUTTYPE_ASIO);
    result = system->getRecordNumDrivers(&numdrivers, &numconnected);
    ERRCHECK(result);

    /*
        Enumerate record devices
    */
    printf("---------------------------------------------------------\n");
    printf("Choose a RECORD driver\n");
    printf("---------------------------------------------------------\n");
    for (count = 0; count < numdrivers; count++)
    {
        char name[256];

        result = system->getRecordDriverInfo(count, name, 256, 0, &systemrate, &speakermode, &speakermodechannels, &state);
        ERRCHECK(result);

        printf("%d : %s\n", count + 1, name);
    }
    printf("---------------------------------------------------------\n");
    printf("Press a corresponding number or ESC to quit\n");

    recorddriver = 0;
    do
    {
        key = _getch();
        if (key == 27)
        {
            return 0;
        }
        recorddriver = key - '1';
    } while (recorddriver < 0 || recorddriver >= numdrivers);

    memset(&exinfo, 0, sizeof(FMOD_CREATESOUNDEXINFO));

    exinfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO);
    exinfo.numchannels = 1;
    exinfo.format = FMOD_SOUND_FORMAT_PCM16;
    exinfo.defaultfrequency = 44100;
    exinfo.length = exinfo.defaultfrequency * sizeof(short) * exinfo.numchannels * 2;


    result = system->createSound("", FMOD_2D | FMOD_OPENUSER, &exinfo, &sound);
    ERRCHECK(result);


    printf("Press a key to start recording to record.wav\n");
    printf("\n");


    _getch();

    result = system->recordStart(recorddriver, sound, true);
    ERRCHECK(result);

    printf("Press 'Esc' to quit\n");
    printf("\n");

    fp = fopen("record.wav", "wb");
    if (!fp)
    {
        printf("ERROR : could not open record.wav for writing.\n");
        return 1;
    }

    /*
        Write out the wav header.  As we don't know the length yet it will be 0.
    */
    WriteWavHeader(fp, sound, datalength);

    result = sound->getLength(&soundlength, FMOD_TIMEUNIT_PCM);
    ERRCHECK(result);

    do
    {
        static unsigned int lastrecordpos = 0;
        unsigned int recordpos = 0;

        if (_kbhit())
        {
            key = _getch();
        }

        result = system->getRecordPosition(recorddriver, &recordpos);
        ERRCHECK(result);

        std::cout << recordpos << "\n";
        if (recordpos != lastrecordpos)
        {
            void* ptr1, * ptr2;
            int blocklength;
            unsigned int len1, len2;

            blocklength = (int)recordpos - (int)lastrecordpos;
            if (blocklength < 0)
            {
                blocklength += soundlength;
            }

            
            /*
                Lock the sound to get access to the raw data.
            */
            sound->lock(lastrecordpos * exinfo.numchannels * 2, blocklength * exinfo.numchannels * 2, &ptr1, &ptr2, &len1, &len2);   /* * exinfo.numchannels * 2 = stereo 16bit.  1 sample = 4 bytes. */
            /*
                Write it to disk.
            */
            if (ptr1 && len1)
            {
                datalength += fwrite(ptr1, 1, len1, fp);
            }
            if (ptr2 && len2)
            {
                datalength += fwrite(ptr2, 1, len2, fp);
            }
            /*
                Unlock the sound to allow FMOD to use it again.
            */
            sound->unlock(ptr1, ptr2, len1, len2);
        }

        lastrecordpos = recordpos;

        printf("%-23s. Record buffer pos = %6d : Record time = %02d:%02d\r", (timeGetTime() / 500) & 1 ? "Recording to record.wav" : "", recordpos, datalength / exinfo.defaultfrequency / exinfo.numchannels / 2 / 60, (datalength / exinfo.defaultfrequency / exinfo.numchannels / 2) % 60);

        system->update();

        Sleep(10);

    } while (key != 27);

    printf("\n");

    /*
        Write back the wav header now that we know its length.
    */
    WriteWavHeader(fp, sound, datalength);

    fclose(fp);

    /*
        Shut down
    */
    result = sound->release();
    ERRCHECK(result);

    result = system->release();
    ERRCHECK(result);

    return 0;
}

I found the issue: the exinfo.defaultfrequency was set to a different value than my Scarlett 2i2 sample rate settings. I set both to 48000, and now my program works perfectly

1 Like

Happy to hear you resolved the issue!

1 Like