ASIO to JACK driver for WINE
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616
  1. /*
  2. * Copyright (C) 2006 Robert Reif
  3. * Portions copyright (C) 2007 Ralf Beck
  4. * Portions copyright (C) 2007 Johnny Petrantoni
  5. * Portions copyright (C) 2007 Stephane Letz
  6. * Portions copyright (C) 2008 William Steidtmann
  7. * Portions copyright (C) 2010 Peter L Jones
  8. * Portions copyright (C) 2010 Torben Hohn
  9. * Portions copyright (C) 2010 Nedko Arnaudov
  10. * Portions copyright (C) 2013 Joakim Hernberg
  11. *
  12. * This library is free software; you can redistribute it and/or
  13. * modify it under the terms of the GNU Lesser General Public
  14. * License as published by the Free Software Foundation; either
  15. * version 2.1 of the License, or (at your option) any later version.
  16. *
  17. * This library is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  20. * Lesser General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU Lesser General Public
  23. * License along with this library; if not, write to the Free Software
  24. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  25. */
  26. #include <stdio.h>
  27. #include <errno.h>
  28. #include <limits.h>
  29. #include <unistd.h>
  30. #include <sys/mman.h>
  31. #include <pthread.h>
  32. #include <jack/jack.h>
  33. #include <jack/thread.h>
  34. #ifdef DEBUG
  35. #include "wine/debug.h"
  36. #else
  37. #define TRACE(...) {}
  38. #define WARN(fmt, ...) {} fprintf(stdout, fmt, ##__VA_ARGS__)
  39. #define ERR(fmt, ...) {} fprintf(stderr, fmt, ##__VA_ARGS__)
  40. #endif
  41. #include "objbase.h"
  42. #include "mmsystem.h"
  43. #include "winreg.h"
  44. #ifdef WINE_WITH_UNICODE
  45. #include "wine/unicode.h"
  46. #endif
  47. #define IEEE754_64FLOAT 1
  48. #undef NATIVE_INT64
  49. #include "asio.h"
  50. #define NATIVE_INT64
  51. #ifdef DEBUG
  52. WINE_DEFAULT_DEBUG_CHANNEL(asio);
  53. #endif
  54. #define MAX_ENVIRONMENT_SIZE 6
  55. #define ASIO_MAX_NAME_LENGTH 32
  56. #define ASIO_MINIMUM_BUFFERSIZE 16
  57. #define ASIO_MAXIMUM_BUFFERSIZE 8192
  58. #define ASIO_PREFERRED_BUFFERSIZE 1024
  59. /* ASIO drivers (breaking the COM specification) use the Microsoft variety of
  60. * thiscall calling convention which gcc is unable to produce. These macros
  61. * add an extra layer to fixup the registers. Borrowed from config.h and the
  62. * wine source code.
  63. */
  64. /* From config.h */
  65. #define __ASM_DEFINE_FUNC(name,suffix,code) asm(".text\n\t.align 4\n\t.globl " #name suffix "\n\t.type " #name suffix ",@function\n" #name suffix ":\n\t.cfi_startproc\n\t" code "\n\t.cfi_endproc\n\t.previous");
  66. #define __ASM_GLOBAL_FUNC(name,code) __ASM_DEFINE_FUNC(name,"",code)
  67. #define __ASM_NAME(name) name
  68. #define __ASM_STDCALL(args) ""
  69. /* From wine source */
  70. #ifdef __i386__ /* thiscall functions are i386-specific */
  71. #define THISCALL(func) __thiscall_ ## func
  72. #define THISCALL_NAME(func) __ASM_NAME("__thiscall_" #func)
  73. #define __thiscall __stdcall
  74. #define DEFINE_THISCALL_WRAPPER(func,args) \
  75. extern void THISCALL(func)(void); \
  76. __ASM_GLOBAL_FUNC(__thiscall_ ## func, \
  77. "popl %eax\n\t" \
  78. "pushl %ecx\n\t" \
  79. "pushl %eax\n\t" \
  80. "jmp " __ASM_NAME(#func) __ASM_STDCALL(args) )
  81. #else /* __i386__ */
  82. #define THISCALL(func) func
  83. #define THISCALL_NAME(func) __ASM_NAME(#func)
  84. #define __thiscall __stdcall
  85. #define DEFINE_THISCALL_WRAPPER(func,args) /* nothing */
  86. #endif /* __i386__ */
  87. /* Hide ELF symbols for the COM members - No need to to export them */
  88. #define HIDDEN __attribute__ ((visibility("hidden")))
  89. /*****************************************************************************
  90. * IWineAsio interface
  91. */
  92. #define INTERFACE IWineASIO
  93. DECLARE_INTERFACE_(IWineASIO,IUnknown)
  94. {
  95. STDMETHOD_(HRESULT, QueryInterface) (THIS_ IID riid, void** ppvObject) PURE;
  96. STDMETHOD_(ULONG, AddRef) (THIS) PURE;
  97. STDMETHOD_(ULONG, Release) (THIS) PURE;
  98. STDMETHOD_(ASIOBool, Init) (THIS_ void *sysRef) PURE;
  99. STDMETHOD_(void, GetDriverName) (THIS_ char *name) PURE;
  100. STDMETHOD_(LONG, GetDriverVersion) (THIS) PURE;
  101. STDMETHOD_(void, GetErrorMessage) (THIS_ char *string) PURE;
  102. STDMETHOD_(ASIOError, Start) (THIS) PURE;
  103. STDMETHOD_(ASIOError, Stop) (THIS) PURE;
  104. STDMETHOD_(ASIOError, GetChannels) (THIS_ LONG *numInputChannels, LONG *numOutputChannels) PURE;
  105. STDMETHOD_(ASIOError, GetLatencies) (THIS_ LONG *inputLatency, LONG *outputLatency) PURE;
  106. STDMETHOD_(ASIOError, GetBufferSize) (THIS_ LONG *minSize, LONG *maxSize, LONG *preferredSize, LONG *granularity) PURE;
  107. STDMETHOD_(ASIOError, CanSampleRate) (THIS_ ASIOSampleRate sampleRate) PURE;
  108. STDMETHOD_(ASIOError, GetSampleRate) (THIS_ ASIOSampleRate *sampleRate) PURE;
  109. STDMETHOD_(ASIOError, SetSampleRate) (THIS_ ASIOSampleRate sampleRate) PURE;
  110. STDMETHOD_(ASIOError, GetClockSources) (THIS_ ASIOClockSource *clocks, LONG *numSources) PURE;
  111. STDMETHOD_(ASIOError, SetClockSource) (THIS_ LONG index) PURE;
  112. STDMETHOD_(ASIOError, GetSamplePosition) (THIS_ ASIOSamples *sPos, ASIOTimeStamp *tStamp) PURE;
  113. STDMETHOD_(ASIOError, GetChannelInfo) (THIS_ ASIOChannelInfo *info) PURE;
  114. STDMETHOD_(ASIOError, CreateBuffers) (THIS_ ASIOBufferInfo *bufferInfo, LONG numChannels, LONG bufferSize, ASIOCallbacks *asioCallbacks) PURE;
  115. STDMETHOD_(ASIOError, DisposeBuffers) (THIS) PURE;
  116. STDMETHOD_(ASIOError, ControlPanel) (THIS) PURE;
  117. STDMETHOD_(ASIOError, Future) (THIS_ LONG selector,void *opt) PURE;
  118. STDMETHOD_(ASIOError, OutputReady) (THIS) PURE;
  119. };
  120. #undef INTERFACE
  121. typedef struct IWineASIO *LPWINEASIO;
  122. typedef struct IOChannel
  123. {
  124. ASIOBool active;
  125. jack_default_audio_sample_t *audio_buffer;
  126. char port_name[ASIO_MAX_NAME_LENGTH];
  127. jack_port_t *port;
  128. } IOChannel;
  129. typedef struct IWineASIOImpl
  130. {
  131. /* COM stuff */
  132. const IWineASIOVtbl *lpVtbl;
  133. LONG ref;
  134. /* The app's main window handle on windows, 0 on OS/X */
  135. HWND sys_ref;
  136. /* ASIO stuff */
  137. LONG asio_active_inputs;
  138. LONG asio_active_outputs;
  139. BOOL asio_buffer_index;
  140. ASIOCallbacks *asio_callbacks;
  141. BOOL asio_can_time_code;
  142. LONG asio_current_buffersize;
  143. INT asio_driver_state;
  144. ASIOSamples asio_sample_position;
  145. ASIOSampleRate asio_sample_rate;
  146. ASIOTime asio_time;
  147. BOOL asio_time_info_mode;
  148. ASIOTimeStamp asio_time_stamp;
  149. LONG asio_version;
  150. /* WineASIO configuration options */
  151. int wineasio_number_inputs;
  152. int wineasio_number_outputs;
  153. BOOL wineasio_autostart_server;
  154. BOOL wineasio_connect_to_hardware;
  155. BOOL wineasio_fixed_buffersize;
  156. LONG wineasio_preferred_buffersize;
  157. /* JACK stuff */
  158. jack_client_t *jack_client;
  159. char jack_client_name[ASIO_MAX_NAME_LENGTH];
  160. int jack_num_input_ports;
  161. int jack_num_output_ports;
  162. const char **jack_input_ports;
  163. const char **jack_output_ports;
  164. /* jack process callback buffers */
  165. jack_default_audio_sample_t *callback_audio_buffer;
  166. IOChannel *input_channel;
  167. IOChannel *output_channel;
  168. } IWineASIOImpl;
  169. enum { Loaded, Initialized, Prepared, Running };
  170. /****************************************************************************
  171. * Interface Methods
  172. */
  173. /*
  174. * as seen from the WineASIO source
  175. */
  176. HIDDEN HRESULT STDMETHODCALLTYPE QueryInterface(LPWINEASIO iface, REFIID riid, void **ppvObject);
  177. HIDDEN ULONG STDMETHODCALLTYPE AddRef(LPWINEASIO iface);
  178. HIDDEN ULONG STDMETHODCALLTYPE Release(LPWINEASIO iface);
  179. HIDDEN ASIOBool STDMETHODCALLTYPE Init(LPWINEASIO iface, void *sysRef);
  180. HIDDEN void STDMETHODCALLTYPE GetDriverName(LPWINEASIO iface, char *name);
  181. HIDDEN LONG STDMETHODCALLTYPE GetDriverVersion(LPWINEASIO iface);
  182. HIDDEN void STDMETHODCALLTYPE GetErrorMessage(LPWINEASIO iface, char *string);
  183. HIDDEN ASIOError STDMETHODCALLTYPE Start(LPWINEASIO iface);
  184. HIDDEN ASIOError STDMETHODCALLTYPE Stop(LPWINEASIO iface);
  185. HIDDEN ASIOError STDMETHODCALLTYPE GetChannels (LPWINEASIO iface, LONG *numInputChannels, LONG *numOutputChannels);
  186. HIDDEN ASIOError STDMETHODCALLTYPE GetLatencies(LPWINEASIO iface, LONG *inputLatency, LONG *outputLatency);
  187. HIDDEN ASIOError STDMETHODCALLTYPE GetBufferSize(LPWINEASIO iface, LONG *minSize, LONG *maxSize, LONG *preferredSize, LONG *granularity);
  188. HIDDEN ASIOError STDMETHODCALLTYPE CanSampleRate(LPWINEASIO iface, ASIOSampleRate sampleRate);
  189. HIDDEN ASIOError STDMETHODCALLTYPE GetSampleRate(LPWINEASIO iface, ASIOSampleRate *sampleRate);
  190. HIDDEN ASIOError STDMETHODCALLTYPE SetSampleRate(LPWINEASIO iface, ASIOSampleRate sampleRate);
  191. HIDDEN ASIOError STDMETHODCALLTYPE GetClockSources(LPWINEASIO iface, ASIOClockSource *clocks, LONG *numSources);
  192. HIDDEN ASIOError STDMETHODCALLTYPE SetClockSource(LPWINEASIO iface, LONG index);
  193. HIDDEN ASIOError STDMETHODCALLTYPE GetSamplePosition(LPWINEASIO iface, ASIOSamples *sPos, ASIOTimeStamp *tStamp);
  194. HIDDEN ASIOError STDMETHODCALLTYPE GetChannelInfo(LPWINEASIO iface, ASIOChannelInfo *info);
  195. HIDDEN ASIOError STDMETHODCALLTYPE CreateBuffers(LPWINEASIO iface, ASIOBufferInfo *bufferInfo, LONG numChannels, LONG bufferSize, ASIOCallbacks *asioCallbacks);
  196. HIDDEN ASIOError STDMETHODCALLTYPE DisposeBuffers(LPWINEASIO iface);
  197. HIDDEN ASIOError STDMETHODCALLTYPE ControlPanel(LPWINEASIO iface);
  198. HIDDEN ASIOError STDMETHODCALLTYPE Future(LPWINEASIO iface, LONG selector, void *opt);
  199. HIDDEN ASIOError STDMETHODCALLTYPE OutputReady(LPWINEASIO iface);
  200. /*
  201. * thiscall wrappers for the vtbl (as seen from app side 32bit)
  202. */
  203. HIDDEN void __thiscall_Init(void);
  204. HIDDEN void __thiscall_GetDriverName(void);
  205. HIDDEN void __thiscall_GetDriverVersion(void);
  206. HIDDEN void __thiscall_GetErrorMessage(void);
  207. HIDDEN void __thiscall_Start(void);
  208. HIDDEN void __thiscall_Stop(void);
  209. HIDDEN void __thiscall_GetChannels(void);
  210. HIDDEN void __thiscall_GetLatencies(void);
  211. HIDDEN void __thiscall_GetBufferSize(void);
  212. HIDDEN void __thiscall_CanSampleRate(void);
  213. HIDDEN void __thiscall_GetSampleRate(void);
  214. HIDDEN void __thiscall_SetSampleRate(void);
  215. HIDDEN void __thiscall_GetClockSources(void);
  216. HIDDEN void __thiscall_SetClockSource(void);
  217. HIDDEN void __thiscall_GetSamplePosition(void);
  218. HIDDEN void __thiscall_GetChannelInfo(void);
  219. HIDDEN void __thiscall_CreateBuffers(void);
  220. HIDDEN void __thiscall_DisposeBuffers(void);
  221. HIDDEN void __thiscall_ControlPanel(void);
  222. HIDDEN void __thiscall_Future(void);
  223. HIDDEN void __thiscall_OutputReady(void);
  224. /*
  225. * Jack callbacks
  226. */
  227. static inline int jack_buffer_size_callback (jack_nframes_t nframes, void *arg);
  228. static inline void jack_latency_callback(jack_latency_callback_mode_t mode, void *arg);
  229. static inline int jack_process_callback (jack_nframes_t nframes, void *arg);
  230. static inline int jack_sample_rate_callback (jack_nframes_t nframes, void *arg);
  231. /*
  232. * Support functions
  233. */
  234. HRESULT WINAPI WineASIOCreateInstance(REFIID riid, LPVOID *ppobj);
  235. static VOID configure_driver(IWineASIOImpl *This);
  236. static DWORD WINAPI jack_thread_creator_helper(LPVOID arg);
  237. static int jack_thread_creator(pthread_t* thread_id, const pthread_attr_t* attr, void *(*function)(void*), void* arg);
  238. /* {48D0C522-BFCC-45cc-8B84-17F25F33E6E8} */
  239. static GUID const CLSID_WineASIO = {
  240. 0x48d0c522, 0xbfcc, 0x45cc, { 0x8b, 0x84, 0x17, 0xf2, 0x5f, 0x33, 0xe6, 0xe8 } };
  241. static const IWineASIOVtbl WineASIO_Vtbl =
  242. {
  243. (void *) QueryInterface,
  244. (void *) AddRef,
  245. (void *) Release,
  246. (void *) THISCALL(Init),
  247. (void *) THISCALL(GetDriverName),
  248. (void *) THISCALL(GetDriverVersion),
  249. (void *) THISCALL(GetErrorMessage),
  250. (void *) THISCALL(Start),
  251. (void *) THISCALL(Stop),
  252. (void *) THISCALL(GetChannels),
  253. (void *) THISCALL(GetLatencies),
  254. (void *) THISCALL(GetBufferSize),
  255. (void *) THISCALL(CanSampleRate),
  256. (void *) THISCALL(GetSampleRate),
  257. (void *) THISCALL(SetSampleRate),
  258. (void *) THISCALL(GetClockSources),
  259. (void *) THISCALL(SetClockSource),
  260. (void *) THISCALL(GetSamplePosition),
  261. (void *) THISCALL(GetChannelInfo),
  262. (void *) THISCALL(CreateBuffers),
  263. (void *) THISCALL(DisposeBuffers),
  264. (void *) THISCALL(ControlPanel),
  265. (void *) THISCALL(Future),
  266. (void *) THISCALL(OutputReady)
  267. };
  268. /* structure needed to create the JACK callback thread in the wine process context */
  269. struct {
  270. void *(*jack_callback_thread) (void*);
  271. void *arg;
  272. pthread_t jack_callback_pthread_id;
  273. HANDLE jack_callback_thread_created;
  274. } jack_thread_creator_privates;
  275. /*****************************************************************************
  276. * Interface method definitions
  277. */
  278. HIDDEN HRESULT STDMETHODCALLTYPE QueryInterface(LPWINEASIO iface, REFIID riid, void **ppvObject)
  279. {
  280. IWineASIOImpl *This = (IWineASIOImpl *)iface;
  281. TRACE("iface: %p, riid: %s, ppvObject: %p)\n", iface, debugstr_guid(riid), ppvObject);
  282. if (ppvObject == NULL)
  283. return E_INVALIDARG;
  284. if (IsEqualIID(&CLSID_WineASIO, riid))
  285. {
  286. AddRef(iface);
  287. *ppvObject = This;
  288. return S_OK;
  289. }
  290. return E_NOINTERFACE;
  291. }
  292. /*
  293. * ULONG STDMETHODCALLTYPE AddRef(LPWINEASIO iface);
  294. * Function: Increment the reference count on the object
  295. * Returns: Ref count
  296. */
  297. HIDDEN ULONG STDMETHODCALLTYPE AddRef(LPWINEASIO iface)
  298. {
  299. IWineASIOImpl *This = (IWineASIOImpl *)iface;
  300. ULONG ref = InterlockedIncrement(&(This->ref));
  301. TRACE("iface: %p, ref count is %d\n", iface, ref);
  302. return ref;
  303. }
  304. /*
  305. * ULONG Release (LPWINEASIO iface);
  306. * Function: Destroy the interface
  307. * Returns: Ref count
  308. * Implies: ASIOStop() and ASIODisposeBuffers()
  309. */
  310. HIDDEN ULONG STDMETHODCALLTYPE Release(LPWINEASIO iface)
  311. {
  312. IWineASIOImpl *This = (IWineASIOImpl *)iface;
  313. ULONG ref = InterlockedDecrement(&This->ref);
  314. TRACE("iface: %p, ref count is %d\n", iface, ref);
  315. if (This->asio_driver_state == Running)
  316. Stop(iface);
  317. if (This->asio_driver_state == Prepared)
  318. DisposeBuffers(iface);
  319. if (This->asio_driver_state == Initialized)
  320. {
  321. /* just for good measure we deinitialize IOChannel structures and unregister JACK ports */
  322. for (int i = 0; i < This->wineasio_number_inputs; i++)
  323. {
  324. jack_port_unregister (This->jack_client, This->input_channel[i].port);
  325. This->input_channel[i].active = ASIOFalse;
  326. This->input_channel[i].port = NULL;
  327. }
  328. for (int i = 0; i < This->wineasio_number_outputs; i++)
  329. {
  330. jack_port_unregister (This->jack_client, This->output_channel[i].port);
  331. This->output_channel[i].active = ASIOFalse;
  332. This->output_channel[i].port = NULL;
  333. }
  334. This->asio_active_inputs = This->asio_active_outputs = 0;
  335. TRACE("%i IOChannel structures released\n", This->wineasio_number_inputs + This->wineasio_number_outputs);
  336. jack_free (This->jack_output_ports);
  337. jack_free (This->jack_input_ports);
  338. jack_client_close(This->jack_client);
  339. if (This->input_channel)
  340. HeapFree(GetProcessHeap(), 0, This->input_channel);
  341. }
  342. TRACE("WineASIO terminated\n\n");
  343. if (ref == 0)
  344. HeapFree(GetProcessHeap(), 0, This);
  345. return ref;
  346. }
  347. /*
  348. * ASIOBool Init (void *sysRef);
  349. * Function: Initialize the driver
  350. * Parameters: Pointer to "This"
  351. * sysHanle is 0 on OS/X and on windows it contains the applications main window handle
  352. * Returns: ASIOFalse on error, and ASIOTrue on success
  353. */
  354. DEFINE_THISCALL_WRAPPER(Init,8)
  355. HIDDEN ASIOBool STDMETHODCALLTYPE Init(LPWINEASIO iface, void *sysRef)
  356. {
  357. IWineASIOImpl *This = (IWineASIOImpl *)iface;
  358. jack_status_t jack_status;
  359. jack_options_t jack_options = This->wineasio_autostart_server ? JackNullOption : JackNoStartServer;
  360. int i;
  361. This->sys_ref = sysRef;
  362. mlockall(MCL_FUTURE);
  363. configure_driver(This);
  364. if (!(This->jack_client = jack_client_open(This->jack_client_name, jack_options, &jack_status)))
  365. {
  366. WARN("Unable to open a JACK client as: %s\n", This->jack_client_name);
  367. return ASIOFalse;
  368. }
  369. TRACE("JACK client opened as: '%s'\n", jack_get_client_name(This->jack_client));
  370. This->asio_sample_rate = jack_get_sample_rate(This->jack_client);
  371. This->asio_current_buffersize = jack_get_buffer_size(This->jack_client);
  372. /* Allocate IOChannel structures */
  373. This->input_channel = HeapAlloc(GetProcessHeap(), 0, (This->wineasio_number_inputs + This->wineasio_number_outputs) * sizeof(IOChannel));
  374. if (!This->input_channel)
  375. {
  376. jack_client_close(This->jack_client);
  377. ERR("Unable to allocate IOChannel structures for %i channels\n", This->wineasio_number_inputs);
  378. return ASIOFalse;
  379. }
  380. This->output_channel = This->input_channel + This->wineasio_number_inputs;
  381. TRACE("%i IOChannel structures allocated\n", This->wineasio_number_inputs + This->wineasio_number_outputs);
  382. /* Get and count physical JACK ports */
  383. This->jack_input_ports = jack_get_ports(This->jack_client, NULL, NULL, JackPortIsPhysical | JackPortIsOutput);
  384. for (This->jack_num_input_ports = 0; This->jack_input_ports && This->jack_input_ports[This->jack_num_input_ports]; This->jack_num_input_ports++)
  385. ;
  386. This->jack_output_ports = jack_get_ports(This->jack_client, NULL, NULL, JackPortIsPhysical | JackPortIsInput);
  387. for (This->jack_num_output_ports = 0; This->jack_output_ports && This->jack_output_ports[This->jack_num_output_ports]; This->jack_num_output_ports++)
  388. ;
  389. /* Initialize IOChannel structures */
  390. for (i = 0; i < This->wineasio_number_inputs; i++)
  391. {
  392. This->input_channel[i].active = ASIOFalse;
  393. This->input_channel[i].port = NULL;
  394. snprintf(This->input_channel[i].port_name, ASIO_MAX_NAME_LENGTH, "in_%i", i + 1);
  395. This->input_channel[i].port = jack_port_register(This->jack_client,
  396. This->input_channel[i].port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, i);
  397. /* TRACE("IOChannel structure initialized for input %d: '%s'\n", i, This->input_channel[i].port_name); */
  398. }
  399. for (i = 0; i < This->wineasio_number_outputs; i++)
  400. {
  401. This->output_channel[i].active = ASIOFalse;
  402. This->output_channel[i].port = NULL;
  403. snprintf(This->output_channel[i].port_name, ASIO_MAX_NAME_LENGTH, "out_%i", i + 1);
  404. This->output_channel[i].port = jack_port_register(This->jack_client,
  405. This->output_channel[i].port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, i);
  406. /* TRACE("IOChannel structure initialized for output %d: '%s'\n", i, This->output_channel[i].port_name); */
  407. }
  408. TRACE("%i IOChannel structures initialized\n", This->wineasio_number_inputs + This->wineasio_number_outputs);
  409. jack_set_thread_creator(jack_thread_creator);
  410. if (jack_set_buffer_size_callback(This->jack_client, jack_buffer_size_callback, This))
  411. {
  412. jack_client_close(This->jack_client);
  413. HeapFree(GetProcessHeap(), 0, This->input_channel);
  414. ERR("Unable to register JACK buffer size change callback\n");
  415. return ASIOFalse;
  416. }
  417. if (jack_set_latency_callback(This->jack_client, jack_latency_callback, This))
  418. {
  419. jack_client_close(This->jack_client);
  420. HeapFree(GetProcessHeap(), 0, This->input_channel);
  421. ERR("Unable to register JACK latency callback\n");
  422. return ASIOFalse;
  423. }
  424. if (jack_set_process_callback(This->jack_client, jack_process_callback, This))
  425. {
  426. jack_client_close(This->jack_client);
  427. HeapFree(GetProcessHeap(), 0, This->input_channel);
  428. ERR("Unable to register JACK process callback\n");
  429. return ASIOFalse;
  430. }
  431. if (jack_set_sample_rate_callback (This->jack_client, jack_sample_rate_callback, This))
  432. {
  433. jack_client_close(This->jack_client);
  434. HeapFree(GetProcessHeap(), 0, This->input_channel);
  435. ERR("Unable to register JACK sample rate change callback\n");
  436. return ASIOFalse;
  437. }
  438. This->asio_driver_state = Initialized;
  439. TRACE("WineASIO 0.%.1f initialized\n",(float) This->asio_version / 10);
  440. return ASIOTrue;
  441. }
  442. /*
  443. * void GetDriverName(char *name);
  444. * Function: Returns the driver name in name
  445. */
  446. DEFINE_THISCALL_WRAPPER(GetDriverName,8)
  447. HIDDEN void STDMETHODCALLTYPE GetDriverName(LPWINEASIO iface, char *name)
  448. {
  449. TRACE("iface: %p, name: %p\n", iface, name);
  450. strcpy(name, "WineASIO");
  451. return;
  452. }
  453. /*
  454. * LONG GetDriverVersion (void);
  455. * Function: Returns the driver version number
  456. */
  457. DEFINE_THISCALL_WRAPPER(GetDriverVersion,4)
  458. HIDDEN LONG STDMETHODCALLTYPE GetDriverVersion(LPWINEASIO iface)
  459. {
  460. IWineASIOImpl *This = (IWineASIOImpl*)iface;
  461. TRACE("iface: %p\n", iface);
  462. return This->asio_version;
  463. }
  464. /*
  465. * void GetErrorMessage(char *string);
  466. * Function: Returns an error message for the last occured error in string
  467. */
  468. DEFINE_THISCALL_WRAPPER(GetErrorMessage,8)
  469. HIDDEN void STDMETHODCALLTYPE GetErrorMessage(LPWINEASIO iface, char *string)
  470. {
  471. TRACE("iface: %p, string: %p)\n", iface, string);
  472. strcpy(string, "WineASIO does not return error messages\n");
  473. return;
  474. }
  475. /*
  476. * ASIOError Start(void);
  477. * Function: Start JACK IO processing and reset the sample counter to zero
  478. * Returns: ASE_NotPresent if IO is missing
  479. * ASE_HWMalfunction if JACK fails to start
  480. */
  481. DEFINE_THISCALL_WRAPPER(Start,4)
  482. HIDDEN ASIOError STDMETHODCALLTYPE Start(LPWINEASIO iface)
  483. {
  484. IWineASIOImpl *This = (IWineASIOImpl*)iface;
  485. int i;
  486. DWORD time;
  487. TRACE("iface: %p\n", iface);
  488. if (This->asio_driver_state != Prepared)
  489. return ASE_NotPresent;
  490. /* Zero the audio buffer */
  491. for (i = 0; i < (This->wineasio_number_inputs + This->wineasio_number_outputs) * 2 * This->asio_current_buffersize; i++)
  492. This->callback_audio_buffer[i] = 0;
  493. /* prime the callback by preprocessing one outbound ASIO bufffer */
  494. This->asio_buffer_index = 0;
  495. This->asio_sample_position.hi = This->asio_sample_position.lo = 0;
  496. time = timeGetTime();
  497. This->asio_time_stamp.lo = time * 1000000;
  498. This->asio_time_stamp.hi = ((unsigned long long) time * 1000000) >> 32;
  499. if (This->asio_time_info_mode) /* use the newer bufferSwitchTimeInfo method if supported */
  500. {
  501. This->asio_time.timeInfo.samplePosition.lo = This->asio_time.timeInfo.samplePosition.hi = 0;
  502. This->asio_time.timeInfo.systemTime.lo = This->asio_time_stamp.lo;
  503. This->asio_time.timeInfo.systemTime.hi = This->asio_time_stamp.hi;
  504. This->asio_time.timeInfo.sampleRate = This->asio_sample_rate;
  505. This->asio_time.timeInfo.flags = kSystemTimeValid | kSamplePositionValid | kSampleRateValid;
  506. if (This->asio_can_time_code) /* addionally use time code if supported */
  507. {
  508. This->asio_time.timeCode.speed = 1; /* FIXME */
  509. This->asio_time.timeCode.timeCodeSamples.lo = This->asio_time_stamp.lo;
  510. This->asio_time.timeCode.timeCodeSamples.hi = This->asio_time_stamp.hi;
  511. This->asio_time.timeCode.flags = ~(kTcValid | kTcRunning);
  512. }
  513. This->asio_callbacks->bufferSwitchTimeInfo(&This->asio_time, This->asio_buffer_index, ASIOTrue);
  514. }
  515. else
  516. { /* use the old bufferSwitch method */
  517. This->asio_callbacks->bufferSwitch(This->asio_buffer_index, ASIOTrue);
  518. }
  519. /* swith asio buffer */
  520. This->asio_buffer_index = This->asio_buffer_index ? 0 : 1;
  521. This->asio_driver_state = Running;
  522. TRACE("WineASIO successfully loaded\n");
  523. return ASE_OK;
  524. }
  525. /*
  526. * ASIOError Stop(void);
  527. * Function: Stop JACK IO processing
  528. * Returns: ASE_NotPresent on missing IO
  529. * Note: BufferSwitch() must not called after returning
  530. */
  531. DEFINE_THISCALL_WRAPPER(Stop,4)
  532. HIDDEN ASIOError STDMETHODCALLTYPE Stop(LPWINEASIO iface)
  533. {
  534. IWineASIOImpl *This = (IWineASIOImpl*)iface;
  535. TRACE("iface: %p\n", iface);
  536. if (This->asio_driver_state != Running)
  537. return ASE_NotPresent;
  538. This->asio_driver_state = Prepared;
  539. return ASE_OK;
  540. }
  541. /*
  542. * ASIOError GetChannels(LONG *numInputChannels, LONG *numOutputChannels);
  543. * Function: Report number of IO channels
  544. * Parameters: numInputChannels and numOutputChannels will hold number of channels on returning
  545. * Returns: ASE_NotPresent if no channels are available, otherwise AES_OK
  546. */
  547. DEFINE_THISCALL_WRAPPER(GetChannels,12)
  548. HIDDEN ASIOError STDMETHODCALLTYPE GetChannels (LPWINEASIO iface, LONG *numInputChannels, LONG *numOutputChannels)
  549. {
  550. IWineASIOImpl *This = (IWineASIOImpl*)iface;
  551. if (!numInputChannels || !numOutputChannels)
  552. return ASE_InvalidParameter;
  553. *numInputChannels = This->wineasio_number_inputs;
  554. *numOutputChannels = This->wineasio_number_outputs;
  555. TRACE("iface: %p, inputs: %i, outputs: %i\n", iface, This->wineasio_number_inputs, This->wineasio_number_outputs);
  556. return ASE_OK;
  557. }
  558. /*
  559. * ASIOError GetLatencies(LONG *inputLatency, LONG *outputLatency);
  560. * Function: Return latency in frames
  561. * Returns: ASE_NotPresent if no IO is available, otherwise AES_OK
  562. */
  563. DEFINE_THISCALL_WRAPPER(GetLatencies,12)
  564. HIDDEN ASIOError STDMETHODCALLTYPE GetLatencies(LPWINEASIO iface, LONG *inputLatency, LONG *outputLatency)
  565. {
  566. IWineASIOImpl *This = (IWineASIOImpl*)iface;
  567. jack_latency_range_t range;
  568. if (!inputLatency || !outputLatency)
  569. return ASE_InvalidParameter;
  570. if (This->asio_driver_state == Loaded)
  571. return ASE_NotPresent;
  572. jack_port_get_latency_range(This->input_channel[0].port, JackCaptureLatency, &range);
  573. *inputLatency = range.max;
  574. jack_port_get_latency_range(This->output_channel[0].port, JackPlaybackLatency, &range);
  575. *outputLatency = range.max;
  576. TRACE("iface: %p, input latency: %d, output latency: %d\n", iface, *inputLatency, *outputLatency);
  577. return ASE_OK;
  578. }
  579. /*
  580. * ASIOError GetBufferSize(LONG *minSize, LONG *maxSize, LONG *preferredSize, LONG *granularity);
  581. * Function: Return minimum, maximum, preferred buffer sizes, and granularity
  582. * At the moment return all the same, and granularity 0
  583. * Returns: ASE_NotPresent on missing IO
  584. */
  585. DEFINE_THISCALL_WRAPPER(GetBufferSize,20)
  586. HIDDEN ASIOError STDMETHODCALLTYPE GetBufferSize(LPWINEASIO iface, LONG *minSize, LONG *maxSize, LONG *preferredSize, LONG *granularity)
  587. {
  588. IWineASIOImpl *This = (IWineASIOImpl*)iface;
  589. TRACE("iface: %p, minSize: %p, maxSize: %p, preferredSize: %p, granularity: %p\n", iface, minSize, maxSize, preferredSize, granularity);
  590. if (!minSize || !maxSize || !preferredSize || !granularity)
  591. return ASE_InvalidParameter;
  592. if (This->wineasio_fixed_buffersize)
  593. {
  594. *minSize = *maxSize = *preferredSize = This->asio_current_buffersize;
  595. *granularity = 0;
  596. TRACE("Buffersize fixed at %i\n", This->asio_current_buffersize);
  597. return ASE_OK;
  598. }
  599. *minSize = ASIO_MINIMUM_BUFFERSIZE;
  600. *maxSize = ASIO_MAXIMUM_BUFFERSIZE;
  601. *preferredSize = This->wineasio_preferred_buffersize;
  602. *granularity = -1;
  603. TRACE("The ASIO host can control buffersize\nMinimum: %i, maximum: %i, preferred: %i, granularity: %i, current: %i\n",
  604. *minSize, *maxSize, *preferredSize, *granularity, This->asio_current_buffersize);
  605. return ASE_OK;
  606. }
  607. /*
  608. * ASIOError CanSampleRate(ASIOSampleRate sampleRate);
  609. * Function: Ask if specific SR is available
  610. * Returns: ASE_NoClock if SR isn't available, ASE_NotPresent on missing IO
  611. */
  612. DEFINE_THISCALL_WRAPPER(CanSampleRate,12)
  613. HIDDEN ASIOError STDMETHODCALLTYPE CanSampleRate(LPWINEASIO iface, ASIOSampleRate sampleRate)
  614. {
  615. IWineASIOImpl *This = (IWineASIOImpl*)iface;
  616. TRACE("iface: %p, Samplerate = %li, requested samplerate = %li\n", iface, (long) This->asio_sample_rate, (long) sampleRate);
  617. if (sampleRate != This->asio_sample_rate)
  618. return ASE_NoClock;
  619. return ASE_OK;
  620. }
  621. /*
  622. * ASIOError GetSampleRate(ASIOSampleRate *currentRate);
  623. * Function: Return current SR
  624. * Parameters: currentRate will hold SR on return, 0 if unknown
  625. * Returns: ASE_NoClock if SR is unknown, ASE_NotPresent on missing IO
  626. */
  627. DEFINE_THISCALL_WRAPPER(GetSampleRate,8)
  628. HIDDEN ASIOError STDMETHODCALLTYPE GetSampleRate(LPWINEASIO iface, ASIOSampleRate *sampleRate)
  629. {
  630. IWineASIOImpl *This = (IWineASIOImpl*)iface;
  631. TRACE("iface: %p, Sample rate is %i\n", iface, (int) This->asio_sample_rate);
  632. if (!sampleRate)
  633. return ASE_InvalidParameter;
  634. *sampleRate = This->asio_sample_rate;
  635. return ASE_OK;
  636. }
  637. /*
  638. * ASIOError SetSampleRate(ASIOSampleRate sampleRate);
  639. * Function: Set requested SR, enable external sync if SR == 0
  640. * Returns: ASE_NoClock if unknown SR
  641. * ASE_InvalidMode if current clock is external and SR != 0
  642. * ASE_NotPresent on missing IO
  643. */
  644. DEFINE_THISCALL_WRAPPER(SetSampleRate,12)
  645. HIDDEN ASIOError STDMETHODCALLTYPE SetSampleRate(LPWINEASIO iface, ASIOSampleRate sampleRate)
  646. {
  647. IWineASIOImpl *This = (IWineASIOImpl*)iface;
  648. TRACE("iface: %p, Sample rate %f requested\n", iface, sampleRate);
  649. if (sampleRate != This->asio_sample_rate)
  650. return ASE_NoClock;
  651. return ASE_OK;
  652. }
  653. /*
  654. * ASIOError GetClockSources(ASIOClockSource *clocks, LONG *numSources);
  655. * Function: Return available clock sources
  656. * Parameters: clocks - a pointer to an array of ASIOClockSource structures.
  657. * numSources - when called: number of allocated members
  658. * - on return: number of clock sources, the minimum is 1 - the internal clock
  659. * Returns: ASE_NotPresent on missing IO
  660. */
  661. DEFINE_THISCALL_WRAPPER(GetClockSources,12)
  662. HIDDEN ASIOError STDMETHODCALLTYPE GetClockSources(LPWINEASIO iface, ASIOClockSource *clocks, LONG *numSources)
  663. {
  664. TRACE("iface: %p, clocks: %p, numSources: %p\n", iface, clocks, numSources);
  665. if (!clocks || !numSources)
  666. return ASE_InvalidParameter;
  667. clocks->index = 0;
  668. clocks->associatedChannel = -1;
  669. clocks->associatedGroup = -1;
  670. clocks->isCurrentSource = ASIOTrue;
  671. strcpy(clocks->name, "Internal");
  672. *numSources = 1;
  673. return ASE_OK;
  674. }
  675. /*
  676. * ASIOError SetClockSource(LONG index);
  677. * Function: Set clock source
  678. * Parameters: index returned by ASIOGetClockSources() - See asio.h for more details
  679. * Returns: ASE_NotPresent on missing IO
  680. * ASE_InvalidMode may be returned if a clock can't be selected
  681. * ASE_NoClock should not be returned
  682. */
  683. DEFINE_THISCALL_WRAPPER(SetClockSource,8)
  684. HIDDEN ASIOError STDMETHODCALLTYPE SetClockSource(LPWINEASIO iface, LONG index)
  685. {
  686. TRACE("iface: %p, index: %i\n", iface, index);
  687. if (index != 0)
  688. return ASE_NotPresent;
  689. return ASE_OK;
  690. }
  691. /*
  692. * ASIOError GetSamplePosition (ASIOSamples *sPos, ASIOTimeStamp *tStamp);
  693. * Function: Return sample position and timestamp
  694. * Parameters: sPos holds the position on return, reset to 0 on ASIOStart()
  695. * tStamp holds the system time of sPos
  696. * Return: ASE_NotPresent on missing IO
  697. * ASE_SPNotAdvancing on missing clock
  698. */
  699. DEFINE_THISCALL_WRAPPER(GetSamplePosition,12)
  700. HIDDEN ASIOError STDMETHODCALLTYPE GetSamplePosition(LPWINEASIO iface, ASIOSamples *sPos, ASIOTimeStamp *tStamp)
  701. {
  702. IWineASIOImpl *This = (IWineASIOImpl*)iface;
  703. TRACE("iface: %p, sPos: %p, tStamp: %p\n", iface, sPos, tStamp);
  704. if (!sPos || !tStamp)
  705. return ASE_InvalidParameter;
  706. tStamp->lo = This->asio_time_stamp.lo;
  707. tStamp->hi = This->asio_time_stamp.hi;
  708. sPos->lo = This->asio_sample_position.lo;
  709. sPos->hi = 0; /* FIXME */
  710. return ASE_OK;
  711. }
  712. /*
  713. * ASIOError GetChannelInfo (ASIOChannelInfo *info);
  714. * Function: Retrive channel info. - See asio.h for more detail
  715. * Returns: ASE_NotPresent on missing IO
  716. */
  717. DEFINE_THISCALL_WRAPPER(GetChannelInfo,8)
  718. HIDDEN ASIOError STDMETHODCALLTYPE GetChannelInfo(LPWINEASIO iface, ASIOChannelInfo *info)
  719. {
  720. IWineASIOImpl *This = (IWineASIOImpl*)iface;
  721. /* TRACE("(iface: %p, info: %p\n", iface, info); */
  722. if (info->channel < 0 || (info->isInput ? info->channel >= This->wineasio_number_inputs : info->channel >= This->wineasio_number_outputs))
  723. return ASE_InvalidParameter;
  724. info->channelGroup = 0;
  725. info->type = ASIOSTFloat32LSB;
  726. if (info->isInput)
  727. {
  728. info->isActive = This->input_channel[info->channel].active;
  729. memcpy(info->name, This->input_channel[info->channel].port_name, ASIO_MAX_NAME_LENGTH);
  730. }
  731. else
  732. {
  733. info->isActive = This->output_channel[info->channel].active;
  734. memcpy(info->name, This->output_channel[info->channel].port_name, ASIO_MAX_NAME_LENGTH);
  735. }
  736. return ASE_OK;
  737. }
  738. /*
  739. * ASIOError CreateBuffers(ASIOBufferInfo *bufferInfo, LONG numChannels, LONG bufferSize, ASIOCallbacks *asioCallbacks);
  740. * Function: Allocate buffers for IO channels
  741. * Parameters: bufferInfo - pointer to an array of ASIOBufferInfo structures
  742. * numChannels - the total number of IO channels to be allocated
  743. * bufferSize - one of the buffer sizes retrieved with ASIOGetBufferSize()
  744. * asioCallbacks - pointer to an ASIOCallbacks structure
  745. * See asio.h for more detail
  746. * Returns: ASE_NoMemory if impossible to allocate enough memory
  747. * ASE_InvalidMode on unsupported bufferSize or invalid bufferInfo data
  748. * ASE_NotPresent on missing IO
  749. */
  750. DEFINE_THISCALL_WRAPPER(CreateBuffers,20)
  751. HIDDEN ASIOError STDMETHODCALLTYPE CreateBuffers(LPWINEASIO iface, ASIOBufferInfo *bufferInfo, LONG numChannels, LONG bufferSize, ASIOCallbacks *asioCallbacks)
  752. {
  753. IWineASIOImpl *This = (IWineASIOImpl*)iface;
  754. ASIOBufferInfo *buffer_info = bufferInfo;
  755. int i, j, k;
  756. TRACE("iface: %p, bufferInfo: %p, numChannels: %i, bufferSize: %i, asioCallbacks: %p\n", iface, bufferInfo, (int)numChannels, (int)bufferSize, asioCallbacks);
  757. if (This->asio_driver_state != Initialized)
  758. return ASE_NotPresent;
  759. if (!bufferInfo || !asioCallbacks)
  760. return ASE_InvalidMode;
  761. /* Check for invalid channel numbers */
  762. for (i = j = k = 0; i < numChannels; i++, buffer_info++)
  763. {
  764. if (buffer_info->isInput)
  765. {
  766. if (j++ >= This->wineasio_number_inputs)
  767. {
  768. WARN("Invalid input channel requested\n");
  769. return ASE_InvalidMode;
  770. }
  771. }
  772. else
  773. {
  774. if (k++ >= This->wineasio_number_outputs)
  775. {
  776. WARN("Invalid output channel requested\n");
  777. return ASE_InvalidMode;
  778. }
  779. }
  780. }
  781. /* set buf_size */
  782. if (This->wineasio_fixed_buffersize)
  783. {
  784. if (This->asio_current_buffersize != bufferSize)
  785. return ASE_InvalidMode;
  786. TRACE("Buffersize fixed at %i\n", (int)This->asio_current_buffersize);
  787. }
  788. else
  789. { /* fail if not a power of two and if out of range */
  790. if (!(bufferSize > 0 && !(bufferSize&(bufferSize-1))
  791. && bufferSize >= ASIO_MINIMUM_BUFFERSIZE
  792. && bufferSize <= ASIO_MAXIMUM_BUFFERSIZE))
  793. {
  794. WARN("Invalid buffersize %i requested\n", (int)bufferSize);
  795. return ASE_InvalidMode;
  796. }
  797. else
  798. {
  799. if (This->asio_current_buffersize == bufferSize)
  800. {
  801. TRACE("Buffer size already set to %i\n", (int)This->asio_current_buffersize);
  802. }
  803. else
  804. {
  805. This->asio_current_buffersize = bufferSize;
  806. if (jack_set_buffer_size(This->jack_client, This->asio_current_buffersize))
  807. {
  808. WARN("JACK is unable to set buffersize to %i\n", (int)This->asio_current_buffersize);
  809. return ASE_HWMalfunction;
  810. }
  811. TRACE("Buffer size changed to %i\n", (int)This->asio_current_buffersize);
  812. }
  813. }
  814. }
  815. /* print/discover ASIO host capabilities */
  816. This->asio_callbacks = asioCallbacks;
  817. This->asio_time_info_mode = This->asio_can_time_code = FALSE;
  818. TRACE("The ASIO host supports ASIO v%i: ", This->asio_callbacks->asioMessage(kAsioEngineVersion, 0, 0, 0));
  819. if (This->asio_callbacks->asioMessage(kAsioSelectorSupported, kAsioBufferSizeChange, 0 , 0))
  820. TRACE("kAsioBufferSizeChange ");
  821. if (This->asio_callbacks->asioMessage(kAsioSelectorSupported, kAsioResetRequest, 0 , 0))
  822. TRACE("kAsioResetRequest ");
  823. if (This->asio_callbacks->asioMessage(kAsioSelectorSupported, kAsioResyncRequest, 0 , 0))
  824. TRACE("kAsioResyncRequest ");
  825. if (This->asio_callbacks->asioMessage(kAsioSelectorSupported, kAsioLatenciesChanged, 0 , 0))
  826. TRACE("kAsioLatenciesChanged ");
  827. if (This->asio_callbacks->asioMessage(kAsioSupportsTimeInfo, 0, 0, 0))
  828. {
  829. TRACE("bufferSwitchTimeInfo ");
  830. This->asio_time_info_mode = TRUE;
  831. if (This->asio_callbacks->asioMessage(kAsioSupportsTimeCode, 0, 0, 0))
  832. {
  833. TRACE("TimeCode");
  834. This->asio_can_time_code = TRUE;
  835. }
  836. }
  837. else
  838. TRACE("BufferSwitch");
  839. TRACE("\n");
  840. /* Allocate audio buffers */
  841. This->callback_audio_buffer = HeapAlloc(GetProcessHeap(), 0,
  842. (This->wineasio_number_inputs + This->wineasio_number_outputs) * 2 * This->asio_current_buffersize * sizeof(jack_default_audio_sample_t));
  843. if (!This->callback_audio_buffer)
  844. {
  845. ERR("Unable to allocate %i ASIO audio buffers\n", This->wineasio_number_inputs + This->wineasio_number_outputs);
  846. return ASE_NoMemory;
  847. }
  848. TRACE("%i ASIO audio buffers allocated (%i kB)\n", This->wineasio_number_inputs + This->wineasio_number_outputs,
  849. (int) ((This->wineasio_number_inputs + This->wineasio_number_outputs) * 2 * This->asio_current_buffersize * sizeof(jack_default_audio_sample_t) / 1024));
  850. for (i = 0; i < This->wineasio_number_inputs; i++)
  851. This->input_channel[i].audio_buffer = This->callback_audio_buffer + (i * 2 * This->asio_current_buffersize);
  852. for (i = 0; i < This->wineasio_number_outputs; i++)
  853. This->output_channel[i].audio_buffer = This->callback_audio_buffer + ((This->wineasio_number_inputs + i) * 2 * This->asio_current_buffersize);
  854. /* initialize ASIOBufferInfo structures */
  855. buffer_info = bufferInfo;
  856. This->asio_active_inputs = This->asio_active_outputs = 0;
  857. for (i = 0; i < This->wineasio_number_inputs; i++) {
  858. This->input_channel[i].active = ASIOFalse;
  859. }
  860. for (i = 0; i < This->wineasio_number_outputs; i++) {
  861. This->output_channel[i].active = ASIOFalse;
  862. }
  863. for (i = 0; i < numChannels; i++, buffer_info++)
  864. {
  865. if (buffer_info->isInput)
  866. {
  867. buffer_info->buffers[0] = &This->input_channel[buffer_info->channelNum].audio_buffer[0];
  868. buffer_info->buffers[1] = &This->input_channel[buffer_info->channelNum].audio_buffer[This->asio_current_buffersize];
  869. This->input_channel[buffer_info->channelNum].active = ASIOTrue;
  870. This->asio_active_inputs++;
  871. /* TRACE("ASIO audio buffer for channel %i as input %li created\n", i, This->asio_active_inputs); */
  872. }
  873. else
  874. {
  875. buffer_info->buffers[0] = &This->output_channel[buffer_info->channelNum].audio_buffer[0];
  876. buffer_info->buffers[1] = &This->output_channel[buffer_info->channelNum].audio_buffer[This->asio_current_buffersize];
  877. This->output_channel[buffer_info->channelNum].active = ASIOTrue;
  878. This->asio_active_outputs++;
  879. /* TRACE("ASIO audio buffer for channel %i as output %li created\n", i, This->asio_active_outputs); */
  880. }
  881. }
  882. TRACE("%i audio channels initialized\n", This->asio_active_inputs + This->asio_active_outputs);
  883. if (jack_activate(This->jack_client))
  884. return ASE_NotPresent;
  885. /* connect to the hardware io */
  886. if (This->wineasio_connect_to_hardware)
  887. {
  888. for (i = 0; i < This->jack_num_input_ports && i < This->wineasio_number_inputs; i++)
  889. if (strstr(jack_port_type(jack_port_by_name(This->jack_client, This->jack_input_ports[i])), "audio"))
  890. jack_connect(This->jack_client, This->jack_input_ports[i], jack_port_name(This->input_channel[i].port));
  891. for (i = 0; i < This->jack_num_output_ports && i < This->wineasio_number_outputs; i++)
  892. if (strstr(jack_port_type(jack_port_by_name(This->jack_client, This->jack_output_ports[i])), "audio"))
  893. jack_connect(This->jack_client, jack_port_name(This->output_channel[i].port), This->jack_output_ports[i]);
  894. }
  895. /* at this point all the connections are made and the jack process callback is outputting silence */
  896. This->asio_driver_state = Prepared;
  897. return ASE_OK;
  898. }
  899. /*
  900. * ASIOError DisposeBuffers(void);
  901. * Function: Release allocated buffers
  902. * Returns: ASE_InvalidMode if no buffers were previously allocated
  903. * ASE_NotPresent on missing IO
  904. * Implies: ASIOStop()
  905. */
  906. DEFINE_THISCALL_WRAPPER(DisposeBuffers,4)
  907. HIDDEN ASIOError STDMETHODCALLTYPE DisposeBuffers(LPWINEASIO iface)
  908. {
  909. IWineASIOImpl *This = (IWineASIOImpl*)iface;
  910. int i;
  911. TRACE("iface: %p\n", iface);
  912. if (This->asio_driver_state == Running)
  913. Stop (iface);
  914. if (This->asio_driver_state != Prepared)
  915. return ASE_NotPresent;
  916. if (jack_deactivate(This->jack_client))
  917. return ASE_NotPresent;
  918. This->asio_callbacks = NULL;
  919. for (i = 0; i < This->wineasio_number_inputs; i++)
  920. {
  921. This->input_channel[i].audio_buffer = NULL;
  922. This->input_channel[i].active = ASIOFalse;
  923. }
  924. for (i = 0; i < This->wineasio_number_outputs; i++)
  925. {
  926. This->output_channel[i].audio_buffer = NULL;
  927. This->output_channel[i].active = ASIOFalse;
  928. }
  929. This->asio_active_inputs = This->asio_active_outputs = 0;
  930. if (This->callback_audio_buffer)
  931. HeapFree(GetProcessHeap(), 0, This->callback_audio_buffer);
  932. This->asio_driver_state = Initialized;
  933. return ASE_OK;
  934. }
  935. /*
  936. * ASIOError ControlPanel(void);
  937. * Function: Open a control panel for driver settings
  938. * Returns: ASE_NotPresent if no control panel exists. Actually return code should be ignored
  939. * Note: Call the asioMessage callback if something has changed
  940. */
  941. DEFINE_THISCALL_WRAPPER(ControlPanel,4)
  942. HIDDEN ASIOError STDMETHODCALLTYPE ControlPanel(LPWINEASIO iface)
  943. {
  944. static char arg0[] = "wineasio-settings\0";
  945. static char *arg_list[] = { arg0, NULL };
  946. TRACE("iface: %p\n", iface);
  947. if (vfork() == 0)
  948. {
  949. execvp (arg0, arg_list);
  950. _exit(1);
  951. }
  952. return ASE_OK;
  953. }
  954. /*
  955. * ASIOError Future(LONG selector, void *opt);
  956. * Function: Various, See asio.h for more detail
  957. * Returns: Depends on the selector but in general ASE_InvalidParameter on invalid selector
  958. * ASE_InvalidParameter if function is unsupported to disable further calls
  959. * ASE_SUCCESS on success, do not use AES_OK
  960. */
  961. DEFINE_THISCALL_WRAPPER(Future,12)
  962. HIDDEN ASIOError STDMETHODCALLTYPE Future(LPWINEASIO iface, LONG selector, void *opt)
  963. {
  964. IWineASIOImpl *This = (IWineASIOImpl *) iface;
  965. TRACE("iface: %p, selector: %i, opt: %p\n", iface, selector, opt);
  966. switch (selector)
  967. {
  968. case kAsioEnableTimeCodeRead:
  969. This->asio_can_time_code = TRUE;
  970. TRACE("The ASIO host enabled TimeCode\n");
  971. return ASE_SUCCESS;
  972. case kAsioDisableTimeCodeRead:
  973. This->asio_can_time_code = FALSE;
  974. TRACE("The ASIO host disabled TimeCode\n");
  975. return ASE_SUCCESS;
  976. case kAsioSetInputMonitor:
  977. TRACE("The driver denied request to set input monitor\n");
  978. return ASE_NotPresent;
  979. case kAsioTransport:
  980. TRACE("The driver denied request for ASIO Transport control\n");
  981. return ASE_InvalidParameter;
  982. case kAsioSetInputGain:
  983. TRACE("The driver denied request to set input gain\n");
  984. return ASE_InvalidParameter;
  985. case kAsioGetInputMeter:
  986. TRACE("The driver denied request to get input meter \n");
  987. return ASE_InvalidParameter;
  988. case kAsioSetOutputGain:
  989. TRACE("The driver denied request to set output gain\n");
  990. return ASE_InvalidParameter;
  991. case kAsioGetOutputMeter:
  992. TRACE("The driver denied request to get output meter\n");
  993. return ASE_InvalidParameter;
  994. case kAsioCanInputMonitor:
  995. TRACE("The driver does not support input monitor\n");
  996. return ASE_InvalidParameter;
  997. case kAsioCanTimeInfo:
  998. TRACE("The driver supports TimeInfo\n");
  999. return ASE_SUCCESS;
  1000. case kAsioCanTimeCode:
  1001. TRACE("The driver supports TimeCode\n");
  1002. return ASE_SUCCESS;
  1003. case kAsioCanTransport:
  1004. TRACE("The driver denied request for ASIO Transport\n");
  1005. return ASE_InvalidParameter;
  1006. case kAsioCanInputGain:
  1007. TRACE("The driver does not support input gain\n");
  1008. return ASE_InvalidParameter;
  1009. case kAsioCanInputMeter:
  1010. TRACE("The driver does not support input meter\n");
  1011. return ASE_InvalidParameter;
  1012. case kAsioCanOutputGain:
  1013. TRACE("The driver does not support output gain\n");
  1014. return ASE_InvalidParameter;
  1015. case kAsioCanOutputMeter:
  1016. TRACE("The driver does not support output meter\n");
  1017. return ASE_InvalidParameter;
  1018. case kAsioSetIoFormat:
  1019. TRACE("The driver denied request to set DSD IO format\n");
  1020. return ASE_NotPresent;
  1021. case kAsioGetIoFormat:
  1022. TRACE("The driver denied request to get DSD IO format\n");
  1023. return ASE_NotPresent;
  1024. case kAsioCanDoIoFormat:
  1025. TRACE("The driver does not support DSD IO format\n");
  1026. return ASE_NotPresent;
  1027. default:
  1028. TRACE("ASIOFuture() called with undocumented selector\n");
  1029. return ASE_InvalidParameter;
  1030. }
  1031. }
  1032. /*
  1033. * ASIOError OutputReady(void);
  1034. * Function: Tells the driver that output bufffers are ready
  1035. * Returns: ASE_OK if supported
  1036. * ASE_NotPresent to disable
  1037. */
  1038. DEFINE_THISCALL_WRAPPER(OutputReady,4)
  1039. HIDDEN ASIOError STDMETHODCALLTYPE OutputReady(LPWINEASIO iface)
  1040. {
  1041. /* disabled to stop stand alone NI programs from spamming the console
  1042. TRACE("iface: %p\n", iface); */
  1043. return ASE_NotPresent;
  1044. }
  1045. /****************************************************************************
  1046. * JACK callbacks
  1047. */
  1048. static inline int jack_buffer_size_callback(jack_nframes_t nframes, void *arg)
  1049. {
  1050. IWineASIOImpl *This = (IWineASIOImpl*)arg;
  1051. if(This->asio_driver_state != Running)
  1052. return 0;
  1053. if (This->asio_callbacks->asioMessage(kAsioSelectorSupported, kAsioResetRequest, 0 , 0))
  1054. This->asio_callbacks->asioMessage(kAsioResetRequest, 0, 0, 0);
  1055. return 0;
  1056. }
  1057. static inline void jack_latency_callback(jack_latency_callback_mode_t mode, void *arg)
  1058. {
  1059. IWineASIOImpl *This = (IWineASIOImpl*)arg;
  1060. if(This->asio_driver_state != Running)
  1061. return;
  1062. if (This->asio_callbacks->asioMessage(kAsioSelectorSupported, kAsioLatenciesChanged, 0 , 0))
  1063. This->asio_callbacks->asioMessage(kAsioLatenciesChanged, 0, 0, 0);
  1064. return;
  1065. }
  1066. static inline int jack_process_callback(jack_nframes_t nframes, void *arg)
  1067. {
  1068. IWineASIOImpl *This = (IWineASIOImpl*)arg;
  1069. int i;
  1070. jack_transport_state_t jack_transport_state;
  1071. jack_position_t jack_position;
  1072. DWORD time;
  1073. /* output silence if the ASIO callback isn't running yet */
  1074. if (This->asio_driver_state != Running)
  1075. {
  1076. for (i = 0; i < This->asio_active_outputs; i++)
  1077. bzero(jack_port_get_buffer(This->output_channel[i].port, nframes), sizeof (jack_default_audio_sample_t) * nframes);
  1078. return 0;
  1079. }
  1080. /* copy jack to asio buffers */
  1081. for (i = 0; i < This->wineasio_number_inputs; i++)
  1082. if (This->input_channel[i].active == ASIOTrue)
  1083. memcpy (&This->input_channel[i].audio_buffer[nframes * This->asio_buffer_index],
  1084. jack_port_get_buffer(This->input_channel[i].port, nframes),
  1085. sizeof (jack_default_audio_sample_t) * nframes);
  1086. if (This->asio_sample_position.lo > ULONG_MAX - nframes)
  1087. This->asio_sample_position.hi++;
  1088. This->asio_sample_position.lo += nframes;
  1089. time = timeGetTime();
  1090. This->asio_time_stamp.lo = time * 1000000;
  1091. This->asio_time_stamp.hi = ((unsigned long long) time * 1000000) >> 32;
  1092. if (This->asio_time_info_mode) /* use the newer bufferSwitchTimeInfo method if supported */
  1093. {
  1094. This->asio_time.timeInfo.samplePosition.lo = This->asio_sample_position.lo;
  1095. This->asio_time.timeInfo.samplePosition.hi = This->asio_sample_position.hi;
  1096. This->asio_time.timeInfo.systemTime.lo = This->asio_time_stamp.lo;
  1097. This->asio_time.timeInfo.systemTime.hi = This->asio_time_stamp.hi;
  1098. This->asio_time.timeInfo.sampleRate = This->asio_sample_rate;
  1099. This->asio_time.timeInfo.flags = kSystemTimeValid | kSamplePositionValid | kSampleRateValid;
  1100. if (This->asio_can_time_code) /* FIXME addionally use time code if supported */
  1101. {
  1102. jack_transport_state = jack_transport_query(This->jack_client, &jack_position);
  1103. This->asio_time.timeCode.flags = kTcValid;
  1104. if (jack_transport_state == JackTransportRolling)
  1105. This->asio_time.timeCode.flags |= kTcRunning;
  1106. }
  1107. This->asio_callbacks->bufferSwitchTimeInfo(&This->asio_time, This->asio_buffer_index, ASIOTrue);
  1108. }
  1109. else
  1110. { /* use the old bufferSwitch method */
  1111. This->asio_callbacks->bufferSwitch(This->asio_buffer_index, ASIOTrue);
  1112. }
  1113. /* copy asio to jack buffers */
  1114. for (i = 0; i < This->wineasio_number_outputs; i++)
  1115. if (This->output_channel[i].active == ASIOTrue)
  1116. memcpy(jack_port_get_buffer(This->output_channel[i].port, nframes),
  1117. &This->output_channel[i].audio_buffer[nframes * This->asio_buffer_index],
  1118. sizeof (jack_default_audio_sample_t) * nframes);
  1119. /* swith asio buffer */
  1120. This->asio_buffer_index = This->asio_buffer_index ? 0 : 1;
  1121. return 0;
  1122. }
  1123. static inline int jack_sample_rate_callback(jack_nframes_t nframes, void *arg)
  1124. {
  1125. IWineASIOImpl *This = (IWineASIOImpl*)arg;
  1126. if(This->asio_driver_state != Running)
  1127. return 0;
  1128. This->asio_sample_rate = nframes;
  1129. This->asio_callbacks->sampleRateDidChange(nframes);
  1130. return 0;
  1131. }
  1132. /*****************************************************************************
  1133. * Support functions
  1134. */
  1135. #ifndef WINE_WITH_UNICODE
  1136. /* Funtion required as unicode.h no longer in WINE */
  1137. static WCHAR *strrchrW(const WCHAR* str, WCHAR ch)
  1138. {
  1139. WCHAR *ret = NULL;
  1140. do { if (*str == ch) ret = (WCHAR *)(ULONG_PTR)str; } while (*str++);
  1141. return ret;
  1142. }
  1143. #endif
  1144. /* Function called by JACK to create a thread in the wine process context,
  1145. * uses the global structure jack_thread_creator_privates to communicate with jack_thread_creator_helper() */
  1146. static int jack_thread_creator(pthread_t* thread_id, const pthread_attr_t* attr, void *(*function)(void*), void* arg)
  1147. {
  1148. TRACE("arg: %p, thread_id: %p, attr: %p, function: %p\n", arg, thread_id, attr, function);
  1149. jack_thread_creator_privates.jack_callback_thread = function;
  1150. jack_thread_creator_privates.arg = arg;
  1151. jack_thread_creator_privates.jack_callback_thread_created = CreateEventW(NULL, FALSE, FALSE, NULL);
  1152. CreateThread( NULL, 0, jack_thread_creator_helper, arg, 0,0 );
  1153. WaitForSingleObject(jack_thread_creator_privates.jack_callback_thread_created, INFINITE);
  1154. *thread_id = jack_thread_creator_privates.jack_callback_pthread_id;
  1155. return 0;
  1156. }
  1157. /* internal helper function for returning the posix thread_id of the newly created callback thread */
  1158. static DWORD WINAPI jack_thread_creator_helper(LPVOID arg)
  1159. {
  1160. TRACE("arg: %p\n", arg);
  1161. jack_thread_creator_privates.jack_callback_pthread_id = pthread_self();
  1162. SetEvent(jack_thread_creator_privates.jack_callback_thread_created);
  1163. jack_thread_creator_privates.jack_callback_thread(jack_thread_creator_privates.arg);
  1164. return 0;
  1165. }
  1166. static VOID configure_driver(IWineASIOImpl *This)
  1167. {
  1168. HKEY hkey;
  1169. LONG result, value;
  1170. DWORD type, size;
  1171. WCHAR application_path [MAX_PATH];
  1172. WCHAR *application_name;
  1173. char environment_variable[MAX_ENVIRONMENT_SIZE];
  1174. /* Unicode strings used for the registry */
  1175. static const WCHAR key_software_wine_wineasio[] =
  1176. { 'S','o','f','t','w','a','r','e','\\',
  1177. 'W','i','n','e','\\',
  1178. 'W','i','n','e','A','S','I','O',0 };
  1179. static const WCHAR value_wineasio_number_inputs[] =
  1180. { 'N','u','m','b','e','r',' ','o','f',' ','i','n','p','u','t','s',0 };
  1181. static const WCHAR value_wineasio_number_outputs[] =
  1182. { 'N','u','m','b','e','r',' ','o','f',' ','o','u','t','p','u','t','s',0 };
  1183. static const WCHAR value_wineasio_fixed_buffersize[] =
  1184. { 'F','i','x','e','d',' ','b','u','f','f','e','r','s','i','z','e',0 };
  1185. static const WCHAR value_wineasio_preferred_buffersize[] =
  1186. { 'P','r','e','f','e','r','r','e','d',' ','b','u','f','f','e','r','s','i','z','e',0 };
  1187. static const WCHAR wineasio_autostart_server[] =
  1188. { 'A','u','t','o','s','t','a','r','t',' ','s','e','r','v','e','r',0 };
  1189. static const WCHAR value_wineasio_connect_to_hardware[] =
  1190. { 'C','o','n','n','e','c','t',' ','t','o',' ','h','a','r','d','w','a','r','e',0 };
  1191. /* Initialise most member variables,
  1192. * asio_sample_position, asio_time, & asio_time_stamp are initialized in Start()
  1193. * jack_num_input_ports & jack_num_output_ports are initialized in Init() */
  1194. This->asio_active_inputs = 0;
  1195. This->asio_active_outputs = 0;
  1196. This->asio_buffer_index = 0;
  1197. This->asio_callbacks = NULL;
  1198. This->asio_can_time_code = FALSE;
  1199. This->asio_current_buffersize = 0;
  1200. This->asio_driver_state = Loaded;
  1201. This->asio_sample_rate = 0;
  1202. This->asio_time_info_mode = FALSE;
  1203. This->asio_version = 92;
  1204. This->wineasio_number_inputs = 16;
  1205. This->wineasio_number_outputs = 16;
  1206. This->wineasio_autostart_server = FALSE;
  1207. This->wineasio_connect_to_hardware = TRUE;
  1208. This->wineasio_fixed_buffersize = TRUE;
  1209. This->wineasio_preferred_buffersize = ASIO_PREFERRED_BUFFERSIZE;
  1210. This->jack_client = NULL;
  1211. This->jack_client_name[0] = 0;
  1212. This->jack_input_ports = NULL;
  1213. This->jack_output_ports = NULL;
  1214. This->callback_audio_buffer = NULL;
  1215. This->input_channel = NULL;
  1216. This->output_channel = NULL;
  1217. /* create registry entries with defaults if not present */
  1218. result = RegCreateKeyExW(HKEY_CURRENT_USER, key_software_wine_wineasio, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
  1219. /* get/set number of asio inputs */
  1220. size = sizeof(DWORD);
  1221. if (RegQueryValueExW(hkey, value_wineasio_number_inputs, NULL, &type, (LPBYTE) &value, &size) == ERROR_SUCCESS)
  1222. {
  1223. if (type == REG_DWORD)
  1224. This->wineasio_number_inputs = value;
  1225. }
  1226. else
  1227. {
  1228. type = REG_DWORD;
  1229. size = sizeof(DWORD);
  1230. value = This->wineasio_number_inputs;
  1231. result = RegSetValueExW(hkey, value_wineasio_number_inputs, 0, REG_DWORD, (LPBYTE) &value, size);
  1232. }
  1233. /* get/set number of asio outputs */
  1234. size = sizeof(DWORD);
  1235. if (RegQueryValueExW(hkey, value_wineasio_number_outputs, NULL, &type, (LPBYTE) &value, &size) == ERROR_SUCCESS)
  1236. {
  1237. if (type == REG_DWORD)
  1238. This->wineasio_number_outputs = value;
  1239. }
  1240. else
  1241. {
  1242. type = REG_DWORD;
  1243. size = sizeof(DWORD);
  1244. value = This->wineasio_number_outputs;
  1245. result = RegSetValueExW(hkey, value_wineasio_number_outputs, 0, REG_DWORD, (LPBYTE) &value, size);
  1246. }
  1247. /* allow changing of asio buffer sizes */
  1248. size = sizeof(DWORD);
  1249. if (RegQueryValueExW(hkey, value_wineasio_fixed_buffersize, NULL, &type, (LPBYTE) &value, &size) == ERROR_SUCCESS)
  1250. {
  1251. if (type == REG_DWORD)
  1252. This->wineasio_fixed_buffersize = value;
  1253. }
  1254. else
  1255. {
  1256. type = REG_DWORD;
  1257. size = sizeof(DWORD);
  1258. value = This->wineasio_fixed_buffersize;
  1259. result = RegSetValueExW(hkey, value_wineasio_fixed_buffersize, 0, REG_DWORD, (LPBYTE) &value, size);
  1260. }
  1261. /* preferred buffer size (if changing buffersize is allowed) */
  1262. size = sizeof(DWORD);
  1263. if (RegQueryValueExW(hkey, value_wineasio_preferred_buffersize, NULL, &type, (LPBYTE) &value, &size) == ERROR_SUCCESS)
  1264. {
  1265. if (type == REG_DWORD)
  1266. This->wineasio_preferred_buffersize = value;
  1267. }
  1268. else
  1269. {
  1270. type = REG_DWORD;
  1271. size = sizeof(DWORD);
  1272. value = This->wineasio_preferred_buffersize;
  1273. result = RegSetValueExW(hkey, value_wineasio_preferred_buffersize, 0, REG_DWORD, (LPBYTE) &value, size);
  1274. }
  1275. /* get/set JACK autostart */
  1276. size = sizeof(DWORD);
  1277. if (RegQueryValueExW(hkey, wineasio_autostart_server, NULL, &type, (LPBYTE) &value, &size) == ERROR_SUCCESS)
  1278. {
  1279. if (type == REG_DWORD)
  1280. This->wineasio_autostart_server = value;
  1281. }
  1282. else
  1283. {
  1284. type = REG_DWORD;
  1285. size = sizeof(DWORD);
  1286. value = This->wineasio_autostart_server;
  1287. result = RegSetValueExW(hkey, wineasio_autostart_server, 0, REG_DWORD, (LPBYTE) &value, size);
  1288. }
  1289. /* get/set JACK connect to physical io */
  1290. size = sizeof(DWORD);
  1291. if (RegQueryValueExW(hkey, value_wineasio_connect_to_hardware, NULL, &type, (LPBYTE) &value, &size) == ERROR_SUCCESS)
  1292. {
  1293. if (type == REG_DWORD)
  1294. This->wineasio_connect_to_hardware = value;
  1295. }
  1296. else
  1297. {
  1298. type = REG_DWORD;
  1299. size = sizeof(DWORD);
  1300. value = This->wineasio_connect_to_hardware;
  1301. result = RegSetValueExW(hkey, value_wineasio_connect_to_hardware, 0, REG_DWORD, (LPBYTE) &value, size);
  1302. }
  1303. /* get client name by stripping path and extension */
  1304. GetModuleFileNameW(0, application_path, MAX_PATH);
  1305. application_name = strrchrW(application_path, L'.');
  1306. *application_name = 0;
  1307. application_name = strrchrW(application_path, L'\\');
  1308. application_name++;
  1309. WideCharToMultiByte(CP_ACP, WC_SEPCHARS, application_name, -1, This->jack_client_name, ASIO_MAX_NAME_LENGTH, NULL, NULL);
  1310. RegCloseKey(hkey);
  1311. /* Look for environment variables to override registry config values */
  1312. if (GetEnvironmentVariableA("WINEASIO_NUMBER_INPUTS", environment_variable, MAX_ENVIRONMENT_SIZE))
  1313. {
  1314. errno = 0;
  1315. result = strtol(environment_variable, 0, 10);
  1316. if (errno != ERANGE)
  1317. This->wineasio_number_inputs = result;
  1318. }
  1319. if (GetEnvironmentVariableA("WINEASIO_NUMBER_OUTPUTS", environment_variable, MAX_ENVIRONMENT_SIZE))
  1320. {
  1321. errno = 0;
  1322. result = strtol(environment_variable, 0, 10);
  1323. if (errno != ERANGE)
  1324. This->wineasio_number_outputs = result;
  1325. }
  1326. if (GetEnvironmentVariableA("WINEASIO_AUTOSTART_SERVER", environment_variable, MAX_ENVIRONMENT_SIZE))
  1327. {
  1328. if (!strcasecmp(environment_variable, "on"))
  1329. This->wineasio_autostart_server = TRUE;
  1330. else if (!strcasecmp(environment_variable, "off"))
  1331. This->wineasio_autostart_server = FALSE;
  1332. }
  1333. if (GetEnvironmentVariableA("WINEASIO_CONNECT_TO_HARDWARE", environment_variable, MAX_ENVIRONMENT_SIZE))
  1334. {
  1335. if (!strcasecmp(environment_variable, "on"))
  1336. This->wineasio_connect_to_hardware = TRUE;
  1337. else if (!strcasecmp(environment_variable, "off"))
  1338. This->wineasio_connect_to_hardware = FALSE;
  1339. }
  1340. if (GetEnvironmentVariableA("WINEASIO_FIXED_BUFFERSIZE", environment_variable, MAX_ENVIRONMENT_SIZE))
  1341. {
  1342. if (!strcasecmp(environment_variable, "on"))
  1343. This->wineasio_fixed_buffersize = TRUE;
  1344. else if (!strcasecmp(environment_variable, "off"))
  1345. This->wineasio_fixed_buffersize = FALSE;
  1346. }
  1347. if (GetEnvironmentVariableA("WINEASIO_PREFERRED_BUFFERSIZE", environment_variable, MAX_ENVIRONMENT_SIZE))
  1348. {
  1349. errno = 0;
  1350. result = strtol(environment_variable, 0, 10);
  1351. if (errno != ERANGE)
  1352. This->wineasio_preferred_buffersize = result;
  1353. }
  1354. /* over ride the JACK client name gotten from the application name */
  1355. size = GetEnvironmentVariableA("WINEASIO_CLIENT_NAME", environment_variable, ASIO_MAX_NAME_LENGTH);
  1356. if (size > 0 && size < ASIO_MAX_NAME_LENGTH)
  1357. strcpy(This->jack_client_name, environment_variable);
  1358. /* if wineasio_preferred_buffersize is not a power of two or if out of range, then set to ASIO_PREFERRED_BUFFERSIZE */
  1359. if (!(This->wineasio_preferred_buffersize > 0 && !(This->wineasio_preferred_buffersize&(This->wineasio_preferred_buffersize-1))
  1360. && This->wineasio_preferred_buffersize >= ASIO_MINIMUM_BUFFERSIZE
  1361. && This->wineasio_preferred_buffersize <= ASIO_MAXIMUM_BUFFERSIZE))
  1362. This->wineasio_preferred_buffersize = ASIO_PREFERRED_BUFFERSIZE;
  1363. return;
  1364. }
  1365. /* Allocate the interface pointer and associate it with the vtbl/WineASIO object */
  1366. HRESULT WINAPI WineASIOCreateInstance(REFIID riid, LPVOID *ppobj)
  1367. {
  1368. IWineASIOImpl *pobj;
  1369. /* TRACE("riid: %s, ppobj: %p\n", debugstr_guid(riid), ppobj); */
  1370. pobj = HeapAlloc(GetProcessHeap(), 0, sizeof(*pobj));
  1371. if (pobj == NULL)
  1372. {
  1373. WARN("out of memory\n");
  1374. return E_OUTOFMEMORY;
  1375. }
  1376. pobj->lpVtbl = &WineASIO_Vtbl;
  1377. pobj->ref = 1;
  1378. TRACE("pobj = %p\n", pobj);
  1379. *ppobj = pobj;
  1380. /* TRACE("return %p\n", *ppobj); */
  1381. return S_OK;
  1382. }