PB ASIO Updated for PB6x

Share your advanced PureBasic knowledge/code with the community.
AndyMK
Enthusiast
Enthusiast
Posts: 540
Joined: Wed Jul 12, 2006 4:38 pm
Location: UK

PB ASIO Updated for PB6x

Post by AndyMK »

Run as Administrator

Code: Select all

;:=============================================================================
;;- ORIGINAL Source code
;:- 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
;:=============================================================================

;:=============================================================================
;;- x64 ONLY. Updated for PB6
;:- PB_Asio.pb 
;:- Author          : AndyMK
;:- Date            : August 15, 2022
;:- Compiler        : PureBasic 6.0 LTS
;:- Target OS       : Windows x64 Only
;:=============================================================================

;x64 only

#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

; you need the interface definition:
Interface MyUnknown
  QueryInterface.l(*riid.IID, *ppv.Integer)
  AddRef.l()
  Release.l()
EndInterface

Interface MyTestClass Extends IUnknown
  Init.l(sysHandle)
  GetDriverName.l(*Name)
  GetDriverVersion.l()
  GetErrorMessage(*errorStrings)
  Start()
  Stop()
  GetChannels(*numInputChannels.Long, *numOutputChannels.Long)
  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 *MyTestClassObject.MyTestClass = #Null
Global AsioTime.ASIOTime
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_READ,@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 = Len(PeekS(pointer))+2 
  widebuf.i = AllocateMemory(widelen) 
  longlen.w = MultiByteToWideChar_(#CP_ACP,0,pointer,-1,widebuf,widelen) 
  ProcedureReturn widebuf 
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
      *MyTestClassObject\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 *MyTestClassObject\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 *MyTestClassObject\GetChannels(@AsioDriver\inputChannels, @AsioDriver\outputChannels)=#ASE_OK 
    If *MyTestClassObject\GetBufferSize(@AsioDriver\minSize, @AsioDriver\maxSize, @AsioDriver\preferredSize, @AsioDriver\granularity) = #ASE_OK
      If*MyTestClassObject\GetSampleRate(@AsioDriver\SampleRate) = #ASE_OK 
        If Eng\SampleRate=44100 Or Eng\SampleRate=48000 Or Eng\SampleRate=96000
          ;Force to Engine Samplerate
          If *MyTestClassObject\CanSampleRate(Eng\SampleRate) = #ASE_OK
            If *MyTestClassObject\SetSampleRate(Eng\SampleRate) = #ASE_OK
              If *MyTestClassObject\GetSampleRate(@AsioDriver\SampleRate) = #ASE_OK
              EndIf
            EndIf
          EndIf
        EndIf
      
        If AsioDriver\SampleRate <= 0 Or AsioDriver\SampleRate > 96000 
          ;Try 44100
          If *MyTestClassObject\CanSampleRate(44100) = #ASE_OK
            If *MyTestClassObject\SetSampleRate(44100) = #ASE_OK
              If*MyTestClassObject\GetSampleRate(@AsioDriver\SampleRate) = #ASE_OK
                YnSampleRateOK=1
              EndIf
            EndIf
          EndIf
          If YnSampleRateOK=0
            If*MyTestClassObject\CanSampleRate(48000) = #ASE_OK
              If *MyTestClassObject\SetSampleRate(48000) = #ASE_OK
                If*MyTestClassObject\GetSampleRate(@AsioDriver\SampleRate) = #ASE_OK
                  YnSampleRateOK=1
                EndIf
              EndIf
            EndIf
          EndIf
        Else
          YnSampleRateOK=1
        EndIf
      EndIf
      If*MyTestClassObject\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=*MyTestClassObject\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 = *MyTestClassObject\GetChannelInfo(@AsioDriver\channelInfos[i])
    If  Result<>#ASE_OK
      ;Break
    Else
    EndIf
  Next
  If Result=#ASE_OK
    Result=*MyTestClassObject\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)
  
  UuidFromString_(Mid(sCLSID,2, Len(sCLSID) - 2), @CLSID_MyTestClass)
    
  CoInitialize_(0); 
  CoCreateInstance_(@CLSID_MyTestClass, #Null, 1, @CLSID_MyTestClass, @*MyTestClassObject)
  hWnd=WindowID(#WindowDevice)
  Retval= *MyTestClassObject\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 *MyTestClassObject\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 *MyTestClassObject\Stop()=#ASE_OK
    If *MyTestClassObject\DisposeBuffers()=#ASE_OK
      AsioDriver\stopped=1
    EndIf
  EndIf
  *MyTestClassObject\release()
  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
          *MyTestClassObject\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
15/08/2022 - Updated to show drivers without requiring Administrator rights.
Last edited by AndyMK on Mon Aug 15, 2022 4:53 pm, edited 6 times in total.
User avatar
ChrisR
Addict
Addict
Posts: 1127
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: PB ASIO Updated for PB6x

Post by ChrisR »

Thanks AndyMK :)
Aleks_Longard
User
User
Posts: 59
Joined: Mon Dec 24, 2012 9:07 am
Location: Germany, Munich

Re: PB ASIO Updated for PB6x

Post by Aleks_Longard »

AndyMK, thank you!
Sory my bad english
User avatar
idle
Always Here
Always Here
Posts: 5040
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: PB ASIO Updated for PB6x

Post by idle »

Thanks for sharing.
Ziltch
User
User
Posts: 52
Joined: Sun Aug 03, 2003 12:05 am
Location: Australia

Re: PB ASIO Updated for PB6x

Post by Ziltch »

Wow. Thanks!
Post Reply