1 // ****************************************************************************
\r
3 // Changed: I have modified this file slightly (includes) to work with
\r
4 // RtAudio. RtAudio.cpp must include this file after asio.h.
\r
6 // File: IASIOThiscallResolver.h
\r
7 // Description: The IASIOThiscallResolver class implements the IASIO
\r
8 // interface and acts as a proxy to the real IASIO interface by
\r
9 // calling through its vptr table using the thiscall calling
\r
10 // convention. To put it another way, we interpose
\r
11 // IASIOThiscallResolver between ASIO SDK code and the driver.
\r
12 // This is necessary because most non-Microsoft compilers don't
\r
13 // implement the thiscall calling convention used by IASIO.
\r
15 // iasiothiscallresolver.cpp contains the background of this
\r
16 // problem plus a technical description of the vptr
\r
19 // In order to use this mechanism one simply has to add
\r
20 // iasiothiscallresolver.cpp to the list of files to compile
\r
21 // and #include <iasiothiscallresolver.h>
\r
23 // Note that this #include must come after the other ASIO SDK
\r
24 // #includes, for example:
\r
26 // #include <windows.h>
\r
27 // #include <asiosys.h>
\r
28 // #include <asio.h>
\r
29 // #include <asiodrivers.h>
\r
30 // #include <iasiothiscallresolver.h>
\r
32 // Actually the important thing is to #include
\r
33 // <iasiothiscallresolver.h> after <asio.h>. We have
\r
34 // incorporated a test to enforce this ordering.
\r
36 // The code transparently takes care of the interposition by
\r
37 // using macro substitution to intercept calls to ASIOInit()
\r
38 // and ASIOExit(). We save the original ASIO global
\r
39 // "theAsioDriver" in our "that" variable, and then set
\r
40 // "theAsioDriver" to equal our IASIOThiscallResolver instance.
\r
42 // Whilst this method of resolving the thiscall problem requires
\r
43 // the addition of #include <iasiothiscallresolver.h> to client
\r
44 // code it has the advantage that it does not break the terms
\r
45 // of the ASIO licence by publishing it. We are NOT modifying
\r
46 // any Steinberg code here, we are merely implementing the IASIO
\r
47 // interface in the same way that we would need to do if we
\r
48 // wished to provide an open source ASIO driver.
\r
50 // For compilation with MinGW -lole32 needs to be added to the
\r
51 // linker options. For BORLAND, linking with Import32.lib is
\r
54 // The dependencies are with: CoInitialize, CoUninitialize,
\r
55 // CoCreateInstance, CLSIDFromString - used by asiolist.cpp
\r
56 // and are required on Windows whether ThiscallResolver is used
\r
59 // Searching for the above strings in the root library path
\r
60 // of your compiler should enable the correct libraries to be
\r
61 // identified if they aren't immediately obvious.
\r
63 // Note that the current implementation of IASIOThiscallResolver
\r
64 // is not COM compliant - it does not correctly implement the
\r
65 // IUnknown interface. Implementing it is not necessary because
\r
66 // it is not called by parts of the ASIO SDK which call through
\r
67 // theAsioDriver ptr. The IUnknown methods are implemented as
\r
68 // assert(false) to ensure that the code fails if they are
\r
70 // Restrictions: None. Public Domain & Open Source distribute freely
\r
71 // You may use IASIOThiscallResolver commercially as well as
\r
73 // You the user assume the responsibility for the use of the
\r
74 // files, binary or text, and there is no guarantee or warranty,
\r
75 // expressed or implied, including but not limited to the
\r
76 // implied warranties of merchantability and fitness for a
\r
77 // particular purpose. You assume all responsibility and agree
\r
78 // to hold no entity, copyright holder or distributors liable
\r
79 // for any loss of data or inaccurate representations of data
\r
80 // as a result of using IASIOThiscallResolver.
\r
81 // Version: 1.4 Added separate macro CALL_THISCALL_1_DOUBLE from
\r
82 // Andrew Baldwin, and volatile for whole gcc asm blocks,
\r
83 // both for compatibility with newer gcc versions. Cleaned up
\r
84 // Borland asm to use one less register.
\r
85 // 1.3 Switched to including assert.h for better compatibility.
\r
86 // Wrapped entire .h and .cpp contents with a check for
\r
87 // _MSC_VER to provide better compatibility with MS compilers.
\r
88 // Changed Singleton implementation to use static instance
\r
89 // instead of freestore allocated instance. Removed ASIOExit
\r
90 // macro as it is no longer needed.
\r
91 // 1.2 Removed semicolons from ASIOInit and ASIOExit macros to
\r
92 // allow them to be embedded in expressions (if statements).
\r
93 // Cleaned up some comments. Removed combase.c dependency (it
\r
94 // doesn't compile with BCB anyway) by stubbing IUnknown.
\r
95 // 1.1 Incorporated comments from Ross Bencina including things
\r
96 // such as changing name from ThiscallResolver to
\r
97 // IASIOThiscallResolver, tidying up the constructor, fixing
\r
98 // a bug in IASIOThiscallResolver::ASIOExit() and improving
\r
99 // portability through the use of conditional compilation
\r
100 // 1.0 Initial working version.
\r
101 // Created: 6/09/2003
\r
102 // Authors: Fraser Adams
\r
104 // Rene G. Ceballos
\r
109 // ****************************************************************************
\r
112 #ifndef included_iasiothiscallresolver_h
\r
113 #define included_iasiothiscallresolver_h
\r
115 // We only need IASIOThiscallResolver at all if we are on Win32. For other
\r
116 // platforms we simply bypass the IASIOThiscallResolver definition to allow us
\r
117 // to be safely #include'd whatever the platform to keep client code portable
\r
118 //#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
\r
119 #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) && !defined(_WIN64)
\r
122 // If microsoft compiler we can call IASIO directly so IASIOThiscallResolver
\r
124 #if !defined(_MSC_VER)
\r
127 // The following is in order to ensure that this header is only included after
\r
128 // the other ASIO headers (except for the case of iasiothiscallresolver.cpp).
\r
129 // We need to do this because IASIOThiscallResolver works by eclipsing the
\r
130 // original definition of ASIOInit() with a macro (see below).
\r
131 #if !defined(iasiothiscallresolver_sourcefile)
\r
132 #if !defined(__ASIO_H)
\r
133 #error iasiothiscallresolver.h must be included AFTER asio.h
\r
137 #include <windows.h>
\r
138 #include "iasiodrv.h" /* From ASIO SDK */
\r
141 class IASIOThiscallResolver : public IASIO {
\r
143 IASIO* that_; // Points to the real IASIO
\r
145 static IASIOThiscallResolver instance; // Singleton instance
\r
147 // Constructors - declared private so construction is limited to
\r
148 // our Singleton instance
\r
149 IASIOThiscallResolver();
\r
150 IASIOThiscallResolver(IASIO* that);
\r
153 // Methods from the IUnknown interface. We don't fully implement IUnknown
\r
154 // because the ASIO SDK never calls these methods through theAsioDriver ptr.
\r
155 // These methods are implemented as assert(false).
\r
156 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv);
\r
157 virtual ULONG STDMETHODCALLTYPE AddRef();
\r
158 virtual ULONG STDMETHODCALLTYPE Release();
\r
160 // Methods from the IASIO interface, implemented as forwarning calls to that.
\r
161 virtual ASIOBool init(void *sysHandle);
\r
162 virtual void getDriverName(char *name);
\r
163 virtual long getDriverVersion();
\r
164 virtual void getErrorMessage(char *string);
\r
165 virtual ASIOError start();
\r
166 virtual ASIOError stop();
\r
167 virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels);
\r
168 virtual ASIOError getLatencies(long *inputLatency, long *outputLatency);
\r
169 virtual ASIOError getBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity);
\r
170 virtual ASIOError canSampleRate(ASIOSampleRate sampleRate);
\r
171 virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate);
\r
172 virtual ASIOError setSampleRate(ASIOSampleRate sampleRate);
\r
173 virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources);
\r
174 virtual ASIOError setClockSource(long reference);
\r
175 virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp);
\r
176 virtual ASIOError getChannelInfo(ASIOChannelInfo *info);
\r
177 virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks);
\r
178 virtual ASIOError disposeBuffers();
\r
179 virtual ASIOError controlPanel();
\r
180 virtual ASIOError future(long selector,void *opt);
\r
181 virtual ASIOError outputReady();
\r
183 // Class method, see ASIOInit() macro below.
\r
184 static ASIOError ASIOInit(ASIODriverInfo *info); // Delegates to ::ASIOInit
\r
188 // Replace calls to ASIOInit with our interposing version.
\r
189 // This macro enables us to perform thiscall resolution simply by #including
\r
190 // <iasiothiscallresolver.h> after the asio #includes (this file _must_ be
\r
191 // included _after_ the asio #includes)
\r
193 #define ASIOInit(name) IASIOThiscallResolver::ASIOInit((name))
\r
196 #endif /* !defined(_MSC_VER) */
\r
200 #endif /* included_iasiothiscallresolver_h */
\r