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.

1222 lines
37KB

  1. /*
  2. * Copyright (C) 2006,2007 Robert Reif
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  17. */
  18. #include "config.h"
  19. #include "wine/port.h"
  20. #include <stdarg.h>
  21. #include <stdio.h>
  22. #include "windef.h"
  23. #include "winbase.h"
  24. #include "objbase.h"
  25. #include "mmsystem.h"
  26. #ifdef HAVE_PTHREAD_H
  27. #include <pthread.h>
  28. #include <semaphore.h>
  29. #endif
  30. #include "wine/library.h"
  31. #include "wine/debug.h"
  32. #ifdef HAVE_JACK_JACK_H
  33. #include <jack/jack.h>
  34. #endif
  35. #ifdef HAVE_ASIO_SDK_ASIO_H
  36. #define IEEE754_64FLOAT 1
  37. #include <common/asio.h>
  38. #endif
  39. WINE_DEFAULT_DEBUG_CHANNEL(asio);
  40. #if defined(HAVE_JACK_JACK_H) && defined(HAVE_ASIO_SDK_ASIO_H) && defined(HAVE_PTHREAD_H)
  41. #ifndef SONAME_LIBJACK
  42. #define SONAME_LIBJACK "libjack.so"
  43. #endif
  44. #define MAKE_FUNCPTR(f) static typeof(f) * fp_##f = NULL;
  45. /* Function pointers for dynamic loading of libjack */
  46. /* these are prefixed with "fp_", ie. "fp_jack_client_new" */
  47. MAKE_FUNCPTR(jack_activate);
  48. MAKE_FUNCPTR(jack_deactivate);
  49. MAKE_FUNCPTR(jack_connect);
  50. MAKE_FUNCPTR(jack_client_open);
  51. MAKE_FUNCPTR(jack_client_close);
  52. MAKE_FUNCPTR(jack_transport_query);
  53. MAKE_FUNCPTR(jack_transport_start);
  54. MAKE_FUNCPTR(jack_set_process_callback);
  55. MAKE_FUNCPTR(jack_get_sample_rate);
  56. MAKE_FUNCPTR(jack_port_register);
  57. MAKE_FUNCPTR(jack_port_get_buffer);
  58. MAKE_FUNCPTR(jack_get_ports);
  59. MAKE_FUNCPTR(jack_port_name);
  60. MAKE_FUNCPTR(jack_get_buffer_size);
  61. MAKE_FUNCPTR(jack_port_unregister);
  62. #undef MAKE_FUNCPTR
  63. void *jackhandle = NULL;
  64. /* JACK callback function */
  65. static int jack_process(jack_nframes_t nframes, void * arg);
  66. /* WIN32 callback function */
  67. static DWORD CALLBACK win32_callback(LPVOID arg);
  68. /* {48D0C522-BFCC-45cc-8B84-17F25F33E6E8} */
  69. static GUID const CLSID_WineASIO = {
  70. 0x48d0c522, 0xbfcc, 0x45cc, { 0x8b, 0x84, 0x17, 0xf2, 0x5f, 0x33, 0xe6, 0xe8 } };
  71. #define twoRaisedTo32 4294967296.0
  72. #define twoRaisedTo32Reciprocal (1.0 / twoRaisedTo32)
  73. #define MAX_INPUTS 32
  74. #define MAX_OUTPUTS 32
  75. /* ASIO drivers use the thiscall calling convention which only Microsoft compilers
  76. * produce. These macros add an extra layer to fixup the registers properly for
  77. * this calling convention.
  78. */
  79. #ifdef __i386__ /* thiscall functions are i386-specific */
  80. #ifdef __GNUC__
  81. /* GCC erroneously warns that the newly wrapped function
  82. * isn't used, lets help it out of it's thinking
  83. */
  84. #define SUPPRESS_NOTUSED __attribute__((used))
  85. #else
  86. #define SUPPRESS_NOTUSED
  87. #endif /* __GNUC__ */
  88. #define WRAP_THISCALL(type, func, parm) \
  89. extern type func parm; \
  90. __ASM_GLOBAL_FUNC( func, \
  91. "popl %eax\n\t" \
  92. "pushl %ecx\n\t" \
  93. "pushl %eax\n\t" \
  94. "jmp " __ASM_NAME("__wrapped_" #func) ); \
  95. SUPPRESS_NOTUSED static type __wrapped_ ## func parm
  96. #else
  97. #define WRAP_THISCALL(functype, function, param) \
  98. functype function param
  99. #endif
  100. /*****************************************************************************
  101. * IWineAsio interface
  102. */
  103. #define INTERFACE IWineASIO
  104. DECLARE_INTERFACE_(IWineASIO,IUnknown)
  105. {
  106. STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;
  107. STDMETHOD_(ULONG,AddRef)(THIS) PURE;
  108. STDMETHOD_(ULONG,Release)(THIS) PURE;
  109. STDMETHOD_(ASIOBool,init)(THIS_ void *sysHandle) PURE;
  110. STDMETHOD_(void,getDriverName)(THIS_ char *name) PURE;
  111. STDMETHOD_(long,getDriverVersion)(THIS) PURE;
  112. STDMETHOD_(void,getErrorMessage)(THIS_ char *string) PURE;
  113. STDMETHOD_(ASIOError,start)(THIS) PURE;
  114. STDMETHOD_(ASIOError,stop)(THIS) PURE;
  115. STDMETHOD_(ASIOError,getChannels)(THIS_ long *numInputChannels, long *numOutputChannels) PURE;
  116. STDMETHOD_(ASIOError,getLatencies)(THIS_ long *inputLatency, long *outputLatency) PURE;
  117. STDMETHOD_(ASIOError,getBufferSize)(THIS_ long *minSize, long *maxSize, long *preferredSize, long *granularity) PURE;
  118. STDMETHOD_(ASIOError,canSampleRate)(THIS_ ASIOSampleRate sampleRate) PURE;
  119. STDMETHOD_(ASIOError,getSampleRate)(THIS_ ASIOSampleRate *sampleRate) PURE;
  120. STDMETHOD_(ASIOError,setSampleRate)(THIS_ ASIOSampleRate sampleRate) PURE;
  121. STDMETHOD_(ASIOError,getClockSources)(THIS_ ASIOClockSource *clocks, long *numSources) PURE;
  122. STDMETHOD_(ASIOError,setClockSource)(THIS_ long reference) PURE;
  123. STDMETHOD_(ASIOError,getSamplePosition)(THIS_ ASIOSamples *sPos, ASIOTimeStamp *tStamp) PURE;
  124. STDMETHOD_(ASIOError,getChannelInfo)(THIS_ ASIOChannelInfo *info) PURE;
  125. STDMETHOD_(ASIOError,createBuffers)(THIS_ ASIOBufferInfo *bufferInfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks) PURE;
  126. STDMETHOD_(ASIOError,disposeBuffers)(THIS) PURE;
  127. STDMETHOD_(ASIOError,controlPanel)(THIS) PURE;
  128. STDMETHOD_(ASIOError,future)(THIS_ long selector,void *opt) PURE;
  129. STDMETHOD_(ASIOError,outputReady)(THIS) PURE;
  130. };
  131. #undef INTERFACE
  132. typedef struct IWineASIO *LPWINEASIO, **LPLPWINEASIO;
  133. enum
  134. {
  135. Init,
  136. Run,
  137. Exit
  138. };
  139. struct IWineASIOImpl
  140. {
  141. /* COM stuff */
  142. const IWineASIOVtbl *lpVtbl;
  143. LONG ref;
  144. /* ASIO stuff */
  145. HWND hwnd;
  146. ASIOSampleRate sample_rate;
  147. long input_latency;
  148. long output_latency;
  149. long block_frames;
  150. ASIOTime asio_time;
  151. long miliseconds;
  152. ASIOTimeStamp system_time;
  153. double sample_position;
  154. ASIOBufferInfo *bufferInfos;
  155. ASIOCallbacks *callbacks;
  156. char error_message[256];
  157. long in_map[MAX_INPUTS];
  158. long out_map[MAX_OUTPUTS];
  159. void *input_buffers[MAX_INPUTS][2];
  160. void *output_buffers[MAX_OUTPUTS][2];
  161. long active_inputs;
  162. long active_outputs;
  163. BOOL time_info_mode;
  164. BOOL tc_read;
  165. long state;
  166. unsigned int sample_size;
  167. int sample_type;
  168. /* JACK stuff */
  169. char client_name[64];
  170. unsigned int num_inputs;
  171. jack_port_t *input_port[MAX_INPUTS];
  172. const char *input_names[MAX_INPUTS];
  173. unsigned int num_outputs;
  174. jack_port_t *output_port[MAX_OUTPUTS];
  175. const char *output_names[MAX_INPUTS];
  176. jack_client_t *client;
  177. long client_state;
  178. long toggle;
  179. /* callback stuff */
  180. HANDLE thread;
  181. HANDLE start_event;
  182. HANDLE stop_event;
  183. DWORD thread_id;
  184. sem_t semaphore1;
  185. sem_t semaphore2;
  186. BOOL terminate;
  187. };
  188. typedef struct IWineASIOImpl IWineASIOImpl;
  189. static ULONG WINAPI IWineASIOImpl_AddRef(LPWINEASIO iface)
  190. {
  191. IWineASIOImpl *This = (IWineASIOImpl *)iface;
  192. ULONG ref = InterlockedIncrement(&(This->ref));
  193. TRACE("(%p) ref was %d\n", This, ref - 1);
  194. return ref;
  195. }
  196. static ULONG WINAPI IWineASIOImpl_Release(LPWINEASIO iface)
  197. {
  198. IWineASIOImpl *This = (IWineASIOImpl *)iface;
  199. ULONG ref = InterlockedDecrement(&(This->ref));
  200. TRACE("(%p) ref was %d\n", This, ref + 1);
  201. if (!ref) {
  202. fp_jack_client_close(This->client);
  203. TRACE("JACK client closed\n");
  204. wine_dlclose(jackhandle, NULL, 0);
  205. jackhandle = NULL;
  206. This->terminate = TRUE;
  207. sem_post(&This->semaphore1);
  208. WaitForSingleObject(This->stop_event, INFINITE);
  209. sem_destroy(&This->semaphore1);
  210. sem_destroy(&This->semaphore2);
  211. HeapFree(GetProcessHeap(),0,This);
  212. TRACE("(%p) released\n", This);
  213. }
  214. return ref;
  215. }
  216. static HRESULT WINAPI IWineASIOImpl_QueryInterface(LPWINEASIO iface, REFIID riid, void** ppvObject)
  217. {
  218. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  219. TRACE("(%p, %s, %p)\n", iface, debugstr_guid(riid), ppvObject);
  220. if (ppvObject == NULL)
  221. return E_INVALIDARG;
  222. if (IsEqualIID(&CLSID_WineASIO, riid))
  223. {
  224. IWineASIOImpl_AddRef(iface);
  225. *ppvObject = This;
  226. return S_OK;
  227. }
  228. return E_NOINTERFACE;
  229. }
  230. WRAP_THISCALL( ASIOBool __stdcall, IWineASIOImpl_init, (LPWINEASIO iface, void *sysHandle))
  231. {
  232. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  233. jack_port_t *input, *output;
  234. jack_status_t status;
  235. int i;
  236. const char ** ports;
  237. TRACE("(%p, %p)\n", iface, sysHandle);
  238. strcpy(This->client_name, "Wine_ASIO_Jack_Client");
  239. #if 0
  240. This->sample_type = ASIOSTInt16LSB;
  241. This->sample_size = 2;
  242. #endif
  243. #if 1
  244. This->sample_type = ASIOSTInt32LSB;
  245. This->sample_size = 4;
  246. #endif
  247. #if 0
  248. This->sample_type = ASIOSTFloat32LSB;
  249. This->sample_size = 4;
  250. #endif
  251. This->sample_rate = 48000.0;
  252. This->block_frames = 1024;
  253. This->input_latency = This->block_frames;
  254. This->output_latency = This->block_frames * 2;
  255. This->miliseconds = (long)((double)(This->block_frames * 1000) / This->sample_rate);
  256. This->callbacks = NULL;
  257. This->sample_position = 0;
  258. strcpy(This->error_message, "No Error");
  259. This->num_inputs = 0;
  260. This->num_outputs = 0;
  261. This->active_inputs = 0;
  262. This->active_outputs = 0;
  263. This->toggle = 0;
  264. This->client_state = Init;
  265. This->time_info_mode = FALSE;
  266. This->tc_read = FALSE;
  267. This->terminate = FALSE;
  268. This->state = Init;
  269. sem_init(&This->semaphore1, 0, 0);
  270. sem_init(&This->semaphore2, 0, 0);
  271. This->start_event = CreateEventW(NULL, FALSE, FALSE, NULL);
  272. This->stop_event = CreateEventW(NULL, FALSE, FALSE, NULL);
  273. This->thread = CreateThread(NULL, 0, win32_callback, (LPVOID)This, 0, &This->thread_id);
  274. if (This->thread)
  275. {
  276. WaitForSingleObject(This->start_event, INFINITE);
  277. CloseHandle(This->start_event);
  278. This->start_event = INVALID_HANDLE_VALUE;
  279. }
  280. else
  281. {
  282. WARN("Couldn't create thread\n");
  283. return ASIOFalse;
  284. }
  285. for (i = 0; i < MAX_INPUTS; i++)
  286. {
  287. This->in_map[i] = 0;
  288. This->input_names[i] = 0;
  289. }
  290. for (i = 0; i < MAX_OUTPUTS; i++)
  291. {
  292. This->out_map[i] = 0;
  293. This->output_names[i] = 0;
  294. }
  295. This->client = fp_jack_client_open(This->client_name, JackNullOption, &status, NULL);
  296. if (This->client == NULL)
  297. {
  298. WARN("failed to open jack server\n");
  299. return ASIOFalse;
  300. }
  301. TRACE("JACK client opened\n");
  302. if (status & JackServerStarted)
  303. TRACE("JACK server started\n");
  304. if (status & JackNameNotUnique)
  305. {
  306. strcpy(This->client_name, jack_get_client_name(This->client));
  307. TRACE("unique name `%s' assigned\n", This->client_name);
  308. }
  309. fp_jack_set_process_callback(This->client, jack_process, This);
  310. This->sample_rate = fp_jack_get_sample_rate(This->client);
  311. This->block_frames = fp_jack_get_buffer_size(This->client);
  312. This->miliseconds = (long)((double)(This->block_frames * 1000) / This->sample_rate);
  313. This->input_latency = This->block_frames;
  314. This->output_latency = This->block_frames * 2;
  315. TRACE("sample rate: %f\n", This->sample_rate);
  316. TRACE("buffer size: %ld\n", This->block_frames);
  317. /* create two temporary ports to see what's out there */
  318. input = fp_jack_port_register(This->client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
  319. output = fp_jack_port_register(This->client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
  320. if ((input == NULL) || (output == NULL))
  321. {
  322. WARN("couldn't register ports\n");
  323. return ASE_NotPresent;
  324. }
  325. /* you need to the client to find out what ports are available */
  326. if (fp_jack_activate(This->client))
  327. {
  328. WARN("couldn't activate client\n");
  329. return ASE_NotPresent;
  330. }
  331. /* get the list of avaliable input ports */
  332. ports = fp_jack_get_ports(This->client, NULL, NULL, JackPortIsPhysical | JackPortIsOutput);
  333. if (ports == NULL)
  334. {
  335. WARN("couldn't get input ports\n");
  336. return ASE_NotPresent;
  337. }
  338. for (This->num_inputs = 0; This->num_inputs < MAX_INPUTS; This->num_inputs++)
  339. {
  340. if (ports[This->num_inputs])
  341. {
  342. This->input_names[This->num_inputs] = strdup(ports[This->num_inputs]);
  343. TRACE("input port[%d] %s\n", This->num_inputs, This->input_names[This->num_inputs]);
  344. }
  345. else
  346. break;
  347. }
  348. free(ports);
  349. /* get the list of avaliable output ports */
  350. ports = fp_jack_get_ports(This->client, NULL, NULL, JackPortIsPhysical | JackPortIsInput);
  351. if (ports == NULL)
  352. {
  353. WARN("couldn't get output ports\n");
  354. return ASE_NotPresent;
  355. }
  356. for (This->num_outputs = 0; This->num_outputs < MAX_OUTPUTS; This->num_outputs++)
  357. {
  358. if (ports[This->num_outputs])
  359. {
  360. This->output_names[This->num_outputs] = strdup(ports[This->num_outputs]);
  361. TRACE("output port[%d] %s\n", This->num_outputs, This->output_names[This->num_outputs]);
  362. }
  363. else
  364. break;
  365. }
  366. free(ports);
  367. /* get rid of temporary ports */
  368. fp_jack_port_unregister(This->client, input);
  369. fp_jack_port_unregister(This->client, output);
  370. TRACE("found %d inputs\n", This->num_inputs);
  371. TRACE("found %d outputs\n", This->num_outputs);
  372. return ASIOTrue;
  373. }
  374. WRAP_THISCALL( void __stdcall, IWineASIOImpl_getDriverName, (LPWINEASIO iface, char *name))
  375. {
  376. TRACE("(%p, %p)\n", iface, name);
  377. strcpy(name, "Wine ASIO");
  378. }
  379. WRAP_THISCALL( long __stdcall, IWineASIOImpl_getDriverVersion, (LPWINEASIO iface))
  380. {
  381. TRACE("(%p)\n", iface);
  382. return 1;
  383. }
  384. WRAP_THISCALL( void __stdcall, IWineASIOImpl_getErrorMessage, (LPWINEASIO iface, char *string))
  385. {
  386. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  387. TRACE("(%p, %p)\n", iface, string);
  388. strcpy(string, This->error_message);
  389. }
  390. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_start, (LPWINEASIO iface))
  391. {
  392. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  393. int i;
  394. TRACE("(%p)\n", iface);
  395. if (This->callbacks)
  396. {
  397. This->sample_position = 0;
  398. This->system_time.lo = 0;
  399. This->system_time.hi = 0;
  400. for (i = 0; i < This->active_inputs; i++)
  401. {
  402. This->input_port[i] = fp_jack_port_register(This->client, This->input_names[i], JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, i);
  403. if (This->input_port[i] == NULL)
  404. {
  405. WARN("input %d connect failed\n", i);
  406. return ASE_NotPresent;
  407. }
  408. TRACE("registered input port %d: %s\n", i, This->input_names[i]);
  409. if (fp_jack_connect(This->client, This->input_names[i], fp_jack_port_name(This->input_port[i])))
  410. {
  411. WARN("input %d connect failed\n", i);
  412. return ASE_NotPresent;
  413. }
  414. }
  415. for (i = 0; i < This->active_outputs; i++)
  416. {
  417. This->output_port[i] = fp_jack_port_register(This->client, This->output_names[i], JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, i);
  418. if (This->output_port[i] == NULL)
  419. {
  420. WARN("output %d connect failed\n", i);
  421. return ASE_NotPresent;
  422. }
  423. TRACE("registered output port %d: %s\n", i, This->output_names[i]);
  424. if (fp_jack_connect(This->client, fp_jack_port_name(This->output_port[i]), This->output_names[i]))
  425. {
  426. WARN("output %d connect failed\n", i);
  427. return ASE_NotPresent;
  428. }
  429. }
  430. This->state = Run;
  431. TRACE("started\n");
  432. return ASE_OK;
  433. }
  434. return ASE_NotPresent;
  435. }
  436. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_stop, (LPWINEASIO iface))
  437. {
  438. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  439. TRACE("(%p)\n", iface);
  440. This->state = Exit;
  441. if (fp_jack_deactivate(This->client))
  442. {
  443. WARN("couldn't deactivate client\n");
  444. return ASE_NotPresent;
  445. }
  446. return ASE_OK;
  447. }
  448. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_getChannels, (LPWINEASIO iface, long *numInputChannels, long *numOutputChannels))
  449. {
  450. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  451. TRACE("(%p, %p, %p)\n", iface, numInputChannels, numOutputChannels);
  452. if (numInputChannels)
  453. *numInputChannels = This->num_inputs;
  454. if (numOutputChannels)
  455. *numOutputChannels = This->num_outputs;
  456. TRACE("inputs: %d outputs: %d\n", This->num_inputs, This->num_outputs);
  457. return ASE_OK;
  458. }
  459. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_getLatencies, (LPWINEASIO iface, long *inputLatency, long *outputLatency))
  460. {
  461. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  462. TRACE("(%p, %p, %p)\n", iface, inputLatency, outputLatency);
  463. if (inputLatency)
  464. *inputLatency = This->input_latency;
  465. if (outputLatency)
  466. *outputLatency = This->output_latency;
  467. return ASE_OK;
  468. }
  469. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_getBufferSize, (LPWINEASIO iface, long *minSize, long *maxSize, long *preferredSize, long *granularity))
  470. {
  471. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  472. TRACE("(%p, %p, %p, %p, %p)\n", iface, minSize, maxSize, preferredSize, granularity);
  473. if (minSize)
  474. *minSize = This->block_frames;
  475. if (maxSize)
  476. *maxSize = This->block_frames;
  477. if (preferredSize)
  478. *preferredSize = This->block_frames;
  479. if (granularity)
  480. *granularity = 0;
  481. TRACE("min: %ld max: %ld preferred: %ld granularity: 0\n", This->block_frames, This->block_frames, This->block_frames);
  482. return ASE_OK;
  483. }
  484. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_canSampleRate, (LPWINEASIO iface, ASIOSampleRate sampleRate))
  485. {
  486. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  487. TRACE("(%p, %f)\n", iface, sampleRate);
  488. if (sampleRate == This->sample_rate)
  489. return ASE_OK;
  490. return ASE_NoClock;
  491. }
  492. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_getSampleRate, (LPWINEASIO iface, ASIOSampleRate *sampleRate))
  493. {
  494. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  495. TRACE("(%p, %p)\n", iface, sampleRate);
  496. if (sampleRate)
  497. *sampleRate = This->sample_rate;
  498. TRACE("rate: %f\n", This->sample_rate);
  499. return ASE_OK;
  500. }
  501. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_setSampleRate, (LPWINEASIO iface, ASIOSampleRate sampleRate))
  502. {
  503. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  504. TRACE("(%p, %f)\n", iface, sampleRate);
  505. if (sampleRate != This->sample_rate)
  506. return ASE_NoClock;
  507. if (sampleRate != This->sample_rate)
  508. {
  509. This->sample_rate = sampleRate;
  510. This->asio_time.timeInfo.sampleRate = sampleRate;
  511. This->asio_time.timeInfo.flags |= kSampleRateChanged;
  512. This->miliseconds = (long)((double)(This->block_frames * 1000) / This->sample_rate);
  513. if (This->callbacks && This->callbacks->sampleRateDidChange)
  514. This->callbacks->sampleRateDidChange(This->sample_rate);
  515. }
  516. TRACE("rate: %f\n", This->sample_rate);
  517. return ASE_OK;
  518. }
  519. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_getClockSources, (LPWINEASIO iface, ASIOClockSource *clocks, long *numSources))
  520. {
  521. TRACE("(%p, %p, %p)\n", iface, clocks, numSources);
  522. if (clocks && numSources)
  523. {
  524. clocks->index = 0;
  525. clocks->associatedChannel = -1;
  526. clocks->associatedGroup = -1;
  527. clocks->isCurrentSource = ASIOTrue;
  528. strcpy(clocks->name, "Internal");
  529. *numSources = 1;
  530. return ASE_OK;
  531. }
  532. return ASE_InvalidParameter;
  533. }
  534. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_setClockSource, (LPWINEASIO iface, long reference))
  535. {
  536. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  537. TRACE("(%p, %ld)\n", iface, reference);
  538. if (reference == 0)
  539. {
  540. This->asio_time.timeInfo.flags |= kClockSourceChanged;
  541. return ASE_OK;
  542. }
  543. return ASE_NotPresent;
  544. }
  545. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_getSamplePosition, (LPWINEASIO iface, ASIOSamples *sPos, ASIOTimeStamp *tStamp))
  546. {
  547. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  548. TRACE("(%p, %p, %p)\n", iface, sPos, tStamp);
  549. tStamp->lo = This->system_time.lo;
  550. tStamp->hi = This->system_time.hi;
  551. if (This->sample_position >= twoRaisedTo32)
  552. {
  553. sPos->hi = (unsigned long)(This->sample_position * twoRaisedTo32Reciprocal);
  554. sPos->lo = (unsigned long)(This->sample_position - (sPos->hi * twoRaisedTo32));
  555. }
  556. else
  557. {
  558. sPos->hi = 0;
  559. sPos->lo = (unsigned long)This->sample_position;
  560. }
  561. return ASE_OK;
  562. }
  563. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_getChannelInfo, (LPWINEASIO iface, ASIOChannelInfo *info))
  564. {
  565. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  566. int i;
  567. const char * name;
  568. TRACE("(%p, %p)\n", iface, info);
  569. if (info->channel < 0 || (info->isInput ? info->channel >= This->num_inputs : info->channel >= This->num_outputs))
  570. return ASE_InvalidParameter;
  571. TRACE("info->channel = %ld\n", info->channel);
  572. TRACE("info->isInput = %ld\n", info->isInput);
  573. info->type = This->sample_type;
  574. info->channelGroup = 0;
  575. info->isActive = ASIOFalse;
  576. if (info->isInput)
  577. {
  578. for (i = 0; i < This->active_inputs; i++)
  579. {
  580. if (This->in_map[i] == info->channel)
  581. {
  582. info->isActive = ASIOTrue;
  583. break;
  584. }
  585. }
  586. name = This->input_names[info->channel];
  587. }
  588. else
  589. {
  590. for (i = 0; i < This->active_outputs; i++)
  591. {
  592. if (This->out_map[i] == info->channel)
  593. {
  594. info->isActive = ASIOTrue;
  595. break;
  596. }
  597. }
  598. name = This->output_names[info->channel];
  599. }
  600. strcpy(info->name, name);
  601. TRACE("info->isActive = %ld\n", info->isActive);
  602. TRACE("info->channelGroup = %ld\n", info->channelGroup);
  603. TRACE("info->type = %ld\n", info->type);
  604. TRACE("info->name = %s\n", info->name);
  605. return ASE_OK;
  606. }
  607. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_disposeBuffers, (LPWINEASIO iface))
  608. {
  609. int i;
  610. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  611. TRACE("(%p)\n", iface);
  612. This->callbacks = NULL;
  613. __wrapped_IWineASIOImpl_stop(iface);
  614. for (i = 0; i < This->active_inputs; i++)
  615. {
  616. HeapFree(GetProcessHeap(), 0, This->input_buffers[i][0]);
  617. HeapFree(GetProcessHeap(), 0, This->input_buffers[i][1]);
  618. }
  619. This->active_inputs = 0;
  620. for (i = 0; i < This->active_outputs; i++)
  621. {
  622. HeapFree(GetProcessHeap(), 0, This->output_buffers[i][0]);
  623. HeapFree(GetProcessHeap(), 0, This->output_buffers[i][1]);
  624. }
  625. This->active_outputs = 0;
  626. return ASE_OK;
  627. }
  628. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_createBuffers, (LPWINEASIO iface, ASIOBufferInfo *bufferInfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks))
  629. {
  630. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  631. ASIOBufferInfo * info = bufferInfos;
  632. int i;
  633. TRACE("(%p, %p, %ld, %ld, %p)\n", iface, bufferInfos, numChannels, bufferSize, callbacks);
  634. This->active_inputs = 0;
  635. This->active_outputs = 0;
  636. This->block_frames = bufferSize;
  637. This->miliseconds = (long)((double)(This->block_frames * 1000) / This->sample_rate);
  638. for (i = 0; i < numChannels; i++, info++)
  639. {
  640. if (info->isInput)
  641. {
  642. if (info->channelNum < 0 || info->channelNum >= This->num_inputs)
  643. {
  644. WARN("invalid input channel: %ld\n", info->channelNum);
  645. goto ERROR_PARAM;
  646. }
  647. if (This->active_inputs >= This->num_inputs)
  648. {
  649. WARN("too many inputs\n");
  650. goto ERROR_PARAM;
  651. }
  652. This->in_map[This->active_inputs] = info->channelNum;
  653. This->input_buffers[This->active_inputs][0] = HeapAlloc(GetProcessHeap(), 0, This->block_frames * This->sample_size);
  654. This->input_buffers[This->active_inputs][1] = HeapAlloc(GetProcessHeap(), 0, This->block_frames * This->sample_size);
  655. if (This->input_buffers[This->active_inputs][0] && This->input_buffers[This->active_inputs][1])
  656. {
  657. info->buffers[0] = This->input_buffers[This->active_inputs][0];
  658. info->buffers[1] = This->input_buffers[This->active_inputs][1];
  659. }
  660. else
  661. {
  662. HeapFree(GetProcessHeap(), 0, This->input_buffers[This->active_inputs][0]);
  663. info->buffers[0] = 0;
  664. info->buffers[1] = 0;
  665. WARN("no input buffer memory\n");
  666. goto ERROR_MEM;
  667. }
  668. This->active_inputs++;
  669. }
  670. else
  671. {
  672. if (info->channelNum < 0 || info->channelNum >= This->num_outputs)
  673. {
  674. WARN("invalid output channel: %ld\n", info->channelNum);
  675. goto ERROR_PARAM;
  676. }
  677. if (This->active_outputs >= This->num_outputs)
  678. {
  679. WARN("too many outputs\n");
  680. goto ERROR_PARAM;
  681. }
  682. This->out_map[This->active_outputs] = info->channelNum;
  683. This->output_buffers[This->active_outputs][0] = HeapAlloc(GetProcessHeap(), 0, This->block_frames * This->sample_size);
  684. This->output_buffers[This->active_outputs][1] = HeapAlloc(GetProcessHeap(), 0, This->block_frames * This->sample_size);
  685. if (This->output_buffers[This->active_outputs][0] && This->output_buffers[This->active_outputs][1])
  686. {
  687. info->buffers[0] = This->output_buffers[This->active_outputs][0];
  688. info->buffers[1] = This->output_buffers[This->active_outputs][1];
  689. }
  690. else
  691. {
  692. HeapFree(GetProcessHeap(), 0, This->output_buffers[This->active_outputs][0]);
  693. info->buffers[0] = 0;
  694. info->buffers[1] = 0;
  695. WARN("no output buffer memory\n");
  696. goto ERROR_MEM;
  697. }
  698. This->active_outputs++;
  699. }
  700. }
  701. This->callbacks = callbacks;
  702. if (This->callbacks->asioMessage)
  703. {
  704. if (This->callbacks->asioMessage(kAsioSupportsTimeInfo, 0, 0, 0))
  705. {
  706. This->time_info_mode = TRUE;
  707. This->asio_time.timeInfo.speed = 1;
  708. This->asio_time.timeInfo.systemTime.hi = 0;
  709. This->asio_time.timeInfo.systemTime.lo = 0;
  710. This->asio_time.timeInfo.samplePosition.hi = 0;
  711. This->asio_time.timeInfo.samplePosition.lo = 0;
  712. This->asio_time.timeInfo.sampleRate = This->sample_rate;
  713. This->asio_time.timeInfo. flags = kSystemTimeValid | kSamplePositionValid | kSampleRateValid;
  714. This->asio_time.timeCode.speed = 1;
  715. This->asio_time.timeCode.timeCodeSamples.hi = 0;
  716. This->asio_time.timeCode.timeCodeSamples.lo = 0;
  717. This->asio_time.timeCode.flags = kTcValid | kTcRunning;
  718. }
  719. else
  720. This->time_info_mode = FALSE;
  721. }
  722. else
  723. {
  724. This->time_info_mode = FALSE;
  725. WARN("asioMessage callback not supplied\n");
  726. goto ERROR_PARAM;
  727. }
  728. return ASE_OK;
  729. ERROR_MEM:
  730. __wrapped_IWineASIOImpl_disposeBuffers(iface);
  731. WARN("no memory\n");
  732. return ASE_NoMemory;
  733. ERROR_PARAM:
  734. __wrapped_IWineASIOImpl_disposeBuffers(iface);
  735. WARN("invalid parameter\n");
  736. return ASE_InvalidParameter;
  737. }
  738. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_controlPanel, (LPWINEASIO iface))
  739. {
  740. TRACE("(%p) stub!\n", iface);
  741. return ASE_OK;
  742. }
  743. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_future, (LPWINEASIO iface, long selector, void *opt))
  744. {
  745. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  746. TRACE("(%p, %ld, %p)\n", iface, selector, opt);
  747. switch (selector)
  748. {
  749. case kAsioEnableTimeCodeRead:
  750. This->tc_read = TRUE;
  751. return ASE_SUCCESS;
  752. case kAsioDisableTimeCodeRead:
  753. This->tc_read = FALSE;
  754. return ASE_SUCCESS;
  755. case kAsioSetInputMonitor:
  756. return ASE_SUCCESS;
  757. case kAsioCanInputMonitor:
  758. return ASE_SUCCESS;
  759. case kAsioCanTimeInfo:
  760. return ASE_SUCCESS;
  761. case kAsioCanTimeCode:
  762. return ASE_SUCCESS;
  763. }
  764. return ASE_NotPresent;
  765. }
  766. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_outputReady, (LPWINEASIO iface))
  767. {
  768. TRACE("(%p)\n", iface);
  769. return ASE_NotPresent;
  770. }
  771. static const IWineASIOVtbl WineASIO_Vtbl =
  772. {
  773. IWineASIOImpl_QueryInterface,
  774. IWineASIOImpl_AddRef,
  775. IWineASIOImpl_Release,
  776. IWineASIOImpl_init,
  777. IWineASIOImpl_getDriverName,
  778. IWineASIOImpl_getDriverVersion,
  779. IWineASIOImpl_getErrorMessage,
  780. IWineASIOImpl_start,
  781. IWineASIOImpl_stop,
  782. IWineASIOImpl_getChannels,
  783. IWineASIOImpl_getLatencies,
  784. IWineASIOImpl_getBufferSize,
  785. IWineASIOImpl_canSampleRate,
  786. IWineASIOImpl_getSampleRate,
  787. IWineASIOImpl_setSampleRate,
  788. IWineASIOImpl_getClockSources,
  789. IWineASIOImpl_setClockSource,
  790. IWineASIOImpl_getSamplePosition,
  791. IWineASIOImpl_getChannelInfo,
  792. IWineASIOImpl_createBuffers,
  793. IWineASIOImpl_disposeBuffers,
  794. IWineASIOImpl_controlPanel,
  795. IWineASIOImpl_future,
  796. IWineASIOImpl_outputReady,
  797. };
  798. BOOL init_jack()
  799. {
  800. jackhandle = wine_dlopen(SONAME_LIBJACK, RTLD_NOW, NULL, 0);
  801. TRACE("SONAME_LIBJACK == %s\n", SONAME_LIBJACK);
  802. TRACE("jackhandle == %p\n", jackhandle);
  803. if (!jackhandle)
  804. {
  805. FIXME("error loading the jack library %s, please install this library to use jack\n", SONAME_LIBJACK);
  806. jackhandle = (void*)-1;
  807. return FALSE;
  808. }
  809. /* setup function pointers */
  810. #define LOAD_FUNCPTR(f) if((fp_##f = wine_dlsym(jackhandle, #f, NULL, 0)) == NULL) goto sym_not_found;
  811. LOAD_FUNCPTR(jack_activate);
  812. LOAD_FUNCPTR(jack_deactivate);
  813. LOAD_FUNCPTR(jack_connect);
  814. LOAD_FUNCPTR(jack_client_open);
  815. LOAD_FUNCPTR(jack_client_close);
  816. LOAD_FUNCPTR(jack_transport_query);
  817. LOAD_FUNCPTR(jack_transport_start);
  818. LOAD_FUNCPTR(jack_set_process_callback);
  819. LOAD_FUNCPTR(jack_get_sample_rate);
  820. LOAD_FUNCPTR(jack_port_register);
  821. LOAD_FUNCPTR(jack_port_get_buffer);
  822. LOAD_FUNCPTR(jack_get_ports);
  823. LOAD_FUNCPTR(jack_port_name);
  824. LOAD_FUNCPTR(jack_get_buffer_size);
  825. LOAD_FUNCPTR(jack_port_unregister);
  826. #undef LOAD_FUNCPTR
  827. return TRUE;
  828. /* error path for function pointer loading errors */
  829. sym_not_found:
  830. WINE_MESSAGE("Wine cannot find certain functions that it needs inside the jack"
  831. "library. To enable Wine to use the jack audio server please "
  832. "install libjack\n");
  833. wine_dlclose(jackhandle, NULL, 0);
  834. jackhandle = NULL;
  835. return FALSE;
  836. }
  837. HRESULT asioCreateInstance(REFIID riid, LPVOID *ppobj)
  838. {
  839. IWineASIOImpl * pobj;
  840. TRACE("(%s, %p)\n", debugstr_guid(riid), ppobj);
  841. if (!init_jack()) {
  842. WARN("init_jack failed!\n");
  843. return ERROR_NOT_SUPPORTED;
  844. }
  845. pobj = HeapAlloc(GetProcessHeap(), 0, sizeof(*pobj));
  846. if (pobj == NULL) {
  847. WARN("out of memory\n");
  848. return E_OUTOFMEMORY;
  849. }
  850. pobj->lpVtbl = &WineASIO_Vtbl;
  851. pobj->ref = 1;
  852. TRACE("pobj = %p\n", pobj);
  853. *ppobj = pobj;
  854. TRACE("return %p\n", *ppobj);
  855. return S_OK;
  856. }
  857. static void getNanoSeconds(ASIOTimeStamp* ts)
  858. {
  859. double nanoSeconds = (double)((unsigned long)timeGetTime ()) * 1000000.;
  860. ts->hi = (unsigned long)(nanoSeconds / twoRaisedTo32);
  861. ts->lo = (unsigned long)(nanoSeconds - (ts->hi * twoRaisedTo32));
  862. }
  863. static int jack_process(jack_nframes_t nframes, void * arg)
  864. {
  865. IWineASIOImpl * This = (IWineASIOImpl*)arg;
  866. int i, j;
  867. jack_default_audio_sample_t * in, *out;
  868. jack_transport_state_t ts;
  869. ts = fp_jack_transport_query(This->client, NULL);
  870. if (ts == JackTransportRolling)
  871. {
  872. if (This->client_state == Init)
  873. This->client_state = Run;
  874. This->toggle = This->toggle ? 0 : 1;
  875. This->sample_position += nframes;
  876. /* get the input data from JACK and copy it to the ASIO buffers */
  877. switch (This->sample_type)
  878. {
  879. case ASIOSTInt16LSB:
  880. for (i = 0; i < This->active_inputs; i++)
  881. {
  882. short * buffer = This->input_buffers[i][This->toggle];
  883. in = fp_jack_port_get_buffer(This->input_port[i], nframes);
  884. for (j = 0; j < nframes; j++)
  885. buffer[j] = in[j] * 32767.0f;
  886. }
  887. break;
  888. case ASIOSTInt32LSB:
  889. for (i = 0; i < This->active_inputs; i++)
  890. {
  891. int32_t * buffer = This->input_buffers[i][This->toggle];
  892. in = fp_jack_port_get_buffer(This->input_port[i], nframes);
  893. for (j = 0; j < nframes; j++)
  894. buffer[j] = in[j] * 2147483647.0f;
  895. }
  896. break;
  897. case ASIOSTFloat32LSB:
  898. for (i = 0; i < This->active_inputs; i++)
  899. {
  900. float * buffer = This->input_buffers[i][This->toggle];
  901. in = fp_jack_port_get_buffer(This->input_port[i], nframes);
  902. for (j = 0; j < nframes; j++)
  903. buffer[j] = in[j];
  904. }
  905. break;
  906. }
  907. /* call the ASIO user callback to read the input data and fill the output data */
  908. getNanoSeconds(&This->system_time);
  909. /* wake up the WIN32 thread so it can do the do it's callback */
  910. sem_post(&This->semaphore1);
  911. /* wait for the WIN32 thread to complete before continuing */
  912. sem_wait(&This->semaphore2);
  913. /* copy the ASIO data to JACK */
  914. switch (This->sample_type)
  915. {
  916. case ASIOSTInt16LSB:
  917. for (i = 0; i < This->active_outputs; i++)
  918. {
  919. short * buffer = This->output_buffers[i][This->toggle];
  920. out = fp_jack_port_get_buffer(This->output_port[i], nframes);
  921. for (j = 0; j < nframes; j++)
  922. out[j] = buffer[j] / 32767.0f;
  923. }
  924. break;
  925. case ASIOSTInt32LSB:
  926. for (i = 0; i < This->active_outputs; i++)
  927. {
  928. int32_t * buffer = This->output_buffers[i][This->toggle];
  929. out = fp_jack_port_get_buffer(This->output_port[i], nframes);
  930. for (j = 0; j < nframes; j++)
  931. out[j] = buffer[j] / 2147483647.0f;
  932. }
  933. break;
  934. case ASIOSTFloat32LSB:
  935. for (i = 0; i < This->active_outputs; i++)
  936. {
  937. float * buffer = This->output_buffers[i][This->toggle];
  938. out = fp_jack_port_get_buffer(This->output_port[i], nframes);
  939. for (j = 0; j < nframes; j++)
  940. out[j] = buffer[j];
  941. }
  942. break;
  943. }
  944. }
  945. else if (ts == JackTransportStopped)
  946. {
  947. if (This->client_state == Run)
  948. This->client_state = Exit;
  949. else
  950. {
  951. /* FIXME why is this needed ? */
  952. fp_jack_transport_start(This->client);
  953. }
  954. }
  955. return 0;
  956. }
  957. /*
  958. * The ASIO callback can make WIN32 calls which require a WIN32 thread.
  959. * Do the callback in this thread and then switch back to the Jack callback thread.
  960. */
  961. static DWORD CALLBACK win32_callback(LPVOID arg)
  962. {
  963. IWineASIOImpl * This = (IWineASIOImpl*)arg;
  964. TRACE("(%p)\n", arg);
  965. /* let IWineASIO_Init know we are alive */
  966. SetEvent(This->start_event);
  967. while (1)
  968. {
  969. /* wait to be woken up by the JAck callback thread */
  970. sem_wait(&This->semaphore1);
  971. /* check for termination */
  972. if (This->terminate)
  973. {
  974. SetEvent(This->stop_event);
  975. TRACE("terminated\n");
  976. return 0;
  977. }
  978. /* make sure we are in the run state */
  979. if (This->state == Run)
  980. {
  981. if (This->time_info_mode)
  982. {
  983. __wrapped_IWineASIOImpl_getSamplePosition((LPWINEASIO)This,
  984. &This->asio_time.timeInfo.samplePosition, &This->asio_time.timeInfo.systemTime);
  985. if (This->tc_read)
  986. {
  987. /* FIXME */
  988. This->asio_time.timeCode.timeCodeSamples.lo = This->asio_time.timeInfo.samplePosition.lo;
  989. This->asio_time.timeCode.timeCodeSamples.hi = 0;
  990. }
  991. This->callbacks->bufferSwitchTimeInfo(&This->asio_time, This->toggle, ASIOFalse);
  992. This->asio_time.timeInfo.flags &= ~(kSampleRateChanged | kClockSourceChanged);
  993. }
  994. else
  995. This->callbacks->bufferSwitch(This->toggle, ASIOFalse);
  996. }
  997. /* let the Jack thread know we are done */
  998. sem_post(&This->semaphore2);
  999. }
  1000. return 0;
  1001. }
  1002. #else
  1003. HRESULT asioCreateInstance(REFIID riid, LPVOID *ppobj)
  1004. {
  1005. WARN("(%s, %p) ASIO support not compiled into wine\n", debugstr_guid(riid), ppobj);
  1006. return ERROR_NOT_SUPPORTED;
  1007. }
  1008. #endif