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;
}