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.

1381 lines
42KB

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