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.

1722 lines
64KB

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