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.

935 lines
26KB

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