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.

1362 lines
50KB

  1. /*
  2. * Copyright (C) 2006 Robert Reif
  3. * Portions copyright (C) 2007 Ralf Beck
  4. * Portions copyright (C) 2007 Johnny Petrantoni
  5. * Portions copyright (C) 2007 Stephane Letz
  6. * Portions copyright (C) 2008 William Steidtmann
  7. * Portions copyright (C) 2010 Peter L Jones
  8. * Portions copyright (C) 2010 Torben Hohn
  9. * Portions copyright (C) 2010 Nedko Arnaudov
  10. * Portions copyright (C) 2013 Joakim Hernberg
  11. *
  12. * This library is free software; you can redistribute it and/or
  13. * modify it under the terms of the GNU Lesser General Public
  14. * License as published by the Free Software Foundation; either
  15. * version 2.1 of the License, or (at your option) any later version.
  16. *
  17. * This library is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  20. * Lesser General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU Lesser General Public
  23. * License along with this library; if not, write to the Free Software
  24. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  25. */
  26. #include <stdio.h>
  27. #include <errno.h>
  28. #include <limits.h>
  29. #include <unistd.h>
  30. #include <pthread.h>
  31. #include <objbase.h>
  32. #include <mmsystem.h>
  33. #include <winreg.h>
  34. #define IEEE754_64FLOAT 1
  35. #undef NATIVE_INT64
  36. #include "asio.h"
  37. #define NATIVE_INT64
  38. #include "JackBridge.h"
  39. // #include <jack/jack.h>
  40. // #include <jack/thread.h>
  41. // #include <sys/mman.h>
  42. #define ASIO_MAX_NAME_LENGTH 32
  43. #define ASIO_MINIMUM_BUFFERSIZE 64
  44. #define ASIO_MAXIMUM_BUFFERSIZE 256
  45. #define ASIO_PREFERRED_BUFFERSIZE 128
  46. #define TRACE(...) {}
  47. #define WARN(fmt, ...) {} fprintf(stdout, fmt, ##__VA_ARGS__)
  48. #define ERR(fmt, ...) {} fprintf(stderr, fmt, ##__VA_ARGS__)
  49. /* From config.h */
  50. #define __ASM_NAME(name) name
  51. #define THISCALL(func) func
  52. #define THISCALL_NAME(func) __ASM_NAME(#func)
  53. // #define __thiscall __stdcall
  54. #define DEFINE_THISCALL_WRAPPER(func,args) /* nothing */
  55. /*****************************************************************************
  56. * IWineAsio interface
  57. */
  58. #undef INTERFACE
  59. #define INTERFACE IWineASIO
  60. DECLARE_INTERFACE_(IWineASIO,IUnknown)
  61. {
  62. STDMETHOD_(HRESULT, QueryInterface) (THIS_ IID riid, void** ppvObject) PURE;
  63. STDMETHOD_(ULONG, AddRef) (THIS) PURE;
  64. STDMETHOD_(ULONG, Release) (THIS) PURE;
  65. STDMETHOD_(ASIOBool, Init) (THIS_ void *sysRef) PURE;
  66. STDMETHOD_(void, GetDriverName) (THIS_ char *name) PURE;
  67. STDMETHOD_(LONG, GetDriverVersion) (THIS) PURE;
  68. STDMETHOD_(void, GetErrorMessage) (THIS_ char *string) PURE;
  69. STDMETHOD_(ASIOError, Start) (THIS) PURE;
  70. STDMETHOD_(ASIOError, Stop) (THIS) PURE;
  71. STDMETHOD_(ASIOError, GetChannels) (THIS_ LONG *numInputChannels, LONG *numOutputChannels) PURE;
  72. STDMETHOD_(ASIOError, GetLatencies) (THIS_ LONG *inputLatency, LONG *outputLatency) PURE;
  73. STDMETHOD_(ASIOError, GetBufferSize) (THIS_ LONG *minSize, LONG *maxSize, LONG *preferredSize, LONG *granularity) PURE;
  74. STDMETHOD_(ASIOError, CanSampleRate) (THIS_ ASIOSampleRate sampleRate) PURE;
  75. STDMETHOD_(ASIOError, GetSampleRate) (THIS_ ASIOSampleRate *sampleRate) PURE;
  76. STDMETHOD_(ASIOError, SetSampleRate) (THIS_ ASIOSampleRate sampleRate) PURE;
  77. STDMETHOD_(ASIOError, GetClockSources) (THIS_ ASIOClockSource *clocks, LONG *numSources) PURE;
  78. STDMETHOD_(ASIOError, SetClockSource) (THIS_ LONG index) PURE;
  79. STDMETHOD_(ASIOError, GetSamplePosition) (THIS_ ASIOSamples *sPos, ASIOTimeStamp *tStamp) PURE;
  80. STDMETHOD_(ASIOError, GetChannelInfo) (THIS_ ASIOChannelInfo *info) PURE;
  81. STDMETHOD_(ASIOError, CreateBuffers) (THIS_ ASIOBufferInfo *bufferInfo, LONG numChannels, LONG bufferSize, ASIOCallbacks *asioCallbacks) PURE;
  82. STDMETHOD_(ASIOError, DisposeBuffers) (THIS) PURE;
  83. STDMETHOD_(ASIOError, ControlPanel) (THIS) PURE;
  84. STDMETHOD_(ASIOError, Future) (THIS_ LONG selector,void *opt) PURE;
  85. STDMETHOD_(ASIOError, OutputReady) (THIS) PURE;
  86. };
  87. #undef INTERFACE
  88. typedef struct IWineASIO *LPWINEASIO;
  89. typedef struct IOChannel
  90. {
  91. ASIOBool active;
  92. jack_default_audio_sample_t *audio_buffer;
  93. char port_name[ASIO_MAX_NAME_LENGTH];
  94. jack_port_t *port;
  95. } IOChannel;
  96. typedef struct IWineASIOImpl
  97. {
  98. /* COM stuff */
  99. const IWineASIOVtbl *lpVtbl;
  100. LONG ref;
  101. /* The app's main window handle on windows, 0 on OS/X */
  102. HWND sys_ref;
  103. /* ASIO stuff */
  104. LONG asio_active_inputs;
  105. LONG asio_active_outputs;
  106. BOOL asio_buffer_index;
  107. ASIOCallbacks *asio_callbacks;
  108. BOOL asio_can_time_code;
  109. LONG asio_current_buffersize;
  110. INT asio_driver_state;
  111. ASIOSamples asio_sample_position;
  112. ASIOSampleRate asio_sample_rate;
  113. ASIOTime asio_time;
  114. BOOL asio_time_info_mode;
  115. ASIOTimeStamp asio_time_stamp;
  116. LONG asio_version;
  117. /* WineASIO configuration options */
  118. int wineasio_number_inputs;
  119. int wineasio_number_outputs;
  120. BOOL wineasio_fixed_buffersize;
  121. /* JACK stuff */
  122. jack_client_t *jack_client;
  123. char jack_client_name[ASIO_MAX_NAME_LENGTH];
  124. /* jack process callback buffers */
  125. jack_default_audio_sample_t *callback_audio_buffer;
  126. IOChannel *input_channel;
  127. IOChannel *output_channel;
  128. } IWineASIOImpl;
  129. enum { Loaded, Initialized, Prepared, Running };
  130. /****************************************************************************
  131. * Interface Methods
  132. */
  133. /*
  134. * as seen from the WineASIO source
  135. */
  136. HRESULT STDMETHODCALLTYPE QueryInterface(LPWINEASIO iface, REFIID riid, void **ppvObject);
  137. ULONG STDMETHODCALLTYPE AddRef(LPWINEASIO iface);
  138. ULONG STDMETHODCALLTYPE Release(LPWINEASIO iface);
  139. ASIOBool STDMETHODCALLTYPE Init(LPWINEASIO iface, void *sysRef);
  140. void STDMETHODCALLTYPE GetDriverName(LPWINEASIO iface, char *name);
  141. LONG STDMETHODCALLTYPE GetDriverVersion(LPWINEASIO iface);
  142. void STDMETHODCALLTYPE GetErrorMessage(LPWINEASIO iface, char *string);
  143. ASIOError STDMETHODCALLTYPE Start(LPWINEASIO iface);
  144. ASIOError STDMETHODCALLTYPE Stop(LPWINEASIO iface);
  145. ASIOError STDMETHODCALLTYPE GetChannels (LPWINEASIO iface, LONG *numInputChannels, LONG *numOutputChannels);
  146. ASIOError STDMETHODCALLTYPE GetLatencies(LPWINEASIO iface, LONG *inputLatency, LONG *outputLatency);
  147. ASIOError STDMETHODCALLTYPE GetBufferSize(LPWINEASIO iface, LONG *minSize, LONG *maxSize, LONG *preferredSize, LONG *granularity);
  148. ASIOError STDMETHODCALLTYPE CanSampleRate(LPWINEASIO iface, ASIOSampleRate sampleRate);
  149. ASIOError STDMETHODCALLTYPE GetSampleRate(LPWINEASIO iface, ASIOSampleRate *sampleRate);
  150. ASIOError STDMETHODCALLTYPE SetSampleRate(LPWINEASIO iface, ASIOSampleRate sampleRate);
  151. ASIOError STDMETHODCALLTYPE GetClockSources(LPWINEASIO iface, ASIOClockSource *clocks, LONG *numSources);
  152. ASIOError STDMETHODCALLTYPE SetClockSource(LPWINEASIO iface, LONG index);
  153. ASIOError STDMETHODCALLTYPE GetSamplePosition(LPWINEASIO iface, ASIOSamples *sPos, ASIOTimeStamp *tStamp);
  154. ASIOError STDMETHODCALLTYPE GetChannelInfo(LPWINEASIO iface, ASIOChannelInfo *info);
  155. ASIOError STDMETHODCALLTYPE CreateBuffers(LPWINEASIO iface, ASIOBufferInfo *bufferInfo, LONG numChannels, LONG bufferSize, ASIOCallbacks *asioCallbacks);
  156. ASIOError STDMETHODCALLTYPE DisposeBuffers(LPWINEASIO iface);
  157. ASIOError STDMETHODCALLTYPE ControlPanel(LPWINEASIO iface);
  158. ASIOError STDMETHODCALLTYPE Future(LPWINEASIO iface, LONG selector, void *opt);
  159. ASIOError STDMETHODCALLTYPE OutputReady(LPWINEASIO iface);
  160. /*
  161. * thiscall wrappers for the vtbl (as seen from app side 32bit)
  162. */
  163. void __thiscall_Init(void);
  164. void __thiscall_GetDriverName(void);
  165. void __thiscall_GetDriverVersion(void);
  166. void __thiscall_GetErrorMessage(void);
  167. void __thiscall_Start(void);
  168. void __thiscall_Stop(void);
  169. void __thiscall_GetChannels(void);
  170. void __thiscall_GetLatencies(void);
  171. void __thiscall_GetBufferSize(void);
  172. void __thiscall_CanSampleRate(void);
  173. void __thiscall_GetSampleRate(void);
  174. void __thiscall_SetSampleRate(void);
  175. void __thiscall_GetClockSources(void);
  176. void __thiscall_SetClockSource(void);
  177. void __thiscall_GetSamplePosition(void);
  178. void __thiscall_GetChannelInfo(void);
  179. void __thiscall_CreateBuffers(void);
  180. void __thiscall_DisposeBuffers(void);
  181. void __thiscall_ControlPanel(void);
  182. void __thiscall_Future(void);
  183. void __thiscall_OutputReady(void);
  184. /*
  185. * Jack callbacks
  186. */
  187. static inline int jack_buffer_size_callback (jack_nframes_t nframes, void *arg);
  188. static inline void jack_latency_callback(jack_latency_callback_mode_t mode, void *arg);
  189. static inline int jack_process_callback (jack_nframes_t nframes, void *arg);
  190. static inline int jack_sample_rate_callback (jack_nframes_t nframes, void *arg);
  191. /*
  192. * Support functions
  193. */
  194. HRESULT WINAPI WineASIOCreateInstance(REFIID riid, LPVOID *ppobj);
  195. static VOID configure_driver(IWineASIOImpl *This);
  196. #if 0
  197. static DWORD WINAPI jack_thread_creator_helper(LPVOID arg);
  198. static int jack_thread_creator(pthread_t* thread_id, const pthread_attr_t* attr, void *(*function)(void*), void* arg);
  199. #endif
  200. /* {48D0C522-BFCC-45cc-8B84-17F25F33E6E9} */
  201. static GUID const CLSID_WineASIO = {
  202. 0x48d0c522, 0xbfcc, 0x45cc, { 0x8b, 0x84, 0x17, 0xf2, 0x5f, 0x33, 0xe6, 0xe9 } };
  203. static const IWineASIOVtbl WineASIO_Vtbl =
  204. {
  205. (void *) QueryInterface,
  206. (void *) AddRef,
  207. (void *) Release,
  208. (void *) THISCALL(Init),
  209. (void *) THISCALL(GetDriverName),
  210. (void *) THISCALL(GetDriverVersion),
  211. (void *) THISCALL(GetErrorMessage),
  212. (void *) THISCALL(Start),
  213. (void *) THISCALL(Stop),
  214. (void *) THISCALL(GetChannels),
  215. (void *) THISCALL(GetLatencies),
  216. (void *) THISCALL(GetBufferSize),
  217. (void *) THISCALL(CanSampleRate),
  218. (void *) THISCALL(GetSampleRate),
  219. (void *) THISCALL(SetSampleRate),
  220. (void *) THISCALL(GetClockSources),
  221. (void *) THISCALL(SetClockSource),
  222. (void *) THISCALL(GetSamplePosition),
  223. (void *) THISCALL(GetChannelInfo),
  224. (void *) THISCALL(CreateBuffers),
  225. (void *) THISCALL(DisposeBuffers),
  226. (void *) THISCALL(ControlPanel),
  227. (void *) THISCALL(Future),
  228. (void *) THISCALL(OutputReady)
  229. };
  230. /* structure needed to create the JACK callback thread in the wine process context */
  231. struct {
  232. void *(*jack_callback_thread) (void*);
  233. void *arg;
  234. pthread_t jack_callback_pthread_id;
  235. HANDLE jack_callback_thread_created;
  236. } jack_thread_creator_privates;
  237. /*****************************************************************************
  238. * Interface method definitions
  239. */
  240. HRESULT STDMETHODCALLTYPE QueryInterface(LPWINEASIO iface, REFIID riid, void **ppvObject)
  241. {
  242. IWineASIOImpl *This = (IWineASIOImpl *)iface;
  243. TRACE("iface: %p, riid: %s, ppvObject: %p)\n", iface, debugstr_guid(riid), ppvObject);
  244. if (ppvObject == NULL)
  245. return E_INVALIDARG;
  246. if (IsEqualIID(&CLSID_WineASIO, riid))
  247. {
  248. AddRef(iface);
  249. *ppvObject = This;
  250. return S_OK;
  251. }
  252. return E_NOINTERFACE;
  253. }
  254. /*
  255. * ULONG STDMETHODCALLTYPE AddRef(LPWINEASIO iface);
  256. * Function: Increment the reference count on the object
  257. * Returns: Ref count
  258. */
  259. ULONG STDMETHODCALLTYPE AddRef(LPWINEASIO iface)
  260. {
  261. IWineASIOImpl *This = (IWineASIOImpl *)iface;
  262. ULONG ref = InterlockedIncrement(&(This->ref));
  263. TRACE("iface: %p, ref count is %d\n", iface, ref);
  264. return ref;
  265. }
  266. /*
  267. * ULONG Release (LPWINEASIO iface);
  268. * Function: Destroy the interface
  269. * Returns: Ref count
  270. * Implies: ASIOStop() and ASIODisposeBuffers()
  271. */
  272. ULONG STDMETHODCALLTYPE Release(LPWINEASIO iface)
  273. {
  274. IWineASIOImpl *This = (IWineASIOImpl *)iface;
  275. ULONG ref = InterlockedDecrement(&This->ref);
  276. TRACE("iface: %p, ref count is %d\n", iface, ref);
  277. if (This->asio_driver_state == Running)
  278. Stop(iface);
  279. if (This->asio_driver_state == Prepared)
  280. DisposeBuffers(iface);
  281. if (This->asio_driver_state == Initialized)
  282. {
  283. /* just for good measure we deinitialize IOChannel structures and unregister JACK ports */
  284. for (int i = 0; i < This->wineasio_number_inputs; i++)
  285. {
  286. jackbridge_port_unregister (This->jack_client, This->input_channel[i].port);
  287. This->input_channel[i].active = ASIOFalse;
  288. This->input_channel[i].port = NULL;
  289. }
  290. for (int i = 0; i < This->wineasio_number_outputs; i++)
  291. {
  292. jackbridge_port_unregister (This->jack_client, This->output_channel[i].port);
  293. This->output_channel[i].active = ASIOFalse;
  294. This->output_channel[i].port = NULL;
  295. }
  296. This->asio_active_inputs = This->asio_active_outputs = 0;
  297. TRACE("%i IOChannel structures released\n", This->wineasio_number_inputs + This->wineasio_number_outputs);
  298. jackbridge_client_close(This->jack_client);
  299. if (This->input_channel)
  300. HeapFree(GetProcessHeap(), 0, This->input_channel);
  301. }
  302. TRACE("MOD Desktop terminated\n\n");
  303. if (ref == 0)
  304. HeapFree(GetProcessHeap(), 0, This);
  305. return ref;
  306. }
  307. /*
  308. * ASIOBool Init (void *sysRef);
  309. * Function: Initialize the driver
  310. * Parameters: Pointer to "This"
  311. * sysHanle is 0 on OS/X and on windows it contains the applications main window handle
  312. * Returns: ASIOFalse on error, and ASIOTrue on success
  313. */
  314. DEFINE_THISCALL_WRAPPER(Init,8)
  315. ASIOBool STDMETHODCALLTYPE Init(LPWINEASIO iface, void *sysRef)
  316. {
  317. IWineASIOImpl *This = (IWineASIOImpl *)iface;
  318. jack_status_t jack_status;
  319. jack_options_t jack_options = JackNoStartServer|JackServerName;
  320. int i;
  321. This->sys_ref = sysRef;
  322. configure_driver(This);
  323. if (!strcmp(This->jack_client_name, "jackd"))
  324. {
  325. // running as jackd service, stop here
  326. return ASIOFalse;
  327. }
  328. if (!jackbridge_is_ok())
  329. {
  330. WARN("MOD Desktop is not installed, cannot use ASIO driver\n");
  331. return ASIOFalse;
  332. }
  333. // TODO
  334. // mlockall(MCL_FUTURE);
  335. // TODO allow any client name on mod-ui side
  336. if (!(This->jack_client = jackbridge_client_open("mod-external", jack_options, &jack_status, "mod-desktop")))
  337. {
  338. WARN("Unable to open a JACK client as: %s\n", "mod-external");
  339. return ASIOFalse;
  340. }
  341. TRACE("JACK client opened as: '%s'\n", jackbridge_get_client_name(This->jack_client));
  342. This->asio_sample_rate = jackbridge_get_sample_rate(This->jack_client);
  343. This->asio_current_buffersize = jackbridge_get_buffer_size(This->jack_client);
  344. /* Allocate IOChannel structures */
  345. This->input_channel = HeapAlloc(GetProcessHeap(), 0, (This->wineasio_number_inputs + This->wineasio_number_outputs) * sizeof(IOChannel));
  346. if (!This->input_channel)
  347. {
  348. jackbridge_client_close(This->jack_client);
  349. ERR("Unable to allocate IOChannel structures for %i channels\n", This->wineasio_number_inputs);
  350. return ASIOFalse;
  351. }
  352. This->output_channel = This->input_channel + This->wineasio_number_inputs;
  353. TRACE("%i IOChannel structures allocated\n", This->wineasio_number_inputs + This->wineasio_number_outputs);
  354. /* Initialize IOChannel structures */
  355. for (i = 0; i < This->wineasio_number_inputs; i++)
  356. {
  357. This->input_channel[i].active = ASIOFalse;
  358. This->input_channel[i].port = NULL;
  359. snprintf(This->input_channel[i].port_name, ASIO_MAX_NAME_LENGTH, "audio_to_external_%i", i + 1);
  360. This->input_channel[i].port = jackbridge_port_register(This->jack_client,
  361. This->input_channel[i].port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, i);
  362. /* TRACE("IOChannel structure initialized for input %d: '%s'\n", i, This->input_channel[i].port_name); */
  363. }
  364. for (i = 0; i < This->wineasio_number_outputs; i++)
  365. {
  366. This->output_channel[i].active = ASIOFalse;
  367. This->output_channel[i].port = NULL;
  368. snprintf(This->output_channel[i].port_name, ASIO_MAX_NAME_LENGTH, "audio_from_external_%i", i + 1);
  369. This->output_channel[i].port = jackbridge_port_register(This->jack_client,
  370. This->output_channel[i].port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput|JackPortIsPhysical, i);
  371. /* TRACE("IOChannel structure initialized for output %d: '%s'\n", i, This->output_channel[i].port_name); */
  372. }
  373. TRACE("%i IOChannel structures initialized\n", This->wineasio_number_inputs + This->wineasio_number_outputs);
  374. if (!jackbridge_set_buffer_size_callback(This->jack_client, jack_buffer_size_callback, This))
  375. {
  376. jackbridge_client_close(This->jack_client);
  377. HeapFree(GetProcessHeap(), 0, This->input_channel);
  378. ERR("Unable to register JACK buffer size change callback\n");
  379. return ASIOFalse;
  380. }
  381. if (!jackbridge_set_latency_callback(This->jack_client, jack_latency_callback, This))
  382. {
  383. jackbridge_client_close(This->jack_client);
  384. HeapFree(GetProcessHeap(), 0, This->input_channel);
  385. ERR("Unable to register JACK latency callback\n");
  386. return ASIOFalse;
  387. }
  388. if (!jackbridge_set_process_callback(This->jack_client, jack_process_callback, This))
  389. {
  390. jackbridge_client_close(This->jack_client);
  391. HeapFree(GetProcessHeap(), 0, This->input_channel);
  392. ERR("Unable to register JACK process callback\n");
  393. return ASIOFalse;
  394. }
  395. if (!jackbridge_set_sample_rate_callback (This->jack_client, jack_sample_rate_callback, This))
  396. {
  397. jackbridge_client_close(This->jack_client);
  398. HeapFree(GetProcessHeap(), 0, This->input_channel);
  399. ERR("Unable to register JACK sample rate change callback\n");
  400. return ASIOFalse;
  401. }
  402. This->asio_driver_state = Initialized;
  403. TRACE("MOD Desktop 0.%.1f initialized\n",(float) This->asio_version / 10);
  404. return ASIOTrue;
  405. }
  406. /*
  407. * void GetDriverName(char *name);
  408. * Function: Returns the driver name in name
  409. */
  410. DEFINE_THISCALL_WRAPPER(GetDriverName,8)
  411. void STDMETHODCALLTYPE GetDriverName(LPWINEASIO iface, char *name)
  412. {
  413. TRACE("iface: %p, name: %p\n", iface, name);
  414. strcpy(name, "MOD Desktop");
  415. return;
  416. }
  417. /*
  418. * LONG GetDriverVersion (void);
  419. * Function: Returns the driver version number
  420. */
  421. DEFINE_THISCALL_WRAPPER(GetDriverVersion,4)
  422. LONG STDMETHODCALLTYPE GetDriverVersion(LPWINEASIO iface)
  423. {
  424. IWineASIOImpl *This = (IWineASIOImpl*)iface;
  425. TRACE("iface: %p\n", iface);
  426. return This->asio_version;
  427. }
  428. /*
  429. * void GetErrorMessage(char *string);
  430. * Function: Returns an error message for the last occured error in string
  431. */
  432. DEFINE_THISCALL_WRAPPER(GetErrorMessage,8)
  433. void STDMETHODCALLTYPE GetErrorMessage(LPWINEASIO iface, char *string)
  434. {
  435. TRACE("iface: %p, string: %p)\n", iface, string);
  436. strcpy(string, "MOD Desktop does not return error messages\n");
  437. return;
  438. }
  439. /*
  440. * ASIOError Start(void);
  441. * Function: Start JACK IO processing and reset the sample counter to zero
  442. * Returns: ASE_NotPresent if IO is missing
  443. * ASE_HWMalfunction if JACK fails to start
  444. */
  445. DEFINE_THISCALL_WRAPPER(Start,4)
  446. ASIOError STDMETHODCALLTYPE Start(LPWINEASIO iface)
  447. {
  448. IWineASIOImpl *This = (IWineASIOImpl*)iface;
  449. int i;
  450. DWORD time;
  451. TRACE("iface: %p\n", iface);
  452. if (This->asio_driver_state != Prepared)
  453. return ASE_NotPresent;
  454. /* Zero the audio buffer */
  455. for (i = 0; i < (This->wineasio_number_inputs + This->wineasio_number_outputs) * 2 * This->asio_current_buffersize; i++)
  456. This->callback_audio_buffer[i] = 0;
  457. /* prime the callback by preprocessing one outbound ASIO bufffer */
  458. This->asio_buffer_index = 0;
  459. This->asio_sample_position.hi = This->asio_sample_position.lo = 0;
  460. time = timeGetTime();
  461. This->asio_time_stamp.lo = time * 1000000;
  462. This->asio_time_stamp.hi = ((unsigned long long) time * 1000000) >> 32;
  463. if (This->asio_time_info_mode) /* use the newer bufferSwitchTimeInfo method if supported */
  464. {
  465. This->asio_time.timeInfo.samplePosition.lo = This->asio_time.timeInfo.samplePosition.hi = 0;
  466. This->asio_time.timeInfo.systemTime.lo = This->asio_time_stamp.lo;
  467. This->asio_time.timeInfo.systemTime.hi = This->asio_time_stamp.hi;
  468. This->asio_time.timeInfo.sampleRate = This->asio_sample_rate;
  469. This->asio_time.timeInfo.flags = kSystemTimeValid | kSamplePositionValid | kSampleRateValid;
  470. if (This->asio_can_time_code) /* addionally use time code if supported */
  471. {
  472. This->asio_time.timeCode.speed = 1; /* FIXME */
  473. This->asio_time.timeCode.timeCodeSamples.lo = This->asio_time_stamp.lo;
  474. This->asio_time.timeCode.timeCodeSamples.hi = This->asio_time_stamp.hi;
  475. This->asio_time.timeCode.flags = ~(kTcValid | kTcRunning);
  476. }
  477. This->asio_callbacks->bufferSwitchTimeInfo(&This->asio_time, This->asio_buffer_index, ASIOTrue);
  478. }
  479. else
  480. { /* use the old bufferSwitch method */
  481. This->asio_callbacks->bufferSwitch(This->asio_buffer_index, ASIOTrue);
  482. }
  483. /* swith asio buffer */
  484. This->asio_buffer_index = This->asio_buffer_index ? 0 : 1;
  485. This->asio_driver_state = Running;
  486. TRACE("MOD Desktop successfully loaded\n");
  487. return ASE_OK;
  488. }
  489. /*
  490. * ASIOError Stop(void);
  491. * Function: Stop JACK IO processing
  492. * Returns: ASE_NotPresent on missing IO
  493. * Note: BufferSwitch() must not called after returning
  494. */
  495. DEFINE_THISCALL_WRAPPER(Stop,4)
  496. ASIOError STDMETHODCALLTYPE Stop(LPWINEASIO iface)
  497. {
  498. IWineASIOImpl *This = (IWineASIOImpl*)iface;
  499. TRACE("iface: %p\n", iface);
  500. if (This->asio_driver_state != Running)
  501. return ASE_NotPresent;
  502. This->asio_driver_state = Prepared;
  503. return ASE_OK;
  504. }
  505. /*
  506. * ASIOError GetChannels(LONG *numInputChannels, LONG *numOutputChannels);
  507. * Function: Report number of IO channels
  508. * Parameters: numInputChannels and numOutputChannels will hold number of channels on returning
  509. * Returns: ASE_NotPresent if no channels are available, otherwise AES_OK
  510. */
  511. DEFINE_THISCALL_WRAPPER(GetChannels,12)
  512. ASIOError STDMETHODCALLTYPE GetChannels (LPWINEASIO iface, LONG *numInputChannels, LONG *numOutputChannels)
  513. {
  514. IWineASIOImpl *This = (IWineASIOImpl*)iface;
  515. if (!numInputChannels || !numOutputChannels)
  516. return ASE_InvalidParameter;
  517. *numInputChannels = This->wineasio_number_inputs;
  518. *numOutputChannels = This->wineasio_number_outputs;
  519. TRACE("iface: %p, inputs: %i, outputs: %i\n", iface, This->wineasio_number_inputs, This->wineasio_number_outputs);
  520. return ASE_OK;
  521. }
  522. /*
  523. * ASIOError GetLatencies(LONG *inputLatency, LONG *outputLatency);
  524. * Function: Return latency in frames
  525. * Returns: ASE_NotPresent if no IO is available, otherwise AES_OK
  526. */
  527. DEFINE_THISCALL_WRAPPER(GetLatencies,12)
  528. ASIOError STDMETHODCALLTYPE GetLatencies(LPWINEASIO iface, LONG *inputLatency, LONG *outputLatency)
  529. {
  530. IWineASIOImpl *This = (IWineASIOImpl*)iface;
  531. jack_latency_range_t range;
  532. if (!inputLatency || !outputLatency)
  533. return ASE_InvalidParameter;
  534. if (This->asio_driver_state == Loaded)
  535. return ASE_NotPresent;
  536. jackbridge_port_get_latency_range(This->input_channel[0].port, JackCaptureLatency, &range);
  537. *inputLatency = range.max;
  538. jackbridge_port_get_latency_range(This->output_channel[0].port, JackPlaybackLatency, &range);
  539. *outputLatency = range.max;
  540. TRACE("iface: %p, input latency: %d, output latency: %d\n", iface, *inputLatency, *outputLatency);
  541. return ASE_OK;
  542. }
  543. /*
  544. * ASIOError GetBufferSize(LONG *minSize, LONG *maxSize, LONG *preferredSize, LONG *granularity);
  545. * Function: Return minimum, maximum, preferred buffer sizes, and granularity
  546. * At the moment return all the same, and granularity 0
  547. * Returns: ASE_NotPresent on missing IO
  548. */
  549. DEFINE_THISCALL_WRAPPER(GetBufferSize,20)
  550. ASIOError STDMETHODCALLTYPE GetBufferSize(LPWINEASIO iface, LONG *minSize, LONG *maxSize, LONG *preferredSize, LONG *granularity)
  551. {
  552. IWineASIOImpl *This = (IWineASIOImpl*)iface;
  553. TRACE("iface: %p, minSize: %p, maxSize: %p, preferredSize: %p, granularity: %p\n", iface, minSize, maxSize, preferredSize, granularity);
  554. if (!minSize || !maxSize || !preferredSize || !granularity)
  555. return ASE_InvalidParameter;
  556. if (This->wineasio_fixed_buffersize)
  557. {
  558. *minSize = *maxSize = *preferredSize = This->asio_current_buffersize;
  559. *granularity = 0;
  560. TRACE("Buffersize fixed at %i\n", This->asio_current_buffersize);
  561. return ASE_OK;
  562. }
  563. *minSize = ASIO_MINIMUM_BUFFERSIZE;
  564. *maxSize = ASIO_MAXIMUM_BUFFERSIZE;
  565. *preferredSize = ASIO_PREFERRED_BUFFERSIZE;
  566. *granularity = -1;
  567. TRACE("The ASIO host can control buffersize\nMinimum: %i, maximum: %i, preferred: %i, granularity: %i, current: %i\n",
  568. *minSize, *maxSize, *preferredSize, *granularity, This->asio_current_buffersize);
  569. return ASE_OK;
  570. }
  571. /*
  572. * ASIOError CanSampleRate(ASIOSampleRate sampleRate);
  573. * Function: Ask if specific SR is available
  574. * Returns: ASE_NoClock if SR isn't available, ASE_NotPresent on missing IO
  575. */
  576. DEFINE_THISCALL_WRAPPER(CanSampleRate,12)
  577. ASIOError STDMETHODCALLTYPE CanSampleRate(LPWINEASIO iface, ASIOSampleRate sampleRate)
  578. {
  579. IWineASIOImpl *This = (IWineASIOImpl*)iface;
  580. TRACE("iface: %p, Samplerate = %li, requested samplerate = %li\n", iface, (long) This->asio_sample_rate, (long) sampleRate);
  581. if (sampleRate != This->asio_sample_rate)
  582. return ASE_NoClock;
  583. return ASE_OK;
  584. }
  585. /*
  586. * ASIOError GetSampleRate(ASIOSampleRate *currentRate);
  587. * Function: Return current SR
  588. * Parameters: currentRate will hold SR on return, 0 if unknown
  589. * Returns: ASE_NoClock if SR is unknown, ASE_NotPresent on missing IO
  590. */
  591. DEFINE_THISCALL_WRAPPER(GetSampleRate,8)
  592. ASIOError STDMETHODCALLTYPE GetSampleRate(LPWINEASIO iface, ASIOSampleRate *sampleRate)
  593. {
  594. IWineASIOImpl *This = (IWineASIOImpl*)iface;
  595. TRACE("iface: %p, Sample rate is %i\n", iface, (int) This->asio_sample_rate);
  596. if (!sampleRate)
  597. return ASE_InvalidParameter;
  598. *sampleRate = This->asio_sample_rate;
  599. return ASE_OK;
  600. }
  601. /*
  602. * ASIOError SetSampleRate(ASIOSampleRate sampleRate);
  603. * Function: Set requested SR, enable external sync if SR == 0
  604. * Returns: ASE_NoClock if unknown SR
  605. * ASE_InvalidMode if current clock is external and SR != 0
  606. * ASE_NotPresent on missing IO
  607. */
  608. DEFINE_THISCALL_WRAPPER(SetSampleRate,12)
  609. ASIOError STDMETHODCALLTYPE SetSampleRate(LPWINEASIO iface, ASIOSampleRate sampleRate)
  610. {
  611. IWineASIOImpl *This = (IWineASIOImpl*)iface;
  612. TRACE("iface: %p, Sample rate %f requested\n", iface, sampleRate);
  613. if (sampleRate != This->asio_sample_rate)
  614. return ASE_NoClock;
  615. return ASE_OK;
  616. }
  617. /*
  618. * ASIOError GetClockSources(ASIOClockSource *clocks, LONG *numSources);
  619. * Function: Return available clock sources
  620. * Parameters: clocks - a pointer to an array of ASIOClockSource structures.
  621. * numSources - when called: number of allocated members
  622. * - on return: number of clock sources, the minimum is 1 - the internal clock
  623. * Returns: ASE_NotPresent on missing IO
  624. */
  625. DEFINE_THISCALL_WRAPPER(GetClockSources,12)
  626. ASIOError STDMETHODCALLTYPE GetClockSources(LPWINEASIO iface, ASIOClockSource *clocks, LONG *numSources)
  627. {
  628. TRACE("iface: %p, clocks: %p, numSources: %p\n", iface, clocks, numSources);
  629. if (!clocks || !numSources)
  630. return ASE_InvalidParameter;
  631. clocks->index = 0;
  632. clocks->associatedChannel = -1;
  633. clocks->associatedGroup = -1;
  634. clocks->isCurrentSource = ASIOTrue;
  635. strcpy(clocks->name, "Internal");
  636. *numSources = 1;
  637. return ASE_OK;
  638. }
  639. /*
  640. * ASIOError SetClockSource(LONG index);
  641. * Function: Set clock source
  642. * Parameters: index returned by ASIOGetClockSources() - See asio.h for more details
  643. * Returns: ASE_NotPresent on missing IO
  644. * ASE_InvalidMode may be returned if a clock can't be selected
  645. * ASE_NoClock should not be returned
  646. */
  647. DEFINE_THISCALL_WRAPPER(SetClockSource,8)
  648. ASIOError STDMETHODCALLTYPE SetClockSource(LPWINEASIO iface, LONG index)
  649. {
  650. TRACE("iface: %p, index: %i\n", iface, index);
  651. if (index != 0)
  652. return ASE_NotPresent;
  653. return ASE_OK;
  654. }
  655. /*
  656. * ASIOError GetSamplePosition (ASIOSamples *sPos, ASIOTimeStamp *tStamp);
  657. * Function: Return sample position and timestamp
  658. * Parameters: sPos holds the position on return, reset to 0 on ASIOStart()
  659. * tStamp holds the system time of sPos
  660. * Return: ASE_NotPresent on missing IO
  661. * ASE_SPNotAdvancing on missing clock
  662. */
  663. DEFINE_THISCALL_WRAPPER(GetSamplePosition,12)
  664. ASIOError STDMETHODCALLTYPE GetSamplePosition(LPWINEASIO iface, ASIOSamples *sPos, ASIOTimeStamp *tStamp)
  665. {
  666. IWineASIOImpl *This = (IWineASIOImpl*)iface;
  667. TRACE("iface: %p, sPos: %p, tStamp: %p\n", iface, sPos, tStamp);
  668. if (!sPos || !tStamp)
  669. return ASE_InvalidParameter;
  670. tStamp->lo = This->asio_time_stamp.lo;
  671. tStamp->hi = This->asio_time_stamp.hi;
  672. sPos->lo = This->asio_sample_position.lo;
  673. sPos->hi = 0; /* FIXME */
  674. return ASE_OK;
  675. }
  676. /*
  677. * ASIOError GetChannelInfo (ASIOChannelInfo *info);
  678. * Function: Retrive channel info. - See asio.h for more detail
  679. * Returns: ASE_NotPresent on missing IO
  680. */
  681. DEFINE_THISCALL_WRAPPER(GetChannelInfo,8)
  682. ASIOError STDMETHODCALLTYPE GetChannelInfo(LPWINEASIO iface, ASIOChannelInfo *info)
  683. {
  684. IWineASIOImpl *This = (IWineASIOImpl*)iface;
  685. /* TRACE("(iface: %p, info: %p\n", iface, info); */
  686. if (info->channel < 0 || (info->isInput ? info->channel >= This->wineasio_number_inputs : info->channel >= This->wineasio_number_outputs))
  687. return ASE_InvalidParameter;
  688. info->channelGroup = 0;
  689. info->type = ASIOSTFloat32LSB;
  690. if (info->isInput)
  691. {
  692. info->isActive = This->input_channel[info->channel].active;
  693. memcpy(info->name, This->input_channel[info->channel].port_name, ASIO_MAX_NAME_LENGTH);
  694. }
  695. else
  696. {
  697. info->isActive = This->output_channel[info->channel].active;
  698. memcpy(info->name, This->output_channel[info->channel].port_name, ASIO_MAX_NAME_LENGTH);
  699. }
  700. return ASE_OK;
  701. }
  702. /*
  703. * ASIOError CreateBuffers(ASIOBufferInfo *bufferInfo, LONG numChannels, LONG bufferSize, ASIOCallbacks *asioCallbacks);
  704. * Function: Allocate buffers for IO channels
  705. * Parameters: bufferInfo - pointer to an array of ASIOBufferInfo structures
  706. * numChannels - the total number of IO channels to be allocated
  707. * bufferSize - one of the buffer sizes retrieved with ASIOGetBufferSize()
  708. * asioCallbacks - pointer to an ASIOCallbacks structure
  709. * See asio.h for more detail
  710. * Returns: ASE_NoMemory if impossible to allocate enough memory
  711. * ASE_InvalidMode on unsupported bufferSize or invalid bufferInfo data
  712. * ASE_NotPresent on missing IO
  713. */
  714. DEFINE_THISCALL_WRAPPER(CreateBuffers,20)
  715. ASIOError STDMETHODCALLTYPE CreateBuffers(LPWINEASIO iface, ASIOBufferInfo *bufferInfo, LONG numChannels, LONG bufferSize, ASIOCallbacks *asioCallbacks)
  716. {
  717. IWineASIOImpl *This = (IWineASIOImpl*)iface;
  718. ASIOBufferInfo *buffer_info = bufferInfo;
  719. int i, j, k;
  720. TRACE("iface: %p, bufferInfo: %p, numChannels: %i, bufferSize: %i, asioCallbacks: %p\n", iface, bufferInfo, (int)numChannels, (int)bufferSize, asioCallbacks);
  721. if (This->asio_driver_state != Initialized)
  722. return ASE_NotPresent;
  723. if (!bufferInfo || !asioCallbacks)
  724. return ASE_InvalidMode;
  725. /* Check for invalid channel numbers */
  726. for (i = j = k = 0; i < numChannels; i++, buffer_info++)
  727. {
  728. if (buffer_info->isInput)
  729. {
  730. if (j++ >= This->wineasio_number_inputs)
  731. {
  732. WARN("Invalid input channel requested\n");
  733. return ASE_InvalidMode;
  734. }
  735. }
  736. else
  737. {
  738. if (k++ >= This->wineasio_number_outputs)
  739. {
  740. WARN("Invalid output channel requested\n");
  741. return ASE_InvalidMode;
  742. }
  743. }
  744. }
  745. /* set buf_size */
  746. if (This->wineasio_fixed_buffersize)
  747. {
  748. if (This->asio_current_buffersize != bufferSize)
  749. return ASE_InvalidMode;
  750. TRACE("Buffersize fixed at %i\n", (int)This->asio_current_buffersize);
  751. }
  752. else
  753. { /* fail if not a power of two and if out of range */
  754. if (!(bufferSize > 0 && !(bufferSize&(bufferSize-1))
  755. && bufferSize >= ASIO_MINIMUM_BUFFERSIZE
  756. && bufferSize <= ASIO_MAXIMUM_BUFFERSIZE))
  757. {
  758. WARN("Invalid buffersize %i requested\n", (int)bufferSize);
  759. return ASE_InvalidMode;
  760. }
  761. else
  762. {
  763. if (This->asio_current_buffersize == bufferSize)
  764. {
  765. TRACE("Buffer size already set to %i\n", (int)This->asio_current_buffersize);
  766. }
  767. else
  768. {
  769. This->asio_current_buffersize = bufferSize;
  770. if (jackbridge_set_buffer_size(This->jack_client, This->asio_current_buffersize))
  771. {
  772. WARN("JACK is unable to set buffersize to %i\n", (int)This->asio_current_buffersize);
  773. return ASE_HWMalfunction;
  774. }
  775. TRACE("Buffer size changed to %i\n", (int)This->asio_current_buffersize);
  776. }
  777. }
  778. }
  779. /* print/discover ASIO host capabilities */
  780. This->asio_callbacks = asioCallbacks;
  781. This->asio_time_info_mode = This->asio_can_time_code = FALSE;
  782. TRACE("The ASIO host supports ASIO v%i: ", This->asio_callbacks->asioMessage(kAsioEngineVersion, 0, 0, 0));
  783. if (This->asio_callbacks->asioMessage(kAsioSelectorSupported, kAsioBufferSizeChange, 0 , 0))
  784. TRACE("kAsioBufferSizeChange ");
  785. if (This->asio_callbacks->asioMessage(kAsioSelectorSupported, kAsioResetRequest, 0 , 0))
  786. TRACE("kAsioResetRequest ");
  787. if (This->asio_callbacks->asioMessage(kAsioSelectorSupported, kAsioResyncRequest, 0 , 0))
  788. TRACE("kAsioResyncRequest ");
  789. if (This->asio_callbacks->asioMessage(kAsioSelectorSupported, kAsioLatenciesChanged, 0 , 0))
  790. TRACE("kAsioLatenciesChanged ");
  791. if (This->asio_callbacks->asioMessage(kAsioSupportsTimeInfo, 0, 0, 0))
  792. {
  793. TRACE("bufferSwitchTimeInfo ");
  794. This->asio_time_info_mode = TRUE;
  795. if (This->asio_callbacks->asioMessage(kAsioSupportsTimeCode, 0, 0, 0))
  796. {
  797. TRACE("TimeCode");
  798. This->asio_can_time_code = TRUE;
  799. }
  800. }
  801. else
  802. TRACE("BufferSwitch");
  803. TRACE("\n");
  804. /* Allocate audio buffers */
  805. This->callback_audio_buffer = HeapAlloc(GetProcessHeap(), 0,
  806. (This->wineasio_number_inputs + This->wineasio_number_outputs) * 2 * This->asio_current_buffersize * sizeof(jack_default_audio_sample_t));
  807. if (!This->callback_audio_buffer)
  808. {
  809. ERR("Unable to allocate %i ASIO audio buffers\n", This->wineasio_number_inputs + This->wineasio_number_outputs);
  810. return ASE_NoMemory;
  811. }
  812. TRACE("%i ASIO audio buffers allocated (%i kB)\n", This->wineasio_number_inputs + This->wineasio_number_outputs,
  813. (int) ((This->wineasio_number_inputs + This->wineasio_number_outputs) * 2 * This->asio_current_buffersize * sizeof(jack_default_audio_sample_t) / 1024));
  814. for (i = 0; i < This->wineasio_number_inputs; i++)
  815. This->input_channel[i].audio_buffer = This->callback_audio_buffer + (i * 2 * This->asio_current_buffersize);
  816. for (i = 0; i < This->wineasio_number_outputs; i++)
  817. This->output_channel[i].audio_buffer = This->callback_audio_buffer + ((This->wineasio_number_inputs + i) * 2 * This->asio_current_buffersize);
  818. /* initialize ASIOBufferInfo structures */
  819. buffer_info = bufferInfo;
  820. This->asio_active_inputs = This->asio_active_outputs = 0;
  821. for (i = 0; i < This->wineasio_number_inputs; i++) {
  822. This->input_channel[i].active = ASIOFalse;
  823. }
  824. for (i = 0; i < This->wineasio_number_outputs; i++) {
  825. This->output_channel[i].active = ASIOFalse;
  826. }
  827. for (i = 0; i < numChannels; i++, buffer_info++)
  828. {
  829. if (buffer_info->isInput)
  830. {
  831. buffer_info->buffers[0] = &This->input_channel[buffer_info->channelNum].audio_buffer[0];
  832. buffer_info->buffers[1] = &This->input_channel[buffer_info->channelNum].audio_buffer[This->asio_current_buffersize];
  833. This->input_channel[buffer_info->channelNum].active = ASIOTrue;
  834. This->asio_active_inputs++;
  835. /* TRACE("ASIO audio buffer for channel %i as input %li created\n", i, This->asio_active_inputs); */
  836. }
  837. else
  838. {
  839. buffer_info->buffers[0] = &This->output_channel[buffer_info->channelNum].audio_buffer[0];
  840. buffer_info->buffers[1] = &This->output_channel[buffer_info->channelNum].audio_buffer[This->asio_current_buffersize];
  841. This->output_channel[buffer_info->channelNum].active = ASIOTrue;
  842. This->asio_active_outputs++;
  843. /* TRACE("ASIO audio buffer for channel %i as output %li created\n", i, This->asio_active_outputs); */
  844. }
  845. }
  846. TRACE("%i audio channels initialized\n", This->asio_active_inputs + This->asio_active_outputs);
  847. if (!jackbridge_activate(This->jack_client))
  848. return ASE_NotPresent;
  849. /* connect to the mod-desktop io */
  850. jackbridge_connect(This->jack_client, "mod-monitor:out_1", jackbridge_port_name(This->input_channel[0].port));
  851. jackbridge_connect(This->jack_client, "mod-monitor:out_2", jackbridge_port_name(This->input_channel[1].port));
  852. // TODO define inputs from mod-desktop side
  853. // jack_connect(This->jack_client, jack_port_name(This->output_channel[0].port), "");
  854. // jack_connect(This->jack_client, jack_port_name(This->output_channel[1].port), "");
  855. /* at this point all the connections are made and the jack process callback is outputting silence */
  856. This->asio_driver_state = Prepared;
  857. return ASE_OK;
  858. }
  859. /*
  860. * ASIOError DisposeBuffers(void);
  861. * Function: Release allocated buffers
  862. * Returns: ASE_InvalidMode if no buffers were previously allocated
  863. * ASE_NotPresent on missing IO
  864. * Implies: ASIOStop()
  865. */
  866. DEFINE_THISCALL_WRAPPER(DisposeBuffers,4)
  867. ASIOError STDMETHODCALLTYPE DisposeBuffers(LPWINEASIO iface)
  868. {
  869. IWineASIOImpl *This = (IWineASIOImpl*)iface;
  870. int i;
  871. TRACE("iface: %p\n", iface);
  872. if (This->asio_driver_state == Running)
  873. Stop (iface);
  874. if (This->asio_driver_state != Prepared)
  875. return ASE_NotPresent;
  876. if (!jackbridge_deactivate(This->jack_client))
  877. return ASE_NotPresent;
  878. This->asio_callbacks = NULL;
  879. for (i = 0; i < This->wineasio_number_inputs; i++)
  880. {
  881. This->input_channel[i].audio_buffer = NULL;
  882. This->input_channel[i].active = ASIOFalse;
  883. }
  884. for (i = 0; i < This->wineasio_number_outputs; i++)
  885. {
  886. This->output_channel[i].audio_buffer = NULL;
  887. This->output_channel[i].active = ASIOFalse;
  888. }
  889. This->asio_active_inputs = This->asio_active_outputs = 0;
  890. if (This->callback_audio_buffer)
  891. HeapFree(GetProcessHeap(), 0, This->callback_audio_buffer);
  892. This->asio_driver_state = Initialized;
  893. return ASE_OK;
  894. }
  895. /*
  896. * ASIOError ControlPanel(void);
  897. * Function: Open a control panel for driver settings
  898. * Returns: ASE_NotPresent if no control panel exists. Actually return code should be ignored
  899. * Note: Call the asioMessage callback if something has changed
  900. */
  901. DEFINE_THISCALL_WRAPPER(ControlPanel,4)
  902. ASIOError STDMETHODCALLTYPE ControlPanel(LPWINEASIO iface)
  903. {
  904. TRACE("iface: %p\n", iface);
  905. HANDLE openEvent = OpenEventA(EVENT_MODIFY_STATE, false, "Global\\mod-desktop-open");
  906. if (openEvent)
  907. {
  908. SetEvent(openEvent);
  909. CloseHandle(openEvent);
  910. }
  911. return ASE_OK;
  912. }
  913. /*
  914. * ASIOError Future(LONG selector, void *opt);
  915. * Function: Various, See asio.h for more detail
  916. * Returns: Depends on the selector but in general ASE_InvalidParameter on invalid selector
  917. * ASE_InvalidParameter if function is unsupported to disable further calls
  918. * ASE_SUCCESS on success, do not use AES_OK
  919. */
  920. DEFINE_THISCALL_WRAPPER(Future,12)
  921. ASIOError STDMETHODCALLTYPE Future(LPWINEASIO iface, LONG selector, void *opt)
  922. {
  923. IWineASIOImpl *This = (IWineASIOImpl *) iface;
  924. TRACE("iface: %p, selector: %i, opt: %p\n", iface, selector, opt);
  925. switch (selector)
  926. {
  927. case kAsioEnableTimeCodeRead:
  928. This->asio_can_time_code = TRUE;
  929. TRACE("The ASIO host enabled TimeCode\n");
  930. return ASE_SUCCESS;
  931. case kAsioDisableTimeCodeRead:
  932. This->asio_can_time_code = FALSE;
  933. TRACE("The ASIO host disabled TimeCode\n");
  934. return ASE_SUCCESS;
  935. case kAsioSetInputMonitor:
  936. TRACE("The driver denied request to set input monitor\n");
  937. return ASE_NotPresent;
  938. case kAsioTransport:
  939. TRACE("The driver denied request for ASIO Transport control\n");
  940. return ASE_InvalidParameter;
  941. case kAsioSetInputGain:
  942. TRACE("The driver denied request to set input gain\n");
  943. return ASE_InvalidParameter;
  944. case kAsioGetInputMeter:
  945. TRACE("The driver denied request to get input meter \n");
  946. return ASE_InvalidParameter;
  947. case kAsioSetOutputGain:
  948. TRACE("The driver denied request to set output gain\n");
  949. return ASE_InvalidParameter;
  950. case kAsioGetOutputMeter:
  951. TRACE("The driver denied request to get output meter\n");
  952. return ASE_InvalidParameter;
  953. case kAsioCanInputMonitor:
  954. TRACE("The driver does not support input monitor\n");
  955. return ASE_InvalidParameter;
  956. case kAsioCanTimeInfo:
  957. TRACE("The driver supports TimeInfo\n");
  958. return ASE_SUCCESS;
  959. case kAsioCanTimeCode:
  960. TRACE("The driver supports TimeCode\n");
  961. return ASE_SUCCESS;
  962. case kAsioCanTransport:
  963. TRACE("The driver denied request for ASIO Transport\n");
  964. return ASE_InvalidParameter;
  965. case kAsioCanInputGain:
  966. TRACE("The driver does not support input gain\n");
  967. return ASE_InvalidParameter;
  968. case kAsioCanInputMeter:
  969. TRACE("The driver does not support input meter\n");
  970. return ASE_InvalidParameter;
  971. case kAsioCanOutputGain:
  972. TRACE("The driver does not support output gain\n");
  973. return ASE_InvalidParameter;
  974. case kAsioCanOutputMeter:
  975. TRACE("The driver does not support output meter\n");
  976. return ASE_InvalidParameter;
  977. case kAsioSetIoFormat:
  978. TRACE("The driver denied request to set DSD IO format\n");
  979. return ASE_NotPresent;
  980. case kAsioGetIoFormat:
  981. TRACE("The driver denied request to get DSD IO format\n");
  982. return ASE_NotPresent;
  983. case kAsioCanDoIoFormat:
  984. TRACE("The driver does not support DSD IO format\n");
  985. return ASE_NotPresent;
  986. default:
  987. TRACE("ASIOFuture() called with undocumented selector\n");
  988. return ASE_InvalidParameter;
  989. }
  990. }
  991. /*
  992. * ASIOError OutputReady(void);
  993. * Function: Tells the driver that output bufffers are ready
  994. * Returns: ASE_OK if supported
  995. * ASE_NotPresent to disable
  996. */
  997. DEFINE_THISCALL_WRAPPER(OutputReady,4)
  998. ASIOError STDMETHODCALLTYPE OutputReady(LPWINEASIO iface)
  999. {
  1000. /* disabled to stop stand alone NI programs from spamming the console
  1001. TRACE("iface: %p\n", iface); */
  1002. return ASE_NotPresent;
  1003. }
  1004. /****************************************************************************
  1005. * JACK callbacks
  1006. */
  1007. static inline int jack_buffer_size_callback(jack_nframes_t nframes, void *arg)
  1008. {
  1009. IWineASIOImpl *This = (IWineASIOImpl*)arg;
  1010. if(This->asio_driver_state != Running)
  1011. return 0;
  1012. if (This->asio_callbacks->asioMessage(kAsioSelectorSupported, kAsioResetRequest, 0 , 0))
  1013. This->asio_callbacks->asioMessage(kAsioResetRequest, 0, 0, 0);
  1014. return 0;
  1015. }
  1016. static inline void jack_latency_callback(jack_latency_callback_mode_t mode, void *arg)
  1017. {
  1018. IWineASIOImpl *This = (IWineASIOImpl*)arg;
  1019. if(This->asio_driver_state != Running)
  1020. return;
  1021. if (This->asio_callbacks->asioMessage(kAsioSelectorSupported, kAsioLatenciesChanged, 0 , 0))
  1022. This->asio_callbacks->asioMessage(kAsioLatenciesChanged, 0, 0, 0);
  1023. return;
  1024. }
  1025. static inline int jack_process_callback(jack_nframes_t nframes, void *arg)
  1026. {
  1027. IWineASIOImpl *This = (IWineASIOImpl*)arg;
  1028. int i;
  1029. jack_transport_state_t jack_transport_state;
  1030. jack_position_t jack_position;
  1031. DWORD time;
  1032. /* output silence if the ASIO callback isn't running yet */
  1033. if (This->asio_driver_state != Running)
  1034. {
  1035. for (i = 0; i < This->asio_active_outputs; i++)
  1036. memset(jackbridge_port_get_buffer(This->output_channel[i].port, nframes),
  1037. 0, sizeof (jack_default_audio_sample_t) * nframes);
  1038. return 0;
  1039. }
  1040. /* copy jack to asio buffers */
  1041. for (i = 0; i < This->wineasio_number_inputs; i++)
  1042. if (This->input_channel[i].active == ASIOTrue)
  1043. memcpy (&This->input_channel[i].audio_buffer[nframes * This->asio_buffer_index],
  1044. jackbridge_port_get_buffer(This->input_channel[i].port, nframes),
  1045. sizeof (jack_default_audio_sample_t) * nframes);
  1046. if (This->asio_sample_position.lo > ULONG_MAX - nframes)
  1047. This->asio_sample_position.hi++;
  1048. This->asio_sample_position.lo += nframes;
  1049. time = timeGetTime();
  1050. This->asio_time_stamp.lo = time * 1000000;
  1051. This->asio_time_stamp.hi = ((unsigned long long) time * 1000000) >> 32;
  1052. if (This->asio_time_info_mode) /* use the newer bufferSwitchTimeInfo method if supported */
  1053. {
  1054. This->asio_time.timeInfo.samplePosition.lo = This->asio_sample_position.lo;
  1055. This->asio_time.timeInfo.samplePosition.hi = This->asio_sample_position.hi;
  1056. This->asio_time.timeInfo.systemTime.lo = This->asio_time_stamp.lo;
  1057. This->asio_time.timeInfo.systemTime.hi = This->asio_time_stamp.hi;
  1058. This->asio_time.timeInfo.sampleRate = This->asio_sample_rate;
  1059. This->asio_time.timeInfo.flags = kSystemTimeValid | kSamplePositionValid | kSampleRateValid;
  1060. if (This->asio_can_time_code) /* FIXME addionally use time code if supported */
  1061. {
  1062. jack_transport_state = jackbridge_transport_query(This->jack_client, &jack_position);
  1063. This->asio_time.timeCode.flags = kTcValid;
  1064. if (jack_transport_state == JackTransportRolling)
  1065. This->asio_time.timeCode.flags |= kTcRunning;
  1066. }
  1067. This->asio_callbacks->bufferSwitchTimeInfo(&This->asio_time, This->asio_buffer_index, ASIOTrue);
  1068. }
  1069. else
  1070. { /* use the old bufferSwitch method */
  1071. This->asio_callbacks->bufferSwitch(This->asio_buffer_index, ASIOTrue);
  1072. }
  1073. /* copy asio to jack buffers */
  1074. for (i = 0; i < This->wineasio_number_outputs; i++)
  1075. if (This->output_channel[i].active == ASIOTrue)
  1076. memcpy(jackbridge_port_get_buffer(This->output_channel[i].port, nframes),
  1077. &This->output_channel[i].audio_buffer[nframes * This->asio_buffer_index],
  1078. sizeof (jack_default_audio_sample_t) * nframes);
  1079. /* swith asio buffer */
  1080. This->asio_buffer_index = This->asio_buffer_index ? 0 : 1;
  1081. return 0;
  1082. }
  1083. static inline int jack_sample_rate_callback(jack_nframes_t nframes, void *arg)
  1084. {
  1085. IWineASIOImpl *This = (IWineASIOImpl*)arg;
  1086. if(This->asio_driver_state != Running)
  1087. return 0;
  1088. This->asio_sample_rate = nframes;
  1089. This->asio_callbacks->sampleRateDidChange(nframes);
  1090. return 0;
  1091. }
  1092. /*****************************************************************************
  1093. * Support functions
  1094. */
  1095. /* Funtion required as unicode.h no longer in WINE */
  1096. static WCHAR *strrchrW(const WCHAR* str, WCHAR ch)
  1097. {
  1098. WCHAR *ret = NULL;
  1099. do { if (*str == ch) ret = (WCHAR *)(ULONG_PTR)str; } while (*str++);
  1100. return ret;
  1101. }
  1102. static VOID configure_driver(IWineASIOImpl *This)
  1103. {
  1104. WCHAR application_path [MAX_PATH];
  1105. WCHAR *application_name;
  1106. /* Initialise most member variables,
  1107. * asio_sample_position, asio_time, & asio_time_stamp are initialized in Start() */
  1108. This->asio_active_inputs = 0;
  1109. This->asio_active_outputs = 0;
  1110. This->asio_buffer_index = 0;
  1111. This->asio_callbacks = NULL;
  1112. This->asio_can_time_code = FALSE;
  1113. This->asio_current_buffersize = 0;
  1114. This->asio_driver_state = Loaded;
  1115. This->asio_sample_rate = 48000;
  1116. This->asio_time_info_mode = FALSE;
  1117. This->asio_version = 92;
  1118. This->wineasio_number_inputs = 2;
  1119. This->wineasio_number_outputs = 2;
  1120. This->wineasio_fixed_buffersize = TRUE;
  1121. This->jack_client = NULL;
  1122. This->jack_client_name[0] = 0;
  1123. This->callback_audio_buffer = NULL;
  1124. This->input_channel = NULL;
  1125. This->output_channel = NULL;
  1126. /* get client name by stripping path and extension */
  1127. GetModuleFileNameW(0, application_path, MAX_PATH);
  1128. application_name = strrchrW(application_path, L'.');
  1129. *application_name = 0;
  1130. application_name = strrchrW(application_path, L'\\');
  1131. application_name++;
  1132. WideCharToMultiByte(CP_ACP, WC_SEPCHARS, application_name, -1, This->jack_client_name, ASIO_MAX_NAME_LENGTH, NULL, NULL);
  1133. return;
  1134. }
  1135. /* Allocate the interface pointer and associate it with the vtbl/WineASIO object */
  1136. HRESULT WINAPI WineASIOCreateInstance(REFIID riid, LPVOID *ppobj)
  1137. {
  1138. IWineASIOImpl *pobj;
  1139. /* TRACE("riid: %s, ppobj: %p\n", debugstr_guid(riid), ppobj); */
  1140. pobj = HeapAlloc(GetProcessHeap(), 0, sizeof(*pobj));
  1141. if (pobj == NULL)
  1142. {
  1143. WARN("out of memory\n");
  1144. return E_OUTOFMEMORY;
  1145. }
  1146. pobj->lpVtbl = &WineASIO_Vtbl;
  1147. pobj->ref = 1;
  1148. TRACE("pobj = %p\n", pobj);
  1149. *ppobj = pobj;
  1150. /* TRACE("return %p\n", *ppobj); */
  1151. return S_OK;
  1152. }