PB Asio

Share your advanced PureBasic knowledge/code with the community.
eriansa
Enthusiast
Enthusiast
Posts: 277
Joined: Wed Mar 17, 2004 12:31 am
Contact:

PB Asio

Post by eriansa »

Feel free to update the code to 5.20 (I still use 4.31)...

Code: Select all

;:=============================================================================
;:- PB_Asio.pb 
;:- Author          : Eric Nassen (www.raxntrax.com) / (www.raxntrax.com/modulys)
;:- Date            : August 21, 2013
;:- Compiler        : PureBasic 4.31
;:- Target OS       : Windows x32, x64
;:=============================================================================

;x32 uses asm to call driver (because of thiscall convention), x64 uses the interface
CompilerIf SizeOf(Integer)=4
  #Asio_Native=1
CompilerElse
  #Asio_Native=0
CompilerEndIf


#Stop=0
#Start=1
#TM_Refresh=0

#EngineOn=1
#Debug=0

#WindowDevice=0
#Gain8=127
#Gain16=32767
#Gain24=8388607
#Gain32=2147483648 - 0.5

#kMaxInputChannels=32
#kMaxOutputChannels=32

#ASIO_PATH = "software\ASIO"

#ERROR_NO_MORE_ITEMS = 259
#HKEY_LOCAL_MACHINE = $80000002
#KEY_ENUMERATE_SUB_KEYS = $8

#WM_ASIO = #WM_USER + 4096;   // unique we hope
#WM_ASIO_Reset=#WM_ASIO+1

Enumeration
 #ASE_OK = 0
 #ASE_SUCCESS = $3F4847A0
 #ASE_NotPresent = -1000
 #ASE_HWMalfunction
 #ASE_InvalidParameter
 #ASE_InvalidMode
 #ASE_SPNotAdvancing
 #ASE_NoClock
 #ASE_NoMemory
EndEnumeration
Enumeration
  #ASIOSTInt16MSB   = 0
  #ASIOSTInt24MSB   = 1
  #ASIOSTInt32MSB   = 2
  #ASIOSTFloat32MSB = 3
  #ASIOSTFloat64MSB = 4

  #ASIOSTInt32MSB16 = 8
  #ASIOSTInt32MSB18 = 9
  #ASIOSTInt32MSB20 = 10
  #ASIOSTInt32MSB24 = 11

  #ASIOSTInt16LSB   = 16
  #ASIOSTInt24LSB   = 17
  #ASIOSTInt32LSB   = 18
  #ASIOSTFloat32LSB = 19
  #ASIOSTFloat64LSB = 20

  #ASIOSTInt32LSB16 = 24
  #ASIOSTInt32LSB18 = 25
  #ASIOSTInt32LSB20 = 26
  #ASIOSTInt32LSB24 = 27
EndEnumeration
Enumeration
  #kAsioSelectorSupported    = 1 
  #kAsioEngineVersion        = 2 
  #kAsioResetRequest         = 3
  #kAsioBufferSizeChange     = 4
  #kAsioResyncRequest        = 5
  #kAsioLatenciesChanged     = 6
  #kAsioSupportsTimeInfo     = 7
  #kAsioSupportsTimeCode     = 8
  #kAsioSupportsInputMonitor = 9
  #kAsioNumMessageSelectors  = 10
EndEnumeration
Enumeration
  #kTcValid      = 1;
  #kTcRunning    = 1 << 1;
  #kTcReverse    = 1 << 2;
  #kTcOnspeed    = 1 << 3;
  #kTcStill      = 1 << 4;
  #kTcSpeedValid = 1 << 8;
EndEnumeration
Enumeration
  #kSystemTimeValid     = 1
  #kSamplePositionValid = 1 << 1
  #kSampleRateValid     = 1 << 2
  #kSpeedValid          = 1 << 3
  #kSampleRateChanged   = 1 << 4
  #kClockSourceChanged  = 1 << 5
EndEnumeration

;Following can be changed (backwards compatibility)
Structure MyDouble
  HI.l
  Lo.l
EndStructure
Structure ASIOInt64
  HI.l
  Lo.l
EndStructure
Structure ASIOTimeStamp
  HI.l
  Lo.l
EndStructure
Structure ASIO64bitFloat
  HI.l
  Lo.l
EndStructure
Structure ASIOSampleRate
  HI.l
  Lo.l
EndStructure
Structure ASIOBool
  l.l
EndStructure
Structure ASIOSamples
  HI.l
  Lo.l
EndStructure
Structure ASIOTimeCodeFlags
  l.l
EndStructure
Structure AsioTimeInfoFlags
  l.l
EndStructure
; --------------------------------------

;Engine simulation....
Structure ENG
  Pause.b
  BufferIndex.l
  SampleRate.d
  BlockSize.l
  AsioReset.b 
EndStructure

Interface IOpenAsio Extends iunknown
  Init(sysHandle)
  GetDriverName(*Name)
  GetDriverVersion()
  GetErrorMessage(*errorStrings)
  Start()
  Stop()
  GetChannels(*numInputChannels, *numOutputChannels)
  GetLatencies(inputLatency, outputLatency)
  GetBufferSize(minSize, maxSize, preferredSize, granularity)
  CanSampleRate(dbl.d)
  GetSampleRate(*dbl)
  SetSampleRate(dbl.d)
  GetClockSources(clocks,numSources)
  SetClockSource(reference)
  GetSamplePosition(sPos,tStamp)
  GetChannelInfo(info)
  CreateBuffers(bufferInfos, numChannels, bufferSize,callbacks)
  DisposeBuffers()
  ControlPanel()
  Future(selector,opt)
  OutputReady()
EndInterface
Structure ASIOCallbacks
  bufferSwitch.i
  sampleRateDidChange.i
  asioMessage.i
  bufferSwitchTimeInfo.i
EndStructure
Structure AsioBufferInfo
  isInput.l
  channelNum.l
  buffers.i[2]
EndStructure
Structure ASIOChannelInfo
  channel.l
  isInput.l
  isActive.l
  channelGroup.l
  vType.l
  Name.c[32]
EndStructure
Structure ASIOTimeCode
  speed.MyDouble 
  timecodeSamples.ASIOSamples
  flags.l
  future.c[64]
EndStructure
Structure AsioTimeInfo
  speed.MyDouble
  SystemTime.ASIOTimeStamp
  samplePosition.ASIOSamples
  SampleRate.ASIOSampleRate
  flags .l
  reserved.c[12]       
EndStructure
Structure ASIOTime
  reserved.l[4]
  timeInfo.AsioTimeInfo
  timeCode.ASIOTimeCode
EndStructure

;User defined driver (can be changed)
Structure AsioDriver
  inputChannels.i
  outputChannels.i
	channelInfos.ASIOChannelInfo[#kMaxInputChannels+#kMaxOutputChannels] 
	inputBuffers.l
	outputBuffers.l
	bufferInfos.AsioBufferInfo[#kMaxInputChannels+#kMaxOutputChannels]
  minSize.l
  maxSize.l
  preferredSize.l
  granularity.l
	SampleRate.d
  postOutput.l
  inputLatency.l
  outputLatency.l
	nanoSeconds.d
	samples.d
	tcSamples.d
	tInfo.ASIOTime
	sysRefTime.l
	stopped.l 
  ActiveInput.l
  ActiveOutput.l
EndStructure
Structure AsioStruct
  DeviceID.l
  AsioName$
  CLSID$
  DLLName$
EndStructure

;Quick 'n dirty.....
Global AsioTime.ASIOTime
Global _IAsio.IOpenAsio
Global AsioDriver.AsioDriver
Global callbacks.ASIOCallbacks
Global gDeviceID=-1
Global gAsioState
Global gTicks.l
Global Eng_Event.l 
Global NewList AsioDeviceInfo.AsioStruct()
Global Eng.ENG


Eng\SampleRate=44100
Eng\BlockSize=512

Procedure myTimerCB(hwnd,uMsg,idEvent,dwTime)
  if AsioTime and gAsioState=#Start
    SetGadgetText(2,Str(AsioTime\timeInfo\samplePosition\HI)+"/"+Str(AsioTime\timeInfo\samplePosition\Lo))
  else
    SetGadgetText(2,"Sampleposition")
  EndIf
EndProcedure

Procedure FillAsioDeviceInfo()
  hKey = 0 : count.l = 0
  buffer$=Space(1024)
  If RegOpenKeyEx_(#HKEY_LOCAL_MACHINE, #ASIO_PATH,0, #KEY_ALL_ACCESS,@hKey)=#ERROR_SUCCESS
    buffsize=255
    index=0
    While RegEnumKeyEx_ (hKey, index, @buffer$, @buffsize, #Null, #Null, #Null, @written.SYSTEMTIME)<>#ERROR_NO_MORE_ITEMS
      AsioName$ = Left(buffer$,buffsize)
      hKey2 = 0
      If RegOpenKeyEx_(#HKEY_LOCAL_MACHINE, #ASIO_PATH+"\"+AsioName$, 0, #KEY_READ, @hKey2)=0 
        DataSize = 255
        If RegQueryValueEx_(hKey2, "CLSID", 0, 0, @buffer$, @DataSize)=0
          CLSID$ = Left(buffer$, DataSize - 1) 
          hKey3=0
          If RegOpenKeyEx_(#HKEY_CLASSES_ROOT, "clsid"+"\"+CLSID$+"\"+"InprocServer32", 0, #KEY_READ, @hKey3)=0
            buffsize=255
            If RegQueryValueEx_(hKey3, "", 0, 0, @buffer$, @buffsize)=0
              DLLName$=Left(buffer$,buffsize)
              lSize=FileSize(DLLName$)
              If lSize=-1
                lLen=GetSystemDirectory_(@buffer$,255)
                szDir.s=Left(buffer$,lLen)
                DLLName$=szDir+"\"+DLLName$
                lSize=FileSize(DLLName$)
              EndIf
              If lSize>0  
                AddElement(AsioDeviceInfo())
                AsioDeviceInfo()\DeviceID=count
                AsioDeviceInfo()\AsioName$=AsioName$
                AsioDeviceInfo()\CLSID$=CLSID$
                AsioDeviceInfo()\DLLName$=DLLName$ 
                count+1
              EndIf
            EndIf
            RegCloseKey_(hKey3)
          EndIf
        EndIf
        RegCloseKey_(hKey2) 
      EndIf
      index+1
      buffsize = 255
    Wend
  RegCloseKey_(hKey)
  EndIf 
EndProcedure
Procedure WideStr(pointer) 
  widelen.w = 2*Len(PeekS(pointer))+2 
  widebuf.i = AllocateMemory(widelen) 
  longlen.w = MultiByteToWideChar_(#CP_ACP,0,pointer,-1,widebuf,widelen) 
  ProcedureReturn widebuf 
EndProcedure 

;Interface 
Procedure _Asio_Release()
CompilerIf #ASIO_NATIVE
! mov eax, [v__IAsio]
! push eax
! mov ecx, dword [v__IAsio]
! mov eax, [ecx]
! call dword [eax+8]
CompilerElse
  _IAsio\Release()
CompilerEndIf
EndProcedure

Procedure _Asio_Init(sysHandle)
Result=0
CompilerIf #ASIO_NATIVE
! mov eax, [p.v_sysHandle]
! push eax
! mov ecx, dword [v__IAsio]
! mov eax, [ecx]
! call dword [eax+12]
! mov [p.v_Result], eax
CompilerElse
Result=_IAsio\Init(sysHandle)
CompilerEndIf
ProcedureReturn Result
EndProcedure

Procedure _Asio_GetDriverName(*char)
Result=0
CompilerIf #ASIO_NATIVE
! mov eax, [p.p_char]
! push eax
! mov ecx, dword [v__IAsio]
! mov eax, [ecx]
! call dword [eax+16]
! mov [p.v_Result], eax
CompilerElse
Result=_IAsio\GetDriverName(*char)
CompilerEndIf
ProcedureReturn Result
EndProcedure

Procedure _Asio_GetDriverVersion()
Result=0
CompilerIf #ASIO_NATIVE
! mov ecx, dword [v__IAsio]
! mov eax, [ecx]
! call dword [eax+20]
! mov [p.v_Result], eax
CompilerElse
Result=_IAsio\GetDriverVersion()
CompilerEndIf
ProcedureReturn Result
EndProcedure

Procedure _Asio_getErrorMessage(*char)
Result=0
CompilerIf #ASIO_NATIVE
! mov eax, [p.p_char]
! push eax
! mov ecx, dword [v__IAsio]
! mov eax, [ecx]
! call dword [eax+24]
! mov [p.v_Result], eax
CompilerElse
Result=_IAsio\getErrorMessage(*char)
CompilerEndIf
ProcedureReturn Result
EndProcedure

Procedure _Asio_Start()
Result=0
CompilerIf #ASIO_NATIVE
! mov ecx, dword [v__IAsio]
! mov eax, [ecx]
! call dword [eax+28]
! mov [p.v_Result], eax
CompilerElse
Result=_IAsio\Start()
CompilerEndIf
ProcedureReturn Result
EndProcedure

Procedure _Asio_Stop()
Result=0
CompilerIf #ASIO_NATIVE
! mov ecx, dword [v__IAsio]
! mov eax, [ecx]
! call dword [eax+32]
! mov [p.v_Result], eax
CompilerElse
Result=_IAsio\Stop()
CompilerEndIf
ProcedureReturn Result
EndProcedure

Procedure _Asio_GetChannels(*inputChannels, *outputChannels)
Result=0
CompilerIf #ASIO_NATIVE
! mov eax, [p.p_outputChannels]
! push eax
! mov eax, [p.p_inputChannels+4]
! push eax
! mov ecx, dword [v__IAsio]
! mov eax, [ecx]
! call dword [eax+36]
! mov [p.v_Result], eax
CompilerElse
Result=_IAsio\GetChannels(*inputChannels, *outputChannels)
CompilerEndIf
ProcedureReturn Result
EndProcedure

Procedure _Asio_GetLatencies(*inputLatency, *outputLatency)
Result=0
CompilerIf #ASIO_NATIVE
! mov eax, [p.p_outputLatency]
! push eax
! mov eax, [p.p_inputLatency+4]
! push eax
! mov ecx, dword [v__IAsio]
! mov eax, [ecx]
! call dword [eax+40]
! mov [p.v_Result], eax
CompilerElse
Result=_IAsio\GetLatencies(*inputLatency, *outputLatency)
CompilerEndIf
ProcedureReturn Result
EndProcedure

Procedure _Asio_GetBufferSize(*minSize, *maxSize, *preferredSize, *granularity)
Result=0
CompilerIf #ASIO_NATIVE
! mov eax, [p.p_granularity]
! push eax
! mov eax, [p.p_preferredSize+4]
! push eax
! mov eax, [p.p_maxSize+8]
! push eax
! mov eax, [p.p_minSize+12]
! push eax
! mov ecx, [v__IAsio]
! mov eax, [ecx]
! call dword [eax+44]
! mov [p.v_Result], eax
CompilerElse
Result=_IAsio\GetBufferSize(*minSize, *maxSize, *preferredSize, *granularity)
CompilerEndIf
 procedurereturn Result;
EndProcedure

Procedure _Asio_CanSampleRate(sampleRate.d)
Result=0
CompilerIf #ASIO_NATIVE
 *sampleRate_=@sampleRate
! mov eax, [p.p_sampleRate_]
! push dword [eax+4]
! push dword [eax]
! mov ecx, [v__IAsio]
! mov eax, [ecx]
! call dword [eax+48]
! mov [p.v_Result], eax
CompilerElse
Result=_IAsio\CanSampleRate(sampleRate.d)
CompilerEndIf
 procedurereturn Result;
EndProcedure

Procedure _Asio_GetSampleRate(*sampleRate)
Result=0
CompilerIf #ASIO_NATIVE
! mov eax, [p.p_sampleRate]
! push eax
! mov ecx, [v__IAsio]
! mov eax, [ecx]
! call dword [eax+52]
! mov [p.v_Result], eax
CompilerElse
Result=_IAsio\GetSampleRate(*sampleRate)
CompilerEndIf
 procedurereturn Result;
EndProcedure

Procedure _Asio_SetSampleRate(sampleRate.d)
Result=0
CompilerIf #ASIO_NATIVE
 *sampleRate_=@sampleRate
! mov eax, [p.p_sampleRate_]
! push dword [eax+4]
! push dword [eax]
! mov ecx, [v__IAsio]
! mov eax, [ecx]
! call dword [eax+56]
! mov [p.v_Result], eax
CompilerElse
Result=_IAsio\SetSampleRate(sampleRate.d)
CompilerEndIf
 procedurereturn Result;
EndProcedure

Procedure _Asio_GetClockSources(*Clocks, *numSources)
Result=0
CompilerIf #ASIO_NATIVE
! mov eax, [p.p_numSources]
! push eax
! mov eax, [p.p_Clocks]
! push eax
! mov ecx, dword [v__IAsio]
! mov eax, [ecx]
! call dword [eax+60]
! mov [p.v_Result], eax
CompilerElse
Result=_IAsio\GetClockSources(*Clocks, *numSources)
CompilerEndIf
 ProcedureReturn Result
EndProcedure

Procedure _Asio_SetClockSource(reference.l)
Result=0
CompilerIf #ASIO_NATIVE
! mov eax, [p.v_reference]
! push eax
! mov ecx, dword [v__IAsio]
! mov eax, [ecx]
! call dword [eax+64]
! mov [p.v_Result], eax
CompilerElse
Result=_IAsio\SetClockSource(reference)
CompilerEndIf
ProcedureReturn Result
EndProcedure

Procedure _Asio_GetSamplePosition(*sPos, *tStamp)
Result=0
CompilerIf #ASIO_NATIVE
! mov eax, [p.p_tStamp]
! push eax
! mov eax, [p.p_sPos+4]
! push eax
! mov ecx, dword [v__IAsio]
! mov eax, [ecx]
! call dword [eax+68]
! mov [p.v_Result], eax
CompilerElse
Result=_IAsio\GetSamplePosition(*sPos, *tStamp)
CompilerEndIf
 procedurereturn Result
EndProcedure

Procedure _Asio_GetChannelInfo(*info)
Result=0
CompilerIf #ASIO_NATIVE
! mov eax, [p.p_info]
! push eax
! mov ecx, [v__IAsio]
! mov eax, [ecx]
! call dword [eax+72]
! mov [p.v_Result], eax
CompilerElse
Result=_IAsio\GetChannelInfo(*info)
CompilerEndIf
 procedurereturn Result;
EndProcedure

Procedure _Asio_CreateBuffers(*bufferInfos, numChannels.l, bufferSize.l, *callbacks)
Result=0
CompilerIf #ASIO_NATIVE
! mov eax, [p.p_callbacks]
! push eax
! mov eax, [p.v_bufferSize+4]
! push eax
! mov eax, [p.v_numChannels+8]
! push eax
! mov eax, [p.p_bufferInfos+12]
! push eax
! mov ecx, [v__IAsio]
! mov eax, [ecx]
! call dword [eax+76]
! mov [p.v_Result], eax
 procedurereturn Result
CompilerElse
Result=_IAsio\CreateBuffers(*bufferInfos, numChannels, bufferSize, *callbacks)
CompilerEndIf
 procedurereturn Result;
EndProcedure

Procedure _Asio_DisposeBuffers()
Result=0
CompilerIf #ASIO_NATIVE
! mov ecx, dword [v__IAsio]
! mov eax, [ecx]
! call dword [eax+80]
! mov [p.v_Result], eax
CompilerElse
Result=_IAsio\DisposeBuffers()
CompilerEndIf
ProcedureReturn Result
EndProcedure

Procedure _Asio_controlPanel()
Result=0
CompilerIf #ASIO_NATIVE
! mov ecx, dword [v__IAsio]
! mov eax, [ecx]
! call dword [eax+84]
! mov [p.v_Result], eax
CompilerElse
Result=_IAsio\controlPanel()
CompilerEndIf
ProcedureReturn Result
EndProcedure

Procedure _Asio_OutputReady()
Result=0
CompilerIf #ASIO_NATIVE
! mov ecx, dword [v__IAsio]
! mov eax, [ecx]
! call dword [eax+92]
! mov [p.v_Result], eax
CompilerElse
Result=_IAsio\OutputReady()
CompilerEndIf
ProcedureReturn Result
EndProcedure

Procedure BufferSwitchTimeInfo(lBufferNumber.l,*AsioTime.ASIOTime)
  Eng\BufferIndex=lBufferNumber
 
  ;AudioIn
  Select AsioDriver\channelInfos[AsioDriver\ActiveInput]\vType
    Case #ASIOSTInt16LSB 
      wSample.w=PeekW(AsioDriver\bufferInfos[AsioDriver\ActiveInput]\buffers[Eng\BufferIndex])
    Case #ASIOSTInt32LSB 
      lSample.l=PeekL(AsioDriver\bufferInfos[AsioDriver\ActiveInput]\buffers[Eng\BufferIndex]) 
  EndSelect      
  
  If Eng\Pause=0
    ;here comes code to generate output
    ;fill outputbuffers
    Select AsioDriver\channelInfos[AsioDriver\ActiveOutput]\vType
      Case #ASIOSTInt16LSB
        For j = 0 To Eng\BlockSize-1    
        Next
      Case #ASIOSTInt32LSB 
        For j = 0 To Eng\BlockSize-1    
        Next
      Case #ASIOSTFloat32LSB
        ;..........
    EndSelect
  EndIf
    
  Tag_Asio_Ready:
    If AsioDriver\postOutput
      _Asio_OutputReady() ;    // some asio drivers require this  
    EndIf
EndProcedure

ProcedureCDLL.l AsioBufferSwitchTimeInfo(*AsioTime.ASIOTime,doubleBufferIndex.l,directProcess.l) ;: PASIOTime; cdecl;
  Select directProcess 
    Case #False 
      ;PostMessage_(WindowID(#WindowDevice), #WM_ASIO, doubleBufferIndex,*AsioTime);
      ;or setevent_() or .....
    Case #True
      BufferSwitchTimeInfo(doubleBufferIndex, *AsioTime);
  EndSelect
  ProcedureReturn 0
EndProcedure
ProcedureCDLL AsioBufferSwitch(doubleBufferIndex.l,directProcess.l)
  If _Asio_GetSamplePosition(@AsioTime\timeInfo\samplePosition, @AsioTime\timeInfo\SystemTime) = #ASE_OK
    AsioTime\timeInfo\flags = #kSystemTimeValid | #kSamplePositionValid
  EndIf
  Select directProcess 
    Case #False 
      ;PostMessage_(WindowID(#WindowDevice), #WM_ASIO, doubleBufferIndex,#Null);
    Case #True
      BufferSwitchTimeInfo(doubleBufferIndex, AsioTime);
  EndSelect
EndProcedure
ProcedureCDLL.l AsioMessage(selector.l, Value.l, *message, *opt.MyDouble) ;: longint; cdecl;
  CompilerIf #Debug:ShowSelector(selector,Value):CompilerEndIf
  Result = 0
  ;ShowSelector(selector)
  Select selector
    Case #kAsioSelectorSupported
      Select Value
        Case #kAsioEngineVersion        :  Result = 1
        Case #kAsioResetRequest         :  Result = 1
        Case #kAsioBufferSizeChange     :  Result = 0
        Case #kAsioResyncRequest        :  Result = 1
        Case #kAsioLatenciesChanged     :  Result = 1
        Case #kAsioSupportsTimeInfo     :  Result = 1
        Case #kAsioSupportsTimeCode     :  Result = 0
        Case #kAsioSupportsInputMonitor :  Result = 0
      EndSelect
    Case #kAsioEngineVersion
      Result=2
    Case #kAsioResetRequest
      Eng\AsioReset=2
      PostMessage_(WindowID(#WindowDevice),#WM_ASIO_Reset,0,0)
      Result=1
    Case #kAsioBufferSizeChange
      Eng\AsioReset=1
      PostMessage_(WindowID(#WindowDevice),#WM_ASIO_Reset,0,0)
      Result=1
    Case #kAsioResyncRequest
      Eng\AsioReset=2
      PostMessage_(WindowID(#WindowDevice),#WM_ASIO_Reset,0,0)
      Result=1
    Case #kAsioLatenciesChanged
      Eng\AsioReset=1
      PostMessage_(WindowID(#WindowDevice),#WM_ASIO_Reset,0,0)
      Result=1
    Case #kAsioSupportsTimeInfo
      Result=1
    Case #kAsioSupportsTimeCode
    Case #kAsioSupportsInputMonitor
  EndSelect
  ProcedureReturn Result
EndProcedure

ProcedureCDLL AsioSampleRateDidChange(sRateHI.l, sRateLO.l)
EndProcedure

Procedure.l Asio_static_data()
  YnSampleRateOK=0
  If _Asio_GetChannels(@AsioDriver\inputChannels, @AsioDriver\outputChannels)=#ASE_OK 
    If _Asio_GetBufferSize(@AsioDriver\minSize, @AsioDriver\maxSize, @AsioDriver\preferredSize, @AsioDriver\granularity) = #ASE_OK
      If _Asio_GetSampleRate(@AsioDriver\SampleRate) = #ASE_OK 
        If Eng\SampleRate=44100 Or Eng\SampleRate=48000 Or Eng\SampleRate=96000
          ;Force to Engine Samplerate
          If _Asio_CanSampleRate(Eng\SampleRate) = #ASE_OK
            If _Asio_SetSampleRate(Eng\SampleRate) = #ASE_OK
              If _Asio_GetSampleRate(@AsioDriver\SampleRate) = #ASE_OK
              EndIf
            EndIf
          EndIf
        EndIf
      
        If AsioDriver\SampleRate <= 0 Or AsioDriver\SampleRate > 96000 
          ;Try 44100
          If _Asio_CanSampleRate(44100) = #ASE_OK
            If _Asio_SetSampleRate(44100) = #ASE_OK
              If _Asio_GetSampleRate(@AsioDriver\SampleRate) = #ASE_OK
                YnSampleRateOK=1
              EndIf
            EndIf
          EndIf
          If YnSampleRateOK=0
            If _Asio_CanSampleRate(48000) = #ASE_OK
              If _Asio_SetSampleRate(48000) = #ASE_OK
                If _Asio_GetSampleRate(@AsioDriver\SampleRate) = #ASE_OK
                  YnSampleRateOK=1
                EndIf
              EndIf
            EndIf
          EndIf
        Else
          YnSampleRateOK=1
        EndIf
      EndIf
      If _Asio_OutputReady() = #ASE_OK
        AsioDriver\postOutput = #True
      Else
        AsioDriver\postOutput = #False
      EndIf
    EndIf
  EndIf
  If YnSampleRateOK
    ProcedureReturn 0
  Else  
    ProcedureReturn 1
  EndIf
  tag_end:
EndProcedure
Procedure.l Asio_create_buffers()
; // fill the bufferInfos from the start without a gap
*info.AsioBufferInfo = @AsioDriver\bufferInfos;
; Inputs
If AsioDriver\inputChannels > #kMaxInputChannels
  AsioDriver\inputBuffers = #kMaxInputChannels;
Else
  AsioDriver\inputBuffers = AsioDriver\inputChannels
EndIf
AsioDriver\ActiveInput=0
AsioDriver\ActiveOutput=AsioDriver\inputBuffers
For i = 0 To AsioDriver\inputBuffers-1
  *info\isInput = #True
  *info\channelNum = i
  *info\buffers[0] = 0
  *info\buffers[1] = 0
  *info+SizeOf(AsioBufferInfo)
Next

; Outputs
If AsioDriver\outputChannels > #kMaxOutputChannels
  AsioDriver\outputBuffers = #kMaxOutputChannels
Else
  AsioDriver\outputBuffers = AsioDriver\outputChannels
EndIf
For i = 0 To AsioDriver\outputBuffers-1
  *info\isInput = #False
  *info\channelNum = i
  *info\buffers[0] = 0
  *info\buffers[1] = 0;
  *info+SizeOf(AsioBufferInfo)
Next

Result=_Asio_CreateBuffers(@AsioDriver\bufferInfos, AsioDriver\inputBuffers + AsioDriver\outputBuffers, AsioDriver\preferredSize, @callbacks)
If Result=#ASE_OK
  For  i = 0 To AsioDriver\inputBuffers + AsioDriver\outputBuffers -1
    AsioDriver\channelInfos[i]\channel = AsioDriver\bufferInfos[i]\channelNum
    AsioDriver\channelInfos[i]\isInput = AsioDriver\bufferInfos[i]\isInput
    Result = _Asio_GetChannelInfo(@AsioDriver\channelInfos[i])
    If  Result<>#ASE_OK
      ;Break
    Else
    EndIf
  Next
  If Result=#ASE_OK
    Result=_Asio_GetLatencies(@AsioDriver\inputLatency, @AsioDriver\outputLatency)
  EndIf
EndIf 
  ;AudioIn
Select AsioDriver\channelInfos[AsioDriver\ActiveInput]\vType
  Case #ASIOSTInt16LSB
  Case #ASIOSTInt32LSB 
EndSelect   
ProcedureReturn Result
EndProcedure

Procedure ASIO_Open()
  SelectElement(AsioDeviceInfo(),gDeviceID)
  sCLSID.s = AsioDeviceInfo()\CLSID$
  Err.l=CLSIDFromString_(WideStr(@sCLSID),@clsid.GUID)
  
  CoInitialize_(0); 
  CoCreateInstance_(@CLSID, #Null, 1, @CLSID, @_IAsio)
  hWnd=WindowID(#WindowDevice)
  Retval= _Asio_Init(hwnd)

  if RetVal
    If Asio_static_data() = 0
      callbacks\bufferSwitch          = @AsioBufferSwitch()
      callbacks\sampleRateDidChange   = @AsioSampleRateDidChange()
      callbacks\asioMessage           = @AsioMessage()
      callbacks\bufferSwitchTimeInfo  = @AsioBufferSwitchTimeInfo() 
      
      If Asio_create_buffers()=#ASE_OK 
        Eng\BlockSize=AsioDriver\preferredSize
        Eng\SampleRate=AsioDriver\SampleRate  
        If #EngineOn
          If _Asio_Start()=#ASE_OK
          Else
            MessageRequester("Asio","Driver could not be started",#MB_TOPMOST)
          EndIf
        EndIf
      Else
        MessageRequester("Asio","Unable to create the buffers",#MB_TOPMOST)
      EndIf
    EndIf
  EndIf

EndProcedure

Procedure ASIO_Close()
  Eng\Pause=1 
  If _Asio_Stop()=#ASE_OK
    If _Asio_DisposeBuffers()=#ASE_OK
      AsioDriver\stopped=1
    EndIf
  EndIf
  _Asio_release()
  _IAsio=0
  CoUninitialize_()
EndProcedure

Procedure.s Info_Refresh()

  With AsioDriver
    info$="Driver info"+chr(13)+chr(13)
    info$=info$+"inputChannels="+str(\inputChannels)+chr(13)
    info$=info$+"outputChannels="+str(\outputChannels)+chr(13)
    info$=info$+"minSize="+str(\minSize)+chr(13)
    info$=info$+"maxsize="+str(\maxSize)+chr(13)
    info$=info$+"preferredSize="+str(\preferredSize)+chr(13)
    info$=info$+"granularity="+str(\granularity)+chr(13)
    info$=info$+"samplerate="+StrD(\SampleRate)+chr(13)
    info$=info$+"postoutput="+str(\postOutput)+chr(13)
    info$=info$+"inputLatency="+str(\inputLatency)+chr(13)
    info$=info$+"outputLatency="+str(\outputLatency)
  EndWith

ProcedureReturn info$
EndProcedure

FillAsioDeviceInfo()

;Quick 'n dirty window implementation ;-)
OpenWindow(0,0,0,620,280,"Select Asio device",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
SetTimer_(WindowID(#WindowDevice),#TM_Refresh,25,@myTimerCB())

ListViewGadget(0,10,10,300,200)
ButtonGadget(1,10,220,300,25,"Start Asio device")
TextGadget(2,10,250,150,25,"Sampleposition")
TextGadget(3,320,10,300,180,"")
ButtonGadget(4,170,250,130,25,"Control Panel")

ResetList(AsioDeviceInfo()) : i = 0 :gDeviceID=-1
While NextElement(AsioDeviceInfo())
  AddGadgetItem(0,-1,AsioDeviceInfo()\AsioName$)
  i+1
Wend
repeat
ev=WaitWindowEvent()
  if ev=#PB_Event_Gadget
    Select EventGadget()
      case 0
        if gDeviceID<>GetGadgetState(0)
          if gAsioState=#Start
            ASIO_Close()
            gAsioState=#Stop
            SetGadgetText(1,"Start Asio device")
            SetGadgetText(2,"Sampleposition") 
            SetGadgetText(3,"")
          EndIf
          gDeviceID=GetGadgetState(0)
        EndIf
      Case 1
        if gAsioState=#Stop
          if gDeviceID>=0
            ASIO_Open()
            gAsioState=#Start
            SetGadgetText(1,"Stop Asio device") 
            SetGadgetText(3,Info_Refresh()) 
          EndIf
        else
          ASIO_Close()
          gAsioState=#Stop
          SetGadgetText(1,"Start Asio device")
          SetGadgetText(2,"Sampleposition")
          SetGadgetText(3,"") 
        endif
      Case 4
        if gAsioState=#Start
          _Asio_controlPanel()
        EndIf
    EndSelect
  EndIf
  if ev=#WM_ASIO_Reset
    if gAsioState=#Start
      Asio_close()
      Eng\AsioReset=0
      Asio_open()
      SetGadgetText(3,Info_Refresh()) 
    EndIf
  EndIf
until ev=#PB_Event_CloseWindow
if gAsioState=#Start
  Asio_close()
EndIf
User avatar
oreopa
Enthusiast
Enthusiast
Posts: 281
Joined: Sat Jun 24, 2006 3:29 am
Location: Edinburgh, Scotland.

Re: PB Asio

Post by oreopa »

Great! Thanx for posting this. :D
Proud supporter of PB! * Musician * C64/6502 Freak
User avatar
oryaaaaa
Enthusiast
Enthusiast
Posts: 791
Joined: Mon Jan 12, 2004 11:40 pm
Location: Okazaki, JAPAN

Re: PB Asio

Post by oryaaaaa »

Nice, thanks.

How output samples?

I want to Raw outputs ASIO library. then, use BASS ASIO.

TUSBAudio ASIO Driver
Driver info

inputChannels=2
outputChannels=2
minSize=272
maxsize=272
preferredSize=272
granularity=0
samplerate=44100
postoutput=0
inputLatency=448
outputLatency=448
eriansa
Enthusiast
Enthusiast
Posts: 277
Joined: Wed Mar 17, 2004 12:31 am
Contact:

Re: PB Asio

Post by eriansa »

oryaaaaa wrote:Nice, thanks.
How output samples?
see procedure "BufferSwitchTimeInfo"
User avatar
Psychophanta
Addict
Addict
Posts: 4996
Joined: Wed Jun 11, 2003 9:33 pm
Location: Lípetsk, Russian Federation
Contact:

Re: PB Asio

Post by Psychophanta »

Thanks :!: :wink:
http://www.zeitgeistmovie.com

While world=business:world+mafia:Wend
Will never leave this forum until the absolute bugfree PB :mrgreen:
cherri123
User
User
Posts: 32
Joined: Tue Apr 13, 2010 5:39 am

Re: PB Asio

Post by cherri123 »

Код работает прекрасно, но без прав администратора не определяет что есть АСИО. Следующий код исправляет недочет. Может я не прав?


The code works fine, but without administrative rights does not define what is ASIO. The following code corrects the defect. Maybe I'm wrong?

(line 279)

Code: Select all

RegOpenKeyEx_(#HKEY_LOCAL_MACHINE, #ASIO_PATH+"\"+AsioName$, 0, #KEY_READ, @hKey2)=0 
Last edited by cherri123 on Wed Aug 20, 2014 10:21 am, edited 1 time in total.
User avatar
Lord
Addict
Addict
Posts: 849
Joined: Tue May 26, 2009 2:11 pm

Re: PB Asio

Post by Lord »

cherri123 wrote:Код работает прекрасно, но без прав администратора не определяет что есть АСИО. Следующий код исправляет недочет. Может я не прав?
Rembrand?
Image
Aleks_Longard
User
User
Posts: 59
Joined: Mon Dec 24, 2012 9:07 am
Location: Germany, Munich

Re: PB Asio

Post by Aleks_Longard »

Very thanks eriansa!
You do not have the simplest code vst synth?
cherri123 wrote:Код работает прекрасно, но без прав администратора не определяет что есть АСИО. Следующий код исправляет недочет. Может я не прав?


The code works fine, but without administrative rights does not define what is ASIO. The following code corrects the defect. Maybe I'm wrong?

(line 279)

Code: Select all

RegOpenKeyEx_(#HKEY_LOCAL_MACHINE, #ASIO_PATH+"\"+AsioName$, 0, #KEY_READ, @hKey2)=0 
You should have the asio driver.
Должен быть установлен asio драйвер.
Sory my bad english
Tranquil
Addict
Addict
Posts: 950
Joined: Mon Apr 28, 2003 2:22 pm
Location: Europe

Re: PB Asio

Post by Tranquil »

Thanks for sharing.
One question: Why do you use Enumeration if you assign the values by your own?
Tranquil
User avatar
oryaaaaa
Enthusiast
Enthusiast
Posts: 791
Joined: Mon Jan 12, 2004 11:40 pm
Location: Okazaki, JAPAN

Re: PB Asio

Post by oryaaaaa »

eriansa wrote:
oryaaaaa wrote:Nice, thanks.
How output samples?
see procedure "BufferSwitchTimeInfo"
I am trying high quality asio output.
If you improve asio sound quality, should use follows tips.

my tips
1. Don't use MOVQ for write memory
2. Use MOVNTQ for write memory
3. Use mmx register for copy memory buffer

my code

Code: Select all

Procedure CopyMemoryMMX(*memory_in, *memory_out, mem_size.i)
  Protected s.i ; this variable use interger for High quality sound
  
  If mem_size%8>0
    s = mem_size + ( 8 - mem_size%8 ) ; adjust align
  Else
    s = mem_size
  EndIf 
  
  If s<1
    ProcedureReturn
  EndIf
  
  CompilerSelect #PB_Compiler_Processor
    CompilerCase #PB_Processor_x86
      !PXOR mm1, mm1
      !MOV Eax, [p.v_s]
      !MOV Ecx, [p.p_memory_in]
      !MOV Edx, [p.p_memory_out]
      !copy_mmx:
      !PXOR mm1, mm1
      !movq mm1, [Ecx]
      !movntq [Edx], mm1 ; don't use CPU cache
      !ADD  Ecx, 8
      !ADD  Edx, 8
      !SUB  Eax, 8
      !JNZ copy_mmx
      !emms
      ProcedureReturn
    CompilerCase #PB_Processor_x64
      !PXOR mm1, mm1
      !MOV Rax, [p.v_s]
      !MOV Rcx, [p.p_memory_in]
      !MOV Rdx, [p.p_memory_out]
      !copy_mmx:
      !PXOR mm1, mm1
      !movq mm1, [Rcx]
      !movntq [Rdx], mm1 ; don't use CPU cache
      !ADD  Rcx, 8
      !ADD  Rdx, 8
      !SUB  Rax, 8
      !JNZ copy_mmx
      !emms
      ProcedureReturn
  CompilerEndSelect
EndProcedure
AndyMK
Enthusiast
Enthusiast
Posts: 540
Joined: Wed Jul 12, 2006 4:38 pm
Location: UK

Re: PB Asio

Post by AndyMK »

Hi, can anyone help me get this running on PB 5.71 LTS? I get and invalid memory access at address 0 in the following procedure

Code: Select all

Procedure _Asio_Init(sysHandle)
Result=0; <----- ERROR
CompilerIf #ASIO_NATIVE
! mov eax, [p.v_sysHandle]
! push eax
! mov ecx, dword [v__IAsio]
! mov eax, [ecx]
! call dword [eax+12]
! mov [p.v_Result], eax
CompilerElse
Result=_IAsio\Init(sysHandle)
CompilerEndIf
ProcedureReturn Result
EndProcedure
The asio driver is listed. It dies when i click start asio device
Post Reply