Here is a modified simple event example, to use ASIO output with the ‘preferred’ buffer size by the ASIO driver.
#define ASIO_NAME_LEN 32
typedef long ASIOBool;
typedef long ASIOError;
typedef double ASIOSampleRate;
typedef struct ASIOChannelInfo ASIOChannelInfo;
typedef struct ASIOClockSource ASIOClockSource;
typedef long long int ASIOSamples;
typedef struct ASIOBufferInfo ASIOBufferInfo;
typedef struct ASIOCallbacks ASIOCallbacks;
typedef long long int ASIOTimeStamp;
typedef long ASIOError;
interface IASIO : public IUnknown
{
virtual ASIOBool init(void *sysHandle) = 0;
virtual void getDriverName(char *name) = 0;
virtual long getDriverVersion() = 0;
virtual void getErrorMessage(char *string) = 0;
virtual ASIOError start() = 0;
virtual ASIOError stop() = 0;
virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels) = 0;
virtual ASIOError getLatencies(long *inputLatency, long *outputLatency) = 0;
virtual ASIOError getBufferSize(long *minSize, long *maxSize,
long *preferredSize, long *granularity) = 0;
virtual ASIOError canSampleRate(ASIOSampleRate sampleRate) = 0;
virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate) = 0;
virtual ASIOError setSampleRate(ASIOSampleRate sampleRate) = 0;
virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources) = 0;
virtual ASIOError setClockSource(long reference) = 0;
virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp) = 0;
virtual ASIOError getChannelInfo(ASIOChannelInfo *info) = 0;
virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels,
long bufferSize, ASIOCallbacks *callbacks) = 0;
virtual ASIOError disposeBuffers() = 0;
virtual ASIOError controlPanel() = 0;
virtual ASIOError future(long selector,void *opt) = 0;
virtual ASIOError outputReady() = 0;
};
int getAsioBufferSize(int device)
{
int buffersize = -1;
HKEY asioKey = NULL;
char name[ASIO_NAME_LEN];
unsigned long nameLen = ASIO_NAME_LEN;
CLSID clsid;
long err = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "software\\asio", 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &asioKey);
if (err != ERROR_SUCCESS) return -1;
/*
Query the device name, use that to get the CLSID
*/
err = RegEnumKeyEx(asioKey, device, name, &nameLen, NULL, NULL, NULL, NULL);
if (err != ERROR_SUCCESS) return -1;
HKEY asioDriverKey = NULL;
err = RegOpenKeyEx(asioKey, name, 0, KEY_QUERY_VALUE, &asioDriverKey);
if (err != ERROR_SUCCESS) return -1;
unsigned char data[128] = { 0 };
unsigned long dataSize = sizeof(data); // We know this is a GUID string so it will always fit
err = RegQueryValueEx(asioDriverKey, "clsid", NULL, NULL, data, &dataSize);
if (err != ERROR_SUCCESS) return -1;
err = RegCloseKey(asioDriverKey);
if (err != ERROR_SUCCESS) return -1;
wchar_t wideData[128] = { 0 };
err = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)data, -1, wideData, sizeof(wideData));
if (err == 0) return -1;
HRESULT hr = CLSIDFromString(wideData, &clsid);
if (hr != NOERROR) return -1;
err = RegCloseKey(asioKey);
if (err != ERROR_SUCCESS) return -1;
/*
Query driver for capabilities
*/
{
IASIO *driver = NULL;
HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, clsid, (void **)&driver);
if (hr == CO_E_NOTINITIALIZED)
{
hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
if (FAILED(hr)) return -1;
hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, clsid, (void **)&driver);
}
if (hr == S_OK)
{
ASIOBool success = driver->init(NULL);
if (success)
{
long bufferMinSize = 0, bufferMaxSize = 0, bufferPreferredSize = 0, bufferGranularity = 0;
ASIOError asioErr = driver->getBufferSize(&bufferMinSize, &bufferMaxSize, &bufferPreferredSize, &bufferGranularity);
if (asioErr == 0) // 0 = success
{
buffersize = bufferPreferredSize;
}
}
driver->Release();
}
}
return buffersize;
}
int FMOD_Main()
{
void *extraDriverData = NULL;
Common_Init(&extraDriverData);
int buffersize = getAsioBufferSize(0);
FMOD::Studio::System* system = NULL;
ERRCHECK( FMOD::Studio::System::create(&system) );
// The example Studio project is authored for 5.1 sound, so set up the system output mode to match
FMOD::System* lowLevelSystem = NULL;
ERRCHECK( system->getLowLevelSystem(&lowLevelSystem) );
if (buffersize > 0)
{
ERRCHECK( lowLevelSystem->setDSPBufferSize(buffersize, 2) );
}
ERRCHECK( lowLevelSystem->setOutput(FMOD_OUTPUTTYPE_ASIO) );
ERRCHECK( lowLevelSystem->setSoftwareFormat(0, FMOD_SPEAKERMODE_5POINT1, 0) );
ERRCHECK( system->initialize(1024, FMOD_STUDIO_INIT_NORMAL, FMOD_INIT_NORMAL, extraDriverData) );