Guest User

asio.c WineASIO Ubuntu 13.04 amd64

a guest
May 18th, 2013
550
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 65.00 KB | None | 0 0
  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) 2010 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.  
  27. /*
  28.  *  Todo (maybe):
  29.  *  create a freely distributable asio.h replacement
  30.  *  add ASIOOutputReady() support
  31.  */
  32.  
  33. #include <stdio.h>
  34. #include <errno.h>
  35. #include <unistd.h>
  36. #include <sys/mman.h>
  37. #include <pthread.h>
  38.  
  39. #include "wine/debug.h"
  40. #include "objbase.h"
  41. #include "mmsystem.h"
  42. #include "winreg.h"
  43. #include "wine/unicode.h"
  44.  
  45. #include <jack/jack.h>
  46. #include <jack/thread.h>
  47.  
  48. #define IEEE754_64FLOAT 1
  49. #include "asio.h"
  50.  
  51. WINE_DEFAULT_DEBUG_CHANNEL(asio);
  52.  
  53. #define MAX_ENVIRONMENT_SIZE        6
  54. #define ASIO_MAX_NAME_LENGTH        32
  55. #define ASIO_MINIMUM_BUFFERSIZE     16
  56. #define ASIO_MAXIMUM_BUFFERSIZE     8192
  57. #define ASIO_PREFERRED_BUFFERSIZE   1024
  58.  
  59. /* ASIO drivers (breaking the COM specification) use the Microsoft variety of
  60.  * thiscall calling convention which gcc is unable to produce.  These macros
  61.  * add an extra layer to fixup the registers. Borrowed from config.h and the
  62.  * wine source code.
  63.  */
  64.  
  65. /* From config.h */
  66. #define __ASM_DEFINE_FUNC(name,suffix,code) asm(".text\n\t.align 4\n\t.globl " #name suffix "\n\t.type " #name suffix ",@function\n" #name suffix ":\n\t.cfi_startproc\n\t" code "\n\t.cfi_endproc\n\t.previous");
  67. #define __ASM_GLOBAL_FUNC(name,code) __ASM_DEFINE_FUNC(name,"",code)
  68. #define __ASM_NAME(name) name
  69. #define __ASM_STDCALL(args) ""
  70.  
  71. /* From wine source */
  72. #ifdef __i386__  /* thiscall functions are i386-specific */
  73.  
  74. #define THISCALL(func) __thiscall_ ## func
  75. #define THISCALL_NAME(func) __ASM_NAME("__thiscall_" #func)
  76. #define __thiscall __stdcall
  77. #define DEFINE_THISCALL_WRAPPER(func,args) \
  78.     extern void THISCALL(func)(void); \
  79.     __ASM_GLOBAL_FUNC(__thiscall_ ## func, \
  80.                       "popl %eax\n\t" \
  81.                       "pushl %ecx\n\t" \
  82.                       "pushl %eax\n\t" \
  83.                       "jmp " __ASM_NAME(#func) __ASM_STDCALL(args) )
  84. #else /* __i386__ */
  85.  
  86. #define THISCALL(func) func
  87. #define THISCALL_NAME(func) __ASM_NAME(#func)
  88. #define __thiscall __cdecl
  89. #define DEFINE_THISCALL_WRAPPER(func,args) /* nothing */
  90.  
  91. #endif /* __i386__ */
  92.  
  93. /* Hide ELF symbols for the COM members - No need to to export them */
  94. #define HIDDEN __attribute__ ((visibility("hidden")))
  95.  
  96. /*****************************************************************************
  97.  * IWineAsio interface
  98.  */
  99.  
  100. #define INTERFACE IWineASIO
  101. DECLARE_INTERFACE_(IWineASIO,IUnknown)
  102. {
  103.     STDMETHOD_(HRESULT, QueryInterface)         (THIS_ IID riid, void** ppvObject) PURE;
  104.     STDMETHOD_(ULONG, AddRef)                   (THIS) PURE;
  105.     STDMETHOD_(ULONG, Release)                  (THIS) PURE;
  106.     STDMETHOD_(ASIOBool, Init)                  (THIS_ void *sysRef) PURE;
  107.     STDMETHOD_(void, GetDriverName)             (THIS_ char *name) PURE;
  108.     STDMETHOD_(LONG, GetDriverVersion)          (THIS) PURE;
  109.     STDMETHOD_(void, GetErrorMessage)           (THIS_ char *string) PURE;
  110.     STDMETHOD_(ASIOError, Start)                (THIS) PURE;
  111.     STDMETHOD_(ASIOError, Stop)                 (THIS) PURE;
  112.     STDMETHOD_(ASIOError, GetChannels)          (THIS_ LONG *numInputChannels, LONG *numOutputChannels) PURE;
  113.     STDMETHOD_(ASIOError, GetLatencies)         (THIS_ LONG *inputLatency, LONG *outputLatency) PURE;
  114.     STDMETHOD_(ASIOError, GetBufferSize)        (THIS_ LONG *minSize, LONG *maxSize, LONG *preferredSize, LONG *granularity) PURE;
  115.     STDMETHOD_(ASIOError, CanSampleRate)        (THIS_ ASIOSampleRate sampleRate) PURE;
  116.     STDMETHOD_(ASIOError, GetSampleRate)        (THIS_ ASIOSampleRate *sampleRate) PURE;
  117.     STDMETHOD_(ASIOError, SetSampleRate)        (THIS_ ASIOSampleRate sampleRate) PURE;
  118.     STDMETHOD_(ASIOError, GetClockSources)      (THIS_ ASIOClockSource *clocks, LONG *numSources) PURE;
  119.     STDMETHOD_(ASIOError, SetClockSource)       (THIS_ LONG index) PURE;
  120.     STDMETHOD_(ASIOError, GetSamplePosition)    (THIS_ ASIOSamples *sPos, ASIOTimeStamp *tStamp) PURE;
  121.     STDMETHOD_(ASIOError, GetChannelInfo)       (THIS_ ASIOChannelInfo *info) PURE;
  122.     STDMETHOD_(ASIOError, CreateBuffers)        (THIS_ ASIOBufferInfo *bufferInfo, LONG numChannels, LONG bufferSize, ASIOCallbacks *asioCallbacks) PURE;
  123.     STDMETHOD_(ASIOError, DisposeBuffers)       (THIS) PURE;
  124.     STDMETHOD_(ASIOError, ControlPanel)         (THIS) PURE;
  125.     STDMETHOD_(ASIOError, Future)               (THIS_ LONG selector,void *opt) PURE;
  126.     STDMETHOD_(ASIOError, OutputReady)          (THIS) PURE;
  127. };
  128. #undef INTERFACE
  129.  
  130. typedef struct IWineASIO *LPWINEASIO;
  131.  
  132. typedef struct IOChannel
  133. {
  134.     ASIOBool                    active;
  135.     jack_default_audio_sample_t *audio_buffer;
  136.     char                        port_name[ASIO_MAX_NAME_LENGTH];
  137.     jack_port_t                 *port;
  138. } IOChannel;
  139.  
  140. typedef struct IWineASIOImpl
  141. {
  142.     /* COM stuff */
  143.     const IWineASIOVtbl         *lpVtbl;
  144.     LONG                        ref;
  145.  
  146.     /* The app's main window handle on windows, 0 on OS/X */
  147.     HWND                        sys_ref;
  148.  
  149.     /* ASIO stuff */
  150.     LONG                        asio_active_inputs;
  151.     LONG                        asio_active_outputs;
  152.     BOOL                        asio_buffer_index;
  153.     ASIOCallbacks               *asio_callbacks;
  154.     BOOL                        asio_can_time_code;
  155.     LONG                        asio_current_buffersize;
  156.     INT                         asio_driver_state;
  157.     ASIOSamples                 asio_sample_position;
  158.     ASIOSampleRate              asio_sample_rate;
  159.     ASIOTime                    asio_time;
  160.     BOOL                        asio_time_info_mode;
  161.     ASIOTimeStamp               asio_time_stamp;
  162.     LONG                        asio_version;
  163.  
  164.     /* WineASIO configuration options */
  165.     LONG                        wineasio_number_inputs;
  166.     LONG                        wineasio_number_outputs;
  167.     BOOL                        wineasio_autostart_server;
  168.     BOOL                        wineasio_connect_to_hardware;
  169.     LONG                        wineasio_fixed_buffersize;
  170.     LONG                        wineasio_preferred_buffersize;
  171.  
  172.     /* JACK stuff */
  173.     jack_client_t               *jack_client;
  174.     char                        jack_client_name[ASIO_MAX_NAME_LENGTH];
  175.     int                         jack_num_input_ports;
  176.     int                         jack_num_output_ports;
  177.     const char                  **jack_input_ports;
  178.     const char                  **jack_output_ports;
  179.  
  180.     /* process callback buffers */
  181.     jack_default_audio_sample_t *callback_audio_buffer;
  182.     IOChannel                   *input_channel;
  183.     IOChannel                   *output_channel;
  184. } IWineASIOImpl;
  185.  
  186. enum { Loaded, Initialized, Prepared, Running };
  187.  
  188. /****************************************************************************
  189.  *  Interface Methods
  190.  */
  191.  
  192. /*
  193.  *  as seen from the WineASIO source
  194.  */
  195.  
  196. HIDDEN HRESULT   STDMETHODCALLTYPE      QueryInterface(LPWINEASIO iface, REFIID riid, void **ppvObject);
  197. HIDDEN ULONG     STDMETHODCALLTYPE      AddRef(LPWINEASIO iface);
  198. HIDDEN ULONG     STDMETHODCALLTYPE      Release(LPWINEASIO iface);
  199. HIDDEN ASIOBool  STDMETHODCALLTYPE      Init(LPWINEASIO iface, void *sysRef);
  200. HIDDEN void      STDMETHODCALLTYPE      GetDriverName(LPWINEASIO iface, char *name);
  201. HIDDEN LONG      STDMETHODCALLTYPE      GetDriverVersion(LPWINEASIO iface);
  202. HIDDEN void      STDMETHODCALLTYPE      GetErrorMessage(LPWINEASIO iface, char *string);
  203. HIDDEN ASIOError STDMETHODCALLTYPE      Start(LPWINEASIO iface);
  204. HIDDEN ASIOError STDMETHODCALLTYPE      Stop(LPWINEASIO iface);
  205. HIDDEN ASIOError STDMETHODCALLTYPE      GetChannels (LPWINEASIO iface, LONG *numInputChannels, LONG *numOutputChannels);
  206. HIDDEN ASIOError STDMETHODCALLTYPE      GetLatencies(LPWINEASIO iface, LONG *inputLatency, LONG *outputLatency);
  207. HIDDEN ASIOError STDMETHODCALLTYPE      GetBufferSize(LPWINEASIO iface, LONG *minSize, LONG *maxSize, LONG *preferredSize, LONG *granularity);
  208. HIDDEN ASIOError STDMETHODCALLTYPE      CanSampleRate(LPWINEASIO iface, ASIOSampleRate sampleRate);
  209. HIDDEN ASIOError STDMETHODCALLTYPE      GetSampleRate(LPWINEASIO iface, ASIOSampleRate *sampleRate);
  210. HIDDEN ASIOError STDMETHODCALLTYPE      SetSampleRate(LPWINEASIO iface, ASIOSampleRate sampleRate);
  211. HIDDEN ASIOError STDMETHODCALLTYPE      GetClockSources(LPWINEASIO iface, ASIOClockSource *clocks, LONG *numSources);
  212. HIDDEN ASIOError STDMETHODCALLTYPE      SetClockSource(LPWINEASIO iface, LONG index);
  213. HIDDEN ASIOError STDMETHODCALLTYPE      GetSamplePosition(LPWINEASIO iface, ASIOSamples *sPos, ASIOTimeStamp *tStamp);
  214. HIDDEN ASIOError STDMETHODCALLTYPE      GetChannelInfo(LPWINEASIO iface, ASIOChannelInfo *info);
  215. HIDDEN ASIOError STDMETHODCALLTYPE      CreateBuffers(LPWINEASIO iface, ASIOBufferInfo *bufferInfo, LONG numChannels, LONG bufferSize, ASIOCallbacks *asioCallbacks);
  216. HIDDEN ASIOError STDMETHODCALLTYPE      DisposeBuffers(LPWINEASIO iface);
  217. HIDDEN ASIOError STDMETHODCALLTYPE      ControlPanel(LPWINEASIO iface);
  218. HIDDEN ASIOError STDMETHODCALLTYPE      Future(LPWINEASIO iface, LONG selector, void *opt);
  219. HIDDEN ASIOError STDMETHODCALLTYPE      OutputReady(LPWINEASIO iface);
  220.  
  221. /*
  222.  * thiscall wrappers for the vtbl (as seen from app side 32bit)
  223.  */
  224.  
  225. HIDDEN void __thiscall_Init(void);
  226. HIDDEN void __thiscall_GetDriverName(void);
  227. HIDDEN void __thiscall_GetDriverVersion(void);
  228. HIDDEN void __thiscall_GetErrorMessage(void);
  229. HIDDEN void __thiscall_Start(void);
  230. HIDDEN void __thiscall_Stop(void);
  231. HIDDEN void __thiscall_GetChannels(void);
  232. HIDDEN void __thiscall_GetLatencies(void);
  233. HIDDEN void __thiscall_GetBufferSize(void);
  234. HIDDEN void __thiscall_CanSampleRate(void);
  235. HIDDEN void __thiscall_GetSampleRate(void);
  236. HIDDEN void __thiscall_SetSampleRate(void);
  237. HIDDEN void __thiscall_GetClockSources(void);
  238. HIDDEN void __thiscall_SetClockSource(void);
  239. HIDDEN void __thiscall_GetSamplePosition(void);
  240. HIDDEN void __thiscall_GetChannelInfo(void);
  241. HIDDEN void __thiscall_CreateBuffers(void);
  242. HIDDEN void __thiscall_DisposeBuffers(void);
  243. HIDDEN void __thiscall_ControlPanel(void);
  244. HIDDEN void __thiscall_Future(void);
  245. HIDDEN void __thiscall_OutputReady(void);
  246.  
  247. /*
  248.  *  Jack callbacks
  249.  */
  250.  
  251. static int  bufsize_callback (jack_nframes_t nframes, void *arg);
  252. static int  process_callback (jack_nframes_t nframes, void *arg);
  253. static int  srate_callback (jack_nframes_t nframes, void *arg);
  254. static int  xrun_callback(void *arg);
  255.  
  256. /*
  257.  *  Support functions
  258.  */
  259.  
  260. HRESULT WINAPI  WineASIOCreateInstance(REFIID riid, LPVOID *ppobj);
  261. static  BOOL    configure_driver(IWineASIOImpl *This);
  262.  
  263. #ifdef __WINESRC__
  264. static DWORD WINAPI jack_thread_creator_helper(LPVOID arg);
  265. static int          jack_thread_creator(pthread_t* thread_id, const pthread_attr_t* attr, void *(*function)(void*), void* arg);
  266. #endif
  267.  
  268. /* {48D0C522-BFCC-45cc-8B84-17F25F33E6E8} */
  269. static GUID const CLSID_WineASIO = {
  270. 0x48d0c522, 0xbfcc, 0x45cc, { 0x8b, 0x84, 0x17, 0xf2, 0x5f, 0x33, 0xe6, 0xe8 } };
  271.  
  272. static const IWineASIOVtbl WineASIO_Vtbl =
  273. {
  274.     (void *) QueryInterface,
  275.     (void *) AddRef,
  276.     (void *) Release,
  277.  
  278.     (void *) THISCALL(Init),
  279.     (void *) THISCALL(GetDriverName),
  280.     (void *) THISCALL(GetDriverVersion),
  281.     (void *) THISCALL(GetErrorMessage),
  282.     (void *) THISCALL(Start),
  283.     (void *) THISCALL(Stop),
  284.     (void *) THISCALL(GetChannels),
  285.     (void *) THISCALL(GetLatencies),
  286.     (void *) THISCALL(GetBufferSize),
  287.     (void *) THISCALL(CanSampleRate),
  288.     (void *) THISCALL(GetSampleRate),
  289.     (void *) THISCALL(SetSampleRate),
  290.     (void *) THISCALL(GetClockSources),
  291.     (void *) THISCALL(SetClockSource),
  292.     (void *) THISCALL(GetSamplePosition),
  293.     (void *) THISCALL(GetChannelInfo),
  294.     (void *) THISCALL(CreateBuffers),
  295.     (void *) THISCALL(DisposeBuffers),
  296.     (void *) THISCALL(ControlPanel),
  297.     (void *) THISCALL(Future),
  298.     (void *) THISCALL(OutputReady)
  299. };
  300.  
  301. #ifdef __WINESRC__
  302. /* structure needed to create the JACK callback thread in the wine process context */
  303. struct {
  304.     void        *(*jack_callback_thread) (void*);
  305.     void        *arg;
  306.     pthread_t   jack_callback_pthread_id;
  307.     HANDLE      jack_callback_thread_created;
  308. } jack_thread_creator_privates;
  309. #endif
  310.  
  311. /*****************************************************************************
  312.  * Interface method definitions
  313.  */
  314.  
  315.  
  316. HIDDEN HRESULT STDMETHODCALLTYPE QueryInterface(LPWINEASIO iface, REFIID riid, void **ppvObject)
  317. {
  318.     IWineASIOImpl   *This = (IWineASIOImpl *)iface;
  319.  
  320.     TRACE("iface: %p, riid: %s, ppvObject: %p)\n", iface, debugstr_guid(riid), ppvObject);
  321.  
  322.     if (ppvObject == NULL)
  323.         return E_INVALIDARG;
  324.  
  325.     if (IsEqualIID(&CLSID_WineASIO, riid))
  326.     {
  327.         AddRef(iface);
  328.         *ppvObject = This;
  329.         return S_OK;
  330.     }
  331.  
  332.     return E_NOINTERFACE;
  333. }
  334.  
  335. /*
  336.  * ULONG STDMETHODCALLTYPE AddRef(LPWINEASIO iface);
  337.  * Function: Increment the reference count on the object
  338.  * Returns:  Ref count
  339.  */
  340.  
  341. HIDDEN ULONG STDMETHODCALLTYPE AddRef(LPWINEASIO iface)
  342. {
  343.     IWineASIOImpl   *This = (IWineASIOImpl *)iface;
  344.     ULONG           ref = InterlockedIncrement(&(This->ref));
  345.  
  346.     TRACE("iface: %p, ref count is %d\n", iface, ref);
  347.     return ref;
  348. }
  349.  
  350. /*
  351.  * ULONG Release (LPWINEASIO iface);
  352.  *  Function:   Destroy the interface
  353.  *  Returns:    Ref count
  354.  *  Implies:    ASIOStop() and ASIODisposeBuffers()
  355.  */
  356.  
  357. HIDDEN ULONG STDMETHODCALLTYPE Release(LPWINEASIO iface)
  358. {
  359.     IWineASIOImpl   *This = (IWineASIOImpl *)iface;
  360.     ULONG            ref = InterlockedDecrement(&This->ref);
  361.     int             i;
  362.  
  363.     TRACE("iface: %p, ref count is %d\n", iface, ref);
  364.  
  365.     if (This->asio_driver_state == Running)
  366.         Stop(iface);
  367.     if (This->asio_driver_state == Prepared)
  368.         DisposeBuffers(iface);
  369.  
  370.     if (This->asio_driver_state == Initialized)
  371.     {
  372.         /* just for good measure we deinitialize IOChannel structures and unregister JACK ports */
  373.         for (i = 0; i < This->wineasio_number_inputs; i++)
  374.         {
  375.             if(jack_port_unregister (This->jack_client, This->input_channel[i].port))
  376.                 MESSAGE("Error trying to unregister port %s\n", This->input_channel[i].port_name);
  377.             This->input_channel[i].active = ASIOFalse;
  378.             This->input_channel[i].port = NULL;
  379.         }
  380.         for (i = 0; i < This->wineasio_number_outputs; i++)
  381.         {
  382.             if(jack_port_unregister (This->jack_client, This->output_channel[i].port))
  383.                 MESSAGE("Error trying to unregister port %s\n", This->output_channel[i].port_name);
  384.             This->output_channel[i].active = ASIOFalse;
  385.             This->output_channel[i].port = NULL;
  386.         }
  387.         This->asio_active_inputs = This->asio_active_outputs = 0;
  388.         TRACE("%i IOChannel structures released\n", This->wineasio_number_inputs + This->wineasio_number_outputs);
  389.  
  390.         if (This->jack_output_ports)
  391.             jack_free (This->jack_output_ports);
  392.         if (This->jack_input_ports)
  393.             jack_free (This->jack_input_ports);
  394.  
  395.         if (This->jack_client)
  396.             if (jack_client_close(This->jack_client))
  397.                 MESSAGE("Error trying to close JACK client\n");
  398.  
  399.         if (This->input_channel)
  400.             HeapFree(GetProcessHeap(), 0, This->input_channel);
  401.     }
  402.     TRACE("WineASIO terminated\n\n");
  403.     if (ref == 0)
  404.         HeapFree(GetProcessHeap(), 0, This);
  405.     return ref;
  406. }
  407.  
  408. /*
  409.  * ASIOBool Init (void *sysRef);
  410.  *  Function:   Initialize the driver
  411.  *  Parameters: Pointer to "This"
  412.  *              sysHanle is 0 on OS/X and on windows it contains the applications main window handle
  413.  *  Returns:    ASIOFalse on error, and ASIOTrue on success
  414.  */
  415.  
  416. DEFINE_THISCALL_WRAPPER(Init,8)
  417. HIDDEN ASIOBool STDMETHODCALLTYPE Init(LPWINEASIO iface, void *sysRef)
  418. {
  419.     IWineASIOImpl   *This = (IWineASIOImpl *)iface;
  420.     jack_status_t   jack_status;
  421.     jack_options_t  jack_options = JackNullOption;
  422.     int             i;
  423.  
  424.     TRACE("iface: %p, sysRef: %p\n", iface, sysRef);
  425.  
  426.     This->sys_ref = sysRef;
  427.  
  428. #ifdef __WINESRC__
  429.     mlockall(MCL_FUTURE);
  430. #endif
  431.  
  432.     if (!configure_driver(This))
  433.     {
  434.         WARN("Unable to configure WineASIO\n");
  435.         return ASIOFalse;
  436.     }
  437.  
  438.     if (!This->wineasio_autostart_server)
  439.         jack_options |= JackNoStartServer;
  440.     This->jack_client = jack_client_open(This->jack_client_name, jack_options, &jack_status);
  441.  
  442.     if (This->jack_client == NULL)
  443.     {
  444.         WARN("Unable to open a JACK client as: %s\n", This->jack_client_name);
  445.         return ASIOFalse;
  446.     }
  447.     TRACE("JACK client opened as: '%s'\n", jack_get_client_name(This->jack_client));
  448.  
  449.     if (!(This->asio_sample_rate = jack_get_sample_rate(This->jack_client)))
  450.     {
  451.         WARN("Unable to get samplerate from JACK\n");
  452.         return ASIOFalse;
  453.     }
  454.  
  455.     if (!(This->asio_current_buffersize = jack_get_buffer_size(This->jack_client)))
  456.     {
  457.         WARN("Unable to get buffer size from JACK\n");
  458.         return ASIOFalse;
  459.     }
  460.  
  461.     /* Allocate IOChannel structures */
  462.     This->input_channel = HeapAlloc(GetProcessHeap(), 0, (This->wineasio_number_inputs + This->wineasio_number_outputs) * sizeof(IOChannel));
  463.     if (!This->input_channel)
  464.     {
  465.         jack_client_close(This->jack_client);
  466.         ERR("Unable to allocate IOChannel structures for %i channels\n", This->wineasio_number_inputs);
  467.         return ASIOFalse;
  468.     }
  469.     This->output_channel = This->input_channel + This->wineasio_number_inputs;
  470.     TRACE("%i IOChannel structures allocated\n", This->wineasio_number_inputs + This->wineasio_number_outputs);
  471.  
  472.     /* Get and count physical JACK ports */
  473.     This->jack_input_ports = jack_get_ports(This->jack_client, NULL, NULL, 0);
  474.     for (This->jack_num_input_ports = 0; This->jack_input_ports && This->jack_input_ports[This->jack_num_input_ports]; This->jack_num_input_ports++)
  475.         ;
  476.     This->jack_output_ports = jack_get_ports(This->jack_client, NULL, NULL, 0);
  477.     for (This->jack_num_output_ports = 0; This->jack_output_ports && This->jack_output_ports[This->jack_num_output_ports]; This->jack_num_output_ports++)
  478.         ;
  479.  
  480.     /* Initialize IOChannel structures */
  481.     for (i = 0; i < This->wineasio_number_inputs; i++)
  482.     {
  483.         This->input_channel[i].active = ASIOFalse;
  484.         This->input_channel[i].port = NULL;
  485.         snprintf(This->input_channel[i].port_name, ASIO_MAX_NAME_LENGTH, "in_%i", i + 1);
  486.         This->input_channel[i].port = jack_port_register(This->jack_client,
  487.             This->input_channel[i].port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, i);
  488.         /* TRACE("IOChannel structure initialized for input %d: '%s'\n", i, This->input_channel[i].port_name); */
  489.     }
  490.     for (i = 0; i < This->wineasio_number_outputs; i++)
  491.     {
  492.         This->output_channel[i].active = ASIOFalse;
  493.         This->output_channel[i].port = NULL;
  494.         snprintf(This->output_channel[i].port_name, ASIO_MAX_NAME_LENGTH, "out_%i", i + 1);
  495.         This->output_channel[i].port = jack_port_register(This->jack_client,
  496.             This->output_channel[i].port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, i);
  497.         /* TRACE("IOChannel structure initialized for output %d: '%s'\n", i, This->output_channel[i].port_name); */
  498.     }
  499.     TRACE("%i IOChannel structures initialized\n", This->wineasio_number_inputs + This->wineasio_number_outputs);
  500.  
  501. #ifdef __WINESRC__
  502.     jack_set_thread_creator(jack_thread_creator);
  503. #endif
  504.  
  505.     if (jack_set_process_callback(This->jack_client, process_callback, This))
  506.     {
  507.         jack_client_close(This->jack_client);
  508.         HeapFree(GetProcessHeap(), 0, This->input_channel);
  509.         ERR("Unable to register JACK process callback\n");
  510.         return ASIOFalse;
  511.     }
  512.  
  513.     if (jack_set_buffer_size_callback(This->jack_client, bufsize_callback, This))
  514.     {
  515.         jack_client_close(This->jack_client);
  516.         HeapFree(GetProcessHeap(), 0, This->input_channel);
  517.         ERR("Unable to register JACK buffersize change callback\n");
  518.         return ASIOFalse;
  519.     }
  520.  
  521.     if (jack_set_sample_rate_callback (This->jack_client, srate_callback, This))
  522.     {
  523.         jack_client_close(This->jack_client);
  524.         HeapFree(GetProcessHeap(), 0, This->input_channel);
  525.         ERR("Unable to register JACK samplerate change callback\n");
  526.         return ASIOFalse;
  527.     }
  528.  
  529.  
  530.     if (jack_set_xrun_callback(This->jack_client, xrun_callback, This))
  531.     {
  532.         jack_client_close(This->jack_client);
  533.         HeapFree(GetProcessHeap(), 0, This->input_channel);
  534.         ERR("Unable to register JACK xrun callback\n");
  535.         return ASIOFalse;
  536.     }
  537.  
  538.     This->asio_driver_state = Initialized;
  539.     TRACE("WineASIO 0.%.1f initialized\n",(float) This->asio_version / 10);
  540.     return ASIOTrue;
  541. }
  542.  
  543. /*
  544.  * void GetDriverName(char *name);
  545.  *  Function:    Returns the driver name in name
  546.  */
  547.  
  548. DEFINE_THISCALL_WRAPPER(GetDriverName,8)
  549. HIDDEN void STDMETHODCALLTYPE GetDriverName(LPWINEASIO iface, char *name)
  550. {
  551.     TRACE("iface: %p, name: %p\n", iface, name);
  552.     strcpy(name, "WineASIO");
  553.     return;
  554. }
  555.  
  556. /*
  557.  * LONG GetDriverVersion (void);
  558.  *  Function:    Returns the driver version number
  559.  */
  560.  
  561. DEFINE_THISCALL_WRAPPER(GetDriverVersion,4)
  562. HIDDEN LONG STDMETHODCALLTYPE GetDriverVersion(LPWINEASIO iface)
  563. {
  564.     IWineASIOImpl   *This = (IWineASIOImpl*)iface;
  565.  
  566.     TRACE("iface: %p\n", iface);
  567.     return This->asio_version;
  568. }
  569.  
  570. /*
  571.  * void GetErrorMessage(char *string);
  572.  *  Function:    Returns an error message for the last occured error in string
  573.  */
  574.  
  575. DEFINE_THISCALL_WRAPPER(GetErrorMessage,8)
  576. HIDDEN void STDMETHODCALLTYPE GetErrorMessage(LPWINEASIO iface, char *string)
  577. {
  578.     TRACE("iface: %p, string: %p)\n", iface, string);
  579.     strcpy(string, "WineASIO does not return error messages\n");
  580.     return;
  581. }
  582.  
  583. /*
  584.  * ASIOError Start(void);
  585.  *  Function:    Start JACK IO processing and reset the sample counter to zero
  586.  *  Returns:     ASE_NotPresent if IO is missing
  587.  *               ASE_HWMalfunction if JACK fails to start
  588.  */
  589.  
  590. DEFINE_THISCALL_WRAPPER(Start,4)
  591. HIDDEN ASIOError STDMETHODCALLTYPE Start(LPWINEASIO iface)
  592. {
  593.     IWineASIOImpl   *This = (IWineASIOImpl*)iface;
  594.     int             i;
  595.  
  596. #ifndef _WIN64x
  597.     DWORD           temp_time;
  598. #endif
  599.  
  600.     TRACE("iface: %p\n", iface);
  601.  
  602.     if (This->asio_driver_state != Prepared)
  603.     {
  604.         ERR("Unable to start WineASIO\n");
  605.         return ASE_NotPresent;
  606.     }
  607.  
  608.     /* Zero the audio buffer */
  609.     for (i = 0; i < (This->wineasio_number_inputs + This->wineasio_number_outputs) * 2 * This->asio_current_buffersize; i++)
  610.         This->callback_audio_buffer[i] = 0;
  611.  
  612.     /* prime the callback */
  613.     This->asio_buffer_index =  0;
  614.     if (This->asio_callbacks)
  615.     {
  616. #ifdef _WIN64x
  617.         This->asio_sample_position = 0;
  618.         This->asio_time_stamp = timeGetTime() * 1000000;
  619. #else
  620.         This->asio_sample_position.hi = This->asio_sample_position.lo = 0;
  621.         temp_time = timeGetTime();
  622.         This->asio_time_stamp.lo = temp_time * 1000000;
  623.         This->asio_time_stamp.hi = ((unsigned long long) temp_time * 1000000) >> 32;
  624. #endif
  625.         This->asio_time_info_mode = FALSE;
  626.         This->asio_can_time_code = FALSE;
  627.  
  628.         if (This->asio_callbacks->asioMessage(kAsioSupportsTimeInfo, 0, 0, 0))
  629.         {
  630.             TRACE("TimeInfo mode enabled\n");
  631.             This->asio_time_info_mode = TRUE;
  632. #ifdef _WIN64x
  633.             This->asio_time.timeInfo.systemTime = This->asio_time_stamp;
  634.             This->asio_time.timeInfo.samplePosition = 0;
  635. #else
  636.             This->asio_time.timeInfo.systemTime.hi = This->asio_time_stamp.hi;
  637.             This->asio_time.timeInfo.systemTime.lo = This->asio_time_stamp.lo;
  638.             This->asio_time.timeInfo.samplePosition.hi = This->asio_time.timeInfo.samplePosition.lo = 0;
  639. #endif
  640.             This->asio_time.timeCode.speed = 0;
  641.             This->asio_time.timeInfo.sampleRate = This->asio_sample_rate;
  642.             This->asio_time.timeInfo.flags = kSystemTimeValid | kSamplePositionValid | kSampleRateValid;
  643.             if (This->asio_callbacks->asioMessage(kAsioSupportsTimeCode,  0, 0, 0))
  644.             {
  645.                 TRACE("TimeCode supported\n");
  646.                 This->asio_can_time_code = TRUE;
  647. #ifdef _WIN64x
  648.                 This->asio_time.timeCode.timeCodeSamples = This->asio_time_stamp;
  649. #else
  650.                 This->asio_time.timeCode.timeCodeSamples.hi = This->asio_time_stamp.hi;
  651.                 This->asio_time.timeCode.timeCodeSamples.lo = This->asio_time_stamp.lo;
  652. #endif
  653.                 This->asio_time.timeCode.flags = ~(kTcValid | kTcRunning);
  654.             }
  655.             This->asio_callbacks->bufferSwitchTimeInfo(&This->asio_time, This->asio_buffer_index, ASIOTrue);
  656.         }
  657.         else
  658.         {
  659.             TRACE("Runnning simple BufferSwitch() callback\n");
  660.             This->asio_callbacks->bufferSwitch(This->asio_buffer_index, ASIOTrue);
  661.         }
  662.         This->asio_buffer_index = This->asio_buffer_index ? 0 : 1;
  663.     }
  664.     else
  665.     {
  666.         WARN("The ASIO host supplied no callback structure\n");
  667.         return ASE_NotPresent;
  668.     }
  669.  
  670.     if (jack_activate(This->jack_client))
  671.     {
  672.         ERR("Unable to activate JACK client\n");
  673.         return ASE_NotPresent;
  674.     }
  675.  
  676.     /* connect to the hardware io */
  677.     jack_connect(This->jack_client, "system:capture_1", jack_port_name(This->input_channel[0].port));
  678.     jack_connect(This->jack_client, "system:capture_2", jack_port_name(This->input_channel[1].port));
  679.     jack_connect(This->jack_client, jack_port_name(This->output_channel[0].port), "system:playback_1");
  680.     jack_connect(This->jack_client, jack_port_name(This->output_channel[1].port), "system:playback_2");
  681.  
  682.     This->asio_driver_state = Running;
  683.     TRACE("WineASIO successfully loaded\n");
  684.     return ASE_OK;
  685. }
  686.  
  687. /*
  688.  * ASIOError Stop(void);
  689.  *  Function:   Stop JACK IO processing
  690.  *  Returns:    ASE_NotPresent on missing IO
  691.  *  Note:       BufferSwitch() must not called after returning
  692.  */
  693.  
  694. DEFINE_THISCALL_WRAPPER(Stop,4)
  695. HIDDEN ASIOError STDMETHODCALLTYPE Stop(LPWINEASIO iface)
  696. {
  697.     IWineASIOImpl   *This = (IWineASIOImpl*)iface;
  698.  
  699.     TRACE("iface: %p\n", iface);
  700.  
  701.     if (This->asio_driver_state != Running)
  702.     {
  703.         WARN("Unable to stop WineASIO, not running\n");
  704.         return ASE_NotPresent;
  705.     }
  706.  
  707.     This->asio_driver_state = Prepared;
  708.  
  709.     if (jack_deactivate(This->jack_client))
  710.     {
  711.         ERR("Unable to deactivate JACK client\n");
  712.         return ASE_NotPresent;
  713.     }
  714.     return ASE_OK;
  715. }
  716.  
  717. /*
  718.  * ASIOError GetChannels(LONG *numInputChannels, LONG *numOutputChannels);
  719.  *  Function:   Report number of IO channels
  720.  *  Parameters: numInputChannels and numOutputChannels will hold number of channels on returning
  721.  *  Returns:    ASE_NotPresent if no channels are available, otherwise AES_OK
  722.  */
  723.  
  724. DEFINE_THISCALL_WRAPPER(GetChannels,12)
  725. HIDDEN ASIOError STDMETHODCALLTYPE GetChannels (LPWINEASIO iface, LONG *numInputChannels, LONG *numOutputChannels)
  726. {
  727.     IWineASIOImpl   *This = (IWineASIOImpl*)iface;
  728.  
  729.     if (!numInputChannels && !numOutputChannels)
  730.     {
  731.         WARN("Nullpointer argument\n");
  732.         return ASE_InvalidParameter;
  733.     }
  734.  
  735.     *numInputChannels = This->wineasio_number_inputs;
  736.     *numOutputChannels = This->wineasio_number_outputs;
  737.     TRACE("iface: %p, inputs: %i, outputs: %i\n", iface, This->wineasio_number_inputs, This->wineasio_number_outputs);
  738.     return ASE_OK;
  739. }
  740.  
  741. /*
  742.  * ASIOError GetLatencies(LONG *inputLatency, LONG *outputLatency);
  743.  *  Function:   Return latency in frames
  744.  *  Returns:    ASE_NotPresent if no IO is available, otherwise AES_OK
  745.  */
  746.  
  747. DEFINE_THISCALL_WRAPPER(GetLatencies,12)
  748. HIDDEN ASIOError STDMETHODCALLTYPE GetLatencies(LPWINEASIO iface, LONG *inputLatency, LONG *outputLatency)
  749. {
  750.     IWineASIOImpl   *This = (IWineASIOImpl*)iface;
  751.  
  752.     if (!inputLatency && !outputLatency)
  753.     {
  754.         WARN("Nullpointer argument\n");
  755.         return ASE_InvalidParameter;
  756.     }
  757.  
  758.     *inputLatency = *outputLatency = This->asio_current_buffersize;
  759.     TRACE("iface: %p Latency = %i frames\n", iface, This->asio_current_buffersize);
  760.     return ASE_OK;
  761. }
  762.  
  763. /*
  764.  * ASIOError GetBufferSize(LONG *minSize, LONG *maxSize, LONG *preferredSize, LONG *granularity);
  765.  *  Function:    Return minimum, maximum, preferred buffer sizes, and granularity
  766.  *               At the moment return all the same, and granularity 0
  767.  *  Returns:    ASE_NotPresent on missing IO
  768.  */
  769.  
  770. DEFINE_THISCALL_WRAPPER(GetBufferSize,20)
  771. HIDDEN ASIOError STDMETHODCALLTYPE GetBufferSize(LPWINEASIO iface, LONG *minSize, LONG *maxSize, LONG *preferredSize, LONG *granularity)
  772. {
  773.     IWineASIOImpl   *This = (IWineASIOImpl*)iface;
  774.  
  775.     TRACE("iface: %p, minSize: %p, maxSize: %p, preferredSize: %p, granularity: %p\n", iface, minSize, maxSize, preferredSize, granularity);
  776.  
  777.     if (!minSize && !maxSize && !preferredSize && !granularity)
  778.     {
  779.         WARN("Nullpointer argument\n");
  780.         return ASE_InvalidParameter;
  781.     }
  782.  
  783.     if (This->wineasio_fixed_buffersize)
  784.     {
  785.         *minSize = *maxSize = *preferredSize = This->asio_current_buffersize;
  786.         *granularity = 0;
  787.         TRACE("Buffersize fixed at %i\n", This->asio_current_buffersize);
  788.         return ASE_OK;
  789.     }
  790.  
  791.     *minSize = ASIO_MINIMUM_BUFFERSIZE;
  792.     *maxSize = ASIO_MAXIMUM_BUFFERSIZE;
  793.     *preferredSize = This->wineasio_preferred_buffersize;
  794.     *granularity = -1;
  795.     TRACE("The ASIO host can control buffersize\nMinimum: %i, maximum: %i, preferred: %i, granularity: %i, current: %i\n",
  796.           *minSize, *maxSize, *preferredSize, *granularity, This->asio_current_buffersize);
  797.     return ASE_OK;
  798. }
  799.  
  800. /*
  801.  * ASIOError CanSampleRate(ASIOSampleRate sampleRate);
  802.  *  Function:   Ask if specific SR is available
  803.  *  Returns:    ASE_NoClock if SR isn't available, ASE_NotPresent on missing IO
  804.  */
  805.  
  806. DEFINE_THISCALL_WRAPPER(CanSampleRate,12)
  807. HIDDEN ASIOError STDMETHODCALLTYPE CanSampleRate(LPWINEASIO iface, ASIOSampleRate sampleRate)
  808. {
  809.     IWineASIOImpl   *This = (IWineASIOImpl*)iface;
  810.  
  811.     TRACE("iface: %p, Samplerate = %li, requested samplerate = %li\n", iface, (long) This->asio_sample_rate, (long) sampleRate);
  812.  
  813.     if (sampleRate != This->asio_sample_rate)
  814.         return ASE_NoClock;
  815.     return ASE_OK;
  816. }
  817.  
  818. /*
  819.  * ASIOError GetSampleRate(ASIOSampleRate *currentRate);
  820.  *  Function:   Return current SR
  821.  *  Parameters: currentRate will hold SR on return, 0 if unknown
  822.  *  Returns:    ASE_NoClock if SR is unknown, ASE_NotPresent on missing IO
  823.  */
  824.  
  825. DEFINE_THISCALL_WRAPPER(GetSampleRate,8)
  826. HIDDEN ASIOError STDMETHODCALLTYPE GetSampleRate(LPWINEASIO iface, ASIOSampleRate *sampleRate)
  827. {
  828.     IWineASIOImpl   *This = (IWineASIOImpl*)iface;
  829.  
  830.     TRACE("iface: %p, Sample rate is %i\n", iface, (int) This->asio_sample_rate);
  831.  
  832.     if (!sampleRate)
  833.     {
  834.         WARN("Nullpointer argument\n");
  835.         return ASE_InvalidParameter;
  836.     }
  837.     *sampleRate = This->asio_sample_rate;
  838.     return ASE_OK;
  839. }
  840.  
  841. /*
  842.  * ASIOError SetSampleRate(ASIOSampleRate sampleRate);
  843.  *  Function:   Set requested SR, enable external sync if SR == 0
  844.  *  Returns:    ASE_NoClock if unknown SR
  845.  *              ASE_InvalidMode if current clock is external and SR != 0
  846.  *              ASE_NotPresent on missing IO
  847.  */
  848.  
  849. DEFINE_THISCALL_WRAPPER(SetSampleRate,12)
  850. HIDDEN ASIOError STDMETHODCALLTYPE SetSampleRate(LPWINEASIO iface, ASIOSampleRate sampleRate)
  851. {
  852.     IWineASIOImpl   *This = (IWineASIOImpl*)iface;
  853.  
  854.     TRACE("iface: %p, Sample rate %f requested\n", iface, sampleRate);
  855.  
  856.     if (sampleRate != This->asio_sample_rate)
  857.         return ASE_NoClock;
  858.     return ASE_OK;
  859. }
  860.  
  861. /*
  862.  * ASIOError GetClockSources(ASIOClockSource *clocks, LONG *numSources);
  863.  *  Function:   Return available clock sources
  864.  *  Parameters: clocks - a pointer to an array of ASIOClockSource structures.
  865.  *              numSources - when called: number of allocated members
  866.  *                         - on return: number of clock sources, the minimum is 1 - the internal clock
  867.  *  Returns:    ASE_NotPresent on missing IO
  868.  */
  869.  
  870. DEFINE_THISCALL_WRAPPER(GetClockSources,12)
  871. HIDDEN ASIOError STDMETHODCALLTYPE GetClockSources(LPWINEASIO iface, ASIOClockSource *clocks, LONG *numSources)
  872. {
  873.     TRACE("iface: %p, clocks: %p, numSources: %p\n", iface, clocks, numSources);
  874.  
  875.     if (!clocks && !numSources)
  876.     {
  877.         WARN("Nullpointer argument\n");
  878.         return ASE_InvalidParameter;
  879.     }
  880.     clocks->index = 0;
  881.     clocks->associatedChannel = -1;
  882.     clocks->associatedGroup = -1;
  883.     clocks->isCurrentSource = ASIOTrue;
  884.     strcpy(clocks->name, "Internal");
  885.     *numSources = 1;
  886.     return ASE_OK;
  887. }
  888.  
  889. /*
  890.  * ASIOError SetClockSource(LONG index);
  891.  *  Function:   Set clock source
  892.  *  Parameters: index returned by ASIOGetClockSources() - See asio.h for more details
  893.  *  Returns:    ASE_NotPresent on missing IO
  894.  *              ASE_InvalidMode may be returned if a clock can't be selected
  895.  *              ASE_NoClock should not be returned
  896.  */
  897.  
  898. DEFINE_THISCALL_WRAPPER(SetClockSource,8)
  899. HIDDEN ASIOError STDMETHODCALLTYPE SetClockSource(LPWINEASIO iface, LONG index)
  900. {
  901.     TRACE("iface: %p, index: %i\n", iface, index);
  902.  
  903.     if (index != 0)
  904.         return ASE_NotPresent;
  905.     return ASE_OK;
  906. }
  907.  
  908. /*
  909.  * ASIOError GetSamplePosition (ASIOSamples *sPos, ASIOTimeStamp *tStamp);
  910.  *  Function:   Return sample position and timestamp
  911.  *  Parameters: sPos holds the position on return, reset to 0 on ASIOStart()
  912.  *              tStamp holds the system time of sPos
  913.  *  Return:     ASE_NotPresent on missing IO
  914.  *              ASE_SPNotAdvancing on missing clock
  915.  */
  916.  
  917. DEFINE_THISCALL_WRAPPER(GetSamplePosition,12)
  918. HIDDEN ASIOError STDMETHODCALLTYPE GetSamplePosition(LPWINEASIO iface, ASIOSamples *sPos, ASIOTimeStamp *tStamp)
  919. {
  920.     IWineASIOImpl   *This = (IWineASIOImpl*)iface;
  921.  
  922.     TRACE("iface: %p, sPos: %p, tStamp: %p\n", iface, sPos, tStamp);
  923.  
  924.     if (!sPos && !tStamp)
  925.     {
  926.         WARN("Nullpointer argument\n");
  927.         return ASE_InvalidParameter;
  928.     }
  929. #ifdef _WIN64x
  930.     *tStamp = This->asio_time_stamp;
  931.     *sPos = This->asio_sample_position;
  932. #else
  933.     tStamp->lo = This->asio_time_stamp.lo;
  934.     tStamp->hi = This->asio_time_stamp.hi;
  935.     sPos->lo = This->asio_sample_position.lo;
  936.     sPos->hi = 0;
  937. #endif
  938.     return ASE_OK;
  939. }
  940.  
  941. /*
  942.  * ASIOError GetChannelInfo (ASIOChannelInfo *info);
  943.  *  Function:   Retrive channel info. - See asio.h for more detail
  944.  *  Returns:    ASE_NotPresent on missing IO
  945.  */
  946.  
  947. DEFINE_THISCALL_WRAPPER(GetChannelInfo,8)
  948. HIDDEN ASIOError STDMETHODCALLTYPE GetChannelInfo(LPWINEASIO iface, ASIOChannelInfo *info)
  949. {
  950.     IWineASIOImpl   *This = (IWineASIOImpl*)iface;
  951.  
  952.     /* TRACE("(iface: %p, info: %p\n", iface, info); */
  953.  
  954.     if (info->channel < 0 || (info->isInput ? info->channel >= This->wineasio_number_inputs : info->channel >= This->wineasio_number_outputs))
  955.     {
  956.         TRACE("Invalid Parameter\n");
  957.         return ASE_InvalidParameter;
  958.     }
  959.  
  960.     info->channelGroup = 0;
  961.  
  962. #ifdef ASIOST32INT
  963.     info->type = ASIOSTInt32LSB;
  964. #else
  965.     info->type = ASIOSTFloat32LSB;
  966. #endif
  967.  
  968.     if (info->isInput)
  969.     {
  970.         info->isActive = This->input_channel[info->channel].active;
  971.         memcpy(info->name, This->input_channel[info->channel].port_name, ASIO_MAX_NAME_LENGTH);
  972.     }
  973.     else
  974.     {
  975.         info->isActive = This->output_channel[info->channel].active;
  976.         memcpy(info->name, This->output_channel[info->channel].port_name, ASIO_MAX_NAME_LENGTH);
  977.     }
  978.     return ASE_OK;
  979. }
  980.  
  981. /*
  982.  * ASIOError CreateBuffers(ASIOBufferInfo *bufferInfo, LONG numChannels, LONG bufferSize, ASIOCallbacks *asioCallbacks);
  983.  *  Function:   Allocate buffers for IO channels
  984.  *  Parameters: bufferInfo      - pointer to an array of ASIOBufferInfo structures
  985.  *              numChannels     - the total number of IO channels to be allocated
  986.  *              bufferSize      - one of the buffer sizes retrieved with ASIOGetBufferSize()
  987.  *              asioCallbacks   - pointer to an ASIOCallbacks structure
  988.  *              See asio.h for more detail
  989.  *  Returns:    ASE_NoMemory if impossible to allocate enough memory
  990.  *              ASE_InvalidMode on unsupported bufferSize or invalid bufferInfo data
  991.  *              ASE_NotPresent on missing IO
  992.  */
  993.  
  994. DEFINE_THISCALL_WRAPPER(CreateBuffers,20)
  995. HIDDEN ASIOError STDMETHODCALLTYPE CreateBuffers(LPWINEASIO iface, ASIOBufferInfo *bufferInfo, LONG numChannels, LONG bufferSize, ASIOCallbacks *asioCallbacks)
  996. {
  997.     IWineASIOImpl   *This = (IWineASIOImpl*)iface;
  998.     ASIOBufferInfo  *buffer_info = bufferInfo;
  999.     int             i, j, k;
  1000.  
  1001.     TRACE("iface: %p, bufferInfo: %p, numChannels: %i, bufferSize: %i, asioCallbacks: %p\n", iface, bufferInfo, numChannels, bufferSize, asioCallbacks);
  1002.  
  1003.     if (This->asio_driver_state != Initialized)
  1004.     {
  1005.         WARN("Unable to create buffers, WineASIO is not in the initialized state\n");
  1006.         return ASE_NotPresent;
  1007.     }
  1008.  
  1009.     if (This->wineasio_fixed_buffersize)
  1010.     {
  1011.         if (This->asio_current_buffersize != bufferSize)
  1012.         {
  1013.             WARN("Invalid buffersize (%i) requested\n", bufferSize);
  1014.             return ASE_InvalidMode;
  1015.         }
  1016.         TRACE("Buffersize fixed at %i\n", This->asio_current_buffersize);
  1017.     }
  1018.     else
  1019.     { /* fail if not a power of two and if out of range */
  1020.         if (!(bufferSize > 0 && !(bufferSize&(bufferSize-1))
  1021.                 && bufferSize >= ASIO_MINIMUM_BUFFERSIZE
  1022.                 && bufferSize <= ASIO_MAXIMUM_BUFFERSIZE))
  1023.         {
  1024.             WARN("Invalid buffersize %i requested\n", bufferSize);
  1025.             return ASE_InvalidMode;
  1026.         }
  1027.         else
  1028.         {
  1029.             if (This->asio_current_buffersize == bufferSize)
  1030.                 TRACE("Buffer size already set to %i\n", This->asio_current_buffersize);
  1031.             else
  1032.             {
  1033.                 This->asio_current_buffersize = bufferSize;
  1034.                 if (jack_set_buffer_size(This->jack_client, This->asio_current_buffersize))
  1035.                 {
  1036.                     WARN("JACK is unable to set buffersize to %i\n", This->asio_current_buffersize);
  1037.                     return ASE_HWMalfunction;
  1038.                 }
  1039.                 TRACE("Buffer size changed to %i\n", This->asio_current_buffersize);
  1040.             }
  1041.         }
  1042.     }
  1043.  
  1044.     This->asio_callbacks = asioCallbacks;
  1045.     if (!This->asio_callbacks->asioMessage)
  1046.     {
  1047.         WARN("No asioMessage callback supplied\n");
  1048.         return ASE_InvalidMode;
  1049.     }
  1050.  
  1051.     TRACE("The ASIO host supports ASIO v%i\n", (int) This->asio_callbacks->asioMessage(kAsioEngineVersion,  0, 0, 0));
  1052.  
  1053.     if (This->asio_callbacks->asioMessage(kAsioSelectorSupported, kAsioResetRequest, 0 , 0))
  1054.         TRACE("The ASIO host supports kAsioResetRequest\n");
  1055.  
  1056.     if (This->asio_callbacks->asioMessage(kAsioSelectorSupported, kAsioResyncRequest, 0 , 0))
  1057.         TRACE("The ASIO host supports kAsioResyncRequest\n");
  1058.  
  1059.     if (This->asio_callbacks->asioMessage(kAsioSelectorSupported, kAsioBufferSizeChange, 0 , 0))
  1060.         TRACE("The ASIO host supports kAsioBufferSizeChange\n");
  1061.  
  1062.     /* Check for invalid channel numbers */
  1063.     for (i = j = k = 0; i < numChannels; i++, buffer_info++)
  1064.     {
  1065.         if (buffer_info->isInput)
  1066.         {
  1067.             if (j++ >= This->wineasio_number_inputs)
  1068.             {
  1069.                 WARN("Invalid input channel requested\n");
  1070.                 return ASE_InvalidMode;
  1071.             }
  1072.         }
  1073.         else
  1074.         {
  1075.             if (k++  >= This->wineasio_number_outputs)
  1076.             {
  1077.                 WARN("Invalid output channel requested\n");
  1078.                 return ASE_InvalidMode;
  1079.             }
  1080.         }
  1081.     }
  1082.  
  1083.     /* Allocate audio buffers */
  1084.     This->callback_audio_buffer = HeapAlloc(GetProcessHeap(), 0,
  1085.         (This->wineasio_number_inputs + This->wineasio_number_outputs) * 2 * This->asio_current_buffersize * sizeof(jack_default_audio_sample_t));
  1086.     if (!This->callback_audio_buffer)
  1087.     {
  1088.         ERR("Unable to allocate %i ASIO audio buffers\n", This->wineasio_number_inputs + This->wineasio_number_outputs);
  1089.         return ASE_NoMemory;
  1090.     }
  1091.     TRACE("%i ASIO audio buffers allocated (%i kB)\n", This->wineasio_number_inputs + This->wineasio_number_outputs,
  1092.           (int) ((This->wineasio_number_inputs + This->wineasio_number_outputs) * 2 * This->asio_current_buffersize * sizeof(jack_default_audio_sample_t) / 1024));
  1093.  
  1094.     for (i = 0; i < This->wineasio_number_inputs; i++)
  1095.         This->input_channel[i].audio_buffer = This->callback_audio_buffer + (i * 2 * This->asio_current_buffersize);
  1096.     for (i = 0; i < This->wineasio_number_outputs; i++)
  1097.         This->output_channel[i].audio_buffer = This->callback_audio_buffer + ((This->wineasio_number_inputs + i) * 2 * This->asio_current_buffersize);
  1098.  
  1099.      /* initialize ASIOBufferInfo structures */
  1100.     buffer_info = bufferInfo;
  1101.     This->asio_active_inputs = This->asio_active_outputs = 0;
  1102.     for (i = 0; i < numChannels; i++, buffer_info++)
  1103.     {
  1104.         if (buffer_info->isInput)
  1105.         {
  1106.             buffer_info->buffers[0] = &This->input_channel[This->asio_active_inputs].audio_buffer[0];
  1107.             buffer_info->buffers[1] = &This->input_channel[This->asio_active_inputs].audio_buffer[This->asio_current_buffersize];
  1108.             This->input_channel[This->asio_active_inputs].active = ASIOTrue;
  1109.             This->asio_active_inputs++;
  1110.             /* TRACE("ASIO audio buffer for channel %i as input %li created\n", i, This->asio_active_inputs); */
  1111.         }
  1112.         else
  1113.         {
  1114.             buffer_info->buffers[0] = &This->output_channel[This->asio_active_outputs].audio_buffer[0];
  1115.             buffer_info->buffers[1] = &This->output_channel[This->asio_active_outputs].audio_buffer[This->asio_current_buffersize];
  1116.             This->output_channel[This->asio_active_outputs].active = ASIOTrue;
  1117.             This->asio_active_outputs++;
  1118.             /* TRACE("ASIO audio buffer for channel %i as output %li created\n", i, This->asio_active_outputs); */
  1119.         }
  1120.     }
  1121.     TRACE("%i audio channels initialized\n", This->asio_active_inputs + This->asio_active_outputs);
  1122.  
  1123.     /* check for TimeInfo or TimeCode mode */
  1124.     if (This->asio_callbacks->asioMessage(kAsioSupportsTimeInfo, 0, 0, 0))
  1125.     {
  1126.         This->asio_time_info_mode = TRUE;
  1127.         if (This->asio_callbacks->asioMessage(kAsioSupportsTimeCode,  0, 0, 0))
  1128.             This->asio_can_time_code = TRUE;
  1129.     }
  1130.     else
  1131.         This->asio_time_info_mode = FALSE;
  1132.  
  1133.     This->asio_driver_state = Prepared;
  1134.     return ASE_OK;
  1135. }
  1136.  
  1137. /*
  1138.  * ASIOError DisposeBuffers(void);
  1139.  *  Function:   Release allocated buffers
  1140.  *  Returns:    ASE_InvalidMode if no buffers were previously allocated
  1141.  *              ASE_NotPresent on missing IO
  1142.  *  Implies:    ASIOStop()
  1143.  */
  1144.  
  1145. DEFINE_THISCALL_WRAPPER(DisposeBuffers,4)
  1146. HIDDEN ASIOError STDMETHODCALLTYPE DisposeBuffers(LPWINEASIO iface)
  1147. {
  1148.     IWineASIOImpl   *This = (IWineASIOImpl*)iface;
  1149.     int             i;
  1150.  
  1151.     TRACE("iface: %p\n", iface);
  1152.  
  1153.     if (This->asio_driver_state == Running)
  1154.         Stop (iface);
  1155.     if (This->asio_driver_state != Prepared)
  1156.     {
  1157.         WARN("Unable to dispose buffers, wrong driver state\n");
  1158.         return ASE_NotPresent;
  1159.     }
  1160.  
  1161.     This->asio_callbacks = NULL;
  1162.  
  1163.     for (i = 0; i < This->wineasio_number_inputs; i++)
  1164.     {
  1165.         This->input_channel[i].audio_buffer = NULL;
  1166.         This->input_channel[i].active = ASIOFalse;
  1167.     }
  1168.     for (i = 0; i < This->wineasio_number_outputs; i++)
  1169.     {
  1170.         This->output_channel[i].audio_buffer = NULL;
  1171.         This->output_channel[i].active = ASIOFalse;
  1172.     }
  1173.     This->asio_active_inputs = This->asio_active_outputs = 0;
  1174.  
  1175.     if (This->callback_audio_buffer)
  1176.         HeapFree(GetProcessHeap(), 0, This->callback_audio_buffer);
  1177.  
  1178.     This->asio_driver_state = Initialized;
  1179.     return ASE_OK;
  1180. }
  1181.  
  1182. /*
  1183.  * ASIOError ControlPanel(void);
  1184.  *  Function:   Open a control panel for driver settings
  1185.  *  Returns:    ASE_NotPresent if no control panel exists.  Actually return code should be ignored
  1186.  *  Note:       Call the asioMessage callback if something has changed
  1187.  */
  1188.  
  1189. DEFINE_THISCALL_WRAPPER(ControlPanel,4)
  1190. HIDDEN ASIOError STDMETHODCALLTYPE ControlPanel(LPWINEASIO iface)
  1191. {
  1192.     char    *arg_list[] = { strdup ("qjackctl"), NULL };
  1193.  
  1194.     TRACE("iface: %p\n", iface);
  1195.  
  1196.     if (!fork())
  1197.         execvp (arg_list[0], arg_list);
  1198.     return ASE_OK;
  1199. }
  1200.  
  1201. /*
  1202.  * ASIOError Future(LONG selector, void *opt);
  1203.  *  Function:   Various, See asio.h for more detail
  1204.  *  Returns:    Depends on the selector but in general ASE_InvalidParameter on invalid selector
  1205.  *              ASE_InvalidParameter if function is unsupported to disable further calls
  1206.  *              ASE_SUCCESS on success, do not use AES_OK
  1207.  */
  1208.  
  1209. DEFINE_THISCALL_WRAPPER(Future,12)
  1210. HIDDEN ASIOError STDMETHODCALLTYPE Future(LPWINEASIO iface, LONG selector, void *opt)
  1211. {
  1212.     IWineASIOImpl           *This = (IWineASIOImpl *) iface;
  1213.  
  1214.     TRACE("iface: %p, selector: %i, opt: %p\n", iface, selector, opt);
  1215.  
  1216.     switch (selector)
  1217.     {
  1218.         case kAsioEnableTimeCodeRead:
  1219.             This->asio_can_time_code = TRUE;
  1220.             TRACE("The ASIO host enabled TimeCode\n");
  1221.             return ASE_SUCCESS;
  1222.         case kAsioDisableTimeCodeRead:
  1223.             This->asio_can_time_code = FALSE;
  1224.             TRACE("The ASIO host disabled TimeCode\n");
  1225.             return ASE_SUCCESS;
  1226.         case kAsioSetInputMonitor:
  1227.             TRACE("The driver denied request to set input monitor\n");
  1228.             return ASE_NotPresent;
  1229.         case kAsioTransport:
  1230.             TRACE("The driver denied request for ASIO Transport control\n");
  1231.             return ASE_InvalidParameter;
  1232.         case kAsioSetInputGain:
  1233.             TRACE("The driver denied request to set input gain\n");
  1234.             return ASE_InvalidParameter;
  1235.         case kAsioGetInputMeter:
  1236.             TRACE("The driver denied request to get input meter \n");
  1237.             return ASE_InvalidParameter;
  1238.         case kAsioSetOutputGain:
  1239.             TRACE("The driver denied request to set output gain\n");
  1240.             return ASE_InvalidParameter;
  1241.         case kAsioGetOutputMeter:
  1242.             TRACE("The driver denied request to get output meter\n");
  1243.             return ASE_InvalidParameter;
  1244.         case kAsioCanInputMonitor:
  1245.             TRACE("The driver does not support input monitor\n");
  1246.             return ASE_InvalidParameter;
  1247.         case kAsioCanTimeInfo:
  1248.             TRACE("The driver supports TimeInfo\n");
  1249.             return ASE_SUCCESS;
  1250.         case kAsioCanTimeCode:
  1251.             TRACE("The driver supports TimeCode\n");
  1252.             return ASE_SUCCESS;
  1253.         case kAsioCanTransport:
  1254.             TRACE("The driver denied request for ASIO Transport\n");
  1255.             return ASE_InvalidParameter;
  1256.         case kAsioCanInputGain:
  1257.             TRACE("The driver does not support input gain\n");
  1258.             return ASE_InvalidParameter;
  1259.         case kAsioCanInputMeter:
  1260.             TRACE("The driver does not support input meter\n");
  1261.             return ASE_InvalidParameter;
  1262.         case kAsioCanOutputGain:
  1263.             TRACE("The driver does not support output gain\n");
  1264.             return ASE_InvalidParameter;
  1265.         case kAsioCanOutputMeter:
  1266.             TRACE("The driver does not support output meter\n");
  1267.             return ASE_InvalidParameter;
  1268.         case kAsioSetIoFormat:
  1269.             TRACE("The driver denied request to set DSD IO format\n");
  1270.             return ASE_NotPresent;
  1271.         case kAsioGetIoFormat:
  1272.             TRACE("The driver denied request to get DSD IO format\n");
  1273.             return ASE_NotPresent;
  1274.         case kAsioCanDoIoFormat:
  1275.             TRACE("The driver does not support DSD IO format\n");
  1276.             return ASE_NotPresent;
  1277.         default:
  1278.             TRACE("ASIOFuture() called with undocumented selector\n");
  1279.             return ASE_InvalidParameter;
  1280.     }
  1281. }
  1282.  
  1283. /*
  1284.  * ASIOError OutputReady(void);
  1285.  *  Function:   Tells the driver that output bufffers are ready
  1286.  *  Returns:    ASE_OK if supported
  1287.  *              ASE_NotPresent to disable
  1288.  */
  1289.  
  1290. DEFINE_THISCALL_WRAPPER(OutputReady,4)
  1291. HIDDEN ASIOError STDMETHODCALLTYPE OutputReady(LPWINEASIO iface)
  1292. {
  1293.     /* disabled to stop stand alone NI programs from spamming the console
  1294.     TRACE("iface: %p\n", iface); */
  1295.     return ASE_NotPresent;
  1296. }
  1297.  
  1298. /****************************************************************************
  1299.  *  JACK callbacks
  1300.  */
  1301.  
  1302. static int bufsize_callback(jack_nframes_t nframes, void *arg)
  1303. {
  1304.     IWineASIOImpl   *This = (IWineASIOImpl*)arg;
  1305.  
  1306.     if(This->asio_driver_state != Running)
  1307.         return 1;
  1308.  
  1309.     if (This->asio_callbacks->asioMessage(kAsioSelectorSupported, kAsioResetRequest, 0 , 0))
  1310.         This->asio_callbacks->asioMessage(kAsioResetRequest, 0, 0, 0);
  1311.     return 0;
  1312. }
  1313.  
  1314. static int process_callback(jack_nframes_t nframes, void *arg)
  1315. {
  1316.     IWineASIOImpl               *This = (IWineASIOImpl*)arg;
  1317.     int                         i;
  1318.     jack_transport_state_t      jack_transport_state;
  1319.     jack_position_t             jack_position;
  1320.  
  1321. #ifdef ASIOST32INT
  1322.     jack_default_audio_sample_t *in, *out;
  1323.     jack_nframes_t              j;
  1324. #endif
  1325.  
  1326. #ifndef _WIN64x
  1327.     DWORD                       temp_time;
  1328. #endif
  1329.  
  1330.     if (This->asio_driver_state != Running)
  1331.         return 1;
  1332.  
  1333.     /* get the input data from JACK and copy it to the ASIO buffers */
  1334. #ifdef ASIOST32INT
  1335.     for (i = 0; i < This->asio_active_inputs; i++)
  1336.         if (This->input_channel[i].active == ASIOTrue)
  1337.         {
  1338.             in = jack_port_get_buffer(This->input_channel[i].port, nframes);
  1339.             for (j = 0; j < nframes; j++)
  1340.                 ((int *)This->input_channel[i].audio_buffer)[nframes * This->asio_buffer_index + j] = in[j] * 0x7fffffff;
  1341.         }
  1342. #else
  1343.     for (i = 0; i < This->asio_active_inputs; i++)
  1344.         if (This->input_channel[i].active == ASIOTrue)
  1345.             memcpy (&This->input_channel[i].audio_buffer[nframes * This->asio_buffer_index],
  1346.                     jack_port_get_buffer(This->input_channel[i].port, nframes),
  1347.                     sizeof (jack_default_audio_sample_t) * nframes);
  1348. #endif
  1349.  
  1350. #ifdef _WIN64x
  1351.     This->asio_sample_position += nframes;
  1352.     This->asio_sample_position & 0xffffffff;    /* make 32bit since JACK's position is 32bit anyways */
  1353.     This->asio_time_stamp = timeGetTime() * 1000000;
  1354. #else
  1355.     This->asio_sample_position.lo += nframes;
  1356.     temp_time = timeGetTime();
  1357.     This->asio_time_stamp.lo = temp_time * 1000000;
  1358.     This->asio_time_stamp.hi = ((unsigned long long) temp_time * 1000000) >> 32;
  1359. #endif
  1360.  
  1361.     /* time info & time code */
  1362.     if (This->asio_time_info_mode)
  1363.     {
  1364. #ifdef _WIN64x
  1365.         This->asio_time.timeInfo.samplePosition = This->asio_sample_position;
  1366.         This->asio_time.timeInfo.systemTime = This->asio_time_stamp;
  1367. #else
  1368.         This->asio_time.timeInfo.samplePosition.lo = This->asio_sample_position.lo;
  1369.         This->asio_time.timeInfo.samplePosition.hi = 0;
  1370.         This->asio_time.timeInfo.systemTime.lo = This->asio_time_stamp.lo;
  1371.         This->asio_time.timeInfo.systemTime.hi = This->asio_time_stamp.hi;
  1372. #endif
  1373.         This->asio_time.timeInfo.sampleRate = This->asio_sample_rate;
  1374.         This->asio_time.timeInfo.flags  = kSystemTimeValid | kSamplePositionValid | kSampleRateValid;
  1375.  
  1376.         if (This->asio_can_time_code)
  1377.         {
  1378.             jack_transport_state = jack_transport_query(This->jack_client, &jack_position);
  1379. #ifdef _WIN64x
  1380.             This->asio_time.timeCode.timeCodeSamples = jack_position.frame;
  1381. #else
  1382.             This->asio_time.timeCode.timeCodeSamples.lo = jack_position.frame;
  1383.             This->asio_time.timeCode.timeCodeSamples.hi = 0;
  1384. #endif
  1385.             This->asio_time.timeCode.flags = kTcValid;
  1386.             if (jack_transport_state == JackTransportRolling)
  1387.                 This->asio_time.timeCode.flags |= kTcRunning;
  1388.         }
  1389.         This->asio_callbacks->bufferSwitchTimeInfo(&This->asio_time, This->asio_buffer_index, ASIOTrue);
  1390.     }
  1391.     else
  1392.         This->asio_callbacks->bufferSwitch(This->asio_buffer_index, ASIOTrue);
  1393.  
  1394.     /* copy the ASIO data to JACK */
  1395. #ifdef ASIOST32INT
  1396.     for (i = 0; i < This->asio_active_outputs; i++)
  1397.         if (This->output_channel[i].active == ASIOTrue)
  1398.         {
  1399.             out = jack_port_get_buffer(This->output_channel[i].port, nframes);
  1400.             for (j = 0; j < nframes; j++)
  1401.                 out[j] = ((int *) This->output_channel[i].audio_buffer)[nframes * This->asio_buffer_index + j] / (float) 0x7fffffff;
  1402.         }
  1403. #else
  1404.     for (i = 0; i < This->asio_active_outputs; i++)
  1405.         if (This->output_channel[i].active == ASIOTrue)
  1406.             memcpy(jack_port_get_buffer(This->output_channel[i].port, nframes),
  1407.                     &This->output_channel[i].audio_buffer[nframes * This->asio_buffer_index],
  1408.                     sizeof (jack_default_audio_sample_t) * nframes);
  1409. #endif
  1410.     This->asio_buffer_index = This->asio_buffer_index ? 0 : 1;
  1411.     return 0;
  1412. }
  1413.  
  1414. static int srate_callback(jack_nframes_t nframes, void *arg)
  1415. {
  1416.     IWineASIOImpl   *This = (IWineASIOImpl*)arg;
  1417.  
  1418.     if(This->asio_driver_state != Running)
  1419.         return 1;
  1420.  
  1421.     This->asio_sample_rate = nframes;
  1422.     This->asio_callbacks->sampleRateDidChange(nframes);
  1423.     return 0;
  1424. }
  1425.  
  1426. static int xrun_callback(void *arg)
  1427. {
  1428.     IWineASIOImpl   *This = (IWineASIOImpl*)arg;
  1429.  
  1430.     if(This->asio_driver_state != Running)
  1431.         return 1;
  1432.  
  1433.     if (This->asio_callbacks->asioMessage(kAsioSelectorSupported, kAsioResyncRequest, 0 , 0))
  1434.         This->asio_callbacks->asioMessage(kAsioResyncRequest, 0, 0, 0);
  1435.     return 0;
  1436. }
  1437.  
  1438. /*****************************************************************************
  1439.  *  Support functions
  1440.  */
  1441.  
  1442. #ifdef __WINESRC__
  1443. /* Function called by JACK to create a thread in the wine process context,
  1444.  *  uses the global structure jack_thread_creator_privates to communicate with jack_thread_creator_helper() */
  1445. static int jack_thread_creator(pthread_t* thread_id, const pthread_attr_t* attr, void *(*function)(void*), void* arg)
  1446. {
  1447.     TRACE("arg: %p, thread_id: %p, attr: %p, function: %p\n", arg, thread_id, attr, function);
  1448.  
  1449.     jack_thread_creator_privates.jack_callback_thread = function;
  1450.     jack_thread_creator_privates.arg = arg;
  1451.     jack_thread_creator_privates.jack_callback_thread_created = CreateEventW(NULL, FALSE, FALSE, NULL);
  1452.     CreateThread( NULL, 0, jack_thread_creator_helper, arg, 0,0 );
  1453.     WaitForSingleObject(jack_thread_creator_privates.jack_callback_thread_created, INFINITE);
  1454.     *thread_id = jack_thread_creator_privates.jack_callback_pthread_id;
  1455.     return 0;
  1456. }
  1457.  
  1458. /* internal helper function for returning the posix thread_id of the newly created callback thread */
  1459. static DWORD WINAPI jack_thread_creator_helper(LPVOID arg)
  1460. {
  1461.     TRACE("arg: %p\n", arg);
  1462.  
  1463.     jack_thread_creator_privates.jack_callback_pthread_id = pthread_self();
  1464.     SetEvent(jack_thread_creator_privates.jack_callback_thread_created);
  1465.     jack_thread_creator_privates.jack_callback_thread(jack_thread_creator_privates.arg);
  1466.     return 0;
  1467. }
  1468. #endif
  1469.  
  1470. static BOOL configure_driver(IWineASIOImpl *This)
  1471. {
  1472.     HKEY    hkey;
  1473.     LONG    result, value;
  1474.     DWORD   type, size;
  1475.     WCHAR   application_path [MAX_PATH];
  1476.     WCHAR   *application_name;
  1477.     char    environment_variable[MAX_ENVIRONMENT_SIZE];
  1478.  
  1479.     /* Unicode strings used for the registry */
  1480.     static const WCHAR key_software_wine_wineasio[] =
  1481.         { 'S','o','f','t','w','a','r','e','\\',
  1482.           'W','i','n','e','\\',
  1483.           'W','i','n','e','A','S','I','O',0 };
  1484.     static const WCHAR value_wineasio_number_inputs[] =
  1485.         { 'N','u','m','b','e','r',' ','o','f',' ','i','n','p','u','t','s',0 };
  1486.     static const WCHAR value_wineasio_number_outputs[] =
  1487.         { 'N','u','m','b','e','r',' ','o','f',' ','o','u','t','p','u','t','s',0 };
  1488.     static const WCHAR value_wineasio_fixed_buffersize[] =
  1489.         { 'F','i','x','e','d',' ','b','u','f','f','e','r','s','i','z','e',0 };
  1490.     static const WCHAR value_wineasio_preferred_buffersize[] =
  1491.         { 'P','r','e','f','e','r','r','e','d',' ','b','u','f','f','e','r','s','i','z','e',0 };
  1492.     static const WCHAR wineasio_autostart_server[] =
  1493.         { 'A','u','t','o','s','t','a','r','t',' ','s','e','r','v','e','r',0 };
  1494.     static const WCHAR value_wineasio_connect_to_hardware[] =
  1495.         { 'C','o','n','n','e','c','t',' ','t','o',' ','h','a','r','d','w','a','r','e',0 };
  1496.  
  1497.     /* Initialise most member variables,
  1498.      * asio_sample_position, asio_time, & asio_time_stamp are initialized in Start()
  1499.      * jack_num_input_ports & jack_num_output_ports are initialized in Init() */
  1500.     This->asio_active_inputs = 0;
  1501.     This->asio_active_outputs = 0;
  1502.     This->asio_buffer_index = 0;
  1503.     This->asio_callbacks = NULL;
  1504.     This->asio_can_time_code = FALSE;
  1505.     This->asio_current_buffersize = 0;
  1506.     This->asio_driver_state = Loaded;
  1507.     This->asio_sample_rate = 0;
  1508.     This->asio_time_info_mode = FALSE;
  1509.     This->asio_version = 90;
  1510.  
  1511.     This->wineasio_number_inputs = 16;
  1512.     This->wineasio_number_outputs = 16;
  1513.     This->wineasio_autostart_server = FALSE;
  1514.     This->wineasio_connect_to_hardware = TRUE;
  1515.     This->wineasio_fixed_buffersize = TRUE;
  1516.     This->wineasio_preferred_buffersize = ASIO_PREFERRED_BUFFERSIZE;
  1517.  
  1518.     This->jack_client = NULL;
  1519.     This->jack_client_name[0] = 0;
  1520.     This->jack_input_ports = NULL;
  1521.     This->jack_output_ports = NULL;
  1522.     This->callback_audio_buffer = NULL;
  1523.     This->input_channel = NULL;
  1524.     This->output_channel = NULL;
  1525.  
  1526.     /* create registry entries with defaults if not present */
  1527.     result = RegCreateKeyExW(HKEY_CURRENT_USER, key_software_wine_wineasio, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
  1528.     if (result != ERROR_SUCCESS)
  1529.     {
  1530.         ERR("Unable to open registry\n");
  1531.         return FALSE;
  1532.     }
  1533.  
  1534.     /* get/set number of asio inputs */
  1535.     size = sizeof(DWORD);
  1536.     if (RegQueryValueExW(hkey, value_wineasio_number_inputs, NULL, &type, (LPBYTE) &value, &size) == ERROR_SUCCESS)
  1537.     {
  1538.         if (type == REG_DWORD)
  1539.             This->wineasio_number_inputs = value;
  1540.     }
  1541.     else
  1542.     {
  1543.         type = REG_DWORD;
  1544.         size = sizeof(DWORD);
  1545.         value = This->wineasio_number_inputs;
  1546.         result = RegSetValueExW(hkey, value_wineasio_number_inputs, 0, REG_DWORD, (LPBYTE) &value, size);
  1547.     }
  1548.  
  1549.     /* get/set number of asio outputs */
  1550.     size = sizeof(DWORD);
  1551.     if (RegQueryValueExW(hkey, value_wineasio_number_outputs, NULL, &type, (LPBYTE) &value, &size) == ERROR_SUCCESS)
  1552.     {
  1553.         if (type == REG_DWORD)
  1554.             This->wineasio_number_outputs = value;
  1555.     }
  1556.     else
  1557.     {
  1558.         type = REG_DWORD;
  1559.         size = sizeof(DWORD);
  1560.         value = This->wineasio_number_outputs;
  1561.         result = RegSetValueExW(hkey, value_wineasio_number_outputs, 0, REG_DWORD, (LPBYTE) &value, size);
  1562.     }
  1563.  
  1564.     /* allow changing of asio buffer sizes */
  1565.     size = sizeof(DWORD);
  1566.     if (RegQueryValueExW(hkey, value_wineasio_fixed_buffersize, NULL, &type, (LPBYTE) &value, &size) == ERROR_SUCCESS)
  1567.     {
  1568.         if (type == REG_DWORD)
  1569.             This->wineasio_fixed_buffersize = value;
  1570.     }
  1571.     else
  1572.     {
  1573.         type = REG_DWORD;
  1574.         size = sizeof(DWORD);
  1575.         value = This->wineasio_fixed_buffersize;
  1576.         result = RegSetValueExW(hkey, value_wineasio_fixed_buffersize, 0, REG_DWORD, (LPBYTE) &value, size);
  1577.     }
  1578.  
  1579.     /* preferred buffer size (if changing buffersize is allowed) */
  1580.     size = sizeof(DWORD);
  1581.     if (RegQueryValueExW(hkey, value_wineasio_preferred_buffersize, NULL, &type, (LPBYTE) &value, &size) == ERROR_SUCCESS)
  1582.     {
  1583.         if (type == REG_DWORD)
  1584.             This->wineasio_preferred_buffersize = value;
  1585.     }
  1586.     else
  1587.     {
  1588.         type = REG_DWORD;
  1589.         size = sizeof(DWORD);
  1590.         value = This->wineasio_preferred_buffersize;
  1591.         result = RegSetValueExW(hkey, value_wineasio_preferred_buffersize, 0, REG_DWORD, (LPBYTE) &value, size);
  1592.     }
  1593.  
  1594.     /* get/set JACK autostart */
  1595.     size = sizeof(DWORD);
  1596.     if (RegQueryValueExW(hkey, wineasio_autostart_server, NULL, &type, (LPBYTE) &value, &size) == ERROR_SUCCESS)
  1597.     {
  1598.         if (type == REG_DWORD)
  1599.             This->wineasio_autostart_server = value;
  1600.     }
  1601.     else
  1602.     {
  1603.         type = REG_DWORD;
  1604.         size = sizeof(DWORD);
  1605.         value = This->wineasio_autostart_server;
  1606.         result = RegSetValueExW(hkey, wineasio_autostart_server, 0, REG_DWORD, (LPBYTE) &value, size);
  1607.     }
  1608.  
  1609.     /* get/set JACK connect to physical io */
  1610.     size = sizeof(DWORD);
  1611.     if (RegQueryValueExW(hkey, value_wineasio_connect_to_hardware, NULL, &type, (LPBYTE) &value, &size) == ERROR_SUCCESS)
  1612.     {
  1613.         if (type == REG_DWORD)
  1614.             This->wineasio_connect_to_hardware = value;
  1615.     }
  1616.     else
  1617.     {
  1618.         type = REG_DWORD;
  1619.         size = sizeof(DWORD);
  1620.         value = This->wineasio_connect_to_hardware;
  1621.         result = RegSetValueExW(hkey, value_wineasio_connect_to_hardware, 0, REG_DWORD, (LPBYTE) &value, size);
  1622.     }
  1623.  
  1624.     /* get client name by stripping path and extension */
  1625.     GetModuleFileNameW(0, application_path, MAX_PATH);
  1626.     application_name = strrchrW(application_path, L'.');
  1627.     *application_name = 0;
  1628.     application_name = strrchrW(application_path, L'\\');
  1629.     application_name++;
  1630.     WideCharToMultiByte(CP_ACP, WC_SEPCHARS, application_name, -1, This->jack_client_name, ASIO_MAX_NAME_LENGTH, NULL, NULL);
  1631.  
  1632.     RegCloseKey(hkey);
  1633.  
  1634.     /* Look for environment variables to override registry config values */
  1635.  
  1636.     if (GetEnvironmentVariableA("WINEASIO_NUMBER_INPUTS", environment_variable, MAX_ENVIRONMENT_SIZE))
  1637.     {
  1638.         errno = 0;
  1639.         result = strtol(environment_variable, 0, 10);
  1640.         if (errno != ERANGE)
  1641.             This->wineasio_number_inputs = result;
  1642.     }
  1643.  
  1644.     if (GetEnvironmentVariableA("WINEASIO_NUMBER_OUTPUTS", environment_variable, MAX_ENVIRONMENT_SIZE))
  1645.     {
  1646.         errno = 0;
  1647.         result = strtol(environment_variable, 0, 10);
  1648.         if (errno != ERANGE)
  1649.             This->wineasio_number_outputs = result;
  1650.     }
  1651.  
  1652.     if (GetEnvironmentVariableA("WINEASIO_AUTOSTART_SERVER", environment_variable, MAX_ENVIRONMENT_SIZE))
  1653.     {
  1654.         if (!strcasecmp(environment_variable, "on"))
  1655.             This->wineasio_autostart_server = TRUE;
  1656.         else if (!strcasecmp(environment_variable, "off"))
  1657.             This->wineasio_autostart_server = FALSE;
  1658.     }
  1659.  
  1660.     if (GetEnvironmentVariableA("WINEASIO_CONNECT_TO_HARDWARE", environment_variable, MAX_ENVIRONMENT_SIZE))
  1661.     {
  1662.         if (!strcasecmp(environment_variable, "on"))
  1663.             This->wineasio_autostart_server = TRUE;
  1664.         else if (!strcasecmp(environment_variable, "off"))
  1665.             This->wineasio_autostart_server = FALSE;
  1666.     }
  1667.  
  1668.     if (GetEnvironmentVariableA("WINEASIO_FIXED_BUFFERSIZE", environment_variable, MAX_ENVIRONMENT_SIZE))
  1669.     {
  1670.         if (!strcasecmp(environment_variable, "on"))
  1671.             This->wineasio_fixed_buffersize = TRUE;
  1672.         if (!strcasecmp(environment_variable, "off"))
  1673.             This->wineasio_fixed_buffersize = FALSE;
  1674.     }
  1675.  
  1676.     if (GetEnvironmentVariableA("WINEASIO_PREFERRED_BUFFERSIZE", environment_variable, MAX_ENVIRONMENT_SIZE))
  1677.     {
  1678.         errno = 0;
  1679.         result = strtol(environment_variable, 0, 10);
  1680.         if (errno != ERANGE)
  1681.             This->wineasio_preferred_buffersize = result;
  1682.     }
  1683.  
  1684.     /* over ride the JACK client name gotten from the application name */
  1685.     size = GetEnvironmentVariableA("WINEASIO_CLIENT_NAME", environment_variable, ASIO_MAX_NAME_LENGTH);
  1686.     if (size > 0 && size < ASIO_MAX_NAME_LENGTH)
  1687.         strcpy(This->jack_client_name, environment_variable);
  1688.  
  1689.     /* if wineasio_preferred_buffersize is not a power of two or if out of range, then set to ASIO_PREFERRED_BUFFERSIZE */
  1690.     if (!(This->wineasio_preferred_buffersize > 0 && !(This->wineasio_preferred_buffersize&(This->wineasio_preferred_buffersize-1))
  1691.             && This->wineasio_preferred_buffersize >= ASIO_MINIMUM_BUFFERSIZE
  1692.             && This->wineasio_preferred_buffersize <= ASIO_MAXIMUM_BUFFERSIZE))
  1693.         This->wineasio_preferred_buffersize = ASIO_PREFERRED_BUFFERSIZE;
  1694.  
  1695.     return TRUE;
  1696. }
  1697.  
  1698. /* Allocate the interface pointer and associate it with the vtbl/WineASIO object */
  1699. HRESULT WINAPI WineASIOCreateInstance(REFIID riid, LPVOID *ppobj)
  1700. {
  1701.     IWineASIOImpl   *pobj;
  1702.  
  1703.     TRACE("riid: %s, ppobj: %p\n", debugstr_guid(riid), ppobj);
  1704.  
  1705.     pobj = HeapAlloc(GetProcessHeap(), 0, sizeof(*pobj));
  1706.     if (pobj == NULL)
  1707.     {
  1708.         WARN("out of memory\n");
  1709.         return E_OUTOFMEMORY;
  1710.     }
  1711.  
  1712.     pobj->lpVtbl = &WineASIO_Vtbl;
  1713.     pobj->ref = 1;
  1714.     TRACE("pobj = %p\n", pobj);
  1715.     *ppobj = pobj;
  1716.     TRACE("return %p\n", *ppobj);
  1717.     return S_OK;
  1718. }
Advertisement
Add Comment
Please, Sign In to add comment