summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.in16
-rw-r--r--RtAudio.cpp23
-rw-r--r--RtAudio.h8
-rw-r--r--configure.ac13
-rw-r--r--doc/release.txt6
-rw-r--r--include/iasiothiscallresolver.cpp1135
-rw-r--r--include/iasiothiscallresolver.h3
-rw-r--r--tests/Makefile.in2
-rw-r--r--tests/duplex.cpp2
-rw-r--r--tests/playraw.cpp6
10 files changed, 628 insertions, 586 deletions
diff --git a/Makefile.in b/Makefile.in
index 5429b77..10b7ac3 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -2,11 +2,13 @@
### RtAudio library Makefile
RM = /bin/rm
+LN = /bin/ln
OBJECTS = RtAudio.o @objects@
STATIC = librtaudio.a
-SHARED = librtaudio.so
+SHARED = @sharedlib@
+RELEASE = 4.0.7
LIBRARIES = $(STATIC) $(SHARED)
CC = @CXX@
@@ -24,7 +26,10 @@ tests:
$(LIBRARIES): $(OBJECTS)
$(AR) ruv $(STATIC) $(OBJECTS)
ranlib $(STATIC)
- $(CC) -shared $(OBJECTS) -o $(SHARED) @LIBS@
+ $(CC) -fPIC @libflags@ $(OBJECTS) @LIBS@
+ $(LN) -s @sharedname@ $(SHARED)
+
+# $(CC) -shared $(OBJECTS) -o $(SHARED) @LIBS@
%.o : %.cpp
$(CC) $(CFLAGS) $(DEFS) -c $(<) -o $@
@@ -33,12 +38,15 @@ $(LIBRARIES): $(OBJECTS)
$(CC) $(CFLAGS) $(DEFS) -c $(<) -o $@
clean :
- $(RM) -f $(LIBRARIES)
+ $(RM) -f $(LIBRARIES) @sharedname@ $(SHARED)*
$(RM) -f $(OBJECTS)
$(RM) -f *~
cd tests && $(MAKE) clean
-distclean: clean
+distclean:
+ $(RM) -f $(LIBRARIES) @sharedname@ $(SHARED)*
+ $(RM) -f $(OBJECTS)
+ $(RM) -f *~
$(RM) -rf config.log config.status autom4te.cache Makefile rtaudio-config
cd tests && $(MAKE) distclean
diff --git a/RtAudio.cpp b/RtAudio.cpp
index 9ac6c5b..028fffa 100644
--- a/RtAudio.cpp
+++ b/RtAudio.cpp
@@ -10,7 +10,7 @@
RtAudio WWW site: http://www.music.mcgill.ca/~gary/rtaudio/
RtAudio: realtime audio i/o C++ classes
- Copyright (c) 2001-2010 Gary P. Scavone
+ Copyright (c) 2001-2011 Gary P. Scavone
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
@@ -38,7 +38,7 @@
*/
/************************************************************************/
-// RtAudio: Version 4.0.7
+// RtAudio: Version 4.0.8
#include "RtAudio.h"
#include <iostream>
@@ -557,10 +557,14 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
return info;
}
- const char *mname = CFStringGetCStringPtr( cfname, CFStringGetSystemEncoding() );
+ //const char *mname = CFStringGetCStringPtr( cfname, CFStringGetSystemEncoding() );
+ int length = CFStringGetLength(cfname);
+ char *mname = (char *)malloc(length * 3 + 1);
+ CFStringGetCString(cfname, mname, length * 3 + 1, CFStringGetSystemEncoding());
info.name.append( (const char *)mname, strlen(mname) );
info.name.append( ": " );
CFRelease( cfname );
+ free(mname);
property.mSelector = kAudioObjectPropertyName;
result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &cfname );
@@ -571,9 +575,13 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
return info;
}
- const char *name = CFStringGetCStringPtr( cfname, CFStringGetSystemEncoding() );
+ //const char *name = CFStringGetCStringPtr( cfname, CFStringGetSystemEncoding() );
+ length = CFStringGetLength(cfname);
+ char *name = (char *)malloc(length * 3 + 1);
+ CFStringGetCString(cfname, name, length * 3 + 1, CFStringGetSystemEncoding());
info.name.append( (const char *)name, strlen(name) );
CFRelease( cfname );
+ free(name);
// Get the output stream "configuration".
AudioBufferList *bufferList = nil;
@@ -1392,7 +1400,9 @@ void RtApiCore :: stopStream( void )
if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) {
+ MUTEX_UNLOCK( &stream_.mutex );
result = AudioDeviceStop( handle->id[1], callbackHandler );
+ MUTEX_LOCK( &stream_.mutex );
if ( result != noErr ) {
errorStream_ << "RtApiCore::stopStream: system error (" << getErrorCode( result ) << ") stopping input callback procedure on device (" << stream_.device[1] << ").";
errorText_ = errorStream_.str();
@@ -1472,6 +1482,7 @@ bool RtApiCore :: callbackEvent( AudioDeviceID deviceId,
status |= RTAUDIO_INPUT_OVERFLOW;
handle->xrun[1] = false;
}
+
handle->drainCounter = callback( stream_.userBuffer[0], stream_.userBuffer[1],
stream_.bufferSize, streamTime, status, info->userData );
if ( handle->drainCounter == 2 ) {
@@ -7393,7 +7404,7 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
{
// This function does format conversion, input/output channel compensation, and
// data interleaving/deinterleaving. 24-bit integers are assumed to occupy
- // the upper three bytes of a 32-bit integer.
+ // the lower three bytes of a 32-bit integer.
// Clear our device buffer when in/out duplex device channels are different
if ( outBuffer == stream_.deviceBuffer && stream_.mode == DUPLEX &&
@@ -7581,7 +7592,7 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
out += info.outJump;
}
}
- else if (info.inFormat == RTAUDIO_SINT24) {
+ else if (info.inFormat == RTAUDIO_SINT24) { // Hmmm ... we could just leave it in the lower 3 bytes
Int32 *in = (Int32 *)inBuffer;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
diff --git a/RtAudio.h b/RtAudio.h
index feb26a3..d1624cf 100644
--- a/RtAudio.h
+++ b/RtAudio.h
@@ -10,7 +10,7 @@
RtAudio WWW site: http://www.music.mcgill.ca/~gary/rtaudio/
RtAudio: realtime audio i/o C++ classes
- Copyright (c) 2001-2010 Gary P. Scavone
+ Copyright (c) 2001-2011 Gary P. Scavone
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
@@ -42,7 +42,7 @@
\file RtAudio.h
*/
-// RtAudio: Version 4.0.7
+// RtAudio: Version 4.0.8
#ifndef __RTAUDIO_H
#define __RTAUDIO_H
@@ -59,10 +59,12 @@
internal routines will automatically take care of any necessary
byte-swapping between the host format and the soundcard. Thus,
endian-ness is not a concern in the following format definitions.
+ Note that 24-bit data is expected to be encapsulated in a 32-bit
+ format.
- \e RTAUDIO_SINT8: 8-bit signed integer.
- \e RTAUDIO_SINT16: 16-bit signed integer.
- - \e RTAUDIO_SINT24: Upper 3 bytes of 32-bit signed integer.
+ - \e RTAUDIO_SINT24: Lower 3 bytes of 32-bit signed integer.
- \e RTAUDIO_SINT32: 32-bit signed integer.
- \e RTAUDIO_FLOAT32: Normalized between plus/minus 1.0.
- \e RTAUDIO_FLOAT64: Normalized between plus/minus 1.0.
diff --git a/configure.ac b/configure.ac
index 616ad54..422d257 100644
--- a/configure.ac
+++ b/configure.ac
@@ -44,9 +44,20 @@ fi
CXXFLAGS="$CXXFLAGS $cxxflag"
+AC_CANONICAL_HOST
+
+AC_SUBST( sharedlib, ["librtaudio.so"] )
+AC_SUBST( sharedname, ["librtaudio.so.\$(RELEASE)"] )
+AC_SUBST( libflags, ["-shared -Wl,-soname,\$(SHAREDLIB).\$(MAJOR) -o \$(SHAREDLIB).\$(RELEASE)"] )
+case $host in
+ *-apple*)
+ AC_SUBST( sharedlib, ["librtaudio.dylib"] )
+ AC_SUBST( sharedname, ["librtaudio.\$(RELEASE).dylib"] )
+ AC_SUBST( libflags, ["-dynamiclib -o librtaudio.\$(RELEASE).dylib"] )
+esac
+
# Checks for package options and external software
AC_SUBST( api, [""] )
-AC_CANONICAL_HOST
AC_MSG_CHECKING(for audio API)
case $host in
*-*-netbsd*)
diff --git a/doc/release.txt b/doc/release.txt
index 3165e3d..06d5b0c 100644
--- a/doc/release.txt
+++ b/doc/release.txt
@@ -1,6 +1,10 @@
RtAudio - a set of C++ classes that provide a common API for realtime audio input/output across Linux (native ALSA, JACK, and OSS), Macintosh OS X (CoreAudio and JACK), and Windows (DirectSound and ASIO) operating systems.
-By Gary P. Scavone, 2001-2010.
+By Gary P. Scavone, 2001-2011.
+
+v4.0.8: (?? February 2011)
+- fix for MinGW4 problem enumerating and setting sample rates
+
v4.0.7: (4 February 2010)
- revised Windows DS code and device enumeration to speed up device queries
diff --git a/include/iasiothiscallresolver.cpp b/include/iasiothiscallresolver.cpp
index 38c39d2..08c55ea 100644
--- a/include/iasiothiscallresolver.cpp
+++ b/include/iasiothiscallresolver.cpp
@@ -1,563 +1,572 @@
-/*
- 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 */
-
+/*
+ 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__)) && !defined(_WIN64)
+
+
+// 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 */ \
+ : "%edx" /* Clobbered Registers */ \
+ ); \
+
+
+#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) \
+ : "%edx" /* Clobbered Registers */ \
+ ); \
+
+
+#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) \
+ : "%edx" /* Clobbered Registers */ \
+ ); \
+
+
+#define CALL_THISCALL_1_DOUBLE( resultName, thisPtr, funcOffset, param1 ) \
+ do { \
+ double param1f64 = param1; /* Cast explicitly to double */ \
+ double *param1f64Ptr = &param1f64; /* Make pointer to address */ \
+ __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 */ \
+ : "r"(param1f64Ptr), /* Input Operands */ \
+ "c"(thisPtr), \
+ "m"(*param1f64Ptr) /* Using address */ \
+ : "%edx" /* Clobbered Registers */ \
+ ); \
+ } while (0); \
+
+
+#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) \
+ : "%edx" /* Clobbered Registers */ \
+ ); \
+
+
+#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) \
+ : "%edx" /* Clobbered Registers */ \
+ ); \
+
+#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/include/iasiothiscallresolver.h b/include/iasiothiscallresolver.h
index b59d910..63e91ca 100644
--- a/include/iasiothiscallresolver.h
+++ b/include/iasiothiscallresolver.h
@@ -115,7 +115,8 @@
// 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 defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
+#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) && !defined(_WIN64)
// If microsoft compiler we can call IASIO directly so IASIOThiscallResolver
diff --git a/tests/Makefile.in b/tests/Makefile.in
index 6947676..0236fbe 100644
--- a/tests/Makefile.in
+++ b/tests/Makefile.in
@@ -49,7 +49,7 @@ clean :
$(RM) -fR *.dSYM
distclean: clean
- $(RM) Makefile
+ $(RM) -f Makefile
strip :
strip $(PROGRAMS)
diff --git a/tests/duplex.cpp b/tests/duplex.cpp
index 125b56e..938a7f8 100644
--- a/tests/duplex.cpp
+++ b/tests/duplex.cpp
@@ -53,7 +53,7 @@ int inout( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
// a simple buffer copy operation here.
if ( status ) std::cout << "Stream over/underflow detected." << std::endl;
- unsigned long *bytes = (unsigned long *) data;
+ unsigned int *bytes = (unsigned int *) data;
memcpy( outputBuffer, inputBuffer, *bytes );
return 0;
}
diff --git a/tests/playraw.cpp b/tests/playraw.cpp
index 5a5e7cd..3b7be76 100644
--- a/tests/playraw.cpp
+++ b/tests/playraw.cpp
@@ -26,11 +26,7 @@ typedef signed short MY_TYPE;
#define SCALE 32767.0
/*
-typedef signed long MY_TYPE;
-#define FORMAT RTAUDIO_SINT24
-#define SCALE 8388607.0
-
-typedef signed long MY_TYPE;
+typedef signed int MY_TYPE;
#define FORMAT RTAUDIO_SINT32
#define SCALE 2147483647.0