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.

1208 lines
37KB

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