aboutsummaryrefslogtreecommitdiff
path: root/pd/portaudio/pa_asio
diff options
context:
space:
mode:
Diffstat (limited to 'pd/portaudio/pa_asio')
-rw-r--r--pd/portaudio/pa_asio/ASIO-README.txt137
-rw-r--r--pd/portaudio/pa_asio/Callback_adaptation_.pdfbin50527 -> 0 bytes
-rw-r--r--pd/portaudio/pa_asio/Pa_ASIO.pdfbin50778 -> 0 bytes
-rw-r--r--pd/portaudio/pa_asio/iasiothiscallresolver.cpp563
-rw-r--r--pd/portaudio/pa_asio/iasiothiscallresolver.h197
-rw-r--r--pd/portaudio/pa_asio/pa_asio.cpp2958
-rw-r--r--pd/portaudio/pa_asio/pa_asio.h122
7 files changed, 0 insertions, 3977 deletions
diff --git a/pd/portaudio/pa_asio/ASIO-README.txt b/pd/portaudio/pa_asio/ASIO-README.txt
deleted file mode 100644
index 9fb74ae1..00000000
--- a/pd/portaudio/pa_asio/ASIO-README.txt
+++ /dev/null
@@ -1,137 +0,0 @@
-ASIO-README.txt
-
-This document contains information to help you compile PortAudio with
-ASIO support. If you find any omissions or errors in this document
-please notify Ross Bencina <rossb@audiomulch.com>.
-
-
-Building PortAudio with ASIO support
-------------------------------------
-
-To build PortAudio with ASIO support you need to compile and link with
-pa_asio.c, and files from the ASIO SDK (see below), along with the common
-files from pa_common/ and platform specific files from pa_win/ (for Win32)
-or pa_mac/ (for Macintosh).
-
-If you are compiling with a non-Microsoft compiler on windows, also
-compile and link with iasiothiscallresolver.cpp (see below for
-an explanation).
-
-For some platforms (MingW, possibly Mac), you may simply
-be able to type:
-
-./configure --with-host_os=mingw --with-winapi=asio [--with-asiodir=/usr/local/asiosdk2]
-make
-
-./configure --with-host_os=darwin --with-winapi=asio [--with-asiodir=/usr/local/asiosdk2]
-make
-
-and life will be good.
-
-
-Obtaining the ASIO SDK
-----------------------
-
-In order to build PortAudio with ASIO support, you need to download
-the ASIO SDK (version 2.0) from Steinberg. Steinberg makes the ASIO
-SDK available to anyone free of charge, however they do not permit its
-source code to be distributed.
-
-NOTE: In some cases the ASIO SDK may require patching, see below
-for further details.
-
-http://www.steinberg.net/en/ps/support/3rdparty/asio_sdk/
-
-If the above link is broken search Google for:
-"download steinberg ASIO SDK"
-
-
-
-Building the ASIO SDK on Macintosh
-----------------------------------
-
-To build the ASIO SDK on Macintosh you need to compile and link with the
-following files from the ASIO SDK:
-
-host/asiodrivers.cpp
-host/mac/asioshlib.cpp
-host/mac/codefragements.cpp
-
-
-
-Building the ASIO SDK on Windows
---------------------------------
-
-To build the ASIO SDK on Windows you need to compile and link with the
-following files from the ASIO SDK:
-
-asio_sdk\common\asio.cpp
-asio_sdk\host\asiodrivers.cpp
-asio_sdk\host\pc\asiolist.cpp
-
-You may also need to adjust your include paths to support inclusion of
-header files from the above directories.
-
-The ASIO SDK depends on the following COM API functions:
-CoInitialize, CoUninitialize, CoCreateInstance, CLSIDFromString
-For compilation with MinGW you will need to link with -lole32, for
-Borland link with Import32.lib.
-
-
-
-Non-Microsoft (MSVC) Compilers on Windows including Borland and GCC
--------------------------------------------------------------------
-
-Steinberg did not specify a calling convention in the IASIO interface
-definition. This causes the Microsoft compiler to use the proprietary
-thiscall convention which is not compatible with other compilers, such
-as compilers from Borland (BCC and C++Builder) and GNU (gcc).
-Steinberg's ASIO SDK will compile but crash on initialization if
-compiled with a non-Microsoft compiler on Windows.
-
-PortAudio solves this problem using the iasiothiscallresolver library
-which is included in the distribution. When building ASIO support for
-non-Microsoft compilers, be sure to compile and link with
-iasiothiscallresolver.cpp. Note that iasiothiscallresolver includes
-conditional directives which cause it to have no effect if it is
-compiled with a Microsoft compiler, or on the Macintosh.
-
-If you use configure and make (see above), this should be handled
-automatically for you.
-
-For further information about the IASIO thiscall problem see this page:
-http://www.audiomulch.com/~rossb/code/calliasio
-
-
-
-Macintosh ASIO SDK Bug Patch
-----------------------------
-
-There is a bug in the ASIO SDK that causes the Macintosh version to
-often fail during initialization. Below is a patch that you can apply.
-
-In codefragments.cpp replace getFrontProcessDirectory function with
-the following one (GetFrontProcess replaced by GetCurrentProcess).
-
-
-bool CodeFragments::getFrontProcessDirectory(void *specs)
-{
- FSSpec *fss = (FSSpec *)specs;
- ProcessInfoRec pif;
- ProcessSerialNumber psn;
-
- memset(&psn,0,(long)sizeof(ProcessSerialNumber));
- // if(GetFrontProcess(&psn) == noErr) // wrong !!!
- if(GetCurrentProcess(&psn) == noErr) // correct !!!
- {
- pif.processName = 0;
- pif.processAppSpec = fss;
- pif.processInfoLength = sizeof(ProcessInfoRec);
- if(GetProcessInformation(&psn, &pif) == noErr)
- return true;
- }
- return false;
-}
-
-
----
diff --git a/pd/portaudio/pa_asio/Callback_adaptation_.pdf b/pd/portaudio/pa_asio/Callback_adaptation_.pdf
deleted file mode 100644
index 76bf6786..00000000
--- a/pd/portaudio/pa_asio/Callback_adaptation_.pdf
+++ /dev/null
Binary files differ
diff --git a/pd/portaudio/pa_asio/Pa_ASIO.pdf b/pd/portaudio/pa_asio/Pa_ASIO.pdf
deleted file mode 100644
index ac5ecadb..00000000
--- a/pd/portaudio/pa_asio/Pa_ASIO.pdf
+++ /dev/null
Binary files differ
diff --git a/pd/portaudio/pa_asio/iasiothiscallresolver.cpp b/pd/portaudio/pa_asio/iasiothiscallresolver.cpp
deleted file mode 100644
index 8dfefbd6..00000000
--- a/pd/portaudio/pa_asio/iasiothiscallresolver.cpp
+++ /dev/null
@@ -1,563 +0,0 @@
-/*
- 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_ (&param1); \
- __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"(&param1), /* 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 */
-
diff --git a/pd/portaudio/pa_asio/iasiothiscallresolver.h b/pd/portaudio/pa_asio/iasiothiscallresolver.h
deleted file mode 100644
index 2ecfed79..00000000
--- a/pd/portaudio/pa_asio/iasiothiscallresolver.h
+++ /dev/null
@@ -1,197 +0,0 @@
-// ****************************************************************************
-// 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 <asiodrvr.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 */
-
-
diff --git a/pd/portaudio/pa_asio/pa_asio.cpp b/pd/portaudio/pa_asio/pa_asio.cpp
deleted file mode 100644
index 21987c71..00000000
--- a/pd/portaudio/pa_asio/pa_asio.cpp
+++ /dev/null
@@ -1,2958 +0,0 @@
-/*
- * $Id: pa_asio.cpp,v 1.7.2.68 2005/12/05 04:55:28 rossbencina Exp $
- * Portable Audio I/O Library for ASIO Drivers
- *
- * Author: Stephane Letz
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 2000-2002 Stephane Letz, Phil Burk, Ross Bencina
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/* Modification History
-
- 08-03-01 First version : Stephane Letz
- 08-06-01 Tweaks for PC, use C++, buffer allocation, Float32 to Int32 conversion : Phil Burk
- 08-20-01 More conversion, PA_StreamTime, Pa_GetHostError : Stephane Letz
- 08-21-01 PaUInt8 bug correction, implementation of ASIOSTFloat32LSB and ASIOSTFloat32MSB native formats : Stephane Letz
- 08-24-01 MAX_INT32_FP hack, another Uint8 fix : Stephane and Phil
- 08-27-01 Implementation of hostBufferSize < userBufferSize case, better management of the ouput buffer when
- the stream is stopped : Stephane Letz
- 08-28-01 Check the stream pointer for null in bufferSwitchTimeInfo, correct bug in bufferSwitchTimeInfo when
- the stream is stopped : Stephane Letz
- 10-12-01 Correct the PaHost_CalcNumHostBuffers function: computes FramesPerHostBuffer to be the lowest that
- respect requested FramesPerUserBuffer and userBuffersPerHostBuffer : Stephane Letz
- 10-26-01 Management of hostBufferSize and userBufferSize of any size : Stephane Letz
- 10-27-01 Improve calculus of hostBufferSize to be multiple or divisor of userBufferSize if possible : Stephane and Phil
- 10-29-01 Change MAX_INT32_FP to (2147483520.0f) to prevent roundup to 0x80000000 : Phil Burk
- 10-31-01 Clear the ouput buffer and user buffers in PaHost_StartOutput, correct bug in GetFirstMultiple : Stephane Letz
- 11-06-01 Rename functions : Stephane Letz
- 11-08-01 New Pa_ASIO_Adaptor_Init function to init Callback adpatation variables, cleanup of Pa_ASIO_Callback_Input: Stephane Letz
- 11-29-01 Break apart device loading to debug random failure in Pa_ASIO_QueryDeviceInfo ; Phil Burk
- 01-03-02 Desallocate all resources in PaHost_Term for cases where Pa_CloseStream is not called properly : Stephane Letz
- 02-01-02 Cleanup, test of multiple-stream opening : Stephane Letz
- 19-02-02 New Pa_ASIO_loadDriver that calls CoInitialize on each thread on Windows : Stephane Letz
- 09-04-02 Correct error code management in PaHost_Term, removes various compiler warning : Stephane Letz
- 12-04-02 Add Mac includes for <Devices.h> and <Timer.h> : Phil Burk
- 13-04-02 Removes another compiler warning : Stephane Letz
- 30-04-02 Pa_ASIO_QueryDeviceInfo bug correction, memory allocation checking, better error handling : D Viens, P Burk, S Letz
- 12-06-02 Rehashed into new multi-api infrastructure, added support for all ASIO sample formats : Ross Bencina
- 18-06-02 Added pa_asio.h, PaAsio_GetAvailableLatencyValues() : Ross B.
- 21-06-02 Added SelectHostBufferSize() which selects host buffer size based on user latency parameters : Ross Bencina
- ** NOTE maintanance history is now stored in CVS **
-*/
-
-/** @file
-
- Note that specific support for paInputUnderflow, paOutputOverflow and
- paNeverDropInput is not necessary or possible with this driver due to the
- synchronous full duplex double-buffered architecture of ASIO.
-
- @todo check that CoInitialize()/CoUninitialize() are always correctly
- paired, even in error cases.
-
- @todo implement host api specific extension to set i/o buffer sizes in frames
-
- @todo implement ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable
-
- @todo implement IsFormatSupported
-
- @todo work out how to implement stream stoppage from callback and
- implement IsStreamActive properly. Stream stoppage could be implemented
- using a high-priority thread blocked on an Event which is signalled
- by the callback. Or, we could just call ASIO stop from the callback
- and see what happens.
-
- @todo rigorously check asio return codes and convert to pa error codes
-
- @todo Different channels of a multichannel stream can have different sample
- formats, but we assume that all are the same as the first channel for now.
- Fixing this will require the block processor to maintain per-channel
- conversion functions - could get nasty.
-
- @todo investigate whether the asio processNow flag needs to be honoured
-
- @todo handle asioMessages() callbacks in a useful way, or at least document
- what cases we don't handle.
-
- @todo miscellaneous other FIXMEs
-
- @todo provide an asio-specific method for setting the systems specific
- value (aka main window handle) - check that this matches the value
- passed to PaAsio_ShowControlPanel, or remove it entirely from
- PaAsio_ShowControlPanel. - this would allow PaAsio_ShowControlPanel
- to be called for the currently open stream (at present all streams
- must be closed).
-*/
-
-
-
-#include <stdio.h>
-#include <assert.h>
-#include <string.h>
-//#include <values.h>
-
-#include <windows.h>
-#include <mmsystem.h>
-
-#include "portaudio.h"
-#include "pa_asio.h"
-#include "pa_util.h"
-#include "pa_allocation.h"
-#include "pa_hostapi.h"
-#include "pa_stream.h"
-#include "pa_cpuload.h"
-#include "pa_process.h"
-
-#include "asiosys.h"
-#include "asio.h"
-#include "asiodrivers.h"
-#include "iasiothiscallresolver.h"
-
-/*
-#if MAC
-#include <Devices.h>
-#include <Timer.h>
-#include <Math64.h>
-#else
-*/
-/*
-#include <math.h>
-#include <windows.h>
-#include <mmsystem.h>
-*/
-/*
-#endif
-*/
-
-/* external references */
-extern AsioDrivers* asioDrivers ;
-bool loadAsioDriver(char *name);
-
-
-/* We are trying to be compatible with CARBON but this has not been thoroughly tested. */
-/* not tested at all since new code was introduced. */
-#define CARBON_COMPATIBLE (0)
-
-
-
-
-/* prototypes for functions declared in this file */
-
-extern "C" PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex );
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
-static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
- PaStream** s,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate,
- unsigned long framesPerBuffer,
- PaStreamFlags streamFlags,
- PaStreamCallback *streamCallback,
- void *userData );
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate );
-static PaError CloseStream( PaStream* stream );
-static PaError StartStream( PaStream *stream );
-static PaError StopStream( PaStream *stream );
-static PaError AbortStream( PaStream *stream );
-static PaError IsStreamStopped( PaStream *s );
-static PaError IsStreamActive( PaStream *stream );
-static PaTime GetStreamTime( PaStream *stream );
-static double GetStreamCpuLoad( PaStream* stream );
-static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
-static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
-static signed long GetStreamReadAvailable( PaStream* stream );
-static signed long GetStreamWriteAvailable( PaStream* stream );
-
-/* our ASIO callback functions */
-
-static void bufferSwitch(long index, ASIOBool processNow);
-static ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow);
-static void sampleRateChanged(ASIOSampleRate sRate);
-static long asioMessages(long selector, long value, void* message, double* opt);
-
-static ASIOCallbacks asioCallbacks_ =
- { bufferSwitch, sampleRateChanged, asioMessages, bufferSwitchTimeInfo };
-
-
-#define PA_ASIO_SET_LAST_HOST_ERROR( errorCode, errorText ) \
- PaUtil_SetLastHostErrorInfo( paASIO, errorCode, errorText )
-
-
-static void PaAsio_SetLastSystemError( DWORD errorCode )
-{
- LPVOID lpMsgBuf;
- FormatMessage(
- FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
- NULL,
- errorCode,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR) &lpMsgBuf,
- 0,
- NULL
- );
- PaUtil_SetLastHostErrorInfo( paASIO, errorCode, (const char*)lpMsgBuf );
- LocalFree( lpMsgBuf );
-}
-
-#define PA_ASIO_SET_LAST_SYSTEM_ERROR( errorCode ) \
- PaAsio_SetLastSystemError( errorCode )
-
-
-static const char* PaAsio_GetAsioErrorText( ASIOError asioError )
-{
- const char *result;
-
- switch( asioError ){
- case ASE_OK:
- case ASE_SUCCESS: result = "Success"; break;
- case ASE_NotPresent: result = "Hardware input or output is not present or available"; break;
- case ASE_HWMalfunction: result = "Hardware is malfunctioning"; break;
- case ASE_InvalidParameter: result = "Input parameter invalid"; break;
- case ASE_InvalidMode: result = "Hardware is in a bad mode or used in a bad mode"; break;
- case ASE_SPNotAdvancing: result = "Hardware is not running when sample position is inquired"; break;
- case ASE_NoClock: result = "Sample clock or rate cannot be determined or is not present"; break;
- case ASE_NoMemory: result = "Not enough memory for completing the request"; break;
- default: result = "Unknown ASIO error"; break;
- }
-
- return result;
-}
-
-
-#define PA_ASIO_SET_LAST_ASIO_ERROR( asioError ) \
- PaUtil_SetLastHostErrorInfo( paASIO, asioError, PaAsio_GetAsioErrorText( asioError ) )
-
-
-
-
-// Atomic increment and decrement operations
-#if MAC
- /* need to be implemented on Mac */
- inline long PaAsio_AtomicIncrement(volatile long* v) {return ++(*const_cast<long*>(v));}
- inline long PaAsio_AtomicDecrement(volatile long* v) {return --(*const_cast<long*>(v));}
-#elif WINDOWS
- inline long PaAsio_AtomicIncrement(volatile long* v) {return InterlockedIncrement(const_cast<long*>(v));}
- inline long PaAsio_AtomicDecrement(volatile long* v) {return InterlockedDecrement(const_cast<long*>(v));}
-#endif
-
-
-
-typedef struct PaAsioDriverInfo
-{
- ASIODriverInfo asioDriverInfo;
- long inputChannelCount, outputChannelCount;
- long bufferMinSize, bufferMaxSize, bufferPreferredSize, bufferGranularity;
- bool postOutput;
-}
-PaAsioDriverInfo;
-
-
-/* PaAsioHostApiRepresentation - host api datastructure specific to this implementation */
-
-typedef struct
-{
- PaUtilHostApiRepresentation inheritedHostApiRep;
- PaUtilStreamInterface callbackStreamInterface;
- PaUtilStreamInterface blockingStreamInterface;
-
- PaUtilAllocationGroup *allocations;
-
- void *systemSpecific;
-
- /* the ASIO C API only allows one ASIO driver to be open at a time,
- so we keep track of whether we have the driver open here, and
- use this information to return errors from OpenStream if the
- driver is already open.
-
- openAsioDeviceIndex will be PaNoDevice if there is no device open
- and a valid pa_asio (not global) device index otherwise.
-
- openAsioDriverInfo is populated with the driver info for the
- currently open device (if any)
- */
- PaDeviceIndex openAsioDeviceIndex;
- PaAsioDriverInfo openAsioDriverInfo;
-}
-PaAsioHostApiRepresentation;
-
-
-/*
- Retrieve <driverCount> driver names from ASIO, returned in a char**
- allocated in <group>.
-*/
-static char **GetAsioDriverNames( PaUtilAllocationGroup *group, long driverCount )
-{
- char **result = 0;
- int i;
-
- result =(char**)PaUtil_GroupAllocateMemory(
- group, sizeof(char*) * driverCount );
- if( !result )
- goto error;
-
- result[0] = (char*)PaUtil_GroupAllocateMemory(
- group, 32 * driverCount );
- if( !result[0] )
- goto error;
-
- for( i=0; i<driverCount; ++i )
- result[i] = result[0] + (32 * i);
-
- asioDrivers->getDriverNames( result, driverCount );
-
-error:
- return result;
-}
-
-
-static PaSampleFormat AsioSampleTypeToPaNativeSampleFormat(ASIOSampleType type)
-{
- switch (type) {
- case ASIOSTInt16MSB:
- case ASIOSTInt16LSB:
- return paInt16;
-
- case ASIOSTFloat32MSB:
- case ASIOSTFloat32LSB:
- case ASIOSTFloat64MSB:
- case ASIOSTFloat64LSB:
- return paFloat32;
-
- case ASIOSTInt32MSB:
- case ASIOSTInt32LSB:
- case ASIOSTInt32MSB16:
- case ASIOSTInt32LSB16:
- case ASIOSTInt32MSB18:
- case ASIOSTInt32MSB20:
- case ASIOSTInt32MSB24:
- case ASIOSTInt32LSB18:
- case ASIOSTInt32LSB20:
- case ASIOSTInt32LSB24:
- return paInt32;
-
- case ASIOSTInt24MSB:
- case ASIOSTInt24LSB:
- return paInt24;
-
- default:
- return paCustomFormat;
- }
-}
-
-void AsioSampleTypeLOG(ASIOSampleType type)
-{
- switch (type) {
- case ASIOSTInt16MSB: PA_DEBUG(("ASIOSTInt16MSB\n")); break;
- case ASIOSTInt16LSB: PA_DEBUG(("ASIOSTInt16LSB\n")); break;
- case ASIOSTFloat32MSB:PA_DEBUG(("ASIOSTFloat32MSB\n"));break;
- case ASIOSTFloat32LSB:PA_DEBUG(("ASIOSTFloat32LSB\n"));break;
- case ASIOSTFloat64MSB:PA_DEBUG(("ASIOSTFloat64MSB\n"));break;
- case ASIOSTFloat64LSB:PA_DEBUG(("ASIOSTFloat64LSB\n"));break;
- case ASIOSTInt32MSB: PA_DEBUG(("ASIOSTInt32MSB\n")); break;
- case ASIOSTInt32LSB: PA_DEBUG(("ASIOSTInt32LSB\n")); break;
- case ASIOSTInt32MSB16:PA_DEBUG(("ASIOSTInt32MSB16\n"));break;
- case ASIOSTInt32LSB16:PA_DEBUG(("ASIOSTInt32LSB16\n"));break;
- case ASIOSTInt32MSB18:PA_DEBUG(("ASIOSTInt32MSB18\n"));break;
- case ASIOSTInt32MSB20:PA_DEBUG(("ASIOSTInt32MSB20\n"));break;
- case ASIOSTInt32MSB24:PA_DEBUG(("ASIOSTInt32MSB24\n"));break;
- case ASIOSTInt32LSB18:PA_DEBUG(("ASIOSTInt32LSB18\n"));break;
- case ASIOSTInt32LSB20:PA_DEBUG(("ASIOSTInt32LSB20\n"));break;
- case ASIOSTInt32LSB24:PA_DEBUG(("ASIOSTInt32LSB24\n"));break;
- case ASIOSTInt24MSB: PA_DEBUG(("ASIOSTInt24MSB\n")); break;
- case ASIOSTInt24LSB: PA_DEBUG(("ASIOSTInt24LSB\n")); break;
- default: PA_DEBUG(("Custom Format%d\n",type));break;
-
- }
-}
-
-static int BytesPerAsioSample( ASIOSampleType sampleType )
-{
- switch (sampleType) {
- case ASIOSTInt16MSB:
- case ASIOSTInt16LSB:
- return 2;
-
- case ASIOSTFloat64MSB:
- case ASIOSTFloat64LSB:
- return 8;
-
- case ASIOSTFloat32MSB:
- case ASIOSTFloat32LSB:
- case ASIOSTInt32MSB:
- case ASIOSTInt32LSB:
- case ASIOSTInt32MSB16:
- case ASIOSTInt32LSB16:
- case ASIOSTInt32MSB18:
- case ASIOSTInt32MSB20:
- case ASIOSTInt32MSB24:
- case ASIOSTInt32LSB18:
- case ASIOSTInt32LSB20:
- case ASIOSTInt32LSB24:
- return 4;
-
- case ASIOSTInt24MSB:
- case ASIOSTInt24LSB:
- return 3;
-
- default:
- return 0;
- }
-}
-
-
-static void Swap16( void *buffer, long shift, long count )
-{
- unsigned short *p = (unsigned short*)buffer;
- unsigned short temp;
- (void) shift; /* unused parameter */
-
- while( count-- )
- {
- temp = *p;
- *p++ = (unsigned short)((temp<<8) | (temp>>8));
- }
-}
-
-static void Swap24( void *buffer, long shift, long count )
-{
- unsigned char *p = (unsigned char*)buffer;
- unsigned char temp;
- (void) shift; /* unused parameter */
-
- while( count-- )
- {
- temp = *p;
- *p = *(p+2);
- *(p+2) = temp;
- p += 3;
- }
-}
-
-#define PA_SWAP32_( x ) ((x>>24) | ((x>>8)&0xFF00) | ((x<<8)&0xFF0000) | (x<<24));
-
-static void Swap32( void *buffer, long shift, long count )
-{
- unsigned long *p = (unsigned long*)buffer;
- unsigned long temp;
- (void) shift; /* unused parameter */
-
- while( count-- )
- {
- temp = *p;
- *p++ = PA_SWAP32_( temp);
- }
-}
-
-static void SwapShiftLeft32( void *buffer, long shift, long count )
-{
- unsigned long *p = (unsigned long*)buffer;
- unsigned long temp;
-
- while( count-- )
- {
- temp = *p;
- temp = PA_SWAP32_( temp);
- *p++ = temp << shift;
- }
-}
-
-static void ShiftRightSwap32( void *buffer, long shift, long count )
-{
- unsigned long *p = (unsigned long*)buffer;
- unsigned long temp;
-
- while( count-- )
- {
- temp = *p >> shift;
- *p++ = PA_SWAP32_( temp);
- }
-}
-
-static void ShiftLeft32( void *buffer, long shift, long count )
-{
- unsigned long *p = (unsigned long*)buffer;
- unsigned long temp;
-
- while( count-- )
- {
- temp = *p;
- *p++ = temp << shift;
- }
-}
-
-static void ShiftRight32( void *buffer, long shift, long count )
-{
- unsigned long *p = (unsigned long*)buffer;
- unsigned long temp;
-
- while( count-- )
- {
- temp = *p;
- *p++ = temp >> shift;
- }
-}
-
-#define PA_SWAP_( x, y ) temp=x; x = y; y = temp;
-
-static void Swap64ConvertFloat64ToFloat32( void *buffer, long shift, long count )
-{
- double *in = (double*)buffer;
- float *out = (float*)buffer;
- unsigned char *p;
- unsigned char temp;
- (void) shift; /* unused parameter */
-
- while( count-- )
- {
- p = (unsigned char*)in;
- PA_SWAP_( p[0], p[7] );
- PA_SWAP_( p[1], p[6] );
- PA_SWAP_( p[2], p[5] );
- PA_SWAP_( p[3], p[4] );
-
- *out++ = (float) (*in++);
- }
-}
-
-static void ConvertFloat64ToFloat32( void *buffer, long shift, long count )
-{
- double *in = (double*)buffer;
- float *out = (float*)buffer;
- (void) shift; /* unused parameter */
-
- while( count-- )
- *out++ = (float) (*in++);
-}
-
-static void ConvertFloat32ToFloat64Swap64( void *buffer, long shift, long count )
-{
- float *in = ((float*)buffer) + (count-1);
- double *out = ((double*)buffer) + (count-1);
- unsigned char *p;
- unsigned char temp;
- (void) shift; /* unused parameter */
-
- while( count-- )
- {
- *out = *in--;
-
- p = (unsigned char*)out;
- PA_SWAP_( p[0], p[7] );
- PA_SWAP_( p[1], p[6] );
- PA_SWAP_( p[2], p[5] );
- PA_SWAP_( p[3], p[4] );
-
- out--;
- }
-}
-
-static void ConvertFloat32ToFloat64( void *buffer, long shift, long count )
-{
- float *in = ((float*)buffer) + (count-1);
- double *out = ((double*)buffer) + (count-1);
- (void) shift; /* unused parameter */
-
- while( count-- )
- *out-- = *in--;
-}
-
-#ifdef MAC
-#define PA_MSB_IS_NATIVE_
-#undef PA_LSB_IS_NATIVE_
-#endif
-
-#ifdef WINDOWS
-#undef PA_MSB_IS_NATIVE_
-#define PA_LSB_IS_NATIVE_
-#endif
-
-typedef void PaAsioBufferConverter( void *, long, long );
-
-static void SelectAsioToPaConverter( ASIOSampleType type, PaAsioBufferConverter **converter, long *shift )
-{
- *shift = 0;
- *converter = 0;
-
- switch (type) {
- case ASIOSTInt16MSB:
- /* dest: paInt16, no conversion necessary, possible byte swap*/
- #ifdef PA_LSB_IS_NATIVE_
- *converter = Swap16;
- #endif
- break;
- case ASIOSTInt16LSB:
- /* dest: paInt16, no conversion necessary, possible byte swap*/
- #ifdef PA_MSB_IS_NATIVE_
- *converter = Swap16;
- #endif
- break;
- case ASIOSTFloat32MSB:
- /* dest: paFloat32, no conversion necessary, possible byte swap*/
- #ifdef PA_LSB_IS_NATIVE_
- *converter = Swap32;
- #endif
- break;
- case ASIOSTFloat32LSB:
- /* dest: paFloat32, no conversion necessary, possible byte swap*/
- #ifdef PA_MSB_IS_NATIVE_
- *converter = Swap32;
- #endif
- break;
- case ASIOSTFloat64MSB:
- /* dest: paFloat32, in-place conversion to/from float32, possible byte swap*/
- #ifdef PA_LSB_IS_NATIVE_
- *converter = Swap64ConvertFloat64ToFloat32;
- #else
- *converter = ConvertFloat64ToFloat32;
- #endif
- break;
- case ASIOSTFloat64LSB:
- /* dest: paFloat32, in-place conversion to/from float32, possible byte swap*/
- #ifdef PA_MSB_IS_NATIVE_
- *converter = Swap64ConvertFloat64ToFloat32;
- #else
- *converter = ConvertFloat64ToFloat32;
- #endif
- break;
- case ASIOSTInt32MSB:
- /* dest: paInt32, no conversion necessary, possible byte swap */
- #ifdef PA_LSB_IS_NATIVE_
- *converter = Swap32;
- #endif
- break;
- case ASIOSTInt32LSB:
- /* dest: paInt32, no conversion necessary, possible byte swap */
- #ifdef PA_MSB_IS_NATIVE_
- *converter = Swap32;
- #endif
- break;
- case ASIOSTInt32MSB16:
- /* dest: paInt32, 16 bit shift, possible byte swap */
- #ifdef PA_LSB_IS_NATIVE_
- *converter = SwapShiftLeft32;
- #else
- *converter = ShiftLeft32;
- #endif
- *shift = 16;
- break;
- case ASIOSTInt32MSB18:
- /* dest: paInt32, 14 bit shift, possible byte swap */
- #ifdef PA_LSB_IS_NATIVE_
- *converter = SwapShiftLeft32;
- #else
- *converter = ShiftLeft32;
- #endif
- *shift = 14;
- break;
- case ASIOSTInt32MSB20:
- /* dest: paInt32, 12 bit shift, possible byte swap */
- #ifdef PA_LSB_IS_NATIVE_
- *converter = SwapShiftLeft32;
- #else
- *converter = ShiftLeft32;
- #endif
- *shift = 12;
- break;
- case ASIOSTInt32MSB24:
- /* dest: paInt32, 8 bit shift, possible byte swap */
- #ifdef PA_LSB_IS_NATIVE_
- *converter = SwapShiftLeft32;
- #else
- *converter = ShiftLeft32;
- #endif
- *shift = 8;
- break;
- case ASIOSTInt32LSB16:
- /* dest: paInt32, 16 bit shift, possible byte swap */
- #ifdef PA_MSB_IS_NATIVE_
- *converter = SwapShiftLeft32;
- #else
- *converter = ShiftLeft32;
- #endif
- *shift = 16;
- break;
- case ASIOSTInt32LSB18:
- /* dest: paInt32, 14 bit shift, possible byte swap */
- #ifdef PA_MSB_IS_NATIVE_
- *converter = SwapShiftLeft32;
- #else
- *converter = ShiftLeft32;
- #endif
- *shift = 14;
- break;
- case ASIOSTInt32LSB20:
- /* dest: paInt32, 12 bit shift, possible byte swap */
- #ifdef PA_MSB_IS_NATIVE_
- *converter = SwapShiftLeft32;
- #else
- *converter = ShiftLeft32;
- #endif
- *shift = 12;
- break;
- case ASIOSTInt32LSB24:
- /* dest: paInt32, 8 bit shift, possible byte swap */
- #ifdef PA_MSB_IS_NATIVE_
- *converter = SwapShiftLeft32;
- #else
- *converter = ShiftLeft32;
- #endif
- *shift = 8;
- break;
- case ASIOSTInt24MSB:
- /* dest: paInt24, no conversion necessary, possible byte swap */
- #ifdef PA_LSB_IS_NATIVE_
- *converter = Swap24;
- #endif
- break;
- case ASIOSTInt24LSB:
- /* dest: paInt24, no conversion necessary, possible byte swap */
- #ifdef PA_MSB_IS_NATIVE_
- *converter = Swap24;
- #endif
- break;
- }
-}
-
-
-static void SelectPaToAsioConverter( ASIOSampleType type, PaAsioBufferConverter **converter, long *shift )
-{
- *shift = 0;
- *converter = 0;
-
- switch (type) {
- case ASIOSTInt16MSB:
- /* src: paInt16, no conversion necessary, possible byte swap*/
- #ifdef PA_LSB_IS_NATIVE_
- *converter = Swap16;
- #endif
- break;
- case ASIOSTInt16LSB:
- /* src: paInt16, no conversion necessary, possible byte swap*/
- #ifdef PA_MSB_IS_NATIVE_
- *converter = Swap16;
- #endif
- break;
- case ASIOSTFloat32MSB:
- /* src: paFloat32, no conversion necessary, possible byte swap*/
- #ifdef PA_LSB_IS_NATIVE_
- *converter = Swap32;
- #endif
- break;
- case ASIOSTFloat32LSB:
- /* src: paFloat32, no conversion necessary, possible byte swap*/
- #ifdef PA_MSB_IS_NATIVE_
- *converter = Swap32;
- #endif
- break;
- case ASIOSTFloat64MSB:
- /* src: paFloat32, in-place conversion to/from float32, possible byte swap*/
- #ifdef PA_LSB_IS_NATIVE_
- *converter = ConvertFloat32ToFloat64Swap64;
- #else
- *converter = ConvertFloat32ToFloat64;
- #endif
- break;
- case ASIOSTFloat64LSB:
- /* src: paFloat32, in-place conversion to/from float32, possible byte swap*/
- #ifdef PA_MSB_IS_NATIVE_
- *converter = ConvertFloat32ToFloat64Swap64;
- #else
- *converter = ConvertFloat32ToFloat64;
- #endif
- break;
- case ASIOSTInt32MSB:
- /* src: paInt32, no conversion necessary, possible byte swap */
- #ifdef PA_LSB_IS_NATIVE_
- *converter = Swap32;
- #endif
- break;
- case ASIOSTInt32LSB:
- /* src: paInt32, no conversion necessary, possible byte swap */
- #ifdef PA_MSB_IS_NATIVE_
- *converter = Swap32;
- #endif
- break;
- case ASIOSTInt32MSB16:
- /* src: paInt32, 16 bit shift, possible byte swap */
- #ifdef PA_LSB_IS_NATIVE_
- *converter = ShiftRightSwap32;
- #else
- *converter = ShiftRight32;
- #endif
- *shift = 16;
- break;
- case ASIOSTInt32MSB18:
- /* src: paInt32, 14 bit shift, possible byte swap */
- #ifdef PA_LSB_IS_NATIVE_
- *converter = ShiftRightSwap32;
- #else
- *converter = ShiftRight32;
- #endif
- *shift = 14;
- break;
- case ASIOSTInt32MSB20:
- /* src: paInt32, 12 bit shift, possible byte swap */
- #ifdef PA_LSB_IS_NATIVE_
- *converter = ShiftRightSwap32;
- #else
- *converter = ShiftRight32;
- #endif
- *shift = 12;
- break;
- case ASIOSTInt32MSB24:
- /* src: paInt32, 8 bit shift, possible byte swap */
- #ifdef PA_LSB_IS_NATIVE_
- *converter = ShiftRightSwap32;
- #else
- *converter = ShiftRight32;
- #endif
- *shift = 8;
- break;
- case ASIOSTInt32LSB16:
- /* src: paInt32, 16 bit shift, possible byte swap */
- #ifdef PA_MSB_IS_NATIVE_
- *converter = ShiftRightSwap32;
- #else
- *converter = ShiftRight32;
- #endif
- *shift = 16;
- break;
- case ASIOSTInt32LSB18:
- /* src: paInt32, 14 bit shift, possible byte swap */
- #ifdef PA_MSB_IS_NATIVE_
- *converter = ShiftRightSwap32;
- #else
- *converter = ShiftRight32;
- #endif
- *shift = 14;
- break;
- case ASIOSTInt32LSB20:
- /* src: paInt32, 12 bit shift, possible byte swap */
- #ifdef PA_MSB_IS_NATIVE_
- *converter = ShiftRightSwap32;
- #else
- *converter = ShiftRight32;
- #endif
- *shift = 12;
- break;
- case ASIOSTInt32LSB24:
- /* src: paInt32, 8 bit shift, possible byte swap */
- #ifdef PA_MSB_IS_NATIVE_
- *converter = ShiftRightSwap32;
- #else
- *converter = ShiftRight32;
- #endif
- *shift = 8;
- break;
- case ASIOSTInt24MSB:
- /* src: paInt24, no conversion necessary, possible byte swap */
- #ifdef PA_LSB_IS_NATIVE_
- *converter = Swap24;
- #endif
- break;
- case ASIOSTInt24LSB:
- /* src: paInt24, no conversion necessary, possible byte swap */
- #ifdef PA_MSB_IS_NATIVE_
- *converter = Swap24;
- #endif
- break;
- }
-}
-
-
-typedef struct PaAsioDeviceInfo
-{
- PaDeviceInfo commonDeviceInfo;
- long minBufferSize;
- long maxBufferSize;
- long preferredBufferSize;
- long bufferGranularity;
-
- ASIOChannelInfo *asioChannelInfos;
-}
-PaAsioDeviceInfo;
-
-
-PaError PaAsio_GetAvailableLatencyValues( PaDeviceIndex device,
- long *minLatency, long *maxLatency, long *preferredLatency, long *granularity )
-{
- PaError result;
- PaUtilHostApiRepresentation *hostApi;
- PaDeviceIndex hostApiDevice;
-
- result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO );
-
- if( result == paNoError )
- {
- result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi );
-
- if( result == paNoError )
- {
- PaAsioDeviceInfo *asioDeviceInfo =
- (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice];
-
- *minLatency = asioDeviceInfo->minBufferSize;
- *maxLatency = asioDeviceInfo->maxBufferSize;
- *preferredLatency = asioDeviceInfo->preferredBufferSize;
- *granularity = asioDeviceInfo->bufferGranularity;
- }
- }
-
- return result;
-}
-
-
-
-/*
- load the asio driver named by <driverName> and return statistics about
- the driver in info. If no error occurred, the driver will remain open
- and must be closed by the called by calling ASIOExit() - if an error
- is returned the driver will already be closed.
-*/
-static PaError LoadAsioDriver( const char *driverName,
- PaAsioDriverInfo *driverInfo, void *systemSpecific )
-{
- PaError result = paNoError;
- ASIOError asioError;
- int asioIsInitialized = 0;
-
- if( !loadAsioDriver( const_cast<char*>(driverName) ) )
- {
- result = paUnanticipatedHostError;
- PA_ASIO_SET_LAST_HOST_ERROR( 0, "Failed to load ASIO driver" );
- goto error;
- }
-
- memset( &driverInfo->asioDriverInfo, 0, sizeof(ASIODriverInfo) );
- driverInfo->asioDriverInfo.asioVersion = 2;
- driverInfo->asioDriverInfo.sysRef = systemSpecific;
- if( (asioError = ASIOInit( &driverInfo->asioDriverInfo )) != ASE_OK )
- {
- result = paUnanticipatedHostError;
- PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
- goto error;
- }
- else
- {
- asioIsInitialized = 1;
- }
-
- if( (asioError = ASIOGetChannels(&driverInfo->inputChannelCount,
- &driverInfo->outputChannelCount)) != ASE_OK )
- {
- result = paUnanticipatedHostError;
- PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
- goto error;
- }
-
- if( (asioError = ASIOGetBufferSize(&driverInfo->bufferMinSize,
- &driverInfo->bufferMaxSize, &driverInfo->bufferPreferredSize,
- &driverInfo->bufferGranularity)) != ASE_OK )
- {
- result = paUnanticipatedHostError;
- PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
- goto error;
- }
-
- if( ASIOOutputReady() == ASE_OK )
- driverInfo->postOutput = true;
- else
- driverInfo->postOutput = false;
-
- return result;
-
-error:
- if( asioIsInitialized )
- ASIOExit();
-
- return result;
-}
-
-
-#define PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_ 13 /* must be the same number of elements as in the array below */
-static ASIOSampleRate defaultSampleRateSearchOrder_[]
- = {44100.0, 48000.0, 32000.0, 24000.0, 22050.0, 88200.0, 96000.0,
- 192000.0, 16000.0, 12000.0, 11025.0, 9600.0, 8000.0 };
-
-
-PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
-{
- PaError result = paNoError;
- int i, driverCount;
- PaAsioHostApiRepresentation *asioHostApi;
- PaAsioDeviceInfo *deviceInfoArray;
- char **names;
- PaAsioDriverInfo paAsioDriverInfo;
-
- asioHostApi = (PaAsioHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaAsioHostApiRepresentation) );
- if( !asioHostApi )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- asioHostApi->allocations = PaUtil_CreateAllocationGroup();
- if( !asioHostApi->allocations )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- asioHostApi->systemSpecific = 0;
- asioHostApi->openAsioDeviceIndex = paNoDevice;
-
- *hostApi = &asioHostApi->inheritedHostApiRep;
- (*hostApi)->info.structVersion = 1;
-
- (*hostApi)->info.type = paASIO;
- (*hostApi)->info.name = "ASIO";
- (*hostApi)->info.deviceCount = 0;
-
- #ifdef WINDOWS
- /* use desktop window as system specific ptr */
- asioHostApi->systemSpecific = GetDesktopWindow();
- CoInitialize(NULL);
- #endif
-
- /* MUST BE CHECKED : to force fragments loading on Mac */
- loadAsioDriver( "dummy" );
-
- /* driverCount is the number of installed drivers - not necessarily
- the number of installed physical devices. */
- #if MAC
- driverCount = asioDrivers->getNumFragments();
- #elif WINDOWS
- driverCount = asioDrivers->asioGetNumDev();
- #endif
-
- if( driverCount > 0 )
- {
- names = GetAsioDriverNames( asioHostApi->allocations, driverCount );
- if( !names )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
-
- /* allocate enough space for all drivers, even if some aren't installed */
-
- (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
- asioHostApi->allocations, sizeof(PaDeviceInfo*) * driverCount );
- if( !(*hostApi)->deviceInfos )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- /* allocate all device info structs in a contiguous block */
- deviceInfoArray = (PaAsioDeviceInfo*)PaUtil_GroupAllocateMemory(
- asioHostApi->allocations, sizeof(PaAsioDeviceInfo) * driverCount );
- if( !deviceInfoArray )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- for( i=0; i < driverCount; ++i )
- {
-
- PA_DEBUG(("ASIO names[%d]:%s\n",i,names[i]));
-
- // Since portaudio opens ALL ASIO drivers, and no one else does that,
- // we face fact that some drivers were not meant for it, drivers which act
- // like shells on top of REAL drivers, for instance.
- // so we get duplicate handles, locks and other problems.
- // so lets NOT try to load any such wrappers.
- // The ones i [davidv] know of so far are:
-
- if ( strcmp (names[i],"ASIO DirectX Full Duplex Driver") == 0
- || strcmp (names[i],"ASIO Multimedia Driver") == 0
- || strncmp(names[i],"Premiere",8) == 0 //"Premiere Elements Windows Sound 1.0"
- || strncmp(names[i],"Adobe",5) == 0 ) //"Adobe Default Windows Sound 1.5"
- {
- PA_DEBUG(("BLACKLISTED!!!\n"));
- continue;
- }
-
-
- /* Attempt to load the asio driver... */
- if( LoadAsioDriver( names[i], &paAsioDriverInfo, asioHostApi->systemSpecific ) == paNoError )
- {
- PaAsioDeviceInfo *asioDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];
- PaDeviceInfo *deviceInfo = &asioDeviceInfo->commonDeviceInfo;
-
- deviceInfo->structVersion = 2;
- deviceInfo->hostApi = hostApiIndex;
-
- deviceInfo->name = names[i];
- PA_DEBUG(("PaAsio_Initialize: drv:%d name = %s\n", i,deviceInfo->name));
- PA_DEBUG(("PaAsio_Initialize: drv:%d inputChannels = %d\n", i, paAsioDriverInfo.inputChannelCount));
- PA_DEBUG(("PaAsio_Initialize: drv:%d outputChannels = %d\n", i, paAsioDriverInfo.outputChannelCount));
- PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMinSize = %d\n", i, paAsioDriverInfo.bufferMinSize));
- PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMaxSize = %d\n", i, paAsioDriverInfo.bufferMaxSize));
- PA_DEBUG(("PaAsio_Initialize: drv:%d bufferPreferredSize = %d\n", i, paAsioDriverInfo.bufferPreferredSize));
- PA_DEBUG(("PaAsio_Initialize: drv:%d bufferGranularity = %d\n", i, paAsioDriverInfo.bufferGranularity));
-
- deviceInfo->maxInputChannels = paAsioDriverInfo.inputChannelCount;
- deviceInfo->maxOutputChannels = paAsioDriverInfo.outputChannelCount;
-
- deviceInfo->defaultSampleRate = 0.;
- bool foundDefaultSampleRate = false;
- for( int j=0; j < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++j )
- {
- ASIOError asioError = ASIOCanSampleRate( defaultSampleRateSearchOrder_[j] );
- if( asioError != ASE_NoClock && asioError != ASE_NotPresent )
- {
- deviceInfo->defaultSampleRate = defaultSampleRateSearchOrder_[j];
- foundDefaultSampleRate = true;
- break;
- }
- }
-
- PA_DEBUG(("PaAsio_Initialize: drv:%d defaultSampleRate = %f\n", i, deviceInfo->defaultSampleRate));
-
- if( foundDefaultSampleRate ){
-
- /* calculate default latency values from bufferPreferredSize
- for default low latency, and bufferPreferredSize * 3
- for default high latency.
- use the default sample rate to convert from samples to
- seconds. Without knowing what sample rate the user will
- use this is the best we can do.
- */
-
- double defaultLowLatency =
- paAsioDriverInfo.bufferPreferredSize / deviceInfo->defaultSampleRate;
-
- deviceInfo->defaultLowInputLatency = defaultLowLatency;
- deviceInfo->defaultLowOutputLatency = defaultLowLatency;
-
- long defaultHighLatencyBufferSize =
- paAsioDriverInfo.bufferPreferredSize * 3;
-
- if( defaultHighLatencyBufferSize > paAsioDriverInfo.bufferMaxSize )
- defaultHighLatencyBufferSize = paAsioDriverInfo.bufferMaxSize;
-
- double defaultHighLatency =
- defaultHighLatencyBufferSize / deviceInfo->defaultSampleRate;
-
- if( defaultHighLatency < defaultLowLatency )
- defaultHighLatency = defaultLowLatency; /* just incase the driver returns something strange */
-
- deviceInfo->defaultHighInputLatency = defaultHighLatency;
- deviceInfo->defaultHighOutputLatency = defaultHighLatency;
-
- }else{
-
- deviceInfo->defaultLowInputLatency = 0.;
- deviceInfo->defaultLowOutputLatency = 0.;
- deviceInfo->defaultHighInputLatency = 0.;
- deviceInfo->defaultHighOutputLatency = 0.;
- }
-
- PA_DEBUG(("PaAsio_Initialize: drv:%d defaultLowInputLatency = %f\n", i, deviceInfo->defaultLowInputLatency));
- PA_DEBUG(("PaAsio_Initialize: drv:%d defaultLowOutputLatency = %f\n", i, deviceInfo->defaultLowOutputLatency));
- PA_DEBUG(("PaAsio_Initialize: drv:%d defaultHighInputLatency = %f\n", i, deviceInfo->defaultHighInputLatency));
- PA_DEBUG(("PaAsio_Initialize: drv:%d defaultHighOutputLatency = %f\n", i, deviceInfo->defaultHighOutputLatency));
-
- asioDeviceInfo->minBufferSize = paAsioDriverInfo.bufferMinSize;
- asioDeviceInfo->maxBufferSize = paAsioDriverInfo.bufferMaxSize;
- asioDeviceInfo->preferredBufferSize = paAsioDriverInfo.bufferPreferredSize;
- asioDeviceInfo->bufferGranularity = paAsioDriverInfo.bufferGranularity;
-
-
- asioDeviceInfo->asioChannelInfos = (ASIOChannelInfo*)PaUtil_GroupAllocateMemory(
- asioHostApi->allocations,
- sizeof(ASIOChannelInfo) * (deviceInfo->maxInputChannels
- + deviceInfo->maxOutputChannels) );
- if( !asioDeviceInfo->asioChannelInfos )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- int a;
-
- for( a=0; a < deviceInfo->maxInputChannels; ++a ){
- asioDeviceInfo->asioChannelInfos[a].channel = a;
- asioDeviceInfo->asioChannelInfos[a].isInput = ASIOTrue;
- ASIOError asioError = ASIOGetChannelInfo( &asioDeviceInfo->asioChannelInfos[a] );
- if( asioError != ASE_OK )
- {
- result = paUnanticipatedHostError;
- PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
- goto error;
- }
- }
-
- for( a=0; a < deviceInfo->maxOutputChannels; ++a ){
- int b = deviceInfo->maxInputChannels + a;
- asioDeviceInfo->asioChannelInfos[b].channel = a;
- asioDeviceInfo->asioChannelInfos[b].isInput = ASIOFalse;
- ASIOError asioError = ASIOGetChannelInfo( &asioDeviceInfo->asioChannelInfos[b] );
- if( asioError != ASE_OK )
- {
- result = paUnanticipatedHostError;
- PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
- goto error;
- }
- }
-
-
- /* unload the driver */
- ASIOExit();
-
- (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo;
- ++(*hostApi)->info.deviceCount;
- }
- }
- }
-
- if( (*hostApi)->info.deviceCount > 0 )
- {
- (*hostApi)->info.defaultInputDevice = 0;
- (*hostApi)->info.defaultOutputDevice = 0;
- }
- else
- {
- (*hostApi)->info.defaultInputDevice = paNoDevice;
- (*hostApi)->info.defaultOutputDevice = paNoDevice;
- }
-
-
- (*hostApi)->Terminate = Terminate;
- (*hostApi)->OpenStream = OpenStream;
- (*hostApi)->IsFormatSupported = IsFormatSupported;
-
- PaUtil_InitializeStreamInterface( &asioHostApi->callbackStreamInterface, CloseStream, StartStream,
- StopStream, AbortStream, IsStreamStopped, IsStreamActive,
- GetStreamTime, GetStreamCpuLoad,
- PaUtil_DummyRead, PaUtil_DummyWrite,
- PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
-
- PaUtil_InitializeStreamInterface( &asioHostApi->blockingStreamInterface, CloseStream, StartStream,
- StopStream, AbortStream, IsStreamStopped, IsStreamActive,
- GetStreamTime, PaUtil_DummyGetCpuLoad,
- ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
-
- return result;
-
-error:
- if( asioHostApi )
- {
- if( asioHostApi->allocations )
- {
- PaUtil_FreeAllAllocations( asioHostApi->allocations );
- PaUtil_DestroyAllocationGroup( asioHostApi->allocations );
- }
-
- PaUtil_FreeMemory( asioHostApi );
- }
- return result;
-}
-
-
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
-{
- PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*)hostApi;
-
- /*
- IMPLEMENT ME:
- - clean up any resources not handled by the allocation group
- */
-
- if( asioHostApi->allocations )
- {
- PaUtil_FreeAllAllocations( asioHostApi->allocations );
- PaUtil_DestroyAllocationGroup( asioHostApi->allocations );
- }
-
- PaUtil_FreeMemory( asioHostApi );
-}
-
-
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate )
-{
- PaError result = paNoError;
- PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*)hostApi;
- PaAsioDriverInfo *driverInfo = &asioHostApi->openAsioDriverInfo;
- int inputChannelCount, outputChannelCount;
- PaSampleFormat inputSampleFormat, outputSampleFormat;
- PaDeviceIndex asioDeviceIndex;
- ASIOError asioError;
-
- if( inputParameters && outputParameters )
- {
- /* full duplex ASIO stream must use the same device for input and output */
-
- if( inputParameters->device != outputParameters->device )
- return paBadIODeviceCombination;
- }
-
- if( inputParameters )
- {
- inputChannelCount = inputParameters->channelCount;
- inputSampleFormat = inputParameters->sampleFormat;
-
- /* all standard sample formats are supported by the buffer adapter,
- this implementation doesn't support any custom sample formats */
- if( inputSampleFormat & paCustomFormat )
- return paSampleFormatNotSupported;
-
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
-
- if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
- return paInvalidDevice;
-
- asioDeviceIndex = inputParameters->device;
-
- /* validate inputStreamInfo */
- /** @todo do more validation here */
- // if( inputParameters->hostApiSpecificStreamInfo )
- // return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
- }
- else
- {
- inputChannelCount = 0;
- }
-
- if( outputParameters )
- {
- outputChannelCount = outputParameters->channelCount;
- outputSampleFormat = outputParameters->sampleFormat;
-
- /* all standard sample formats are supported by the buffer adapter,
- this implementation doesn't support any custom sample formats */
- if( outputSampleFormat & paCustomFormat )
- return paSampleFormatNotSupported;
-
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
-
- if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
- return paInvalidDevice;
-
- asioDeviceIndex = outputParameters->device;
-
- /* validate outputStreamInfo */
- /** @todo do more validation here */
- // if( outputParameters->hostApiSpecificStreamInfo )
- // return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
- }
- else
- {
- outputChannelCount = 0;
- }
-
-
-
- /* if an ASIO device is open we can only get format information for the currently open device */
-
- if( asioHostApi->openAsioDeviceIndex != paNoDevice
- && asioHostApi->openAsioDeviceIndex != asioDeviceIndex )
- {
- return paDeviceUnavailable;
- }
-
-
- /* NOTE: we load the driver and use its current settings
- rather than the ones in our device info structure which may be stale */
-
- /* open the device if it's not already open */
- if( asioHostApi->openAsioDeviceIndex == paNoDevice )
- {
- result = LoadAsioDriver( asioHostApi->inheritedHostApiRep.deviceInfos[ asioDeviceIndex ]->name,
- driverInfo, asioHostApi->systemSpecific );
- if( result != paNoError )
- return result;
- }
-
- /* check that input device can support inputChannelCount */
- if( inputChannelCount > 0 )
- {
- if( inputChannelCount > driverInfo->inputChannelCount )
- {
- result = paInvalidChannelCount;
- goto done;
- }
- }
-
- /* check that output device can support outputChannelCount */
- if( outputChannelCount )
- {
- if( outputChannelCount > driverInfo->outputChannelCount )
- {
- result = paInvalidChannelCount;
- goto done;
- }
- }
-
- /* query for sample rate support */
- asioError = ASIOCanSampleRate( sampleRate );
- if( asioError == ASE_NoClock || asioError == ASE_NotPresent )
- {
- result = paInvalidSampleRate;
- goto done;
- }
-
-done:
- /* close the device if it wasn't already open */
- if( asioHostApi->openAsioDeviceIndex == paNoDevice )
- {
- ASIOExit(); /* not sure if we should check for errors here */
- }
-
- if( result == paNoError )
- return paFormatIsSupported;
- else
- return result;
-}
-
-
-
-/* PaAsioStream - a stream data structure specifically for this implementation */
-
-typedef struct PaAsioStream
-{
- PaUtilStreamRepresentation streamRepresentation;
- PaUtilCpuLoadMeasurer cpuLoadMeasurer;
- PaUtilBufferProcessor bufferProcessor;
-
- PaAsioHostApiRepresentation *asioHostApi;
- unsigned long framesPerHostCallback;
-
- /* ASIO driver info - these may not be needed for the life of the stream,
- but store them here until we work out how format conversion is going
- to work. */
-
- ASIOBufferInfo *asioBufferInfos;
- ASIOChannelInfo *asioChannelInfos;
- long inputLatency, outputLatency; // actual latencies returned by asio
-
- long inputChannelCount, outputChannelCount;
- bool postOutput;
-
- void **bufferPtrs; /* this is carved up for inputBufferPtrs and outputBufferPtrs */
- void **inputBufferPtrs[2];
- void **outputBufferPtrs[2];
-
- PaAsioBufferConverter *inputBufferConverter;
- long inputShift;
- PaAsioBufferConverter *outputBufferConverter;
- long outputShift;
-
- volatile bool stopProcessing;
- int stopPlayoutCount;
- HANDLE completedBuffersPlayedEvent;
-
- bool streamFinishedCallbackCalled;
- volatile int isActive;
- volatile bool zeroOutput; /* all future calls to the callback will output silence */
-
- volatile long reenterCount;
- volatile long reenterError;
-
- PaStreamCallbackFlags callbackFlags;
-}
-PaAsioStream;
-
-static PaAsioStream *theAsioStream = 0; /* due to ASIO sdk limitations there can be only one stream */
-
-
-static void ZeroOutputBuffers( PaAsioStream *stream, long index )
-{
- int i;
-
- for( i=0; i < stream->outputChannelCount; ++i )
- {
- void *buffer = stream->asioBufferInfos[ i + stream->inputChannelCount ].buffers[index];
-
- int bytesPerSample = BytesPerAsioSample( stream->asioChannelInfos[ i + stream->inputChannelCount ].type );
-
- memset( buffer, 0, stream->framesPerHostCallback * bytesPerSample );
- }
-}
-
-
-static unsigned long SelectHostBufferSize( unsigned long suggestedLatencyFrames,
- PaAsioDriverInfo *driverInfo )
-{
- unsigned long result;
-
- if( suggestedLatencyFrames == 0 )
- {
- result = driverInfo->bufferPreferredSize;
- }
- else{
- if( suggestedLatencyFrames <= (unsigned long)driverInfo->bufferMinSize )
- {
- result = driverInfo->bufferMinSize;
- }
- else if( suggestedLatencyFrames >= (unsigned long)driverInfo->bufferMaxSize )
- {
- result = driverInfo->bufferMaxSize;
- }
- else
- {
- if( driverInfo->bufferGranularity == -1 )
- {
- /* power-of-two */
- result = 2;
-
- while( result < suggestedLatencyFrames )
- result *= 2;
-
- if( result < (unsigned long)driverInfo->bufferMinSize )
- result = driverInfo->bufferMinSize;
-
- if( result > (unsigned long)driverInfo->bufferMaxSize )
- result = driverInfo->bufferMaxSize;
- }
- else if( driverInfo->bufferGranularity == 0 )
- {
- /* the documentation states that bufferGranularity should be
- zero when bufferMinSize, bufferMaxSize and
- bufferPreferredSize are the same. We assume that is the case.
- */
-
- result = driverInfo->bufferPreferredSize;
- }
- else
- {
- /* modulo granularity */
-
- unsigned long remainder =
- suggestedLatencyFrames % driverInfo->bufferGranularity;
-
- if( remainder == 0 )
- {
- result = suggestedLatencyFrames;
- }
- else
- {
- result = suggestedLatencyFrames
- + (driverInfo->bufferGranularity - remainder);
-
- if( result > (unsigned long)driverInfo->bufferMaxSize )
- result = driverInfo->bufferMaxSize;
- }
- }
- }
- }
-
- return result;
-}
-
-
-/* returns channelSelectors if present */
-
-static PaError ValidateAsioSpecificStreamInfo(
- const PaStreamParameters *streamParameters,
- const PaAsioStreamInfo *streamInfo,
- int deviceChannelCount,
- int **channelSelectors )
-{
- if( streamInfo )
- {
- if( streamInfo->size != sizeof( PaAsioStreamInfo )
- || streamInfo->version != 1 )
- {
- return paIncompatibleHostApiSpecificStreamInfo;
- }
-
- if( streamInfo->flags & paAsioUseChannelSelectors )
- *channelSelectors = streamInfo->channelSelectors;
-
- if( !(*channelSelectors) )
- return paIncompatibleHostApiSpecificStreamInfo;
-
- for( int i=0; i < streamParameters->channelCount; ++i ){
- if( (*channelSelectors)[i] < 0
- || (*channelSelectors)[i] >= deviceChannelCount ){
- return paInvalidChannelCount;
- }
- }
- }
-
- return paNoError;
-}
-
-
-/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
-
-static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
- PaStream** s,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate,
- unsigned long framesPerBuffer,
- PaStreamFlags streamFlags,
- PaStreamCallback *streamCallback,
- void *userData )
-{
- PaError result = paNoError;
- PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*)hostApi;
- PaAsioStream *stream = 0;
- PaAsioStreamInfo *inputStreamInfo, *outputStreamInfo;
- unsigned long framesPerHostBuffer;
- int inputChannelCount, outputChannelCount;
- PaSampleFormat inputSampleFormat, outputSampleFormat;
- PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
- unsigned long suggestedInputLatencyFrames;
- unsigned long suggestedOutputLatencyFrames;
- PaDeviceIndex asioDeviceIndex;
- ASIOError asioError;
- int asioIsInitialized = 0;
- int asioBuffersCreated = 0;
- int completedBuffersPlayedEventInited = 0;
- int i;
- PaAsioDriverInfo *driverInfo;
- int *inputChannelSelectors = 0;
- int *outputChannelSelectors = 0;
-
- /* unless we move to using lower level ASIO calls, we can only have
- one device open at a time */
- if( asioHostApi->openAsioDeviceIndex != paNoDevice ){
- PA_DEBUG(("OpenStream paDeviceUnavailable\n"));
- return paDeviceUnavailable;
- }
-
- if( inputParameters && outputParameters )
- {
- /* full duplex ASIO stream must use the same device for input and output */
-
- if( inputParameters->device != outputParameters->device ){
- PA_DEBUG(("OpenStream paBadIODeviceCombination\n"));
- return paBadIODeviceCombination;
- }
- }
-
- if( inputParameters )
- {
- inputChannelCount = inputParameters->channelCount;
- inputSampleFormat = inputParameters->sampleFormat;
- suggestedInputLatencyFrames = (unsigned long)((inputParameters->suggestedLatency * sampleRate)+0.5f);
-
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
- if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
- return paInvalidDevice;
-
- asioDeviceIndex = inputParameters->device;
-
- PaAsioDeviceInfo *asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[asioDeviceIndex];
-
- /* validate hostApiSpecificStreamInfo */
- inputStreamInfo = (PaAsioStreamInfo*)inputParameters->hostApiSpecificStreamInfo;
- result = ValidateAsioSpecificStreamInfo( inputParameters, inputStreamInfo,
- asioDeviceInfo->commonDeviceInfo.maxInputChannels,
- &inputChannelSelectors
- );
- if( result != paNoError ) return result;
- }
- else
- {
- inputChannelCount = 0;
- inputSampleFormat = 0;
- suggestedInputLatencyFrames = 0;
- }
-
- if( outputParameters )
- {
- outputChannelCount = outputParameters->channelCount;
- outputSampleFormat = outputParameters->sampleFormat;
- suggestedOutputLatencyFrames = (unsigned long)((outputParameters->suggestedLatency * sampleRate)+0.5f);
-
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
- if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
- return paInvalidDevice;
-
- asioDeviceIndex = outputParameters->device;
-
- PaAsioDeviceInfo *asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[asioDeviceIndex];
-
- /* validate hostApiSpecificStreamInfo */
- outputStreamInfo = (PaAsioStreamInfo*)outputParameters->hostApiSpecificStreamInfo;
- result = ValidateAsioSpecificStreamInfo( outputParameters, outputStreamInfo,
- asioDeviceInfo->commonDeviceInfo.maxOutputChannels,
- &outputChannelSelectors
- );
- if( result != paNoError ) return result;
- }
- else
- {
- outputChannelCount = 0;
- outputSampleFormat = 0;
- suggestedOutputLatencyFrames = 0;
- }
-
- driverInfo = &asioHostApi->openAsioDriverInfo;
-
- /* NOTE: we load the driver and use its current settings
- rather than the ones in our device info structure which may be stale */
-
- result = LoadAsioDriver( asioHostApi->inheritedHostApiRep.deviceInfos[ asioDeviceIndex ]->name,
- driverInfo, asioHostApi->systemSpecific );
- if( result == paNoError )
- asioIsInitialized = 1;
- else{
- PA_DEBUG(("OpenStream ERROR1\n"));
- goto error;
- }
-
- /* check that input device can support inputChannelCount */
- if( inputChannelCount > 0 )
- {
- if( inputChannelCount > driverInfo->inputChannelCount )
- {
- result = paInvalidChannelCount;
- PA_DEBUG(("OpenStream ERROR2\n"));
- goto error;
- }
- }
-
- /* check that output device can support outputChannelCount */
- if( outputChannelCount )
- {
- if( outputChannelCount > driverInfo->outputChannelCount )
- {
- result = paInvalidChannelCount;
- PA_DEBUG(("OpenStream ERROR3\n"));
- goto error;
- }
- }
-
-
- // check that the device supports the requested sample rate
-
- asioError = ASIOCanSampleRate( sampleRate );
- PA_DEBUG(("ASIOCanSampleRate(%f):%d\n",sampleRate, asioError ));
-
- if( asioError != ASE_OK )
- {
- result = paInvalidSampleRate;
- PA_DEBUG(("ERROR: ASIOCanSampleRate: %s\n", PaAsio_GetAsioErrorText(asioError) ));
- goto error;
- }
-
-
- // retrieve the current sample rate, we only change to the requested
- // sample rate if the device is not already in that rate.
-
- ASIOSampleRate oldRate;
- asioError = ASIOGetSampleRate(&oldRate);
- if( asioError != ASE_OK )
- {
- result = paInvalidSampleRate;
- PA_DEBUG(("ERROR: ASIOGetSampleRate: %s\n", PaAsio_GetAsioErrorText(asioError) ));
- goto error;
- }
- PA_DEBUG(("ASIOGetSampleRate:%f\n",oldRate));
-
- if (oldRate != sampleRate){
-
- PA_DEBUG(("before ASIOSetSampleRate(%f)\n",sampleRate));
- asioError = ASIOSetSampleRate( sampleRate );
- /* Set sample rate */
- if( asioError != ASE_OK )
- {
- result = paInvalidSampleRate;
- PA_DEBUG(("ERROR: ASIOSetSampleRate: %s\n", PaAsio_GetAsioErrorText(asioError) ));
- goto error;
- }
- PA_DEBUG(("after ASIOSetSampleRate(%f)\n",sampleRate));
- }
- else
- {
- PA_DEBUG(("No Need to change SR\n"));
- }
-
-
- /*
- IMPLEMENT ME:
- - if a full duplex stream is requested, check that the combination
- of input and output parameters is supported
- */
-
- /* validate platform specific flags */
- if( (streamFlags & paPlatformSpecificFlags) != 0 ){
- PA_DEBUG(("OpenStream invalid flags!!\n"));
- return paInvalidFlag; /* unexpected platform specific flag */
- }
-
-
- stream = (PaAsioStream*)PaUtil_AllocateMemory( sizeof(PaAsioStream) );
- if( !stream )
- {
- result = paInsufficientMemory;
- PA_DEBUG(("OpenStream ERROR5\n"));
- goto error;
- }
-
- stream->completedBuffersPlayedEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
- if( stream->completedBuffersPlayedEvent == NULL )
- {
- result = paUnanticipatedHostError;
- PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
- PA_DEBUG(("OpenStream ERROR6\n"));
- goto error;
- }
- completedBuffersPlayedEventInited = 1;
-
-
- stream->asioBufferInfos = 0; /* for deallocation in error */
- stream->asioChannelInfos = 0; /* for deallocation in error */
- stream->bufferPtrs = 0; /* for deallocation in error */
-
- if( streamCallback )
- {
- PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
- &asioHostApi->callbackStreamInterface, streamCallback, userData );
- }
- else
- {
- PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
- &asioHostApi->blockingStreamInterface, streamCallback, userData );
- }
-
-
- PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
-
-
- stream->asioBufferInfos = (ASIOBufferInfo*)PaUtil_AllocateMemory(
- sizeof(ASIOBufferInfo) * (inputChannelCount + outputChannelCount) );
- if( !stream->asioBufferInfos )
- {
- result = paInsufficientMemory;
- PA_DEBUG(("OpenStream ERROR7\n"));
- goto error;
- }
-
-
- for( i=0; i < inputChannelCount; ++i )
- {
- ASIOBufferInfo *info = &stream->asioBufferInfos[i];
-
- info->isInput = ASIOTrue;
-
- if( inputChannelSelectors ){
- // inputChannelSelectors values have already been validated in
- // ValidateAsioSpecificStreamInfo() above
- info->channelNum = inputChannelSelectors[i];
- }else{
- info->channelNum = i;
- }
-
- info->buffers[0] = info->buffers[1] = 0;
- }
-
- for( i=0; i < outputChannelCount; ++i ){
- ASIOBufferInfo *info = &stream->asioBufferInfos[inputChannelCount+i];
-
- info->isInput = ASIOFalse;
-
- if( outputChannelSelectors ){
- // outputChannelSelectors values have already been validated in
- // ValidateAsioSpecificStreamInfo() above
- info->channelNum = outputChannelSelectors[i];
- }else{
- info->channelNum = i;
- }
-
- info->buffers[0] = info->buffers[1] = 0;
- }
-
-
- framesPerHostBuffer = SelectHostBufferSize(
- (( suggestedInputLatencyFrames > suggestedOutputLatencyFrames )
- ? suggestedInputLatencyFrames : suggestedOutputLatencyFrames),
- driverInfo );
-
-
- PA_DEBUG(("PaAsioOpenStream: framesPerHostBuffer :%d\n", framesPerHostBuffer));
-
- asioError = ASIOCreateBuffers( stream->asioBufferInfos,
- inputChannelCount+outputChannelCount,
- framesPerHostBuffer, &asioCallbacks_ );
-
- if( asioError != ASE_OK
- && framesPerHostBuffer != (unsigned long)driverInfo->bufferPreferredSize )
- {
- PA_DEBUG(("ERROR: ASIOCreateBuffers: %s\n", PaAsio_GetAsioErrorText(asioError) ));
- /*
- Some buggy drivers (like the Hoontech DSP24) give incorrect
- [min, preferred, max] values They should work with the preferred size
- value, thus if Pa_ASIO_CreateBuffers fails with the hostBufferSize
- computed in SelectHostBufferSize, we try again with the preferred size.
- */
-
- framesPerHostBuffer = driverInfo->bufferPreferredSize;
-
- PA_DEBUG(("PaAsioOpenStream: CORRECTED framesPerHostBuffer :%d\n", framesPerHostBuffer));
-
- ASIOError asioError2 = ASIOCreateBuffers( stream->asioBufferInfos,
- inputChannelCount+outputChannelCount,
- framesPerHostBuffer, &asioCallbacks_ );
- if( asioError2 == ASE_OK )
- asioError = ASE_OK;
- }
-
- if( asioError != ASE_OK )
- {
- result = paUnanticipatedHostError;
- PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
- PA_DEBUG(("OpenStream ERROR9\n"));
- goto error;
- }
-
- asioBuffersCreated = 1;
-
- stream->asioChannelInfos = (ASIOChannelInfo*)PaUtil_AllocateMemory(
- sizeof(ASIOChannelInfo) * (inputChannelCount + outputChannelCount) );
- if( !stream->asioChannelInfos )
- {
- result = paInsufficientMemory;
- PA_DEBUG(("OpenStream ERROR10\n"));
- goto error;
- }
-
- for( i=0; i < inputChannelCount + outputChannelCount; ++i )
- {
- stream->asioChannelInfos[i].channel = stream->asioBufferInfos[i].channelNum;
- stream->asioChannelInfos[i].isInput = stream->asioBufferInfos[i].isInput;
- asioError = ASIOGetChannelInfo( &stream->asioChannelInfos[i] );
- if( asioError != ASE_OK )
- {
- result = paUnanticipatedHostError;
- PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
- PA_DEBUG(("OpenStream ERROR11\n"));
- goto error;
- }
- }
-
- stream->bufferPtrs = (void**)PaUtil_AllocateMemory(
- 2 * sizeof(void*) * (inputChannelCount + outputChannelCount) );
- if( !stream->bufferPtrs )
- {
- result = paInsufficientMemory;
- PA_DEBUG(("OpenStream ERROR12\n"));
- goto error;
- }
-
- if( inputChannelCount > 0 )
- {
- stream->inputBufferPtrs[0] = stream-> bufferPtrs;
- stream->inputBufferPtrs[1] = &stream->bufferPtrs[inputChannelCount];
-
- for( i=0; i<inputChannelCount; ++i )
- {
- stream->inputBufferPtrs[0][i] = stream->asioBufferInfos[i].buffers[0];
- stream->inputBufferPtrs[1][i] = stream->asioBufferInfos[i].buffers[1];
- }
- }
- else
- {
- stream->inputBufferPtrs[0] = 0;
- stream->inputBufferPtrs[1] = 0;
- }
-
- if( outputChannelCount > 0 )
- {
- stream->outputBufferPtrs[0] = &stream->bufferPtrs[inputChannelCount*2];
- stream->outputBufferPtrs[1] = &stream->bufferPtrs[inputChannelCount*2 + outputChannelCount];
-
- for( i=0; i<outputChannelCount; ++i )
- {
- stream->outputBufferPtrs[0][i] = stream->asioBufferInfos[inputChannelCount+i].buffers[0];
- stream->outputBufferPtrs[1][i] = stream->asioBufferInfos[inputChannelCount+i].buffers[1];
- }
- }
- else
- {
- stream->outputBufferPtrs[0] = 0;
- stream->outputBufferPtrs[1] = 0;
- }
-
- if( inputChannelCount > 0 )
- {
- /* FIXME: assume all channels use the same type for now */
- ASIOSampleType inputType = stream->asioChannelInfos[0].type;
-
- PA_DEBUG(("ASIO Input type:%d",inputType));
- AsioSampleTypeLOG(inputType);
- hostInputSampleFormat = AsioSampleTypeToPaNativeSampleFormat( inputType );
-
- SelectAsioToPaConverter( inputType, &stream->inputBufferConverter, &stream->inputShift );
- }
- else
- {
- hostInputSampleFormat = 0;
- stream->inputBufferConverter = 0;
- }
-
- if( outputChannelCount > 0 )
- {
- /* FIXME: assume all channels use the same type for now */
- ASIOSampleType outputType = stream->asioChannelInfos[inputChannelCount].type;
-
- PA_DEBUG(("ASIO Output type:%d",outputType));
- AsioSampleTypeLOG(outputType);
- hostOutputSampleFormat = AsioSampleTypeToPaNativeSampleFormat( outputType );
-
- SelectPaToAsioConverter( outputType, &stream->outputBufferConverter, &stream->outputShift );
- }
- else
- {
- hostOutputSampleFormat = 0;
- stream->outputBufferConverter = 0;
- }
-
- result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
- inputChannelCount, inputSampleFormat, hostInputSampleFormat,
- outputChannelCount, outputSampleFormat, hostOutputSampleFormat,
- sampleRate, streamFlags, framesPerBuffer,
- framesPerHostBuffer, paUtilFixedHostBufferSize,
- streamCallback, userData );
- if( result != paNoError ){
- PA_DEBUG(("OpenStream ERROR13\n"));
- goto error;
- }
-
-
- ASIOGetLatencies( &stream->inputLatency, &stream->outputLatency );
-
- stream->streamRepresentation.streamInfo.inputLatency =
- (double)( PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor)
- + stream->inputLatency) / sampleRate; // seconds
- stream->streamRepresentation.streamInfo.outputLatency =
- (double)( PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor)
- + stream->outputLatency) / sampleRate; // seconds
- stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
-
- // the code below prints the ASIO latency which doesn't include the
- // buffer processor latency. it reports the added latency separately
- PA_DEBUG(("PaAsio : ASIO InputLatency = %ld (%ld ms), added buffProc:%ld (%ld ms)\n",
- stream->inputLatency,
- (long)((stream->inputLatency*1000)/ sampleRate),
- PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor),
- (long)((PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor)*1000)/ sampleRate)
- ));
-
- PA_DEBUG(("PaAsio : ASIO OuputLatency = %ld (%ld ms), added buffProc:%ld (%ld ms)\n",
- stream->outputLatency,
- (long)((stream->outputLatency*1000)/ sampleRate),
- PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor),
- (long)((PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor)*1000)/ sampleRate)
- ));
-
- stream->asioHostApi = asioHostApi;
- stream->framesPerHostCallback = framesPerHostBuffer;
-
- stream->inputChannelCount = inputChannelCount;
- stream->outputChannelCount = outputChannelCount;
- stream->postOutput = driverInfo->postOutput;
- stream->isActive = 0;
-
- asioHostApi->openAsioDeviceIndex = asioDeviceIndex;
-
- *s = (PaStream*)stream;
-
- return result;
-
-error:
- PA_DEBUG(("goto errored\n"));
- if( stream )
- {
- if( completedBuffersPlayedEventInited )
- CloseHandle( stream->completedBuffersPlayedEvent );
-
- if( stream->asioBufferInfos )
- PaUtil_FreeMemory( stream->asioBufferInfos );
-
- if( stream->asioChannelInfos )
- PaUtil_FreeMemory( stream->asioChannelInfos );
-
- if( stream->bufferPtrs )
- PaUtil_FreeMemory( stream->bufferPtrs );
-
- PaUtil_FreeMemory( stream );
- }
-
- if( asioBuffersCreated )
- ASIODisposeBuffers();
-
- if( asioIsInitialized )
- ASIOExit();
-
- return result;
-}
-
-
-/*
- When CloseStream() is called, the multi-api layer ensures that
- the stream has already been stopped or aborted.
-*/
-static PaError CloseStream( PaStream* s )
-{
- PaError result = paNoError;
- PaAsioStream *stream = (PaAsioStream*)s;
-
- /*
- IMPLEMENT ME:
- - additional stream closing + cleanup
- */
-
- PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
- PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
-
- stream->asioHostApi->openAsioDeviceIndex = paNoDevice;
-
- CloseHandle( stream->completedBuffersPlayedEvent );
-
- PaUtil_FreeMemory( stream->asioBufferInfos );
- PaUtil_FreeMemory( stream->asioChannelInfos );
- PaUtil_FreeMemory( stream->bufferPtrs );
- PaUtil_FreeMemory( stream );
-
- ASIODisposeBuffers();
- ASIOExit();
-
- return result;
-}
-
-
-static void bufferSwitch(long index, ASIOBool directProcess)
-{
-//TAKEN FROM THE ASIO SDK
-
- // the actual processing callback.
- // Beware that this is normally in a seperate thread, hence be sure that
- // you take care about thread synchronization. This is omitted here for
- // simplicity.
-
- // as this is a "back door" into the bufferSwitchTimeInfo a timeInfo needs
- // to be created though it will only set the timeInfo.samplePosition and
- // timeInfo.systemTime fields and the according flags
-
- ASIOTime timeInfo;
- memset( &timeInfo, 0, sizeof (timeInfo) );
-
- // get the time stamp of the buffer, not necessary if no
- // synchronization to other media is required
- if( ASIOGetSamplePosition(&timeInfo.timeInfo.samplePosition, &timeInfo.timeInfo.systemTime) == ASE_OK)
- timeInfo.timeInfo.flags = kSystemTimeValid | kSamplePositionValid;
-
- // Call the real callback
- bufferSwitchTimeInfo( &timeInfo, index, directProcess );
-}
-
-
-// conversion from 64 bit ASIOSample/ASIOTimeStamp to double float
-#if NATIVE_INT64
- #define ASIO64toDouble(a) (a)
-#else
- const double twoRaisedTo32 = 4294967296.;
- #define ASIO64toDouble(a) ((a).lo + (a).hi * twoRaisedTo32)
-#endif
-
-static ASIOTime *bufferSwitchTimeInfo( ASIOTime *timeInfo, long index, ASIOBool directProcess )
-{
- // the actual processing callback.
- // Beware that this is normally in a seperate thread, hence be sure that
- // you take care about thread synchronization.
-
-
- /* The SDK says the following about the directProcess flag:
- suggests to the host whether it should immediately start processing
- (directProcess == ASIOTrue), or whether its process should be deferred
- because the call comes from a very low level (for instance, a high level
- priority interrupt), and direct processing would cause timing instabilities for
- the rest of the system. If in doubt, directProcess should be set to ASIOFalse.
-
- We just ignore directProcess. This could cause incompatibilities with
- drivers which really don't want the audio processing to occur in this
- callback, but none have been identified yet.
- */
-
- (void) directProcess; /* suppress unused parameter warning */
-
-#if 0
- // store the timeInfo for later use
- asioDriverInfo.tInfo = *timeInfo;
-
- // get the time stamp of the buffer, not necessary if no
- // synchronization to other media is required
-
- if (timeInfo->timeInfo.flags & kSystemTimeValid)
- asioDriverInfo.nanoSeconds = ASIO64toDouble(timeInfo->timeInfo.systemTime);
- else
- asioDriverInfo.nanoSeconds = 0;
-
- if (timeInfo->timeInfo.flags & kSamplePositionValid)
- asioDriverInfo.samples = ASIO64toDouble(timeInfo->timeInfo.samplePosition);
- else
- asioDriverInfo.samples = 0;
-
- if (timeInfo->timeCode.flags & kTcValid)
- asioDriverInfo.tcSamples = ASIO64toDouble(timeInfo->timeCode.timeCodeSamples);
- else
- asioDriverInfo.tcSamples = 0;
-
- // get the system reference time
- asioDriverInfo.sysRefTime = get_sys_reference_time();
-#endif
-
-#if 0
- // a few debug messages for the Windows device driver developer
- // tells you the time when driver got its interrupt and the delay until the app receives
- // the event notification.
- static double last_samples = 0;
- char tmp[128];
- sprintf (tmp, "diff: %d / %d ms / %d ms / %d samples \n", asioDriverInfo.sysRefTime - (long)(asioDriverInfo.nanoSeconds / 1000000.0), asioDriverInfo.sysRefTime, (long)(asioDriverInfo.nanoSeconds / 1000000.0), (long)(asioDriverInfo.samples - last_samples));
- OutputDebugString (tmp);
- last_samples = asioDriverInfo.samples;
-#endif
-
-
- if( !theAsioStream )
- return 0L;
-
- // Keep sample position
- // FIXME: asioDriverInfo.pahsc_NumFramesDone = timeInfo->timeInfo.samplePosition.lo;
-
-
- // protect against reentrancy
- if( PaAsio_AtomicIncrement(&theAsioStream->reenterCount) )
- {
- theAsioStream->reenterError++;
- //DBUG(("bufferSwitchTimeInfo : reentrancy detection = %d\n", asioDriverInfo.reenterError));
- return 0L;
- }
-
- int buffersDone = 0;
-
- do
- {
- if( buffersDone > 0 )
- {
- // this is a reentered buffer, we missed processing it on time
- // set the input overflow and output underflow flags as appropriate
-
- if( theAsioStream->inputChannelCount > 0 )
- theAsioStream->callbackFlags |= paInputOverflow;
-
- if( theAsioStream->outputChannelCount > 0 )
- theAsioStream->callbackFlags |= paOutputUnderflow;
- }
- else
- {
- if( theAsioStream->zeroOutput )
- {
- ZeroOutputBuffers( theAsioStream, index );
-
- // Finally if the driver supports the ASIOOutputReady() optimization,
- // do it here, all data are in place
- if( theAsioStream->postOutput )
- ASIOOutputReady();
-
- if( theAsioStream->stopProcessing )
- {
- if( theAsioStream->stopPlayoutCount < 2 )
- {
- ++theAsioStream->stopPlayoutCount;
- if( theAsioStream->stopPlayoutCount == 2 )
- {
- theAsioStream->isActive = 0;
- if( theAsioStream->streamRepresentation.streamFinishedCallback != 0 )
- theAsioStream->streamRepresentation.streamFinishedCallback( theAsioStream->streamRepresentation.userData );
- theAsioStream->streamFinishedCallbackCalled = true;
- SetEvent( theAsioStream->completedBuffersPlayedEvent );
- }
- }
- }
- }
- else
- {
-
-#if 0
-// test code to try to detect slip conditions... these may work on some systems
-// but neither of them work on the RME Digi96
-
-// check that sample delta matches buffer size (otherwise we must have skipped
-// a buffer.
-static double last_samples = -512;
-double samples;
-//if( timeInfo->timeCode.flags & kTcValid )
-// samples = ASIO64toDouble(timeInfo->timeCode.timeCodeSamples);
-//else
- samples = ASIO64toDouble(timeInfo->timeInfo.samplePosition);
-int delta = samples - last_samples;
-//printf( "%d\n", delta);
-last_samples = samples;
-
-if( delta > theAsioStream->framesPerHostCallback )
-{
- if( theAsioStream->inputChannelCount > 0 )
- theAsioStream->callbackFlags |= paInputOverflow;
-
- if( theAsioStream->outputChannelCount > 0 )
- theAsioStream->callbackFlags |= paOutputUnderflow;
-}
-
-// check that the buffer index is not the previous index (which would indicate
-// that a buffer was skipped.
-static int previousIndex = 1;
-if( index == previousIndex )
-{
- if( theAsioStream->inputChannelCount > 0 )
- theAsioStream->callbackFlags |= paInputOverflow;
-
- if( theAsioStream->outputChannelCount > 0 )
- theAsioStream->callbackFlags |= paOutputUnderflow;
-}
-previousIndex = index;
-#endif
-
- int i;
-
- PaUtil_BeginCpuLoadMeasurement( &theAsioStream->cpuLoadMeasurer );
-
- PaStreamCallbackTimeInfo paTimeInfo;
-
- // asio systemTime is supposed to be measured according to the same
- // clock as timeGetTime
- paTimeInfo.currentTime = (ASIO64toDouble( timeInfo->timeInfo.systemTime ) * .000000001);
-
- /* patch from Paul Boege */
- paTimeInfo.inputBufferAdcTime = paTimeInfo.currentTime -
- ((double)theAsioStream->inputLatency/theAsioStream->streamRepresentation.streamInfo.sampleRate);
-
- paTimeInfo.outputBufferDacTime = paTimeInfo.currentTime +
- ((double)theAsioStream->outputLatency/theAsioStream->streamRepresentation.streamInfo.sampleRate);
-
- /* old version is buggy because the buffer processor also adds in its latency to the time parameters
- paTimeInfo.inputBufferAdcTime = paTimeInfo.currentTime - theAsioStream->streamRepresentation.streamInfo.inputLatency;
- paTimeInfo.outputBufferDacTime = paTimeInfo.currentTime + theAsioStream->streamRepresentation.streamInfo.outputLatency;
- */
-#if 1
-// detect underflows by checking inter-callback time > 2 buffer period
-static double previousTime = -1;
-if( previousTime > 0 ){
-
- double delta = paTimeInfo.currentTime - previousTime;
-
- if( delta >= 2. * (theAsioStream->framesPerHostCallback / theAsioStream->streamRepresentation.streamInfo.sampleRate) ){
- if( theAsioStream->inputChannelCount > 0 )
- theAsioStream->callbackFlags |= paInputOverflow;
-
- if( theAsioStream->outputChannelCount > 0 )
- theAsioStream->callbackFlags |= paOutputUnderflow;
- }
-}
-previousTime = paTimeInfo.currentTime;
-#endif
-
- // note that the above input and output times do not need to be
- // adjusted for the latency of the buffer processor -- the buffer
- // processor handles that.
-
- if( theAsioStream->inputBufferConverter )
- {
- for( i=0; i<theAsioStream->inputChannelCount; i++ )
- {
- theAsioStream->inputBufferConverter( theAsioStream->inputBufferPtrs[index][i],
- theAsioStream->inputShift, theAsioStream->framesPerHostCallback );
- }
- }
-
- PaUtil_BeginBufferProcessing( &theAsioStream->bufferProcessor, &paTimeInfo, theAsioStream->callbackFlags );
-
- /* reset status flags once they've been passed to the callback */
- theAsioStream->callbackFlags = 0;
-
- PaUtil_SetInputFrameCount( &theAsioStream->bufferProcessor, 0 /* default to host buffer size */ );
- for( i=0; i<theAsioStream->inputChannelCount; ++i )
- PaUtil_SetNonInterleavedInputChannel( &theAsioStream->bufferProcessor, i, theAsioStream->inputBufferPtrs[index][i] );
-
- PaUtil_SetOutputFrameCount( &theAsioStream->bufferProcessor, 0 /* default to host buffer size */ );
- for( i=0; i<theAsioStream->outputChannelCount; ++i )
- PaUtil_SetNonInterleavedOutputChannel( &theAsioStream->bufferProcessor, i, theAsioStream->outputBufferPtrs[index][i] );
-
- int callbackResult;
- if( theAsioStream->stopProcessing )
- callbackResult = paComplete;
- else
- callbackResult = paContinue;
- unsigned long framesProcessed = PaUtil_EndBufferProcessing( &theAsioStream->bufferProcessor, &callbackResult );
-
- if( theAsioStream->outputBufferConverter )
- {
- for( i=0; i<theAsioStream->outputChannelCount; i++ )
- {
- theAsioStream->outputBufferConverter( theAsioStream->outputBufferPtrs[index][i],
- theAsioStream->outputShift, theAsioStream->framesPerHostCallback );
- }
- }
-
- PaUtil_EndCpuLoadMeasurement( &theAsioStream->cpuLoadMeasurer, framesProcessed );
-
- // Finally if the driver supports the ASIOOutputReady() optimization,
- // do it here, all data are in place
- if( theAsioStream->postOutput )
- ASIOOutputReady();
-
- if( callbackResult == paContinue )
- {
- /* nothing special to do */
- }
- else if( callbackResult == paAbort )
- {
- /* finish playback immediately */
- theAsioStream->isActive = 0;
- if( theAsioStream->streamRepresentation.streamFinishedCallback != 0 )
- theAsioStream->streamRepresentation.streamFinishedCallback( theAsioStream->streamRepresentation.userData );
- theAsioStream->streamFinishedCallbackCalled = true;
- SetEvent( theAsioStream->completedBuffersPlayedEvent );
- theAsioStream->zeroOutput = true;
- }
- else /* paComplete or other non-zero value indicating complete */
- {
- /* Finish playback once currently queued audio has completed. */
- theAsioStream->stopProcessing = true;
-
- if( PaUtil_IsBufferProcessorOutputEmpty( &theAsioStream->bufferProcessor ) )
- {
- theAsioStream->zeroOutput = true;
- theAsioStream->stopPlayoutCount = 0;
- }
- }
- }
- }
-
- ++buffersDone;
- }while( PaAsio_AtomicDecrement(&theAsioStream->reenterCount) >= 0 );
-
- return 0L;
-}
-
-
-static void sampleRateChanged(ASIOSampleRate sRate)
-{
- // TAKEN FROM THE ASIO SDK
- // do whatever you need to do if the sample rate changed
- // usually this only happens during external sync.
- // Audio processing is not stopped by the driver, actual sample rate
- // might not have even changed, maybe only the sample rate status of an
- // AES/EBU or S/PDIF digital input at the audio device.
- // You might have to update time/sample related conversion routines, etc.
-
- (void) sRate; /* unused parameter */
- PA_DEBUG( ("sampleRateChanged : %d \n", sRate));
-}
-
-static long asioMessages(long selector, long value, void* message, double* opt)
-{
-// TAKEN FROM THE ASIO SDK
- // currently the parameters "value", "message" and "opt" are not used.
- long ret = 0;
-
- (void) message; /* unused parameters */
- (void) opt;
-
- PA_DEBUG( ("asioMessages : %d , %d \n", selector, value));
-
- switch(selector)
- {
- case kAsioSelectorSupported:
- if(value == kAsioResetRequest
- || value == kAsioEngineVersion
- || value == kAsioResyncRequest
- || value == kAsioLatenciesChanged
- // the following three were added for ASIO 2.0, you don't necessarily have to support them
- || value == kAsioSupportsTimeInfo
- || value == kAsioSupportsTimeCode
- || value == kAsioSupportsInputMonitor)
- ret = 1L;
- break;
-
- case kAsioBufferSizeChange:
- //printf("kAsioBufferSizeChange \n");
- break;
-
- case kAsioResetRequest:
- // defer the task and perform the reset of the driver during the next "safe" situation
- // You cannot reset the driver right now, as this code is called from the driver.
- // Reset the driver is done by completely destruct is. I.e. ASIOStop(), ASIODisposeBuffers(), Destruction
- // Afterwards you initialize the driver again.
-
- /*FIXME: commented the next line out */
- //asioDriverInfo.stopped; // In this sample the processing will just stop
- ret = 1L;
- break;
-
- case kAsioResyncRequest:
- // This informs the application, that the driver encountered some non fatal data loss.
- // It is used for synchronization purposes of different media.
- // Added mainly to work around the Win16Mutex problems in Windows 95/98 with the
- // Windows Multimedia system, which could loose data because the Mutex was hold too long
- // by another thread.
- // However a driver can issue it in other situations, too.
- ret = 1L;
- break;
-
- case kAsioLatenciesChanged:
- // This will inform the host application that the drivers were latencies changed.
- // Beware, it this does not mean that the buffer sizes have changed!
- // You might need to update internal delay data.
- ret = 1L;
- //printf("kAsioLatenciesChanged \n");
- break;
-
- case kAsioEngineVersion:
- // return the supported ASIO version of the host application
- // If a host applications does not implement this selector, ASIO 1.0 is assumed
- // by the driver
- ret = 2L;
- break;
-
- case kAsioSupportsTimeInfo:
- // informs the driver wether the asioCallbacks.bufferSwitchTimeInfo() callback
- // is supported.
- // For compatibility with ASIO 1.0 drivers the host application should always support
- // the "old" bufferSwitch method, too.
- ret = 1;
- break;
-
- case kAsioSupportsTimeCode:
- // informs the driver wether application is interested in time code info.
- // If an application does not need to know about time code, the driver has less work
- // to do.
- ret = 0;
- break;
- }
- return ret;
-}
-
-
-static PaError StartStream( PaStream *s )
-{
- PaError result = paNoError;
- PaAsioStream *stream = (PaAsioStream*)s;
- ASIOError asioError;
-
- if( stream->outputChannelCount > 0 )
- {
- ZeroOutputBuffers( stream, 0 );
- ZeroOutputBuffers( stream, 1 );
- }
-
- PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
- stream->stopProcessing = false;
- stream->zeroOutput = false;
-
- /* Reentrancy counter initialisation */
- stream->reenterCount = -1;
- stream->reenterError = 0;
-
- stream->callbackFlags = 0;
-
- if( ResetEvent( stream->completedBuffersPlayedEvent ) == 0 )
- {
- result = paUnanticipatedHostError;
- PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
- }
-
- if( result == paNoError )
- {
- theAsioStream = stream;
- asioError = ASIOStart();
- if( asioError == ASE_OK )
- {
- stream->isActive = 1;
- stream->streamFinishedCallbackCalled = false;
- }
- else
- {
- theAsioStream = 0;
- result = paUnanticipatedHostError;
- PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
- }
- }
-
- return result;
-}
-
-
-static PaError StopStream( PaStream *s )
-{
- PaError result = paNoError;
- PaAsioStream *stream = (PaAsioStream*)s;
- ASIOError asioError;
-
- if( stream->isActive )
- {
- stream->stopProcessing = true;
-
- /* wait for the stream to finish playing out enqueued buffers.
- timeout after four times the stream latency.
-
- @todo should use a better time out value - if the user buffer
- length is longer than the asio buffer size then that should
- be taken into account.
- */
- if( WaitForSingleObject( theAsioStream->completedBuffersPlayedEvent,
- (DWORD)(stream->streamRepresentation.streamInfo.outputLatency * 1000. * 4.) )
- == WAIT_TIMEOUT )
- {
- PA_DEBUG(("WaitForSingleObject() timed out in StopStream()\n" ));
- }
- }
-
- asioError = ASIOStop();
- if( asioError != ASE_OK )
- {
- result = paUnanticipatedHostError;
- PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
- }
-
- theAsioStream = 0;
- stream->isActive = 0;
-
- if( !stream->streamFinishedCallbackCalled )
- {
- if( stream->streamRepresentation.streamFinishedCallback != 0 )
- stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
- }
-
- return result;
-}
-
-
-static PaError AbortStream( PaStream *s )
-{
- PaError result = paNoError;
- PaAsioStream *stream = (PaAsioStream*)s;
- ASIOError asioError;
-
- stream->zeroOutput = true;
-
- asioError = ASIOStop();
- if( asioError != ASE_OK )
- {
- result = paUnanticipatedHostError;
- PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
- }
- else
- {
- // make sure that the callback is not still in-flight when ASIOStop()
- // returns. This has been observed to happen on the Hoontech DSP24 for
- // example.
- int count = 2000; // only wait for 2 seconds, rather than hanging.
- while( theAsioStream->reenterCount != -1 && count > 0 )
- {
- Sleep(1);
- --count;
- }
- }
-
- /* it is questionable whether we should zero theAsioStream if ASIOStop()
- returns an error, because the callback could still be active. We assume
- not - this is based on the fact that ASIOStop is unlikely to fail
- if the callback is running - it's more likely to fail because the
- callback is not running. */
-
- theAsioStream = 0;
- stream->isActive = 0;
-
- if( !stream->streamFinishedCallbackCalled )
- {
- if( stream->streamRepresentation.streamFinishedCallback != 0 )
- stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
- }
-
- return result;
-}
-
-
-static PaError IsStreamStopped( PaStream *s )
-{
- //PaAsioStream *stream = (PaAsioStream*)s;
- (void) s; /* unused parameter */
- return theAsioStream == 0;
-}
-
-
-static PaError IsStreamActive( PaStream *s )
-{
- PaAsioStream *stream = (PaAsioStream*)s;
-
- return stream->isActive;
-}
-
-
-static PaTime GetStreamTime( PaStream *s )
-{
- (void) s; /* unused parameter */
- return (double)timeGetTime() * .001;
-}
-
-
-static double GetStreamCpuLoad( PaStream* s )
-{
- PaAsioStream *stream = (PaAsioStream*)s;
-
- return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
-}
-
-
-/*
- As separate stream interfaces are used for blocking and callback
- streams, the following functions can be guaranteed to only be called
- for blocking streams.
-*/
-
-static PaError ReadStream( PaStream* s,
- void *buffer,
- unsigned long frames )
-{
- PaAsioStream *stream = (PaAsioStream*)s;
-
- /* IMPLEMENT ME, see portaudio.h for required behavior*/
- (void) stream; /* unused parameters */
- (void) buffer;
- (void) frames;
-
- return paNoError;
-}
-
-
-static PaError WriteStream( PaStream* s,
- const void *buffer,
- unsigned long frames )
-{
- PaAsioStream *stream = (PaAsioStream*)s;
-
- /* IMPLEMENT ME, see portaudio.h for required behavior*/
- (void) stream; /* unused parameters */
- (void) buffer;
- (void) frames;
-
- return paNoError;
-}
-
-
-static signed long GetStreamReadAvailable( PaStream* s )
-{
- PaAsioStream *stream = (PaAsioStream*)s;
-
- /* IMPLEMENT ME, see portaudio.h for required behavior*/
- (void) stream; /* unused parameter */
-
- return 0;
-}
-
-
-static signed long GetStreamWriteAvailable( PaStream* s )
-{
- PaAsioStream *stream = (PaAsioStream*)s;
-
- /* IMPLEMENT ME, see portaudio.h for required behavior*/
- (void) stream; /* unused parameter */
-
- return 0;
-}
-
-
-PaError PaAsio_ShowControlPanel( PaDeviceIndex device, void* systemSpecific )
-{
- PaError result = paNoError;
- PaUtilHostApiRepresentation *hostApi;
- PaDeviceIndex hostApiDevice;
- ASIODriverInfo asioDriverInfo;
- ASIOError asioError;
- int asioIsInitialized = 0;
- PaAsioHostApiRepresentation *asioHostApi;
- PaAsioDeviceInfo *asioDeviceInfo;
-
-
- result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO );
- if( result != paNoError )
- goto error;
-
- result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi );
- if( result != paNoError )
- goto error;
-
- /*
- In theory we could proceed if the currently open device was the same
- one for which the control panel was requested, however because the
- window pointer is not available until this function is called we
- currently need to call ASIOInit() again here, which of course can't be
- done safely while a stream is open.
- */
-
- asioHostApi = (PaAsioHostApiRepresentation*)hostApi;
- if( asioHostApi->openAsioDeviceIndex != paNoDevice )
- {
- result = paDeviceUnavailable;
- goto error;
- }
-
- asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice];
-
- if( !loadAsioDriver( const_cast<char*>(asioDeviceInfo->commonDeviceInfo.name) ) )
- {
- result = paUnanticipatedHostError;
- goto error;
- }
-
- /* CRUCIAL!!! */
- memset( &asioDriverInfo, 0, sizeof(ASIODriverInfo) );
- asioDriverInfo.asioVersion = 2;
- asioDriverInfo.sysRef = systemSpecific;
- asioError = ASIOInit( &asioDriverInfo );
- if( asioError != ASE_OK )
- {
- result = paUnanticipatedHostError;
- PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
- goto error;
- }
- else
- {
- asioIsInitialized = 1;
- }
-
-PA_DEBUG(("PaAsio_ShowControlPanel: ASIOInit(): %s\n", PaAsio_GetAsioErrorText(asioError) ));
-PA_DEBUG(("asioVersion: ASIOInit(): %ld\n", asioDriverInfo.asioVersion ));
-PA_DEBUG(("driverVersion: ASIOInit(): %ld\n", asioDriverInfo.driverVersion ));
-PA_DEBUG(("Name: ASIOInit(): %s\n", asioDriverInfo.name ));
-PA_DEBUG(("ErrorMessage: ASIOInit(): %s\n", asioDriverInfo.errorMessage ));
-
- asioError = ASIOControlPanel();
- if( asioError != ASE_OK )
- {
- PA_DEBUG(("PaAsio_ShowControlPanel: ASIOControlPanel(): %s\n", PaAsio_GetAsioErrorText(asioError) ));
- result = paUnanticipatedHostError;
- PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
- goto error;
- }
-
-PA_DEBUG(("PaAsio_ShowControlPanel: ASIOControlPanel(): %s\n", PaAsio_GetAsioErrorText(asioError) ));
-
- asioError = ASIOExit();
- if( asioError != ASE_OK )
- {
- result = paUnanticipatedHostError;
- PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
- asioIsInitialized = 0;
- goto error;
- }
-
-PA_DEBUG(("PaAsio_ShowControlPanel: ASIOExit(): %s\n", PaAsio_GetAsioErrorText(asioError) ));
-
- return result;
-
-error:
- if( asioIsInitialized )
- ASIOExit();
-
- return result;
-}
-
-
-PaError PaAsio_GetInputChannelName( PaDeviceIndex device, int channelIndex,
- const char** channelName )
-{
- PaError result = paNoError;
- PaUtilHostApiRepresentation *hostApi;
- PaDeviceIndex hostApiDevice;
- PaAsioDeviceInfo *asioDeviceInfo;
-
-
- result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO );
- if( result != paNoError )
- goto error;
-
- result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi );
- if( result != paNoError )
- goto error;
-
- asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice];
-
- if( channelIndex < 0 || channelIndex >= asioDeviceInfo->commonDeviceInfo.maxInputChannels ){
- result = paInvalidChannelCount;
- goto error;
- }
-
- *channelName = asioDeviceInfo->asioChannelInfos[channelIndex].name;
-
- return paNoError;
-
-error:
- return result;
-}
-
-
-PaError PaAsio_GetOutputChannelName( PaDeviceIndex device, int channelIndex,
- const char** channelName )
-{
- PaError result = paNoError;
- PaUtilHostApiRepresentation *hostApi;
- PaDeviceIndex hostApiDevice;
- PaAsioDeviceInfo *asioDeviceInfo;
-
-
- result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO );
- if( result != paNoError )
- goto error;
-
- result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi );
- if( result != paNoError )
- goto error;
-
- asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice];
-
- if( channelIndex < 0 || channelIndex >= asioDeviceInfo->commonDeviceInfo.maxOutputChannels ){
- result = paInvalidChannelCount;
- goto error;
- }
-
- *channelName = asioDeviceInfo->asioChannelInfos[
- asioDeviceInfo->commonDeviceInfo.maxInputChannels + channelIndex].name;
-
- return paNoError;
-
-error:
- return result;
-}
diff --git a/pd/portaudio/pa_asio/pa_asio.h b/pd/portaudio/pa_asio/pa_asio.h
deleted file mode 100644
index 230fb2d8..00000000
--- a/pd/portaudio/pa_asio/pa_asio.h
+++ /dev/null
@@ -1,122 +0,0 @@
-#ifndef PA_ASIO_H
-#define PA_ASIO_H
-/*
- * $Id: pa_asio.h,v 1.1.2.7 2005/01/01 19:35:33 rossbencina Exp $
- * PortAudio Portable Real-Time Audio Library
- * ASIO specific extensions
- *
- * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-/** @file
- @brief ASIO-specific PortAudio API extension header file.
-*/
-
-
-#include "portaudio.h"
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-
-/** Retrieve legal latency settings for the specificed device, in samples.
-
- @param device The global index of the device about which the query is being made.
- @param minLatency A pointer to the location which will recieve the minimum latency value.
- @param maxLatency A pointer to the location which will recieve the maximum latency value.
- @param preferredLatency A pointer to the location which will recieve the preferred latency value.
- @param granularity A pointer to the location which will recieve the granularity. This value
- determines which values between minLatency and maxLatency are available. ie the step size,
- if granularity is -1 then available latency settings are powers of two.
-
- @see ASIOGetBufferSize in the ASIO SDK.
-
- @todo This function should have a better name, any suggestions?
-*/
-PaError PaAsio_GetAvailableLatencyValues( PaDeviceIndex device,
- long *minLatency, long *maxLatency, long *preferredLatency, long *granularity );
-
-
-/** Display the ASIO control panel for the specified device.
-
- @param device The global index of the device whose control panel is to be displayed.
- @param systemSpecific On Windows, the calling application's main window handle,
- on Macintosh this value should be zero.
-*/
-PaError PaAsio_ShowControlPanel( PaDeviceIndex device, void* systemSpecific );
-
-
-
-
-/** Retrieve a pointer to a string containing the name of the specified
- input channel. The string is valid until Pa_Terminate is called.
-
- The string will be no longer than 32 characters including the null terminator.
-*/
-PaError PaAsio_GetInputChannelName( PaDeviceIndex device, int channelIndex,
- const char** channelName );
-
-
-/** Retrieve a pointer to a string containing the name of the specified
- input channel. The string is valid until Pa_Terminate is called.
-
- The string will be no longer than 32 characters including the null terminator.
-*/
-PaError PaAsio_GetOutputChannelName( PaDeviceIndex device, int channelIndex,
- const char** channelName );
-
-
-#define paAsioUseChannelSelectors (0x01)
-
-typedef struct PaAsioStreamInfo{
- unsigned long size; /**< sizeof(PaAsioStreamInfo) */
- PaHostApiTypeId hostApiType; /**< paASIO */
- unsigned long version; /**< 1 */
-
- unsigned long flags;
-
- /* Support for opening only specific channels of an ASIO device.
- If the paAsioUseChannelSelectors flag is set, channelSelectors is a
- pointer to an array of integers specifying the device channels to use.
- When used, the length of the channelSelectors array must match the
- corresponding channelCount parameter to Pa_OpenStream() otherwise a
- crash may result.
- The values in the selectors array must specify channels within the
- range of supported channels for the device or paInvalidChannelCount will
- result.
- */
- int *channelSelectors;
-}PaAsioStreamInfo;
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* PA_ASIO_H */