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.

1240 lines
38KB

  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 74; // 0.7 (patch level 4)
  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; 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. if (j < numports) {
  487. // Get the desired JACK output (source) name, if there is one, for this ASIO input
  488. envi = get_targetname(This, ENVVAR_INMAP, i);
  489. TRACE("(%p) %d: Connect JACK output '%s' to my input '%s'\n", This, i
  490. ,(envi ? envi : ports[j])
  491. ,jack_port_name(This->input[i].port)
  492. );
  493. if (jack_connect(This->client
  494. ,(envi ? envi : ports[j++])
  495. ,jack_port_name(This->input[i].port)
  496. ))
  497. {
  498. MESSAGE("(%p) Connect failed\n", This);
  499. }
  500. }
  501. }
  502. if (ports)
  503. free(ports);
  504. // get list of port names
  505. ports = jack_get_ports(This->client, NULL, NULL, JackPortIsPhysical | JackPortIsInput);
  506. for(numports = 0; ports && ports[numports]; numports++);
  507. TRACE("(%p) JACK inputs: %d; outputs desired: %d\n", This, numports, This->num_outputs);
  508. for (i = j = 0; i < This->num_outputs; i++)
  509. {
  510. if (This->output[i].active != ASIOTrue)
  511. continue;
  512. This->output[i].port = jack_port_register(This->client,
  513. This->output[i].port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, i);
  514. if (This->output[i].port)
  515. TRACE("(%p) Registered output port %i: '%s' (%p)\n", This, i, This->output[i].port_name, This->output[i].port);
  516. else {
  517. MESSAGE("(%p) Failed to register output port %i ('%s')\n", This, i, This->output[i].port_name);
  518. return ASE_NotPresent;
  519. }
  520. if (j < numports) {
  521. // Get the desired JACK input (target) name, if there is one, for this ASIO output
  522. envi = get_targetname(This, ENVVAR_OUTMAP, i);
  523. TRACE("(%p) %d: Connect my output '%s' to JACK input '%s'\n", This, i
  524. ,jack_port_name(This->output[i].port)
  525. ,(envi ? envi : ports[j])
  526. );
  527. if (jack_connect(This->client
  528. ,jack_port_name(This->output[i].port)
  529. ,(envi ? envi : ports[j++])
  530. ))
  531. {
  532. MESSAGE("(%p) Connect failed\n", This);
  533. }
  534. }
  535. }
  536. if (ports)
  537. free(ports);
  538. This->state = Run;
  539. TRACE("started\n");
  540. return ASE_OK;
  541. }
  542. return ASE_NotPresent;
  543. }
  544. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_stop, (LPWINEASIO iface))
  545. {
  546. int i;
  547. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  548. TRACE("(%p)\n", iface);
  549. This->state = Exit;
  550. for (i = 0; i < This->num_inputs; i++) {
  551. if (This->input[i].port == NULL) {
  552. TRACE("(%p) Not registered input port %i\n", This, i);
  553. continue;
  554. }
  555. if (jack_port_unregister(This->client, This->input[i].port)) {
  556. TRACE("(%p) Unregistered input port %i: '%s' (%p)\n", This, i, This->input[i].port_name, This->input[i].port);
  557. }
  558. }
  559. for (i = 0; i < This->num_outputs; i++) {
  560. if (This->output[i].port == NULL) {
  561. TRACE("(%p) Not registered output port %i\n", This, i);
  562. continue;
  563. }
  564. if (jack_port_unregister(This->client, This->output[i].port)) {
  565. TRACE("(%p) Unregistered output port %i: '%s' (%p)\n", This, i, This->output[i].port_name, This->output[i].port);
  566. }
  567. }
  568. if (jack_deactivate(This->client))
  569. {
  570. WARN("couldn't deactivate client\n");
  571. return ASE_NotPresent;
  572. }
  573. return ASE_OK;
  574. }
  575. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_getChannels, (LPWINEASIO iface, long *numInputChannels, long *numOutputChannels))
  576. {
  577. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  578. TRACE("(%p, %p, %p)\n", iface, numInputChannels, numOutputChannels);
  579. if (numInputChannels)
  580. *numInputChannels = This->num_inputs;
  581. if (numOutputChannels)
  582. *numOutputChannels = This->num_outputs;
  583. TRACE("inputs: %d outputs: %d\n", This->num_inputs, This->num_outputs);
  584. return ASE_OK;
  585. }
  586. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_getLatencies, (LPWINEASIO iface, long *inputLatency, long *outputLatency))
  587. {
  588. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  589. TRACE("(%p, %p, %p)\n", iface, inputLatency, outputLatency);
  590. if (inputLatency)
  591. *inputLatency = This->input_latency;
  592. if (outputLatency)
  593. *outputLatency = This->output_latency;
  594. return ASE_OK;
  595. }
  596. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_getBufferSize, (LPWINEASIO iface, long *minSize, long *maxSize, long *preferredSize, long *granularity))
  597. {
  598. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  599. TRACE("(%p, %p, %p, %p, %p)\n", iface, minSize, maxSize, preferredSize, granularity);
  600. if (minSize)
  601. *minSize = This->block_frames;
  602. if (maxSize)
  603. *maxSize = This->block_frames;
  604. if (preferredSize)
  605. *preferredSize = This->block_frames;
  606. if (granularity)
  607. *granularity = 0;
  608. TRACE("min: %ld max: %ld preferred: %ld granularity: 0\n", This->block_frames, This->block_frames, This->block_frames);
  609. return ASE_OK;
  610. }
  611. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_canSampleRate, (LPWINEASIO iface, ASIOSampleRate sampleRate))
  612. {
  613. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  614. TRACE("(%p, %f)\n", iface, sampleRate);
  615. if (sampleRate == This->sample_rate)
  616. return ASE_OK;
  617. return ASE_NoClock;
  618. }
  619. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_getSampleRate, (LPWINEASIO iface, ASIOSampleRate *sampleRate))
  620. {
  621. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  622. TRACE("(%p, %p)\n", iface, sampleRate);
  623. if (sampleRate)
  624. *sampleRate = This->sample_rate;
  625. TRACE("rate: %f\n", This->sample_rate);
  626. return ASE_OK;
  627. }
  628. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_setSampleRate, (LPWINEASIO iface, ASIOSampleRate sampleRate))
  629. {
  630. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  631. TRACE("(%p, %f)\n", iface, sampleRate);
  632. if (sampleRate != This->sample_rate)
  633. return ASE_NoClock;
  634. return ASE_OK;
  635. }
  636. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_getClockSources, (LPWINEASIO iface, ASIOClockSource *clocks, long *numSources))
  637. {
  638. TRACE("(%p, %p, %p)\n", iface, clocks, numSources);
  639. if (clocks && numSources)
  640. {
  641. clocks->index = 0;
  642. clocks->associatedChannel = -1;
  643. clocks->associatedGroup = -1;
  644. clocks->isCurrentSource = ASIOTrue;
  645. strcpy(clocks->name, "Internal");
  646. *numSources = 1;
  647. return ASE_OK;
  648. }
  649. return ASE_InvalidParameter;
  650. }
  651. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_setClockSource, (LPWINEASIO iface, long reference))
  652. {
  653. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  654. TRACE("(%p, %ld)\n", iface, reference);
  655. if (reference == 0)
  656. {
  657. This->asio_time.timeInfo.flags |= kClockSourceChanged;
  658. return ASE_OK;
  659. }
  660. return ASE_NotPresent;
  661. }
  662. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_getSamplePosition, (LPWINEASIO iface, ASIOSamples *sPos, ASIOTimeStamp *tStamp))
  663. {
  664. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  665. // TRACE("(%p, %p, %p)\n", iface, sPos, tStamp);
  666. tStamp->lo = This->system_time.lo;
  667. tStamp->hi = This->system_time.hi;
  668. if (This->sample_position >= twoRaisedTo32)
  669. {
  670. sPos->hi = (unsigned long)(This->sample_position * twoRaisedTo32Reciprocal);
  671. sPos->lo = (unsigned long)(This->sample_position - (sPos->hi * twoRaisedTo32));
  672. }
  673. else
  674. {
  675. sPos->hi = 0;
  676. sPos->lo = (unsigned long)This->sample_position;
  677. }
  678. return ASE_OK;
  679. }
  680. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_getChannelInfo, (LPWINEASIO iface, ASIOChannelInfo *info))
  681. {
  682. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  683. // int i;
  684. // const char * name;
  685. TRACE("(%p, %p)\n", iface, info);
  686. if (info->channel < 0 || (info->isInput ? info->channel >= This->num_inputs : info->channel >= This->num_outputs))
  687. return ASE_InvalidParameter;
  688. // TRACE("info->channel = %ld\n", info->channel);
  689. // TRACE("info->isInput = %ld\n", info->isInput);
  690. info->type = ASIOSTInt32LSB; // info->type = This->sample_type;
  691. info->channelGroup = 0;
  692. if (info->isInput)
  693. {
  694. info->isActive = This->input[info->channel].active;
  695. strcpy(info->name, This->input[info->channel].port_name);
  696. }
  697. else
  698. {
  699. info->isActive = This->output[info->channel].active;
  700. strcpy(info->name, This->output[info->channel].port_name);
  701. }
  702. // TRACE("info->isActive = %ld\n", info->isActive);
  703. // TRACE("info->channelGroup = %ld\n", info->channelGroup);
  704. // TRACE("info->type = %ld\n", info->type);
  705. // TRACE("info->name = %s\n", info->name);
  706. return ASE_OK;
  707. }
  708. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_disposeBuffers, (LPWINEASIO iface))
  709. {
  710. int i;
  711. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  712. TRACE("(%p)\n", iface);
  713. This->callbacks = NULL;
  714. __wrapped_IWineASIOImpl_stop(iface);
  715. for (i = This->active_inputs; --i >= 0; )
  716. {
  717. if (This->input[i].active)
  718. {
  719. HeapFree(GetProcessHeap(), 0, This->input[i].buffer);
  720. This->input[i].buffer = 0;
  721. This->input[i].active = ASIOFalse;
  722. }
  723. This->active_inputs--;
  724. }
  725. for (i = This->active_outputs; --i >= 0; )
  726. {
  727. if (This->output[i].active)
  728. {
  729. HeapFree(GetProcessHeap(), 0, This->output[i].buffer);
  730. This->output[i].buffer = 0;
  731. This->output[i].active = ASIOFalse;
  732. }
  733. This->active_outputs--;
  734. }
  735. return ASE_OK;
  736. }
  737. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_createBuffers, (LPWINEASIO iface, ASIOBufferInfo *bufferInfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks))
  738. {
  739. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  740. ASIOBufferInfo * info = bufferInfos;
  741. int i, j;
  742. TRACE("(%p, %p, %ld, %ld, %p)\n", iface, bufferInfos, numChannels, bufferSize, callbacks);
  743. // Just to be on the safe side:
  744. This->active_inputs = 0;
  745. for(i = 0; i < This->num_inputs; i++) This->input[i].active = ASIOFalse;
  746. This->active_outputs = 0;
  747. for(i = 0; i < This->num_outputs; i++) This->output[i].active = ASIOFalse;
  748. This->block_frames = bufferSize;
  749. This->miliseconds = (long)((double)(This->block_frames * 1000) / This->sample_rate);
  750. for (i = 0; i < numChannels; i++, info++)
  751. {
  752. if (info->isInput)
  753. {
  754. if (info->channelNum < 0 || info->channelNum >= This->num_inputs)
  755. {
  756. WARN("invalid input channel: %ld\n", info->channelNum);
  757. goto ERROR_PARAM;
  758. }
  759. if (This->active_inputs >= This->num_inputs)
  760. {
  761. WARN("too many inputs\n");
  762. goto ERROR_PARAM;
  763. }
  764. // ASIOSTInt32LSB support only
  765. This->input[This->active_inputs].buffer = HeapAlloc(GetProcessHeap(), 0, 2 * This->block_frames * sizeof(int));
  766. if (This->input[This->active_inputs].buffer)
  767. {
  768. info->buffers[0] = &This->input[This->active_inputs].buffer[0];
  769. info->buffers[1] = &This->input[This->active_inputs].buffer[This->block_frames];
  770. This->input[This->active_inputs].active = ASIOTrue;
  771. for (j = 0; j < This->block_frames * 2; j++)
  772. This->input[This->active_inputs].buffer[j] = 0;
  773. }
  774. else
  775. {
  776. HeapFree(GetProcessHeap(), 0, This->input[This->active_inputs].buffer);
  777. info->buffers[0] = 0;
  778. info->buffers[1] = 0;
  779. WARN("no input buffer memory\n");
  780. goto ERROR_MEM;
  781. }
  782. This->active_inputs++;
  783. }
  784. else
  785. {
  786. if (info->channelNum < 0 || info->channelNum >= This->num_outputs)
  787. {
  788. WARN("invalid output channel: %ld\n", info->channelNum);
  789. goto ERROR_PARAM;
  790. }
  791. if (This->active_outputs >= This->num_outputs)
  792. {
  793. WARN("too many outputs\n");
  794. goto ERROR_PARAM;
  795. }
  796. // ASIOSTInt32LSB support only
  797. This->output[This->active_outputs].buffer = HeapAlloc(GetProcessHeap(), 0, 2 * This->block_frames * sizeof(int));
  798. if (This->output[This->active_outputs].buffer)
  799. {
  800. info->buffers[0] = &This->output[This->active_outputs].buffer[0];
  801. info->buffers[1] = &This->output[This->active_outputs].buffer[This->block_frames];
  802. This->output[This->active_outputs].active = ASIOTrue;
  803. for (j = 0; j < This->block_frames * 2; j++)
  804. This->output[This->active_outputs].buffer[j] = 0;
  805. }
  806. else
  807. {
  808. HeapFree(GetProcessHeap(), 0, This->output[This->active_inputs].buffer);
  809. info->buffers[0] = 0;
  810. info->buffers[1] = 0;
  811. WARN("no input buffer memory\n");
  812. goto ERROR_MEM;
  813. }
  814. This->active_outputs++;
  815. }
  816. }
  817. This->callbacks = callbacks;
  818. if (This->callbacks->asioMessage)
  819. {
  820. if (This->callbacks->asioMessage(kAsioSupportsTimeInfo, 0, 0, 0))
  821. {
  822. This->time_info_mode = TRUE;
  823. This->asio_time.timeInfo.speed = 1;
  824. This->asio_time.timeInfo.systemTime.hi = 0;
  825. This->asio_time.timeInfo.systemTime.lo = 0;
  826. This->asio_time.timeInfo.samplePosition.hi = 0;
  827. This->asio_time.timeInfo.samplePosition.lo = 0;
  828. This->asio_time.timeInfo.sampleRate = This->sample_rate;
  829. This->asio_time.timeInfo. flags = kSystemTimeValid | kSamplePositionValid | kSampleRateValid;
  830. This->asio_time.timeCode.speed = 1;
  831. This->asio_time.timeCode.timeCodeSamples.hi = 0;
  832. This->asio_time.timeCode.timeCodeSamples.lo = 0;
  833. This->asio_time.timeCode.flags = kTcValid | kTcRunning;
  834. }
  835. else
  836. This->time_info_mode = FALSE;
  837. }
  838. else
  839. {
  840. This->time_info_mode = FALSE;
  841. WARN("asioMessage callback not supplied\n");
  842. goto ERROR_PARAM;
  843. }
  844. return ASE_OK;
  845. ERROR_MEM:
  846. __wrapped_IWineASIOImpl_disposeBuffers(iface);
  847. WARN("no memory\n");
  848. return ASE_NoMemory;
  849. ERROR_PARAM:
  850. __wrapped_IWineASIOImpl_disposeBuffers(iface);
  851. WARN("invalid parameter\n");
  852. return ASE_InvalidParameter;
  853. }
  854. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_controlPanel, (LPWINEASIO iface))
  855. {
  856. TRACE("(%p) stub!\n", iface);
  857. return ASE_OK;
  858. }
  859. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_future, (LPWINEASIO iface, long selector, void *opt))
  860. {
  861. IWineASIOImpl * This = (IWineASIOImpl*)iface;
  862. TRACE("(%p, %ld, %p)\n", iface, selector, opt);
  863. switch (selector)
  864. {
  865. case kAsioEnableTimeCodeRead:
  866. This->tc_read = TRUE;
  867. return ASE_SUCCESS;
  868. case kAsioDisableTimeCodeRead:
  869. This->tc_read = FALSE;
  870. return ASE_SUCCESS;
  871. case kAsioSetInputMonitor:
  872. return ASE_SUCCESS;
  873. case kAsioCanInputMonitor:
  874. return ASE_SUCCESS;
  875. case kAsioCanTimeInfo:
  876. return ASE_SUCCESS;
  877. case kAsioCanTimeCode:
  878. return ASE_SUCCESS;
  879. }
  880. return ASE_NotPresent;
  881. }
  882. WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_outputReady, (LPWINEASIO iface))
  883. {
  884. TRACE("(%p)\n", iface);
  885. return ASE_NotPresent;
  886. }
  887. static const IWineASIOVtbl WineASIO_Vtbl =
  888. {
  889. IWineASIOImpl_QueryInterface,
  890. IWineASIOImpl_AddRef,
  891. IWineASIOImpl_Release,
  892. IWineASIOImpl_init,
  893. IWineASIOImpl_getDriverName,
  894. IWineASIOImpl_getDriverVersion,
  895. IWineASIOImpl_getErrorMessage,
  896. IWineASIOImpl_start,
  897. IWineASIOImpl_stop,
  898. IWineASIOImpl_getChannels,
  899. IWineASIOImpl_getLatencies,
  900. IWineASIOImpl_getBufferSize,
  901. IWineASIOImpl_canSampleRate,
  902. IWineASIOImpl_getSampleRate,
  903. IWineASIOImpl_setSampleRate,
  904. IWineASIOImpl_getClockSources,
  905. IWineASIOImpl_setClockSource,
  906. IWineASIOImpl_getSamplePosition,
  907. IWineASIOImpl_getChannelInfo,
  908. IWineASIOImpl_createBuffers,
  909. IWineASIOImpl_disposeBuffers,
  910. IWineASIOImpl_controlPanel,
  911. IWineASIOImpl_future,
  912. IWineASIOImpl_outputReady,
  913. };
  914. HRESULT asioCreateInstance(REFIID riid, LPVOID *ppobj)
  915. {
  916. IWineASIOImpl * pobj;
  917. TRACE("(%s, %p)\n", debugstr_guid(riid), ppobj);
  918. pobj = HeapAlloc(GetProcessHeap(), 0, sizeof(*pobj));
  919. if (pobj == NULL) {
  920. WARN("out of memory\n");
  921. return E_OUTOFMEMORY;
  922. }
  923. pobj->lpVtbl = &WineASIO_Vtbl;
  924. pobj->ref = 1;
  925. TRACE("pobj = %p\n", pobj);
  926. *ppobj = pobj;
  927. TRACE("return %p\n", *ppobj);
  928. return S_OK;
  929. }
  930. static void getNanoSeconds(ASIOTimeStamp* ts)
  931. {
  932. double nanoSeconds = (double)((unsigned long)timeGetTime ()) * 1000000.;
  933. ts->hi = (unsigned long)(nanoSeconds / twoRaisedTo32);
  934. ts->lo = (unsigned long)(nanoSeconds - (ts->hi * twoRaisedTo32));
  935. }
  936. static int jack_process(jack_nframes_t nframes, void * arg)
  937. {
  938. IWineASIOImpl * This = (IWineASIOImpl*)arg;
  939. int i, j;
  940. jack_default_audio_sample_t *in, *out;
  941. jack_transport_state_t ts;
  942. jack_position_t transport;
  943. // ASIOSTInt32LSB support only
  944. int *buffer;
  945. if (This->state != Run)
  946. return 0;
  947. ts = jack_transport_query(This->client, &transport);
  948. // if (ts == JackTransportRolling)
  949. // {
  950. if (This->client_state == Init)
  951. This->client_state = Run;
  952. This->sample_position = transport.frame;
  953. /* get the input data from JACK and copy it to the ASIO buffers */
  954. for (i = 0; i < This->active_inputs; i++)
  955. {
  956. if (This->input[i].active == ASIOTrue) {
  957. buffer = &This->input[i].buffer[This->block_frames * This->toggle];
  958. in = jack_port_get_buffer(This->input[i].port, nframes);
  959. for (j = 0; j < nframes; j++)
  960. buffer[j] = (int)(in[j] * (float)(0x7fffffff));
  961. }
  962. }
  963. /* call the ASIO user callback to read the input data and fill the output data */
  964. // getNanoSeconds(&This->system_time);
  965. /* wake up the WIN32 thread so it can do its callback */
  966. sem_post(&This->semaphore1);
  967. /* wait for the WIN32 thread to complete before continuing */
  968. sem_wait(&This->semaphore2);
  969. /* copy the ASIO data to JACK */
  970. for (i = 0; i < This->num_outputs; i++)
  971. {
  972. if (This->output[i].active == ASIOTrue) {
  973. buffer = &This->output[i].buffer[This->block_frames * (This->toggle)];
  974. out = jack_port_get_buffer(This->output[i].port, nframes);
  975. for (j = 0; j < nframes; j++)
  976. out[j] = ((float)(buffer[j]) / (float)(0x7fffffff));
  977. }
  978. }
  979. This->toggle = This->toggle ? 0 : 1;
  980. // This->callbacks->bufferSwitch(This->toggle, ASIOTrue);
  981. // }
  982. return 0;
  983. }
  984. /*
  985. * The ASIO callback can make WIN32 calls which require a WIN32 thread.
  986. * Do the callback in this thread and then switch back to the Jack callback thread.
  987. */
  988. static DWORD CALLBACK win32_callback(LPVOID arg)
  989. {
  990. IWineASIOImpl * This = (IWineASIOImpl*)arg;
  991. struct sched_param attr;
  992. //TRACE("(%p)\n", arg);
  993. attr.sched_priority = 86;
  994. sched_setscheduler(0, SCHED_FIFO, &attr);
  995. /* let IWineASIO_Init know we are alive */
  996. SetEvent(This->start_event);
  997. while (1)
  998. {
  999. /* wait to be woken up by the JACK callback thread */
  1000. sem_wait(&This->semaphore1);
  1001. /* check for termination */
  1002. if (This->terminate)
  1003. {
  1004. SetEvent(This->stop_event);
  1005. TRACE("terminated\n");
  1006. return 0;
  1007. }
  1008. getNanoSeconds(&This->system_time);
  1009. /* make sure we are in the run state */
  1010. if (This->state == Run)
  1011. {
  1012. if (This->time_info_mode)
  1013. {
  1014. __wrapped_IWineASIOImpl_getSamplePosition((LPWINEASIO)This,
  1015. &This->asio_time.timeInfo.samplePosition, &This->asio_time.timeInfo.systemTime);
  1016. if (This->tc_read)
  1017. {
  1018. This->asio_time.timeCode.timeCodeSamples.lo = This->asio_time.timeInfo.samplePosition.lo;
  1019. This->asio_time.timeCode.timeCodeSamples.hi = 0;
  1020. }
  1021. This->callbacks->bufferSwitchTimeInfo(&This->asio_time, This->toggle, ASIOFalse);
  1022. This->asio_time.timeInfo.flags &= ~(kSampleRateChanged | kClockSourceChanged);
  1023. }
  1024. else
  1025. This->callbacks->bufferSwitch(This->toggle, ASIOTrue);
  1026. }
  1027. /* let the JACK thread know we are done */
  1028. sem_post(&This->semaphore2);
  1029. }
  1030. return 0;
  1031. }