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.

1081 lines
32KB

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