mirror of
https://github.com/thestk/stk
synced 2026-01-15 22:11:52 +00:00
Version 4.3.1
This commit is contained in:
committed by
Stephen Sinclair
parent
27d9b79dc7
commit
d199342e86
257
src/include/asio.cpp
Normal file
257
src/include/asio.cpp
Normal file
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
Steinberg Audio Stream I/O API
|
||||
(c) 1996, Steinberg Soft- und Hardware GmbH
|
||||
|
||||
asio.cpp
|
||||
|
||||
asio functions entries which translate the
|
||||
asio interface to the asiodrvr class methods
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "asiosys.h" // platform definition
|
||||
#include "asio.h"
|
||||
|
||||
#if MAC
|
||||
#include "asiodrvr.h"
|
||||
|
||||
#pragma export on
|
||||
|
||||
AsioDriver *theAsioDriver = 0;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
long main()
|
||||
{
|
||||
return 'ASIO';
|
||||
}
|
||||
|
||||
#elif WINDOWS
|
||||
|
||||
#include "windows.h"
|
||||
#include "iasiodrv.h"
|
||||
#include "asiodrivers.h"
|
||||
|
||||
IASIO *theAsioDriver = 0;
|
||||
extern AsioDrivers *asioDrivers;
|
||||
|
||||
#elif SGI || SUN || BEOS || LINUX
|
||||
#include "asiodrvr.h"
|
||||
static AsioDriver *theAsioDriver = 0;
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
ASIOError ASIOInit(ASIODriverInfo *info)
|
||||
{
|
||||
#if MAC || SGI || SUN || BEOS || LINUX
|
||||
if(theAsioDriver)
|
||||
{
|
||||
delete theAsioDriver;
|
||||
theAsioDriver = 0;
|
||||
}
|
||||
info->driverVersion = 0;
|
||||
strcpy(info->name, "No ASIO Driver");
|
||||
theAsioDriver = getDriver();
|
||||
if(!theAsioDriver)
|
||||
{
|
||||
strcpy(info->errorMessage, "Not enough memory for the ASIO driver!");
|
||||
return ASE_NotPresent;
|
||||
}
|
||||
if(!theAsioDriver->init(info->sysRef))
|
||||
{
|
||||
theAsioDriver->getErrorMessage(info->errorMessage);
|
||||
delete theAsioDriver;
|
||||
theAsioDriver = 0;
|
||||
return ASE_NotPresent;
|
||||
}
|
||||
strcpy(info->errorMessage, "No ASIO Driver Error");
|
||||
theAsioDriver->getDriverName(info->name);
|
||||
info->driverVersion = theAsioDriver->getDriverVersion();
|
||||
return ASE_OK;
|
||||
|
||||
#else
|
||||
|
||||
info->driverVersion = 0;
|
||||
strcpy(info->name, "No ASIO Driver");
|
||||
if(theAsioDriver) // must be loaded!
|
||||
{
|
||||
if(!theAsioDriver->init(info->sysRef))
|
||||
{
|
||||
theAsioDriver->getErrorMessage(info->errorMessage);
|
||||
theAsioDriver = 0;
|
||||
return ASE_NotPresent;
|
||||
}
|
||||
|
||||
strcpy(info->errorMessage, "No ASIO Driver Error");
|
||||
theAsioDriver->getDriverName(info->name);
|
||||
info->driverVersion = theAsioDriver->getDriverVersion();
|
||||
return ASE_OK;
|
||||
}
|
||||
return ASE_NotPresent;
|
||||
|
||||
#endif // !MAC
|
||||
}
|
||||
|
||||
ASIOError ASIOExit(void)
|
||||
{
|
||||
if(theAsioDriver)
|
||||
{
|
||||
#if WINDOWS
|
||||
asioDrivers->removeCurrentDriver();
|
||||
#else
|
||||
delete theAsioDriver;
|
||||
#endif
|
||||
}
|
||||
theAsioDriver = 0;
|
||||
return ASE_OK;
|
||||
}
|
||||
|
||||
ASIOError ASIOStart(void)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
return ASE_NotPresent;
|
||||
return theAsioDriver->start();
|
||||
}
|
||||
|
||||
ASIOError ASIOStop(void)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
return ASE_NotPresent;
|
||||
return theAsioDriver->stop();
|
||||
}
|
||||
|
||||
ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
{
|
||||
*numInputChannels = *numOutputChannels = 0;
|
||||
return ASE_NotPresent;
|
||||
}
|
||||
return theAsioDriver->getChannels(numInputChannels, numOutputChannels);
|
||||
}
|
||||
|
||||
ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
{
|
||||
*inputLatency = *outputLatency = 0;
|
||||
return ASE_NotPresent;
|
||||
}
|
||||
return theAsioDriver->getLatencies(inputLatency, outputLatency);
|
||||
}
|
||||
|
||||
ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
{
|
||||
*minSize = *maxSize = *preferredSize = *granularity = 0;
|
||||
return ASE_NotPresent;
|
||||
}
|
||||
return theAsioDriver->getBufferSize(minSize, maxSize, preferredSize, granularity);
|
||||
}
|
||||
|
||||
ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
return ASE_NotPresent;
|
||||
return theAsioDriver->canSampleRate(sampleRate);
|
||||
}
|
||||
|
||||
ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
return ASE_NotPresent;
|
||||
return theAsioDriver->getSampleRate(currentRate);
|
||||
}
|
||||
|
||||
ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
return ASE_NotPresent;
|
||||
return theAsioDriver->setSampleRate(sampleRate);
|
||||
}
|
||||
|
||||
ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
{
|
||||
*numSources = 0;
|
||||
return ASE_NotPresent;
|
||||
}
|
||||
return theAsioDriver->getClockSources(clocks, numSources);
|
||||
}
|
||||
|
||||
ASIOError ASIOSetClockSource(long reference)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
return ASE_NotPresent;
|
||||
return theAsioDriver->setClockSource(reference);
|
||||
}
|
||||
|
||||
ASIOError ASIOGetSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
return ASE_NotPresent;
|
||||
return theAsioDriver->getSamplePosition(sPos, tStamp);
|
||||
}
|
||||
|
||||
ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
{
|
||||
info->channelGroup = -1;
|
||||
info->type = ASIOSTInt16MSB;
|
||||
strcpy(info->name, "None");
|
||||
return ASE_NotPresent;
|
||||
}
|
||||
return theAsioDriver->getChannelInfo(info);
|
||||
}
|
||||
|
||||
ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels,
|
||||
long bufferSize, ASIOCallbacks *callbacks)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
{
|
||||
ASIOBufferInfo *info = bufferInfos;
|
||||
for(long i = 0; i < numChannels; i++, info++)
|
||||
info->buffers[0] = info->buffers[1] = 0;
|
||||
return ASE_NotPresent;
|
||||
}
|
||||
return theAsioDriver->createBuffers(bufferInfos, numChannels, bufferSize, callbacks);
|
||||
}
|
||||
|
||||
ASIOError ASIODisposeBuffers(void)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
return ASE_NotPresent;
|
||||
return theAsioDriver->disposeBuffers();
|
||||
}
|
||||
|
||||
ASIOError ASIOControlPanel(void)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
return ASE_NotPresent;
|
||||
return theAsioDriver->controlPanel();
|
||||
}
|
||||
|
||||
ASIOError ASIOFuture(long selector, void *opt)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
return ASE_NotPresent;
|
||||
return theAsioDriver->future(selector, opt);
|
||||
}
|
||||
|
||||
ASIOError ASIOOutputReady(void)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
return ASE_NotPresent;
|
||||
return theAsioDriver->outputReady();
|
||||
}
|
||||
|
||||
#if MAC
|
||||
} // extern "C"
|
||||
#pragma export off
|
||||
#endif
|
||||
|
||||
|
||||
1054
src/include/asio.h
Normal file
1054
src/include/asio.h
Normal file
File diff suppressed because it is too large
Load Diff
186
src/include/asiodrivers.cpp
Normal file
186
src/include/asiodrivers.cpp
Normal file
@@ -0,0 +1,186 @@
|
||||
#include <string.h>
|
||||
#include "asiodrivers.h"
|
||||
|
||||
AsioDrivers* asioDrivers = 0;
|
||||
|
||||
bool loadAsioDriver(char *name);
|
||||
|
||||
bool loadAsioDriver(char *name)
|
||||
{
|
||||
if(!asioDrivers)
|
||||
asioDrivers = new AsioDrivers();
|
||||
if(asioDrivers)
|
||||
return asioDrivers->loadDriver(name);
|
||||
return false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
|
||||
#if MAC
|
||||
|
||||
bool resolveASIO(unsigned long aconnID);
|
||||
|
||||
AsioDrivers::AsioDrivers() : CodeFragments("ASIO Drivers", 'AsDr', 'Asio')
|
||||
{
|
||||
connID = -1;
|
||||
curIndex = -1;
|
||||
}
|
||||
|
||||
AsioDrivers::~AsioDrivers()
|
||||
{
|
||||
removeCurrentDriver();
|
||||
}
|
||||
|
||||
bool AsioDrivers::getCurrentDriverName(char *name)
|
||||
{
|
||||
if(curIndex >= 0)
|
||||
return getName(curIndex, name);
|
||||
return false;
|
||||
}
|
||||
|
||||
long AsioDrivers::getDriverNames(char **names, long maxDrivers)
|
||||
{
|
||||
for(long i = 0; i < getNumFragments() && i < maxDrivers; i++)
|
||||
getName(i, names[i]);
|
||||
return getNumFragments() < maxDrivers ? getNumFragments() : maxDrivers;
|
||||
}
|
||||
|
||||
bool AsioDrivers::loadDriver(char *name)
|
||||
{
|
||||
char dname[64];
|
||||
unsigned long newID;
|
||||
|
||||
for(long i = 0; i < getNumFragments(); i++)
|
||||
{
|
||||
if(getName(i, dname) && !strcmp(name, dname))
|
||||
{
|
||||
if(newInstance(i, &newID))
|
||||
{
|
||||
if(resolveASIO(newID))
|
||||
{
|
||||
if(connID != -1)
|
||||
removeInstance(curIndex, connID);
|
||||
curIndex = i;
|
||||
connID = newID;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AsioDrivers::removeCurrentDriver()
|
||||
{
|
||||
if(connID != -1)
|
||||
removeInstance(curIndex, connID);
|
||||
connID = -1;
|
||||
curIndex = -1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
|
||||
#elif WINDOWS
|
||||
|
||||
#include "iasiodrv.h"
|
||||
|
||||
extern IASIO* theAsioDriver;
|
||||
|
||||
AsioDrivers::AsioDrivers() : AsioDriverList()
|
||||
{
|
||||
curIndex = -1;
|
||||
}
|
||||
|
||||
AsioDrivers::~AsioDrivers()
|
||||
{
|
||||
}
|
||||
|
||||
bool AsioDrivers::getCurrentDriverName(char *name)
|
||||
{
|
||||
if(curIndex >= 0)
|
||||
return asioGetDriverName(curIndex, name, 32) == 0 ? true : false;
|
||||
name[0] = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
long AsioDrivers::getDriverNames(char **names, long maxDrivers)
|
||||
{
|
||||
for(long i = 0; i < asioGetNumDev() && i < maxDrivers; i++)
|
||||
asioGetDriverName(i, names[i], 32);
|
||||
return asioGetNumDev() < maxDrivers ? asioGetNumDev() : maxDrivers;
|
||||
}
|
||||
|
||||
bool AsioDrivers::loadDriver(char *name)
|
||||
{
|
||||
char dname[64];
|
||||
char curName[64];
|
||||
|
||||
for(long i = 0; i < asioGetNumDev(); i++)
|
||||
{
|
||||
if(!asioGetDriverName(i, dname, 32) && !strcmp(name, dname))
|
||||
{
|
||||
curName[0] = 0;
|
||||
getCurrentDriverName(curName); // in case we fail...
|
||||
removeCurrentDriver();
|
||||
|
||||
if(!asioOpenDriver(i, (void **)&theAsioDriver))
|
||||
{
|
||||
curIndex = i;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
theAsioDriver = 0;
|
||||
if(curName[0] && strcmp(dname, curName))
|
||||
loadDriver(curName); // try restore
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AsioDrivers::removeCurrentDriver()
|
||||
{
|
||||
if(curIndex != -1)
|
||||
asioCloseDriver(curIndex);
|
||||
curIndex = -1;
|
||||
}
|
||||
|
||||
#elif SGI || BEOS
|
||||
|
||||
#include "asiolist.h"
|
||||
|
||||
AsioDrivers::AsioDrivers()
|
||||
: AsioDriverList()
|
||||
{
|
||||
curIndex = -1;
|
||||
}
|
||||
|
||||
AsioDrivers::~AsioDrivers()
|
||||
{
|
||||
}
|
||||
|
||||
bool AsioDrivers::getCurrentDriverName(char *name)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
long AsioDrivers::getDriverNames(char **names, long maxDrivers)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool AsioDrivers::loadDriver(char *name)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void AsioDrivers::removeCurrentDriver()
|
||||
{
|
||||
}
|
||||
|
||||
#else
|
||||
#error implement me
|
||||
#endif
|
||||
41
src/include/asiodrivers.h
Normal file
41
src/include/asiodrivers.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef __AsioDrivers__
|
||||
#define __AsioDrivers__
|
||||
|
||||
#include "ginclude.h"
|
||||
|
||||
#if MAC
|
||||
#include "CodeFragments.hpp"
|
||||
|
||||
class AsioDrivers : public CodeFragments
|
||||
|
||||
#elif WINDOWS
|
||||
#include <windows.h>
|
||||
#include "asiolist.h"
|
||||
|
||||
class AsioDrivers : public AsioDriverList
|
||||
|
||||
#elif SGI || BEOS
|
||||
#include "asiolist.h"
|
||||
|
||||
class AsioDrivers : public AsioDriverList
|
||||
|
||||
#else
|
||||
#error implement me
|
||||
#endif
|
||||
|
||||
{
|
||||
public:
|
||||
AsioDrivers();
|
||||
~AsioDrivers();
|
||||
|
||||
bool getCurrentDriverName(char *name);
|
||||
long getDriverNames(char **names, long maxDrivers);
|
||||
bool loadDriver(char *name);
|
||||
void removeCurrentDriver();
|
||||
long getCurrentDriverIndex() {return curIndex;}
|
||||
protected:
|
||||
unsigned long connID;
|
||||
long curIndex;
|
||||
};
|
||||
|
||||
#endif
|
||||
76
src/include/asiodrvr.h
Normal file
76
src/include/asiodrvr.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
Steinberg Audio Stream I/O API
|
||||
(c) 1996, Steinberg Soft- und Hardware GmbH
|
||||
charlie (May 1996)
|
||||
|
||||
asiodrvr.h
|
||||
c++ superclass to implement asio functionality. from this,
|
||||
you can derive whatever required
|
||||
*/
|
||||
|
||||
#ifndef _asiodrvr_
|
||||
#define _asiodrvr_
|
||||
|
||||
// cpu and os system we are running on
|
||||
#include "asiosys.h"
|
||||
// basic "C" interface
|
||||
#include "asio.h"
|
||||
|
||||
class AsioDriver;
|
||||
extern AsioDriver *getDriver(); // for generic constructor
|
||||
|
||||
#if WINDOWS
|
||||
#include <windows.h>
|
||||
#include "combase.h"
|
||||
#include "iasiodrv.h"
|
||||
class AsioDriver : public IASIO ,public CUnknown
|
||||
{
|
||||
public:
|
||||
AsioDriver(LPUNKNOWN pUnk, HRESULT *phr);
|
||||
|
||||
DECLARE_IUNKNOWN
|
||||
// Factory method
|
||||
static CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr);
|
||||
// IUnknown
|
||||
virtual HRESULT STDMETHODCALLTYPE NonDelegatingQueryInterface(REFIID riid,void **ppvObject);
|
||||
|
||||
#else
|
||||
|
||||
class AsioDriver
|
||||
{
|
||||
public:
|
||||
AsioDriver();
|
||||
#endif
|
||||
virtual ~AsioDriver();
|
||||
|
||||
virtual ASIOBool init(void* sysRef);
|
||||
virtual void getDriverName(char *name); // max 32 bytes incl. terminating zero
|
||||
virtual long getDriverVersion();
|
||||
virtual void getErrorMessage(char *string); // max 124 bytes incl.
|
||||
|
||||
virtual ASIOError start();
|
||||
virtual ASIOError stop();
|
||||
|
||||
virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels);
|
||||
virtual ASIOError getLatencies(long *inputLatency, long *outputLatency);
|
||||
virtual ASIOError getBufferSize(long *minSize, long *maxSize,
|
||||
long *preferredSize, long *granularity);
|
||||
|
||||
virtual ASIOError canSampleRate(ASIOSampleRate sampleRate);
|
||||
virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate);
|
||||
virtual ASIOError setSampleRate(ASIOSampleRate sampleRate);
|
||||
virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources);
|
||||
virtual ASIOError setClockSource(long reference);
|
||||
|
||||
virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp);
|
||||
virtual ASIOError getChannelInfo(ASIOChannelInfo *info);
|
||||
|
||||
virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels,
|
||||
long bufferSize, ASIOCallbacks *callbacks);
|
||||
virtual ASIOError disposeBuffers();
|
||||
|
||||
virtual ASIOError controlPanel();
|
||||
virtual ASIOError future(long selector, void *opt);
|
||||
virtual ASIOError outputReady();
|
||||
};
|
||||
#endif
|
||||
268
src/include/asiolist.cpp
Normal file
268
src/include/asiolist.cpp
Normal file
@@ -0,0 +1,268 @@
|
||||
#include <windows.h>
|
||||
#include "iasiodrv.h"
|
||||
#include "asiolist.h"
|
||||
|
||||
#define ASIODRV_DESC "description"
|
||||
#define INPROC_SERVER "InprocServer32"
|
||||
#define ASIO_PATH "software\\asio"
|
||||
#define COM_CLSID "clsid"
|
||||
|
||||
// ******************************************************************
|
||||
// Local Functions
|
||||
// ******************************************************************
|
||||
static LONG findDrvPath (char *clsidstr,char *dllpath,int dllpathsize)
|
||||
{
|
||||
HKEY hkEnum,hksub,hkpath;
|
||||
char databuf[512];
|
||||
LONG cr,rc = -1;
|
||||
DWORD datatype,datasize;
|
||||
DWORD index;
|
||||
OFSTRUCT ofs;
|
||||
HFILE hfile;
|
||||
BOOL found = FALSE;
|
||||
|
||||
CharLowerBuff(clsidstr,strlen(clsidstr));
|
||||
if ((cr = RegOpenKey(HKEY_CLASSES_ROOT,COM_CLSID,&hkEnum)) == ERROR_SUCCESS) {
|
||||
|
||||
index = 0;
|
||||
while (cr == ERROR_SUCCESS && !found) {
|
||||
cr = RegEnumKey(hkEnum,index++,(LPTSTR)databuf,512);
|
||||
if (cr == ERROR_SUCCESS) {
|
||||
CharLowerBuff(databuf,strlen(databuf));
|
||||
if (!(strcmp(databuf,clsidstr))) {
|
||||
if ((cr = RegOpenKeyEx(hkEnum,(LPCTSTR)databuf,0,KEY_READ,&hksub)) == ERROR_SUCCESS) {
|
||||
if ((cr = RegOpenKeyEx(hksub,(LPCTSTR)INPROC_SERVER,0,KEY_READ,&hkpath)) == ERROR_SUCCESS) {
|
||||
datatype = REG_SZ; datasize = (DWORD)dllpathsize;
|
||||
cr = RegQueryValueEx(hkpath,0,0,&datatype,(LPBYTE)dllpath,&datasize);
|
||||
if (cr == ERROR_SUCCESS) {
|
||||
memset(&ofs,0,sizeof(OFSTRUCT));
|
||||
ofs.cBytes = sizeof(OFSTRUCT);
|
||||
hfile = OpenFile(dllpath,&ofs,OF_EXIST);
|
||||
if (hfile) rc = 0;
|
||||
}
|
||||
RegCloseKey(hkpath);
|
||||
}
|
||||
RegCloseKey(hksub);
|
||||
}
|
||||
found = TRUE; // break out
|
||||
}
|
||||
}
|
||||
}
|
||||
RegCloseKey(hkEnum);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static LPASIODRVSTRUCT newDrvStruct (HKEY hkey,char *keyname,int drvID,LPASIODRVSTRUCT lpdrv)
|
||||
{
|
||||
HKEY hksub;
|
||||
char databuf[256];
|
||||
char dllpath[MAXPATHLEN];
|
||||
WORD wData[100];
|
||||
CLSID clsid;
|
||||
DWORD datatype,datasize;
|
||||
LONG cr,rc;
|
||||
|
||||
if (!lpdrv) {
|
||||
if ((cr = RegOpenKeyEx(hkey,(LPCTSTR)keyname,0,KEY_READ,&hksub)) == ERROR_SUCCESS) {
|
||||
|
||||
datatype = REG_SZ; datasize = 256;
|
||||
cr = RegQueryValueEx(hksub,COM_CLSID,0,&datatype,(LPBYTE)databuf,&datasize);
|
||||
if (cr == ERROR_SUCCESS) {
|
||||
rc = findDrvPath (databuf,dllpath,MAXPATHLEN);
|
||||
if (rc == 0) {
|
||||
lpdrv = new ASIODRVSTRUCT[1];
|
||||
if (lpdrv) {
|
||||
memset(lpdrv,0,sizeof(ASIODRVSTRUCT));
|
||||
lpdrv->drvID = drvID;
|
||||
MultiByteToWideChar(CP_ACP,0,(LPCSTR)databuf,-1,(LPWSTR)wData,100);
|
||||
if ((cr = CLSIDFromString((LPOLESTR)wData,(LPCLSID)&clsid)) == S_OK) {
|
||||
memcpy(&lpdrv->clsid,&clsid,sizeof(CLSID));
|
||||
}
|
||||
|
||||
datatype = REG_SZ; datasize = 256;
|
||||
cr = RegQueryValueEx(hksub,ASIODRV_DESC,0,&datatype,(LPBYTE)databuf,&datasize);
|
||||
if (cr == ERROR_SUCCESS) {
|
||||
strcpy(lpdrv->drvname,databuf);
|
||||
}
|
||||
else strcpy(lpdrv->drvname,keyname);
|
||||
}
|
||||
}
|
||||
}
|
||||
RegCloseKey(hksub);
|
||||
}
|
||||
}
|
||||
else lpdrv->next = newDrvStruct(hkey,keyname,drvID+1,lpdrv->next);
|
||||
|
||||
return lpdrv;
|
||||
}
|
||||
|
||||
static void deleteDrvStruct (LPASIODRVSTRUCT lpdrv)
|
||||
{
|
||||
IASIO *iasio;
|
||||
|
||||
if (lpdrv != 0) {
|
||||
deleteDrvStruct(lpdrv->next);
|
||||
if (lpdrv->asiodrv) {
|
||||
iasio = (IASIO *)lpdrv->asiodrv;
|
||||
iasio->Release();
|
||||
}
|
||||
delete lpdrv;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static LPASIODRVSTRUCT getDrvStruct (int drvID,LPASIODRVSTRUCT lpdrv)
|
||||
{
|
||||
while (lpdrv) {
|
||||
if (lpdrv->drvID == drvID) return lpdrv;
|
||||
lpdrv = lpdrv->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
// ******************************************************************
|
||||
|
||||
|
||||
// ******************************************************************
|
||||
// AsioDriverList
|
||||
// ******************************************************************
|
||||
AsioDriverList::AsioDriverList ()
|
||||
{
|
||||
HKEY hkEnum = 0;
|
||||
char keyname[MAXDRVNAMELEN];
|
||||
LPASIODRVSTRUCT pdl;
|
||||
LONG cr;
|
||||
DWORD index = 0;
|
||||
BOOL fin = FALSE;
|
||||
|
||||
numdrv = 0;
|
||||
lpdrvlist = 0;
|
||||
|
||||
cr = RegOpenKey(HKEY_LOCAL_MACHINE,ASIO_PATH,&hkEnum);
|
||||
while (cr == ERROR_SUCCESS) {
|
||||
if ((cr = RegEnumKey(hkEnum,index++,(LPTSTR)keyname,MAXDRVNAMELEN))== ERROR_SUCCESS) {
|
||||
lpdrvlist = newDrvStruct (hkEnum,keyname,0,lpdrvlist);
|
||||
}
|
||||
else fin = TRUE;
|
||||
}
|
||||
if (hkEnum) RegCloseKey(hkEnum);
|
||||
|
||||
pdl = lpdrvlist;
|
||||
while (pdl) {
|
||||
numdrv++;
|
||||
pdl = pdl->next;
|
||||
}
|
||||
|
||||
if (numdrv) CoInitialize(0); // initialize COM
|
||||
}
|
||||
|
||||
AsioDriverList::~AsioDriverList ()
|
||||
{
|
||||
if (numdrv) {
|
||||
deleteDrvStruct(lpdrvlist);
|
||||
CoUninitialize();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LONG AsioDriverList::asioGetNumDev (VOID)
|
||||
{
|
||||
return (LONG)numdrv;
|
||||
}
|
||||
|
||||
|
||||
LONG AsioDriverList::asioOpenDriver (int drvID,LPVOID *asiodrv)
|
||||
{
|
||||
LPASIODRVSTRUCT lpdrv = 0;
|
||||
long rc;
|
||||
|
||||
if (!asiodrv) return DRVERR_INVALID_PARAM;
|
||||
|
||||
if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
|
||||
if (!lpdrv->asiodrv) {
|
||||
rc = CoCreateInstance(lpdrv->clsid,0,CLSCTX_INPROC_SERVER,lpdrv->clsid,asiodrv);
|
||||
if (rc == S_OK) {
|
||||
lpdrv->asiodrv = *asiodrv;
|
||||
return 0;
|
||||
}
|
||||
// else if (rc == REGDB_E_CLASSNOTREG)
|
||||
// strcpy (info->messageText, "Driver not registered in the Registration Database!");
|
||||
}
|
||||
else rc = DRVERR_DEVICE_ALREADY_OPEN;
|
||||
}
|
||||
else rc = DRVERR_DEVICE_NOT_FOUND;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
LONG AsioDriverList::asioCloseDriver (int drvID)
|
||||
{
|
||||
LPASIODRVSTRUCT lpdrv = 0;
|
||||
IASIO *iasio;
|
||||
|
||||
if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
|
||||
if (lpdrv->asiodrv) {
|
||||
iasio = (IASIO *)lpdrv->asiodrv;
|
||||
iasio->Release();
|
||||
lpdrv->asiodrv = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LONG AsioDriverList::asioGetDriverName (int drvID,char *drvname,int drvnamesize)
|
||||
{
|
||||
LPASIODRVSTRUCT lpdrv = 0;
|
||||
|
||||
if (!drvname) return DRVERR_INVALID_PARAM;
|
||||
|
||||
if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
|
||||
if (strlen(lpdrv->drvname) < (unsigned int)drvnamesize) {
|
||||
strcpy(drvname,lpdrv->drvname);
|
||||
}
|
||||
else {
|
||||
memcpy(drvname,lpdrv->drvname,drvnamesize-4);
|
||||
drvname[drvnamesize-4] = '.';
|
||||
drvname[drvnamesize-3] = '.';
|
||||
drvname[drvnamesize-2] = '.';
|
||||
drvname[drvnamesize-1] = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return DRVERR_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
LONG AsioDriverList::asioGetDriverPath (int drvID,char *dllpath,int dllpathsize)
|
||||
{
|
||||
LPASIODRVSTRUCT lpdrv = 0;
|
||||
|
||||
if (!dllpath) return DRVERR_INVALID_PARAM;
|
||||
|
||||
if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
|
||||
if (strlen(lpdrv->dllpath) < (unsigned int)dllpathsize) {
|
||||
strcpy(dllpath,lpdrv->dllpath);
|
||||
return 0;
|
||||
}
|
||||
dllpath[0] = 0;
|
||||
return DRVERR_INVALID_PARAM;
|
||||
}
|
||||
return DRVERR_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
LONG AsioDriverList::asioGetDriverCLSID (int drvID,CLSID *clsid)
|
||||
{
|
||||
LPASIODRVSTRUCT lpdrv = 0;
|
||||
|
||||
if (!clsid) return DRVERR_INVALID_PARAM;
|
||||
|
||||
if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
|
||||
memcpy(clsid,&lpdrv->clsid,sizeof(CLSID));
|
||||
return 0;
|
||||
}
|
||||
return DRVERR_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
46
src/include/asiolist.h
Normal file
46
src/include/asiolist.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef __asiolist__
|
||||
#define __asiolist__
|
||||
|
||||
#define DRVERR -5000
|
||||
#define DRVERR_INVALID_PARAM DRVERR-1
|
||||
#define DRVERR_DEVICE_ALREADY_OPEN DRVERR-2
|
||||
#define DRVERR_DEVICE_NOT_FOUND DRVERR-3
|
||||
|
||||
#define MAXPATHLEN 512
|
||||
#define MAXDRVNAMELEN 128
|
||||
|
||||
struct asiodrvstruct
|
||||
{
|
||||
int drvID;
|
||||
CLSID clsid;
|
||||
char dllpath[MAXPATHLEN];
|
||||
char drvname[MAXDRVNAMELEN];
|
||||
LPVOID asiodrv;
|
||||
struct asiodrvstruct *next;
|
||||
};
|
||||
|
||||
typedef struct asiodrvstruct ASIODRVSTRUCT;
|
||||
typedef ASIODRVSTRUCT *LPASIODRVSTRUCT;
|
||||
|
||||
class AsioDriverList {
|
||||
public:
|
||||
AsioDriverList();
|
||||
~AsioDriverList();
|
||||
|
||||
LONG asioOpenDriver (int,VOID **);
|
||||
LONG asioCloseDriver (int);
|
||||
|
||||
// nice to have
|
||||
LONG asioGetNumDev (VOID);
|
||||
LONG asioGetDriverName (int,char *,int);
|
||||
LONG asioGetDriverPath (int,char *,int);
|
||||
LONG asioGetDriverCLSID (int,CLSID *);
|
||||
|
||||
// or use directly access
|
||||
LPASIODRVSTRUCT lpdrvlist;
|
||||
int numdrv;
|
||||
};
|
||||
|
||||
typedef class AsioDriverList *LPASIODRIVERLIST;
|
||||
|
||||
#endif
|
||||
82
src/include/asiosys.h
Normal file
82
src/include/asiosys.h
Normal file
@@ -0,0 +1,82 @@
|
||||
#ifndef __asiosys__
|
||||
#define __asiosys__
|
||||
|
||||
#ifdef WIN32
|
||||
#undef MAC
|
||||
#define PPC 0
|
||||
#define WINDOWS 1
|
||||
#define SGI 0
|
||||
#define SUN 0
|
||||
#define LINUX 0
|
||||
#define BEOS 0
|
||||
|
||||
#define NATIVE_INT64 0
|
||||
#define IEEE754_64FLOAT 1
|
||||
|
||||
#elif BEOS
|
||||
#define MAC 0
|
||||
#define PPC 0
|
||||
#define WINDOWS 0
|
||||
#define PC 0
|
||||
#define SGI 0
|
||||
#define SUN 0
|
||||
#define LINUX 0
|
||||
|
||||
#define NATIVE_INT64 0
|
||||
#define IEEE754_64FLOAT 1
|
||||
|
||||
#ifndef DEBUG
|
||||
#define DEBUG 0
|
||||
#if DEBUG
|
||||
void DEBUGGERMESSAGE(char *string);
|
||||
#else
|
||||
#define DEBUGGERMESSAGE(a)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#elif SGI
|
||||
#define MAC 0
|
||||
#define PPC 0
|
||||
#define WINDOWS 0
|
||||
#define PC 0
|
||||
#define SUN 0
|
||||
#define LINUX 0
|
||||
#define BEOS 0
|
||||
|
||||
#define NATIVE_INT64 0
|
||||
#define IEEE754_64FLOAT 1
|
||||
|
||||
#ifndef DEBUG
|
||||
#define DEBUG 0
|
||||
#if DEBUG
|
||||
void DEBUGGERMESSAGE(char *string);
|
||||
#else
|
||||
#define DEBUGGERMESSAGE(a)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#else // MAC
|
||||
|
||||
#define MAC 1
|
||||
#define PPC 1
|
||||
#define WINDOWS 0
|
||||
#define PC 0
|
||||
#define SGI 0
|
||||
#define SUN 0
|
||||
#define LINUX 0
|
||||
#define BEOS 0
|
||||
|
||||
#define NATIVE_INT64 0
|
||||
#define IEEE754_64FLOAT 1
|
||||
|
||||
#ifndef DEBUG
|
||||
#define DEBUG 0
|
||||
#if DEBUG
|
||||
void DEBUGGERMESSAGE(char *string);
|
||||
#else
|
||||
#define DEBUGGERMESSAGE(a)
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
2369
src/include/dsound.h
Normal file
2369
src/include/dsound.h
Normal file
File diff suppressed because it is too large
Load Diff
38
src/include/ginclude.h
Normal file
38
src/include/ginclude.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef __gInclude__
|
||||
#define __gInclude__
|
||||
|
||||
#if SGI
|
||||
#undef BEOS
|
||||
#undef MAC
|
||||
#undef WINDOWS
|
||||
//
|
||||
#define ASIO_BIG_ENDIAN 1
|
||||
#define ASIO_CPU_MIPS 1
|
||||
#elif defined WIN32
|
||||
#undef BEOS
|
||||
#undef MAC
|
||||
#undef SGI
|
||||
#define WINDOWS 1
|
||||
#define ASIO_LITTLE_ENDIAN 1
|
||||
#define ASIO_CPU_X86 1
|
||||
#elif BEOS
|
||||
#undef MAC
|
||||
#undef SGI
|
||||
#undef WINDOWS
|
||||
#define ASIO_LITTLE_ENDIAN 1
|
||||
#define ASIO_CPU_X86 1
|
||||
//
|
||||
#else
|
||||
#define MAC 1
|
||||
#undef BEOS
|
||||
#undef WINDOWS
|
||||
#undef SGI
|
||||
#define ASIO_BIG_ENDIAN 1
|
||||
#define ASIO_CPU_PPC 1
|
||||
#endif
|
||||
|
||||
// always
|
||||
#define NATIVE_INT64 0
|
||||
#define IEEE754_64FLOAT 1
|
||||
|
||||
#endif // __gInclude__
|
||||
37
src/include/iasiodrv.h
Normal file
37
src/include/iasiodrv.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#include "asiosys.h"
|
||||
#include "asio.h"
|
||||
|
||||
/* Forward Declarations */
|
||||
|
||||
#ifndef __ASIODRIVER_FWD_DEFINED__
|
||||
#define __ASIODRIVER_FWD_DEFINED__
|
||||
typedef interface IASIO IASIO;
|
||||
#endif /* __ASIODRIVER_FWD_DEFINED__ */
|
||||
|
||||
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;
|
||||
};
|
||||
563
src/include/iasiothiscallresolver.cpp
Normal file
563
src/include/iasiothiscallresolver.cpp
Normal file
@@ -0,0 +1,563 @@
|
||||
/*
|
||||
IASIOThiscallResolver.cpp see the comments in iasiothiscallresolver.h for
|
||||
the top level description - this comment describes the technical details of
|
||||
the implementation.
|
||||
|
||||
The latest version of this file is available from:
|
||||
http://www.audiomulch.com/~rossb/code/calliasio
|
||||
|
||||
please email comments to Ross Bencina <rossb@audiomulch.com>
|
||||
|
||||
BACKGROUND
|
||||
|
||||
The IASIO interface declared in the Steinberg ASIO 2 SDK declares
|
||||
functions with no explicit calling convention. This causes MSVC++ to default
|
||||
to using the thiscall convention, which is a proprietary convention not
|
||||
implemented by some non-microsoft compilers - notably borland BCC,
|
||||
C++Builder, and gcc. MSVC++ is the defacto standard compiler used by
|
||||
Steinberg. As a result of this situation, the ASIO sdk will compile with
|
||||
any compiler, however attempting to execute the compiled code will cause a
|
||||
crash due to different default calling conventions on non-Microsoft
|
||||
compilers.
|
||||
|
||||
IASIOThiscallResolver solves the problem by providing an adapter class that
|
||||
delegates to the IASIO interface using the correct calling convention
|
||||
(thiscall). Due to the lack of support for thiscall in the Borland and GCC
|
||||
compilers, the calls have been implemented in assembly language.
|
||||
|
||||
A number of macros are defined for thiscall function calls with different
|
||||
numbers of parameters, with and without return values - it may be possible
|
||||
to modify the format of these macros to make them work with other inline
|
||||
assemblers.
|
||||
|
||||
|
||||
THISCALL DEFINITION
|
||||
|
||||
A number of definitions of the thiscall calling convention are floating
|
||||
around the internet. The following definition has been validated against
|
||||
output from the MSVC++ compiler:
|
||||
|
||||
For non-vararg functions, thiscall works as follows: the object (this)
|
||||
pointer is passed in ECX. All arguments are passed on the stack in
|
||||
right to left order. The return value is placed in EAX. The callee
|
||||
clears the passed arguments from the stack.
|
||||
|
||||
|
||||
FINDING FUNCTION POINTERS FROM AN IASIO POINTER
|
||||
|
||||
The first field of a COM object is a pointer to its vtble. Thus a pointer
|
||||
to an object implementing the IASIO interface also points to a pointer to
|
||||
that object's vtbl. The vtble is a table of function pointers for all of
|
||||
the virtual functions exposed by the implemented interfaces.
|
||||
|
||||
If we consider a variable declared as a pointer to IASO:
|
||||
|
||||
IASIO *theAsioDriver
|
||||
|
||||
theAsioDriver points to:
|
||||
|
||||
object implementing IASIO
|
||||
{
|
||||
IASIOvtbl *vtbl
|
||||
other data
|
||||
}
|
||||
|
||||
in other words, theAsioDriver points to a pointer to an IASIOvtbl
|
||||
|
||||
vtbl points to a table of function pointers:
|
||||
|
||||
IASIOvtbl ( interface IASIO : public IUnknown )
|
||||
{
|
||||
(IUnknown functions)
|
||||
0 virtual HRESULT STDMETHODCALLTYPE (*QueryInterface)(REFIID riid, void **ppv) = 0;
|
||||
4 virtual ULONG STDMETHODCALLTYPE (*AddRef)() = 0;
|
||||
8 virtual ULONG STDMETHODCALLTYPE (*Release)() = 0;
|
||||
|
||||
(IASIO functions)
|
||||
12 virtual ASIOBool (*init)(void *sysHandle) = 0;
|
||||
16 virtual void (*getDriverName)(char *name) = 0;
|
||||
20 virtual long (*getDriverVersion)() = 0;
|
||||
24 virtual void (*getErrorMessage)(char *string) = 0;
|
||||
28 virtual ASIOError (*start)() = 0;
|
||||
32 virtual ASIOError (*stop)() = 0;
|
||||
36 virtual ASIOError (*getChannels)(long *numInputChannels, long *numOutputChannels) = 0;
|
||||
40 virtual ASIOError (*getLatencies)(long *inputLatency, long *outputLatency) = 0;
|
||||
44 virtual ASIOError (*getBufferSize)(long *minSize, long *maxSize,
|
||||
long *preferredSize, long *granularity) = 0;
|
||||
48 virtual ASIOError (*canSampleRate)(ASIOSampleRate sampleRate) = 0;
|
||||
52 virtual ASIOError (*getSampleRate)(ASIOSampleRate *sampleRate) = 0;
|
||||
56 virtual ASIOError (*setSampleRate)(ASIOSampleRate sampleRate) = 0;
|
||||
60 virtual ASIOError (*getClockSources)(ASIOClockSource *clocks, long *numSources) = 0;
|
||||
64 virtual ASIOError (*setClockSource)(long reference) = 0;
|
||||
68 virtual ASIOError (*getSamplePosition)(ASIOSamples *sPos, ASIOTimeStamp *tStamp) = 0;
|
||||
72 virtual ASIOError (*getChannelInfo)(ASIOChannelInfo *info) = 0;
|
||||
76 virtual ASIOError (*createBuffers)(ASIOBufferInfo *bufferInfos, long numChannels,
|
||||
long bufferSize, ASIOCallbacks *callbacks) = 0;
|
||||
80 virtual ASIOError (*disposeBuffers)() = 0;
|
||||
84 virtual ASIOError (*controlPanel)() = 0;
|
||||
88 virtual ASIOError (*future)(long selector,void *opt) = 0;
|
||||
92 virtual ASIOError (*outputReady)() = 0;
|
||||
};
|
||||
|
||||
The numbers in the left column show the byte offset of each function ptr
|
||||
from the beginning of the vtbl. These numbers are used in the code below
|
||||
to select different functions.
|
||||
|
||||
In order to find the address of a particular function, theAsioDriver
|
||||
must first be dereferenced to find the value of the vtbl pointer:
|
||||
|
||||
mov eax, theAsioDriver
|
||||
mov edx, [theAsioDriver] // edx now points to vtbl[0]
|
||||
|
||||
Then an offset must be added to the vtbl pointer to select a
|
||||
particular function, for example vtbl+44 points to the slot containing
|
||||
a pointer to the getBufferSize function.
|
||||
|
||||
Finally vtbl+x must be dereferenced to obtain the value of the function
|
||||
pointer stored in that address:
|
||||
|
||||
call [edx+44] // call the function pointed to by
|
||||
// the value in the getBufferSize field of the vtbl
|
||||
|
||||
|
||||
SEE ALSO
|
||||
|
||||
Martin Fay's OpenASIO DLL at http://www.martinfay.com solves the same
|
||||
problem by providing a new COM interface which wraps IASIO with an
|
||||
interface that uses portable calling conventions. OpenASIO must be compiled
|
||||
with MSVC, and requires that you ship the OpenASIO DLL with your
|
||||
application.
|
||||
|
||||
|
||||
ACKNOWLEDGEMENTS
|
||||
|
||||
Ross Bencina: worked out the thiscall details above, wrote the original
|
||||
Borland asm macros, and a patch for asio.cpp (which is no longer needed).
|
||||
Thanks to Martin Fay for introducing me to the issues discussed here,
|
||||
and to Rene G. Ceballos for assisting with asm dumps from MSVC++.
|
||||
|
||||
Antti Silvast: converted the original calliasio to work with gcc and NASM
|
||||
by implementing the asm code in a separate file.
|
||||
|
||||
Fraser Adams: modified the original calliasio containing the Borland inline
|
||||
asm to add inline asm for gcc i.e. Intel syntax for Borland and AT&T syntax
|
||||
for gcc. This seems a neater approach for gcc than to have a separate .asm
|
||||
file and it means that we only need one version of the thiscall patch.
|
||||
|
||||
Fraser Adams: rewrote the original calliasio patch in the form of the
|
||||
IASIOThiscallResolver class in order to avoid modifications to files from
|
||||
the Steinberg SDK, which may have had potential licence issues.
|
||||
|
||||
Andrew Baldwin: contributed fixes for compatibility problems with more
|
||||
recent versions of the gcc assembler.
|
||||
*/
|
||||
|
||||
|
||||
// We only need IASIOThiscallResolver at all if we are on Win32. For other
|
||||
// platforms we simply bypass the IASIOThiscallResolver definition to allow us
|
||||
// to be safely #include'd whatever the platform to keep client code portable
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
|
||||
|
||||
|
||||
// If microsoft compiler we can call IASIO directly so IASIOThiscallResolver
|
||||
// is not used.
|
||||
#if !defined(_MSC_VER)
|
||||
|
||||
|
||||
#include <new>
|
||||
#include <assert.h>
|
||||
|
||||
// We have a mechanism in iasiothiscallresolver.h to ensure that asio.h is
|
||||
// #include'd before it in client code, we do NOT want to do this test here.
|
||||
#define iasiothiscallresolver_sourcefile 1
|
||||
#include "iasiothiscallresolver.h"
|
||||
#undef iasiothiscallresolver_sourcefile
|
||||
|
||||
// iasiothiscallresolver.h redefines ASIOInit for clients, but we don't want
|
||||
// this macro defined in this translation unit.
|
||||
#undef ASIOInit
|
||||
|
||||
|
||||
// theAsioDriver is a global pointer to the current IASIO instance which the
|
||||
// ASIO SDK uses to perform all actions on the IASIO interface. We substitute
|
||||
// our own forwarding interface into this pointer.
|
||||
extern IASIO* theAsioDriver;
|
||||
|
||||
|
||||
// The following macros define the inline assembler for BORLAND first then gcc
|
||||
|
||||
#if defined(__BCPLUSPLUS__) || defined(__BORLANDC__)
|
||||
|
||||
|
||||
#define CALL_THISCALL_0( resultName, thisPtr, funcOffset )\
|
||||
void *this_ = (thisPtr); \
|
||||
__asm { \
|
||||
mov ecx, this_ ; \
|
||||
mov eax, [ecx] ; \
|
||||
call [eax+funcOffset] ; \
|
||||
mov resultName, eax ; \
|
||||
}
|
||||
|
||||
|
||||
#define CALL_VOID_THISCALL_1( thisPtr, funcOffset, param1 )\
|
||||
void *this_ = (thisPtr); \
|
||||
__asm { \
|
||||
mov eax, param1 ; \
|
||||
push eax ; \
|
||||
mov ecx, this_ ; \
|
||||
mov eax, [ecx] ; \
|
||||
call [eax+funcOffset] ; \
|
||||
}
|
||||
|
||||
|
||||
#define CALL_THISCALL_1( resultName, thisPtr, funcOffset, param1 )\
|
||||
void *this_ = (thisPtr); \
|
||||
__asm { \
|
||||
mov eax, param1 ; \
|
||||
push eax ; \
|
||||
mov ecx, this_ ; \
|
||||
mov eax, [ecx] ; \
|
||||
call [eax+funcOffset] ; \
|
||||
mov resultName, eax ; \
|
||||
}
|
||||
|
||||
|
||||
#define CALL_THISCALL_1_DOUBLE( resultName, thisPtr, funcOffset, param1 )\
|
||||
void *this_ = (thisPtr); \
|
||||
void *doubleParamPtr_ (¶m1); \
|
||||
__asm { \
|
||||
mov eax, doubleParamPtr_ ; \
|
||||
push [eax+4] ; \
|
||||
push [eax] ; \
|
||||
mov ecx, this_ ; \
|
||||
mov eax, [ecx] ; \
|
||||
call [eax+funcOffset] ; \
|
||||
mov resultName, eax ; \
|
||||
}
|
||||
|
||||
|
||||
#define CALL_THISCALL_2( resultName, thisPtr, funcOffset, param1, param2 )\
|
||||
void *this_ = (thisPtr); \
|
||||
__asm { \
|
||||
mov eax, param2 ; \
|
||||
push eax ; \
|
||||
mov eax, param1 ; \
|
||||
push eax ; \
|
||||
mov ecx, this_ ; \
|
||||
mov eax, [ecx] ; \
|
||||
call [eax+funcOffset] ; \
|
||||
mov resultName, eax ; \
|
||||
}
|
||||
|
||||
|
||||
#define CALL_THISCALL_4( resultName, thisPtr, funcOffset, param1, param2, param3, param4 )\
|
||||
void *this_ = (thisPtr); \
|
||||
__asm { \
|
||||
mov eax, param4 ; \
|
||||
push eax ; \
|
||||
mov eax, param3 ; \
|
||||
push eax ; \
|
||||
mov eax, param2 ; \
|
||||
push eax ; \
|
||||
mov eax, param1 ; \
|
||||
push eax ; \
|
||||
mov ecx, this_ ; \
|
||||
mov eax, [ecx] ; \
|
||||
call [eax+funcOffset] ; \
|
||||
mov resultName, eax ; \
|
||||
}
|
||||
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
|
||||
|
||||
#define CALL_THISCALL_0( resultName, thisPtr, funcOffset ) \
|
||||
__asm__ __volatile__ ("movl (%1), %%edx\n\t" \
|
||||
"call *"#funcOffset"(%%edx)\n\t" \
|
||||
:"=a"(resultName) /* Output Operands */ \
|
||||
:"c"(thisPtr) /* Input Operands */ \
|
||||
); \
|
||||
|
||||
|
||||
#define CALL_VOID_THISCALL_1( thisPtr, funcOffset, param1 ) \
|
||||
__asm__ __volatile__ ("pushl %0\n\t" \
|
||||
"movl (%1), %%edx\n\t" \
|
||||
"call *"#funcOffset"(%%edx)\n\t" \
|
||||
: /* Output Operands */ \
|
||||
:"r"(param1), /* Input Operands */ \
|
||||
"c"(thisPtr) \
|
||||
); \
|
||||
|
||||
|
||||
#define CALL_THISCALL_1( resultName, thisPtr, funcOffset, param1 ) \
|
||||
__asm__ __volatile__ ("pushl %1\n\t" \
|
||||
"movl (%2), %%edx\n\t" \
|
||||
"call *"#funcOffset"(%%edx)\n\t" \
|
||||
:"=a"(resultName) /* Output Operands */ \
|
||||
:"r"(param1), /* Input Operands */ \
|
||||
"c"(thisPtr) \
|
||||
); \
|
||||
|
||||
|
||||
#define CALL_THISCALL_1_DOUBLE( resultName, thisPtr, funcOffset, param1 ) \
|
||||
__asm__ __volatile__ ("pushl 4(%1)\n\t" \
|
||||
"pushl (%1)\n\t" \
|
||||
"movl (%2), %%edx\n\t" \
|
||||
"call *"#funcOffset"(%%edx);\n\t" \
|
||||
:"=a"(resultName) /* Output Operands */ \
|
||||
:"a"(¶m1), /* Input Operands */ \
|
||||
/* Note: Using "r" above instead of "a" fails */ \
|
||||
/* when using GCC 3.3.3, and maybe later versions*/\
|
||||
"c"(thisPtr) \
|
||||
); \
|
||||
|
||||
|
||||
#define CALL_THISCALL_2( resultName, thisPtr, funcOffset, param1, param2 ) \
|
||||
__asm__ __volatile__ ("pushl %1\n\t" \
|
||||
"pushl %2\n\t" \
|
||||
"movl (%3), %%edx\n\t" \
|
||||
"call *"#funcOffset"(%%edx)\n\t" \
|
||||
:"=a"(resultName) /* Output Operands */ \
|
||||
:"r"(param2), /* Input Operands */ \
|
||||
"r"(param1), \
|
||||
"c"(thisPtr) \
|
||||
); \
|
||||
|
||||
|
||||
#define CALL_THISCALL_4( resultName, thisPtr, funcOffset, param1, param2, param3, param4 )\
|
||||
__asm__ __volatile__ ("pushl %1\n\t" \
|
||||
"pushl %2\n\t" \
|
||||
"pushl %3\n\t" \
|
||||
"pushl %4\n\t" \
|
||||
"movl (%5), %%edx\n\t" \
|
||||
"call *"#funcOffset"(%%edx)\n\t" \
|
||||
:"=a"(resultName) /* Output Operands */ \
|
||||
:"r"(param4), /* Input Operands */ \
|
||||
"r"(param3), \
|
||||
"r"(param2), \
|
||||
"r"(param1), \
|
||||
"c"(thisPtr) \
|
||||
); \
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Our static singleton instance.
|
||||
IASIOThiscallResolver IASIOThiscallResolver::instance;
|
||||
|
||||
// Constructor called to initialize static Singleton instance above. Note that
|
||||
// it is important not to clear that_ incase it has already been set by the call
|
||||
// to placement new in ASIOInit().
|
||||
IASIOThiscallResolver::IASIOThiscallResolver()
|
||||
{
|
||||
}
|
||||
|
||||
// Constructor called from ASIOInit() below
|
||||
IASIOThiscallResolver::IASIOThiscallResolver(IASIO* that)
|
||||
: that_( that )
|
||||
{
|
||||
}
|
||||
|
||||
// Implement IUnknown methods as assert(false). IASIOThiscallResolver is not
|
||||
// really a COM object, just a wrapper which will work with the ASIO SDK.
|
||||
// If you wanted to use ASIO without the SDK you might want to implement COM
|
||||
// aggregation in these methods.
|
||||
HRESULT STDMETHODCALLTYPE IASIOThiscallResolver::QueryInterface(REFIID riid, void **ppv)
|
||||
{
|
||||
(void)riid; // suppress unused variable warning
|
||||
|
||||
assert( false ); // this function should never be called by the ASIO SDK.
|
||||
|
||||
*ppv = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE IASIOThiscallResolver::AddRef()
|
||||
{
|
||||
assert( false ); // this function should never be called by the ASIO SDK.
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE IASIOThiscallResolver::Release()
|
||||
{
|
||||
assert( false ); // this function should never be called by the ASIO SDK.
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// Implement the IASIO interface methods by performing the vptr manipulation
|
||||
// described above then delegating to the real implementation.
|
||||
ASIOBool IASIOThiscallResolver::init(void *sysHandle)
|
||||
{
|
||||
ASIOBool result;
|
||||
CALL_THISCALL_1( result, that_, 12, sysHandle );
|
||||
return result;
|
||||
}
|
||||
|
||||
void IASIOThiscallResolver::getDriverName(char *name)
|
||||
{
|
||||
CALL_VOID_THISCALL_1( that_, 16, name );
|
||||
}
|
||||
|
||||
long IASIOThiscallResolver::getDriverVersion()
|
||||
{
|
||||
ASIOBool result;
|
||||
CALL_THISCALL_0( result, that_, 20 );
|
||||
return result;
|
||||
}
|
||||
|
||||
void IASIOThiscallResolver::getErrorMessage(char *string)
|
||||
{
|
||||
CALL_VOID_THISCALL_1( that_, 24, string );
|
||||
}
|
||||
|
||||
ASIOError IASIOThiscallResolver::start()
|
||||
{
|
||||
ASIOBool result;
|
||||
CALL_THISCALL_0( result, that_, 28 );
|
||||
return result;
|
||||
}
|
||||
|
||||
ASIOError IASIOThiscallResolver::stop()
|
||||
{
|
||||
ASIOBool result;
|
||||
CALL_THISCALL_0( result, that_, 32 );
|
||||
return result;
|
||||
}
|
||||
|
||||
ASIOError IASIOThiscallResolver::getChannels(long *numInputChannels, long *numOutputChannels)
|
||||
{
|
||||
ASIOBool result;
|
||||
CALL_THISCALL_2( result, that_, 36, numInputChannels, numOutputChannels );
|
||||
return result;
|
||||
}
|
||||
|
||||
ASIOError IASIOThiscallResolver::getLatencies(long *inputLatency, long *outputLatency)
|
||||
{
|
||||
ASIOBool result;
|
||||
CALL_THISCALL_2( result, that_, 40, inputLatency, outputLatency );
|
||||
return result;
|
||||
}
|
||||
|
||||
ASIOError IASIOThiscallResolver::getBufferSize(long *minSize, long *maxSize,
|
||||
long *preferredSize, long *granularity)
|
||||
{
|
||||
ASIOBool result;
|
||||
CALL_THISCALL_4( result, that_, 44, minSize, maxSize, preferredSize, granularity );
|
||||
return result;
|
||||
}
|
||||
|
||||
ASIOError IASIOThiscallResolver::canSampleRate(ASIOSampleRate sampleRate)
|
||||
{
|
||||
ASIOBool result;
|
||||
CALL_THISCALL_1_DOUBLE( result, that_, 48, sampleRate );
|
||||
return result;
|
||||
}
|
||||
|
||||
ASIOError IASIOThiscallResolver::getSampleRate(ASIOSampleRate *sampleRate)
|
||||
{
|
||||
ASIOBool result;
|
||||
CALL_THISCALL_1( result, that_, 52, sampleRate );
|
||||
return result;
|
||||
}
|
||||
|
||||
ASIOError IASIOThiscallResolver::setSampleRate(ASIOSampleRate sampleRate)
|
||||
{
|
||||
ASIOBool result;
|
||||
CALL_THISCALL_1_DOUBLE( result, that_, 56, sampleRate );
|
||||
return result;
|
||||
}
|
||||
|
||||
ASIOError IASIOThiscallResolver::getClockSources(ASIOClockSource *clocks, long *numSources)
|
||||
{
|
||||
ASIOBool result;
|
||||
CALL_THISCALL_2( result, that_, 60, clocks, numSources );
|
||||
return result;
|
||||
}
|
||||
|
||||
ASIOError IASIOThiscallResolver::setClockSource(long reference)
|
||||
{
|
||||
ASIOBool result;
|
||||
CALL_THISCALL_1( result, that_, 64, reference );
|
||||
return result;
|
||||
}
|
||||
|
||||
ASIOError IASIOThiscallResolver::getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp)
|
||||
{
|
||||
ASIOBool result;
|
||||
CALL_THISCALL_2( result, that_, 68, sPos, tStamp );
|
||||
return result;
|
||||
}
|
||||
|
||||
ASIOError IASIOThiscallResolver::getChannelInfo(ASIOChannelInfo *info)
|
||||
{
|
||||
ASIOBool result;
|
||||
CALL_THISCALL_1( result, that_, 72, info );
|
||||
return result;
|
||||
}
|
||||
|
||||
ASIOError IASIOThiscallResolver::createBuffers(ASIOBufferInfo *bufferInfos,
|
||||
long numChannels, long bufferSize, ASIOCallbacks *callbacks)
|
||||
{
|
||||
ASIOBool result;
|
||||
CALL_THISCALL_4( result, that_, 76, bufferInfos, numChannels, bufferSize, callbacks );
|
||||
return result;
|
||||
}
|
||||
|
||||
ASIOError IASIOThiscallResolver::disposeBuffers()
|
||||
{
|
||||
ASIOBool result;
|
||||
CALL_THISCALL_0( result, that_, 80 );
|
||||
return result;
|
||||
}
|
||||
|
||||
ASIOError IASIOThiscallResolver::controlPanel()
|
||||
{
|
||||
ASIOBool result;
|
||||
CALL_THISCALL_0( result, that_, 84 );
|
||||
return result;
|
||||
}
|
||||
|
||||
ASIOError IASIOThiscallResolver::future(long selector,void *opt)
|
||||
{
|
||||
ASIOBool result;
|
||||
CALL_THISCALL_2( result, that_, 88, selector, opt );
|
||||
return result;
|
||||
}
|
||||
|
||||
ASIOError IASIOThiscallResolver::outputReady()
|
||||
{
|
||||
ASIOBool result;
|
||||
CALL_THISCALL_0( result, that_, 92 );
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Implement our substitute ASIOInit() method
|
||||
ASIOError IASIOThiscallResolver::ASIOInit(ASIODriverInfo *info)
|
||||
{
|
||||
// To ensure that our instance's vptr is correctly constructed, even if
|
||||
// ASIOInit is called prior to main(), we explicitly call its constructor
|
||||
// (potentially over the top of an existing instance). Note that this is
|
||||
// pretty ugly, and is only safe because IASIOThiscallResolver has no
|
||||
// destructor and contains no objects with destructors.
|
||||
new((void*)&instance) IASIOThiscallResolver( theAsioDriver );
|
||||
|
||||
// Interpose between ASIO client code and the real driver.
|
||||
theAsioDriver = &instance;
|
||||
|
||||
// Note that we never need to switch theAsioDriver back to point to the
|
||||
// real driver because theAsioDriver is reset to zero in ASIOExit().
|
||||
|
||||
// Delegate to the real ASIOInit
|
||||
return ::ASIOInit(info);
|
||||
}
|
||||
|
||||
|
||||
#endif /* !defined(_MSC_VER) */
|
||||
|
||||
#endif /* Win32 */
|
||||
|
||||
201
src/include/iasiothiscallresolver.h
Normal file
201
src/include/iasiothiscallresolver.h
Normal file
@@ -0,0 +1,201 @@
|
||||
// ****************************************************************************
|
||||
//
|
||||
// Changed: I have modified this file slightly (includes) to work with
|
||||
// RtAudio. RtAudio.cpp must include this file after asio.h.
|
||||
//
|
||||
// File: IASIOThiscallResolver.h
|
||||
// Description: The IASIOThiscallResolver class implements the IASIO
|
||||
// interface and acts as a proxy to the real IASIO interface by
|
||||
// calling through its vptr table using the thiscall calling
|
||||
// convention. To put it another way, we interpose
|
||||
// IASIOThiscallResolver between ASIO SDK code and the driver.
|
||||
// This is necessary because most non-Microsoft compilers don't
|
||||
// implement the thiscall calling convention used by IASIO.
|
||||
//
|
||||
// iasiothiscallresolver.cpp contains the background of this
|
||||
// problem plus a technical description of the vptr
|
||||
// manipulations.
|
||||
//
|
||||
// In order to use this mechanism one simply has to add
|
||||
// iasiothiscallresolver.cpp to the list of files to compile
|
||||
// and #include <iasiothiscallresolver.h>
|
||||
//
|
||||
// Note that this #include must come after the other ASIO SDK
|
||||
// #includes, for example:
|
||||
//
|
||||
// #include <windows.h>
|
||||
// #include <asiosys.h>
|
||||
// #include <asio.h>
|
||||
// #include <asiodrivers.h>
|
||||
// #include <iasiothiscallresolver.h>
|
||||
//
|
||||
// Actually the important thing is to #include
|
||||
// <iasiothiscallresolver.h> after <asio.h>. We have
|
||||
// incorporated a test to enforce this ordering.
|
||||
//
|
||||
// The code transparently takes care of the interposition by
|
||||
// using macro substitution to intercept calls to ASIOInit()
|
||||
// and ASIOExit(). We save the original ASIO global
|
||||
// "theAsioDriver" in our "that" variable, and then set
|
||||
// "theAsioDriver" to equal our IASIOThiscallResolver instance.
|
||||
//
|
||||
// Whilst this method of resolving the thiscall problem requires
|
||||
// the addition of #include <iasiothiscallresolver.h> to client
|
||||
// code it has the advantage that it does not break the terms
|
||||
// of the ASIO licence by publishing it. We are NOT modifying
|
||||
// any Steinberg code here, we are merely implementing the IASIO
|
||||
// interface in the same way that we would need to do if we
|
||||
// wished to provide an open source ASIO driver.
|
||||
//
|
||||
// For compilation with MinGW -lole32 needs to be added to the
|
||||
// linker options. For BORLAND, linking with Import32.lib is
|
||||
// sufficient.
|
||||
//
|
||||
// The dependencies are with: CoInitialize, CoUninitialize,
|
||||
// CoCreateInstance, CLSIDFromString - used by asiolist.cpp
|
||||
// and are required on Windows whether ThiscallResolver is used
|
||||
// or not.
|
||||
//
|
||||
// Searching for the above strings in the root library path
|
||||
// of your compiler should enable the correct libraries to be
|
||||
// identified if they aren't immediately obvious.
|
||||
//
|
||||
// Note that the current implementation of IASIOThiscallResolver
|
||||
// is not COM compliant - it does not correctly implement the
|
||||
// IUnknown interface. Implementing it is not necessary because
|
||||
// it is not called by parts of the ASIO SDK which call through
|
||||
// theAsioDriver ptr. The IUnknown methods are implemented as
|
||||
// assert(false) to ensure that the code fails if they are
|
||||
// ever called.
|
||||
// Restrictions: None. Public Domain & Open Source distribute freely
|
||||
// You may use IASIOThiscallResolver commercially as well as
|
||||
// privately.
|
||||
// You the user assume the responsibility for the use of the
|
||||
// files, binary or text, and there is no guarantee or warranty,
|
||||
// expressed or implied, including but not limited to the
|
||||
// implied warranties of merchantability and fitness for a
|
||||
// particular purpose. You assume all responsibility and agree
|
||||
// to hold no entity, copyright holder or distributors liable
|
||||
// for any loss of data or inaccurate representations of data
|
||||
// as a result of using IASIOThiscallResolver.
|
||||
// Version: 1.4 Added separate macro CALL_THISCALL_1_DOUBLE from
|
||||
// Andrew Baldwin, and volatile for whole gcc asm blocks,
|
||||
// both for compatibility with newer gcc versions. Cleaned up
|
||||
// Borland asm to use one less register.
|
||||
// 1.3 Switched to including assert.h for better compatibility.
|
||||
// Wrapped entire .h and .cpp contents with a check for
|
||||
// _MSC_VER to provide better compatibility with MS compilers.
|
||||
// Changed Singleton implementation to use static instance
|
||||
// instead of freestore allocated instance. Removed ASIOExit
|
||||
// macro as it is no longer needed.
|
||||
// 1.2 Removed semicolons from ASIOInit and ASIOExit macros to
|
||||
// allow them to be embedded in expressions (if statements).
|
||||
// Cleaned up some comments. Removed combase.c dependency (it
|
||||
// doesn't compile with BCB anyway) by stubbing IUnknown.
|
||||
// 1.1 Incorporated comments from Ross Bencina including things
|
||||
// such as changing name from ThiscallResolver to
|
||||
// IASIOThiscallResolver, tidying up the constructor, fixing
|
||||
// a bug in IASIOThiscallResolver::ASIOExit() and improving
|
||||
// portability through the use of conditional compilation
|
||||
// 1.0 Initial working version.
|
||||
// Created: 6/09/2003
|
||||
// Authors: Fraser Adams
|
||||
// Ross Bencina
|
||||
// Rene G. Ceballos
|
||||
// Martin Fay
|
||||
// Antti Silvast
|
||||
// Andrew Baldwin
|
||||
//
|
||||
// ****************************************************************************
|
||||
|
||||
|
||||
#ifndef included_iasiothiscallresolver_h
|
||||
#define included_iasiothiscallresolver_h
|
||||
|
||||
// We only need IASIOThiscallResolver at all if we are on Win32. For other
|
||||
// platforms we simply bypass the IASIOThiscallResolver definition to allow us
|
||||
// to be safely #include'd whatever the platform to keep client code portable
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
|
||||
|
||||
|
||||
// If microsoft compiler we can call IASIO directly so IASIOThiscallResolver
|
||||
// is not used.
|
||||
#if !defined(_MSC_VER)
|
||||
|
||||
|
||||
// The following is in order to ensure that this header is only included after
|
||||
// the other ASIO headers (except for the case of iasiothiscallresolver.cpp).
|
||||
// We need to do this because IASIOThiscallResolver works by eclipsing the
|
||||
// original definition of ASIOInit() with a macro (see below).
|
||||
#if !defined(iasiothiscallresolver_sourcefile)
|
||||
#if !defined(__ASIO_H)
|
||||
#error iasiothiscallresolver.h must be included AFTER asio.h
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include "iasiodrv.h" /* From ASIO SDK */
|
||||
|
||||
|
||||
class IASIOThiscallResolver : public IASIO {
|
||||
private:
|
||||
IASIO* that_; // Points to the real IASIO
|
||||
|
||||
static IASIOThiscallResolver instance; // Singleton instance
|
||||
|
||||
// Constructors - declared private so construction is limited to
|
||||
// our Singleton instance
|
||||
IASIOThiscallResolver();
|
||||
IASIOThiscallResolver(IASIO* that);
|
||||
public:
|
||||
|
||||
// Methods from the IUnknown interface. We don't fully implement IUnknown
|
||||
// because the ASIO SDK never calls these methods through theAsioDriver ptr.
|
||||
// These methods are implemented as assert(false).
|
||||
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv);
|
||||
virtual ULONG STDMETHODCALLTYPE AddRef();
|
||||
virtual ULONG STDMETHODCALLTYPE Release();
|
||||
|
||||
// Methods from the IASIO interface, implemented as forwarning calls to that.
|
||||
virtual ASIOBool init(void *sysHandle);
|
||||
virtual void getDriverName(char *name);
|
||||
virtual long getDriverVersion();
|
||||
virtual void getErrorMessage(char *string);
|
||||
virtual ASIOError start();
|
||||
virtual ASIOError stop();
|
||||
virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels);
|
||||
virtual ASIOError getLatencies(long *inputLatency, long *outputLatency);
|
||||
virtual ASIOError getBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity);
|
||||
virtual ASIOError canSampleRate(ASIOSampleRate sampleRate);
|
||||
virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate);
|
||||
virtual ASIOError setSampleRate(ASIOSampleRate sampleRate);
|
||||
virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources);
|
||||
virtual ASIOError setClockSource(long reference);
|
||||
virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp);
|
||||
virtual ASIOError getChannelInfo(ASIOChannelInfo *info);
|
||||
virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks);
|
||||
virtual ASIOError disposeBuffers();
|
||||
virtual ASIOError controlPanel();
|
||||
virtual ASIOError future(long selector,void *opt);
|
||||
virtual ASIOError outputReady();
|
||||
|
||||
// Class method, see ASIOInit() macro below.
|
||||
static ASIOError ASIOInit(ASIODriverInfo *info); // Delegates to ::ASIOInit
|
||||
};
|
||||
|
||||
|
||||
// Replace calls to ASIOInit with our interposing version.
|
||||
// This macro enables us to perform thiscall resolution simply by #including
|
||||
// <iasiothiscallresolver.h> after the asio #includes (this file _must_ be
|
||||
// included _after_ the asio #includes)
|
||||
|
||||
#define ASIOInit(name) IASIOThiscallResolver::ASIOInit((name))
|
||||
|
||||
|
||||
#endif /* !defined(_MSC_VER) */
|
||||
|
||||
#endif /* Win32 */
|
||||
|
||||
#endif /* included_iasiothiscallresolver_h */
|
||||
|
||||
|
||||
2061
src/include/soundcard.h
Normal file
2061
src/include/soundcard.h
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user