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.

993 lines
28KB

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