For the next version of FBSound i add support for ASIO drivers.
http://en.wikipedia.org/wiki/Audio_Stream_Input/Output
The problem are how can i do it without C++
of course FBSound is written in FreeBASIC.
So what is the main trick ?
The COM interface pointer are not on the stack
like the hidden THIS param of classes
the pointer are in CPU register ECX.
thats all
would be nice if some of you with Asio drivers could test it.
Joshy
Code: Select all
#define WIN_INCLUDEALL
#include "windows.bi"
#include "crt\string.bi"
' #define DEBUG
#ifdef DEBUG
# ifdef UNICODE
# define STRING_T WSTRING
# define MKSTRING(s) wstr(s)
# else
# define STRING_T ZSTRING
# define MKSTRING(s) (s)
# endif
dim shared as STRING_T * 1024 Buffer
' DbgPrint a messages
#macro DMSG(msg)
wsprintf(@Buffer,@MKSTRING("%s"),@MKSTRING(msg))
OutputDebugString(@Buffer)
#endmacro
#else
# define DMSG(msg)
#endif
#define MAXPATHLEN 512
#define MAXDRVNAMELEN 128
#define DRVERR -5000
#define DRVERR_INVALID_PARAM DRVERR-1
#define DRVERR_DEVICE_ALREADY_OPEN DRVERR-2
#define DRVERR_DEVICE_NOT_FOUND DRVERR-3
#define NATIVE_INT64 0
#define IEEE754_64FLOAT 1
#define ASIODRV_DESC "description"
#define INPROC_SERVER "InprocServer32"
#define ASIO_PATH "software\\asio"
#define COM_CLSID "clsid"
type ASIOSamples field=4
as uinteger hi ' note: hi,lo order
as uinteger lo
end type
type ASIOTimeStamp field=4
as uinteger hi ' note: hi,lo order
as uinteger lo
end type
type ASIOSampleRate as double
enum ASIOBool
ASIOFalse
ASIOTrue
end enum
' Sample Types are expressed as long
enum ASIOSampleType
ASIOSTInt16MSB = 0
ASIOSTInt24MSB = 1 ' used for 20 bits as well
ASIOSTInt32MSB = 2
ASIOSTFloat32MSB = 3 ' IEEE 754 32 bit float
ASIOSTFloat64MSB = 4 ' IEEE 754 64 bit double float
' these are used for 32 bit data buffer, with different alignment of the data inside
' 32 bit PCI bus systems can be more easily used with these
ASIOSTInt32MSB16 = 8 ' 32 bit data with 16 bit alignment
ASIOSTInt32MSB18 = 9 ' 32 bit data with 18 bit alignment
ASIOSTInt32MSB20 = 10 ' 32 bit data with 20 bit alignment
ASIOSTInt32MSB24 = 11 ' 32 bit data with 24 bit alignment
ASIOSTInt16LSB = 16
ASIOSTInt24LSB = 17 ' used for 20 bits as well
ASIOSTInt32LSB = 18
ASIOSTFloat32LSB = 19 ' IEEE 754 32 bit float, as found on Intel x86 architecture
ASIOSTFloat64LSB = 20 ' IEEE 754 64 bit double float, as found on Intel x86 architecture
' these are used for 32 bit data buffer, with different alignment of the data inside
' 32 bit PCI bus systems can more easily used with these
ASIOSTInt32LSB16 = 24 ' 32 bit data with 18 bit alignment
ASIOSTInt32LSB18 = 25 ' 32 bit data with 18 bit alignment
ASIOSTInt32LSB20 = 26 ' 32 bit data with 20 bit alignment
ASIOSTInt32LSB24 = 27 ' 32 bit data with 24 bit alignment
' ASIO DSD format.
ASIOSTDSDInt8LSB1 = 32 ' DSD 1 bit data, 8 samples per byte. First sample in Least significant bit.
ASIOSTDSDInt8MSB1 = 33 ' DSD 1 bit data, 8 samples per byte. First sample in Most significant bit.
ASIOSTDSDInt8NER8 = 40 ' DSD 8 bit data, 1 sample per byte. No Endianness required.
ASIOSTLastEntry
end enum
enum ASIOError
ASE_OK = 0 ' This value will be returned whenever the call succeeded
ASE_SUCCESS = &H3f4847a0 ' unique success return value for ASIOFuture calls
ASE_NotPresent = -1000 ' hardware input or output is not present or available
ASE_HWMalfunction ' hardware is malfunctioning (can be returned by any ASIO function)
ASE_InvalidParameter ' input parameter invalid
ASE_InvalidMode ' hardware is in a bad mode or used in a bad mode
ASE_SPNotAdvancing ' hardware is not running when sample position is inquired
ASE_NoClock ' sample clock or rate cannot be determined or is not present
ASE_NoMemory ' not enough memory for completing the request
end enum
enum ASIOTimeCodeFlags
kTcValid = 1 shl 0
kTcRunning = 1 shl 1
kTcReverse = 1 shl 2
kTcOnspeed = 1 shl 3
kTcStill = 1 shl 4
kTcSpeedValid = 1 shl 8
end enum
type ASIOTimeCode field=4
as double speed ' speed relation (fraction of nominal speed)
as ASIOSamples timeCodeSamples ' time in samples
as ASIOTimeCodeFlags flags ' some information flags
as ubyte future(63)
end type
enum AsioTimeInfoFlags
kSystemTimeValid = 1 shl 0 ' must always be valid
kSamplePositionValid = 1 shl 1 ' must always be valid
kSampleRateValid = 1 shl 2
kSpeedValid = 1 shl 3
kSampleRateChanged = 1 shl 4
kClockSourceChanged = 1 shl 5
end enum
type AsioTimeInfo field=4
as double speed ' absolute speed (1. = nominal)
as ASIOTimeStamp systemTime ' system time related to samplePosition, in nanoseconds
as ASIOSamples samplePosition
as ASIOSampleRate sampleRate ' current rate
as AsioTimeInfoFlags flags
as ubyte reserved(11)
end type
type ASIOTime field=4 ' both input/output
as long reserved(3) ' must be 0
as AsioTimeInfo timeInfo ' required
as ASIOTimeCode timeCode ' optional, evaluated if (timeCode.flags and kTcValid)
end type
type ASIOClockSource field=4
as long index ' as used for ASIOSetClockSource()
as long associatedChannel ' for instance, S/PDIF or AES/EBU
as long associatedGroup ' see channel groups (ASIOGetChannelInfo())
as ASIOBool isCurrentSource ' ASIOTrue if this is the current clock source
as zstring * 32 name ' for user selection
end type
type ASIOChannelInfo field=4
as long channel ' on input, channel index
as ASIOBool isInput ' on input
as ASIOBool isActive ' on exit
as long channelGroup ' on exit
as ASIOSampleType type ' on exit
as zstring * 32 name ' on exit
end type
type ASIOBufferInfo field=4
as ASIOBool isInput ' on input ASIOTrue input, else output
as long channelNum ' on input channel index
as any ptr buffers(1) ' on output double buffer addresses
end type
type ASIOCallbacks field=4
bufferSwitch as sub cdecl (DoubleBufferIndex as long, _
DirectProcess as ASIOBool)
sampleRateDidChange as sub cdecl (sRate as ASIOSampleRate)
asioMessage as function cdecl (Selector as long, _
Value as long, _
pMessage as any ptr, _
opt as double ptr) as long
bufferSwitchTimeInfo as function cdecl (pParams as ASIOTime ptr, _
DoubleBufferIndex as long, _
DirectProcess as long) as ASIOTime ptr
end type
enum asioMessageSelectors
kAsioSelectorSupported = 1
kAsioEngineVersion
kAsioResetRequest
kAsioBufferSizeChange
kAsioResyncRequest
kAsioLatenciesChanged
kAsioSupportsTimeInfo
kAsioSupportsTimeCode
kAsioMMCCommand
kAsioSupportsInputMonitor
kAsioSupportsInputGain
kAsioSupportsInputMeter
kAsioSupportsOutputGain
kAsioSupportsOutputMeter
kAsioOverload
kAsioNumMessageSelectors
end enum
type ASIODriverInfo
as long AsioVers ' asioVersion currently, 2
as long DriverVers ' driverVersion driver specific
as zstring * 33 name
as zstring * 124 errorMessage
as any ptr sysRef ' on input: system reference (HWND)
end type
type IASIO
declare constructor (pRealInterface as any ptr)
declare function Init (sysHandle as HWND) as ASIOBool
declare sub GetDriverName (pName as zstring ptr)
declare function GetDriverVersion () as integer
declare sub GetErrorMessage (pMsg as zstring ptr)
declare function Start () as ASIOError
declare function Stop () as ASIOError
declare function GetChannels (numInputChannels as long ptr, _
numOutputChannels as long ptr) as ASIOError
declare function GetLatencies (inputLatency as long ptr, _
outputLatency as long ptr) as ASIOError
declare function GetBufferSize (minSize as long ptr, _
maxSize as long ptr, _
preferredSize as long ptr, _
granularity as long ptr) as ASIOError
declare function CanSampleRate (sampleRate as ASIOSampleRate) as ASIOError
declare function GetSampleRate (sampleRate as ASIOSampleRate ptr) as ASIOError
declare function SetSampleRate (sampleRate as ASIOSampleRate) as ASIOError
declare function GetClockSources (clocks as ASIOClockSource ptr, _
numSources as long ptr) as ASIOError
declare function SetClockSource (reference as long) as ASIOError
declare function GetSamplePosition(sPos as ASIOSamples ptr, _
tStamp as ASIOTimeStamp ptr) as ASIOError
declare function GetChannelInfo (info as ASIOChannelInfo ptr) as ASIOError
declare function CreateBuffers (bufferInfos as ASIOBufferInfo ptr, _
numChannels as long, _
bufferSize as long, _
callbacks as ASIOCallbacks ptr) as ASIOError
declare function DisposeBuffers () as ASIOError
declare function ControlPanel () as ASIOError
declare function Future (selector as long, _
opt as any ptr) as ASIOError
declare function OutputReady () as ASIOError
private:
enum VT_ASIO
VT_QueryInterface = 0
VT_AddRef = 4
VT_Release = 8
VT_init = 12
VT_getDriverName = 16
VT_getDriverVersion = 20
VT_getErrorMessage = 24
VT_start = 28
VT_stop = 32
VT_getChannels = 36
VT_getLatencies = 40
VT_getBufferSize = 44
VT_canSampleRate = 48
VT_getSampleRate = 52
VT_setSampleRate = 56
VT_getClockSources = 60
VT_setClockSource = 64
VT_getSamplePosition = 68
VT_getChannelInfo = 72
VT_createBuffers = 76
VT_disposeBuffers = 80
VT_controlPanel = 84
VT_future = 88
VT_outputReady = 92
end enum
as any ptr pAsioThis
end type
' fetch the interface pointer
constructor IASIO(pRealInterface as any ptr)
DMSG("IASIO()")
pAsioThis = pRealInterface
end constructor
function IASIO.Init(sysHandle as HWND) as ASIOBool
DMSG("IASIO.init()")
if pAsioThis=NULL then beep:return ASIOFalse
dim as any ptr pThis=pAsioThis
dim as ASIOBool result
asm
push dword ptr [sysHandle]
mov ecx,[pThis]
mov eax,[ecx]
call [eax+VT_init]
mov [result],eax
end asm
return result
end function
sub IASIO.GetDriverName(pName as zstring ptr)
DMSG("IASIO.getDriverName()")
if pAsioThis=NULL then beep:return
if pName =NULL then beep:return
dim as any ptr pThis=pAsioThis
asm
push dword ptr [pName]
mov ecx,[pThis]
mov eax,[ecx]
call [eax+VT_getDriverName]
end asm
end sub
function IASIO.GetDriverVersion() as integer
DMSG("IASIO.getDriverVersion()")
if pAsioThis=NULL then beep:return 0
dim as any ptr pThis=pAsioThis
dim as integer result
asm
mov ecx,[pThis]
mov eax,[ecx]
call [eax+VT_getDriverVersion]
mov [result],eax
end asm
return result
end function
sub IASIO.GetErrorMessage(pMsg as zstring ptr)
DMSG("IASIO.getErrorMessage()")
if pAsioThis=NULL then beep
if pMsg =NULL then beep
dim as any ptr pThis=pAsioThis
asm
push dword ptr [pMsg]
mov ecx,[pThis]
mov eax,[ecx]
call [eax+VT_getErrorMessage]
end asm
end sub
function IASIO.Start() as ASIOError
DMSG("IASIO.start()")
if pAsioThis=NULL then beep:return ASE_InvalidParameter
dim as any ptr pThis=pAsioThis
dim as ASIOError result
asm
mov ecx,[pThis]
mov eax,[ecx]
call [eax+VT_start]
mov [result],eax
end asm
return result
end function
function IASIO.Stop() as ASIOError
DMSG("IASIO.stop()")
if pAsioThis=NULL then beep:return ASE_InvalidParameter
dim as any ptr pThis=pAsioThis
dim as ASIOError result
asm
mov ecx,[pThis]
mov eax,[ecx]
call [eax+VT_stop]
mov [result],eax
end asm
return result
end function
function IASIO.GetChannels(pInChannels as long ptr, _
pOutChannels as long ptr) as ASIOError
DMSG("IASIO.getChannels()")
if pAsioThis =NULL then beep:return ASE_InvalidParameter
if pInChannels =NULL then beep:return ASE_InvalidParameter
if pOutChannels=NULL then beep:return ASE_InvalidParameter
dim as any ptr pThis=pAsioThis
dim as ASIOError result
asm
push dword ptr [pOutChannels]
push dword ptr [pInChannels]
mov ecx,[pThis]
mov eax,[ecx]
call [eax+VT_getChannels]
mov [result],eax
end asm
return result
end function
function IASIO.GetLatencies(pInLatency as long ptr, _
pOutLatency as long ptr) as ASIOError
DMSG("IASIO.getLatencies()")
if pAsioThis =NULL then beep:return ASE_InvalidParameter
if pInLatency =NULL then beep:return ASE_InvalidParameter
if pOutLatency=NULL then beep:return ASE_InvalidParameter
dim as any ptr pThis=pAsioThis
dim as ASIOError result
asm
push dword ptr [pOutLatency]
push dword ptr [pInLatency]
mov ecx,[pThis]
mov eax,[ecx]
call [eax+VT_getLatencies]
mov [result],eax
end asm
return result
end function
function IASIO.GetBufferSize(pMinSize as long ptr, _
pMaxSize as long ptr, _
pPreferredSize as long ptr, _
pGranularity as long ptr) as ASIOError
DMSG("IASIO.getBufferSize()")
if pAsioThis =NULL then beep:return ASE_InvalidParameter
if pMinSize =NULL then beep:return ASE_InvalidParameter
if pMaxSize =NULL then beep:return ASE_InvalidParameter
if pPreferredSize=NULL then beep:return ASE_InvalidParameter
if pGranularity =NULL then beep:return ASE_InvalidParameter
dim as any ptr pThis=pAsioThis
dim as ASIOError result
asm
push dword ptr [pGranularity]
push dword ptr [pPreferredSize]
push dword ptr [pMaxSize]
push dword ptr [pMinSize]
mov ecx,[pThis]
mov eax,[ecx]
call [eax+VT_getBufferSize]
mov [result],eax
end asm
return result
end function
function IASIO.CanSampleRate(SampleRate as ASIOSampleRate) as ASIOError
DMSG("IASIO.canSampleRate()")
if pAsioThis=NULL then beep:return ASE_InvalidParameter
dim as any ptr pThis=pAsioThis
dim as ASIOError result
asm
push dword ptr [SampleRate]
mov ecx,[pThis]
mov eax,[ecx]
call [eax+VT_canSampleRate]
mov [result],eax
end asm
return result
end function
function IASIO.GetSampleRate(pSampleRate as ASIOSampleRate ptr) as ASIOError
DMSG("IASIO.getSampleRate()")
if pAsioThis =NULL then beep:return ASE_InvalidParameter
if pSampleRate=NULL then beep:return ASE_InvalidParameter
dim as any ptr pThis=pAsioThis
dim as ASIOError result
asm
push dword ptr [pSampleRate]
mov ecx,[pThis]
mov eax,[ecx]
call [eax+VT_getSampleRate]
mov [result],eax
end asm
return result
end function
function IASIO.SetSampleRate(SampleRate as ASIOSampleRate) as ASIOError
DMSG("IASIO.setSampleRate()")
if pAsioThis=NULL then beep:return ASE_InvalidParameter
dim as any ptr pThis=pAsioThis
dim as ASIOError result
asm
push dword ptr [SampleRate]
mov ecx,[pThis]
mov eax,[ecx]
call [eax+VT_setSampleRate]
mov [result],eax
end asm
return result
end function
function IASIO.GetClockSources(pClocks as ASIOClockSource ptr, _
pnSources as long ptr) as ASIOError
DMSG("IASIO.getClockSources()")
if pAsioThis=NULL then beep:return ASE_InvalidParameter
if pClocks =NULL then beep:return ASE_InvalidParameter
if pnSources=NULL then beep:return ASE_InvalidParameter
dim as any ptr pThis=pAsioThis
dim as ASIOError result
asm
push dword ptr [pnSources]
push dword ptr [pClocks]
mov ecx,[pThis]
mov eax,[ecx]
call [eax+VT_getClockSources]
mov [result],eax
end asm
return result
end function
function IASIO.SetClockSource(reference as long) as ASIOError
DMSG("IASIO.setClockSource()")
if pAsioThis=NULL then beep:return ASE_InvalidParameter
dim as any ptr pThis=pAsioThis
dim as ASIOError result
asm
push dword ptr [reference]
mov ecx,[pThis]
mov eax,[ecx]
call [eax+VT_setClockSource]
mov [result],eax
end asm
return result
end function
function IASIO.GetSamplePosition(pPos as ASIOSamples ptr, _
pStamp as ASIOTimeStamp ptr) as ASIOError
DMSG("IASIO.getSamplePosition()")
if pAsioThis=NULL then beep:return ASE_InvalidParameter
if pPos =NULL then beep:return ASE_InvalidParameter
if pStamp =NULL then beep:return ASE_InvalidParameter
dim as any ptr pThis=pAsioThis
dim as ASIOError result
asm
push dword ptr [pStamp]
push dword ptr [pPos]
mov ecx,[pThis]
mov eax,[ecx]
call [eax+VT_getSamplePosition]
mov [result],eax
end asm
return result
end function
function IASIO.GetChannelInfo(pInfo as ASIOChannelInfo ptr) as ASIOError
DMSG("IASIO.getChannelInfo()")
if pAsioThis=NULL then beep:return ASE_InvalidParameter
if pInfo =NULL then beep:return ASE_InvalidParameter
dim as any ptr pThis=pAsioThis
dim as ASIOError result
asm
push dword ptr [pInfo]
mov ecx,[pThis]
mov eax,[ecx]
call [eax+VT_getChannelInfo]
mov [result],eax
end asm
return result
end function
function IASIO.CreateBuffers(pInfos as ASIOBufferInfo ptr, _
nChannels as long, _
BufferSize as long, _
pCallbacks as ASIOCallbacks ptr) as ASIOError
DMSG("IASIO.CreateBuffers()")
if pAsioThis =NULL then beep:return ASE_InvalidParameter
if pInfos =NULL then beep:return ASE_InvalidParameter
if pCallbacks=NULL then beep:return ASE_InvalidParameter
dim as any ptr pThis=pAsioThis
dim as ASIOError result
asm
push dword ptr [pCallbacks]
push dword ptr [BufferSize]
push dword ptr [nChannels]
push dword ptr [pInfos]
mov ecx,[pThis]
mov eax,[ecx]
call [eax+VT_createBuffers]
mov [result],eax
end asm
return result
end function
function IASIO.DisposeBuffers() as ASIOError
DMSG("IASIO.DisposeBuffers()")
if pAsioThis =NULL then beep:return ASE_InvalidParameter
dim as any ptr pThis=pAsioThis
dim as ASIOError result
asm
mov ecx,[pThis]
mov eax,[ecx]
call [eax+VT_disposeBuffers]
mov [result],eax
end asm
return result
end function
function IASIO.ControlPanel() as ASIOError
DMSG("IASIO.ControlPanel()")
if pAsioThis =NULL then beep:return ASE_InvalidParameter
dim as any ptr pThis=pAsioThis
dim as ASIOError result
asm
mov ecx,[pThis]
mov eax,[ecx]
call [eax+VT_controlPanel]
mov [result],eax
end asm
return result
end function
function IASIO.Future(selector as long, _
pOpt as any ptr) as ASIOError
DMSG("IASIO.Future()")
if pAsioThis=NULL then beep:return ASE_InvalidParameter
if pOpt =NULL then beep:return ASE_InvalidParameter
dim as any ptr pThis=pAsioThis
dim as ASIOError result
asm
push dword ptr [pOpt]
push dword ptr [selector]
mov ecx,[pThis]
mov eax,[ecx]
call [eax+VT_future]
mov [result],eax
end asm
return result
end function
function IASIO.OutputReady() as ASIOError
DMSG("IASIO.OutputReady()")
if pAsioThis=NULL then beep:return ASE_InvalidParameter
dim as any ptr pThis=pAsioThis
dim as ASIOError result
asm
mov ecx,[pThis]
mov eax,[ecx]
call [eax+VT_outputReady]
mov [result],eax
end asm
return result
end function
type ASIODRVSTRUCT
as integer drvID
as CLSID ClassID
as zstring * MAXPATHLEN dllpath
as zstring * MAXDRVNAMELEN drvname
as any ptr pRealThis
as IASIO ptr pIAsio
as ASIODRVSTRUCT ptr next
end type
type LPASIODRVSTRUCT as ASIODRVSTRUCT ptr
function FindDrvPath (ClassIDstr as zstring ptr, _
DllPath as zstring ptr, _
DllPathSize as integer) as long
dim as HKEY hkEnum,hksub,hkpath
dim as zstring * 512 databuf
dim as LONG cr,rc = -1
dim as DWORD datatype,datasize
dim as DWORD index
dim as BOOL found = FALSE
CharLowerBuff(ClassIDstr,len(*ClassIDstr))
cr = RegOpenKey(HKEY_CLASSES_ROOT,COM_CLSID,@hkEnum)
if (cr = ERROR_SUCCESS) then
index = 0
while (cr = ERROR_SUCCESS) and (found=FALSE)
cr = RegEnumKey(hkEnum,index,cptr(LPTSTR,@databuf),512)
index+=1
if (cr = ERROR_SUCCESS) then
CharLowerBuff(@databuf,sizeof(databuf))
if (0=lstrcmp(databuf,ClassIDStr)) then
cr = RegOpenKeyEx(hkEnum,cptr(LPCTSTR,@databuf),0,KEY_READ,@hksub)
if (cr = ERROR_SUCCESS) then
cr = RegOpenKeyEx(hksub,cptr(LPCTSTR,@INPROC_SERVER),0,KEY_READ,@hkpath)
if (cr = ERROR_SUCCESS) then
datatype = REG_SZ
datasize = dllpathsize
cr = RegQueryValueEx(hkpath,0,0,@datatype,cptr(LPBYTE,dllpath),@datasize)
if (cr = ERROR_SUCCESS) then
' ok we found the class id and dll path
' !!! be sure the dll file exist !!!
dim as integer hFile = FreeFile()
if open(*dllpath,for binary, access read, as #hFile) then
beep
rc = 1
else
close #hFile
rc = 0
end if
end if
RegCloseKey(hkpath)
end if
RegCloseKey(hksub)
end if
found = TRUE ' break out
end if
end if
wend
RegCloseKey(hkEnum)
end if
return rc
end function
function NewDrvStruct(hkey as HKEY, _
KeyName as zstring ptr, _
DrvID as integer, _
lpDrv as LPASIODRVSTRUCT) as LPASIODRVSTRUCT
dim as HKEY hksub
dim as zstring * 256 databuf
dim as zstring * MAXPATHLEN dllpath
dim as WORD wData(99)
dim as CLSID clsid
dim as DWORD datatype,datasize
dim as LONG cr,rc
if (lpdrv=NULL) then
cr = RegOpenKeyEx(hkey,cptr(LPCTSTR,keyname),0,KEY_READ,@hksub)
if (cr = ERROR_SUCCESS) then
datatype = REG_SZ
datasize = 256
cr = RegQueryValueEx(hksub,COM_CLSID,0,@datatype,cptr(LPBYTE,@databuf),@datasize)
if (cr = ERROR_SUCCESS) then
rc = findDrvPath (databuf,dllpath,MAXPATHLEN)
if (rc = 0) then
lpdrv = new ASIODRVSTRUCT[1]
if (lpdrv<>NULL) then
memset(lpdrv,0,sizeof(ASIODRVSTRUCT))
lpdrv->drvID = drvID
strcpy(lpdrv->dllpath,@dllpath)
MultiByteToWideChar(CP_ACP,0,cptr(LPCSTR,@databuf),-1,cptr(LPWSTR,@wData(0)),100)
cr = CLSIDFromString(cptr(LPOLESTR,@wData(0)),cptr(LPCLSID,@clsid))
if (cr = S_OK) then
memcpy(@lpdrv->ClassID,@clsid,sizeof(CLSID))
end if
datatype = REG_SZ
datasize = 256
cr = RegQueryValueEx(hksub,ASIODRV_DESC,0,@datatype,cptr(LPBYTE,@databuf),@datasize)
if (cr = ERROR_SUCCESS) then
strcpy(lpdrv->drvname,@databuf)
else
strcpy(lpdrv->drvname,keyname)
end if
end if
end if
end if
RegCloseKey(hksub)
end if
else
lpdrv->next = newDrvStruct(hkey,keyname,drvID+1,lpdrv->next)
end if
return lpdrv
end function
sub DeleteDrvStruct (lpdrv as LPASIODRVSTRUCT)
if (lpdrv<>NULL) then
deleteDrvStruct(lpdrv->next)
if (lpdrv->piAsio<>NULL) then
delete lpdrv->piAsio
end if
delete lpdrv
end if
end sub
function GetDrvStruct(drvID as integer, _
lpdrv as LPASIODRVSTRUCT) as LPASIODRVSTRUCT
while (lpdrv<>NULL)
if (lpdrv->drvID = drvID) then return lpdrv
lpdrv = lpdrv->next
wend
return 0
end function
type ASIODRIVERLIST
declare constructor
declare destructor
declare function OpenDriver (index as integer, _
ppAsio as IASIO ptr ptr) as long
declare function CloseDriver (index as integer) as long
declare function GetNumDev () as long
declare function GetDriverName (index as integer, _
pName as zstring ptr, _
nMaxChars as integer) as long
declare function GetDriverPath (index as integer, _
pPath as zstring ptr, _
nMaxChars as integer) as long
declare function GetDriverCLSID (index as integer, _
pClassID as CLSID ptr) as long
private:
as LPASIODRVSTRUCT lpDrvList
as integer numdrv
end type
type LPASIODRIVERLIST as ASIODRIVERLIST ptr
constructor ASIODRIVERLIST
DMSG("ASIODRIVERLIST()")
dim as HKEY hkEnum = 0
dim as zstring * MAXDRVNAMELEN keyname ' char[MAXDRVNAMELEN]
dim as LPASIODRVSTRUCT pdl
dim as LONG cr
dim as DWORD index = 0
dim as BOOL fin = FALSE
numdrv = 0
lpdrvlist = 0
cr = RegOpenKey(HKEY_LOCAL_MACHINE,ASIO_PATH,@hkEnum)
while (cr = ERROR_SUCCESS)
cr = RegEnumKey(hkEnum,index,cptr(LPTSTR,@keyname),MAXDRVNAMELEN)
index+=1
if (cr = ERROR_SUCCESS) then
lpdrvlist = newDrvStruct(hkEnum,keyname,0,lpdrvlist)
else
fin = TRUE
end if
wend
if (hkEnum) then RegCloseKey(hkEnum)
pdl = lpdrvlist
while (pdl)
numdrv+=1
pdl = pdl->next
wend
if (numdrv>0) then
if CoInitialize(0)<>S_OK then
beep
end if
end if
end constructor
destructor ASIODRIVERLIST
if (numdrv>0) then
deleteDrvStruct(lpdrvlist)
CoUninitialize()
end if
DMSG("ASIODRIVERLIST~")
end destructor
function ASIODRIVERLIST.GetNumDev () as LONG
DMSG("ASIODRIVERLIST.GetNumDev")
return numdrv
end function
function ASIODRIVERLIST.OpenDriver(drvID as integer, _
ppAsioDrv as IASIO ptr ptr) as long
DMSG("ASIODRIVERLIST.OpenDriver")
dim as LPASIODRVSTRUCT lpdrv
dim as integer rc
if (ppAsioDrv=NULL) then
beep
return DRVERR_INVALID_PARAM
end if
lpdrv = getDrvStruct(drvID,lpdrvlist)
if (lpdrv<>NULL) then
if (lpdrv->pRealThis=NULL) then
rc = CoCreateInstance(@lpdrv->ClassID,0,CLSCTX_INPROC_SERVER,@lpdrv->ClassID,@lpdrv->pRealThis)
if (rc = S_OK) then
lpdrv->pIAsio = new IASIO(lpdrv->pRealThis)
*ppAsioDrv = lpdrv->pIAsio
return 0
else
beep
end if
else
rc = DRVERR_DEVICE_ALREADY_OPEN
end if
else
rc = DRVERR_DEVICE_NOT_FOUND
end if
return rc
end function
function ASIODRIVERLIST.CloseDriver(drvID as integer) as long
DMSG("ASIODRIVERLIST.CloseDriver")
dim as LPASIODRVSTRUCT lpdrv
dim as IASIO ptr piAsio
lpdrv = getDrvStruct(drvID,lpdrvlist)
if (lpdrv<>NULL) then
if (lpdrv->pIAsio<>NULL) then
lpdrv->pIAsio = NULL
lpdrv->pRealThis = NULL
end if
end if
return 0
end function
function ASIODRIVERLIST.GetDriverName (DrvID as integer, _
pDrvName as zstring ptr, _
NameSize as integer) as long
DMSG("ASIODRIVERLIST.GetDriverName")
dim as LPASIODRVSTRUCT pDrv
if (pDrvName = NULL) then beep:return DRVERR_INVALID_PARAM
if (NameSize < 5 ) then beep:return DRVERR_INVALID_PARAM
pDrv = getDrvStruct(drvID,lpdrvlist)
if (pDrv<>NULL) then
if (len(pDrv->DrvName) < NameSize) then
strcpy(pDrvName,pDrv->DrvName)
else
memcpy(pDrvName,@pDrv->DrvName,NameSize-4)
pDrvName[NameSize-4] = "."
pDrvName[NameSize-3] = "."
pDrvName[NameSize-2] = "."
pDrvName[NameSize-1] = 0
end if
return 0
else
beep
return DRVERR_DEVICE_NOT_FOUND
end if
end function
function ASIODRIVERLIST.GetDriverPath (DrvID as integer, _
DllPath as zstring ptr, _
DllPathsize as integer) as long
DMSG("ASIODRIVERLIST.GetDriverPath")
dim as LPASIODRVSTRUCT lpdrv
if (dllpath=NULL) then
beep
return DRVERR_INVALID_PARAM
end if
lpdrv = getDrvStruct(drvID,lpdrvlist)
if (lpdrv<>NULL) then
if (sizeof(lpdrv->dllpath) < =dllpathsize) then
strcpy(dllpath,lpdrv->dllpath)
return 0
end if
dllpath[0] = 0
return DRVERR_INVALID_PARAM
else
beep
return DRVERR_DEVICE_NOT_FOUND
end if
end function
function ASIODRIVERLIST.GetDriverCLSID (drvID as integer, _
pClassID as CLSID ptr) as long
DMSG("ASIODRIVERLIST.GetDriverCLSID")
dim as LPASIODRVSTRUCT lpdrv
if (pClassID = NULL) then return DRVERR_INVALID_PARAM
lpdrv = getDrvStruct(drvID,lpdrvlist)
if (lpdrv <>NULL) then
memcpy(pClassID,@lpdrv->ClassID,sizeof(CLSID))
return 0
else
return DRVERR_DEVICE_NOT_FOUND
end if
end function
dim as zstring * MAXDRVNAMELEN DrvName
dim as zstring * MAXPATHLEN DrvPath
dim as IASIO ptr Asio
dim as CLSID ClassID
dim as ASIODRIVERLIST DrvList
dim as ASIOSampleRate SampleRate
dim as integer nDrv,nInChannels,nOutChannels
dim as integer MinSize,MaxSize,PreferredSize,Granularity
nDrv = DrvList.GetNumDev
if nDrv<1 then
print "sorry no ASIO driver installed !"
beep:sleep:end 1
end if
for i as integer=0 to nDrv-1
DrvList.GetDriverPath (i,@DrvPath,sizeof(DrvPath))
DrvList.GetDriverName (i,@DrvName,sizeof(DrvName))
DrvList.GetDriverCLSID(i,@ClassID)
print "[" & i & "] " & DrvPath
print "[" & i & "] " & DrvName
print "[" & i & "] " & hex(ClassID.Data1,8) & "-" _
& hex(ClassID.Data2,4) & "-" _
& hex(ClassID.Data3,4) & "-" _
& hex(ClassID.Data4(0),2) & hex(ClassID.Data4(1),2) & "-" _
& hex(ClassID.Data4(2),2) & hex(ClassID.Data4(3),2) _
& hex(ClassID.Data4(4),2) & hex(ClassID.Data4(5),2) _
& hex(ClassID.Data4(6),2) & hex(ClassID.Data4(7),2)
DrvList.OpenDriver(i,@ASIO)
if ASIO<>NULL then
? "Asio.Init(NULL) " & Asio->Init(NULL)
Asio->getChannels(@nInChannels,@nOutChannels)
? "capture channels " & nInChannels
? "playback channels " & nOutChannels
Asio->getSampleRate(@SampleRate)
? "Samplerate " & SampleRate
Asio->getBufferSize(@MinSize, _
@MaxSize, _
@PreferredSize, _
@Granularity)
? "MinSize " & MinSize
? "MaxSize " & MaxSize
? "PreferredSize " & PreferredSize
if Granularity<>-1 then
? "Granularity " & Granularity
end if
? "press any key to open the conrol panel"
sleep
Asio->controlPanel()
print "ok"
end if
DrvList.CloseDriver(i)
next
sleep
