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.

1617 lines
61KB

  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. }