|
- /*
- * Copyright (C) 2006 Robert Reif
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
- #include "config.h"
- #include "wine/port.h"
-
- #include <stdarg.h>
- #include <stdio.h>
-
- #include "windef.h"
- #include "winbase.h"
- #include "objbase.h"
- #include "mmsystem.h"
-
- #include "wine/debug.h"
-
- #include <jack/jack.h>
-
- #include "asio.h"
-
- WINE_DEFAULT_DEBUG_CHANNEL(asio);
-
- /* JACK callback function */
- static int jack_process(jack_nframes_t nframes, void * arg);
-
- // {48D0C522-BFCC-45cc-8B84-17F25F33E6E8}
- static GUID const CLSID_WineASIO = {
- 0x48d0c522, 0xbfcc, 0x45cc, { 0x8b, 0x84, 0x17, 0xf2, 0x5f, 0x33, 0xe6, 0xe8 } };
-
- #define twoRaisedTo32 4294967296.0
- #define twoRaisedTo32Reciprocal (1.0 / twoRaisedTo32)
-
- #define MAX_INPUTS 2
- #define MAX_OUTPUTS 2
-
- #ifdef __i386__ /* thiscall functions are i386-specific */
-
- #ifdef __GNUC__
- /* GCC erroneously warns that the newly wrapped function
- * isn't used, lets help it out of it's thinking
- */
- #define SUPPRESS_NOTUSED __attribute__((used))
- #else
- #define SUPPRESS_NOTUSED
- #endif /* __GNUC__ */
-
- #define WRAP_THISCALL(type, func, parm) \
- extern type func parm; \
- __ASM_GLOBAL_FUNC( func, \
- "popl %eax\n\t" \
- "pushl %ecx\n\t" \
- "pushl %eax\n\t" \
- "jmp " __ASM_NAME("__wrapped_" #func) ); \
- SUPPRESS_NOTUSED static type __wrapped_ ## func parm
- #else
- #define WRAP_THISCALL(functype, function, param) \
- functype function param
- #endif
-
- /*****************************************************************************
- * IWineAsio interface
- */
- #define INTERFACE IWineASIO
- DECLARE_INTERFACE_(IWineASIO,IUnknown)
- {
- STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;
- STDMETHOD_(ULONG,AddRef)(THIS) PURE;
- STDMETHOD_(ULONG,Release)(THIS) PURE;
- STDMETHOD_(ASIOBool,init)(THIS_ void *sysHandle) PURE;
- STDMETHOD_(void,getDriverName)(THIS_ char *name) PURE;
- STDMETHOD_(long,getDriverVersion)(THIS) PURE;
- STDMETHOD_(void,getErrorMessage)(THIS_ char *string) PURE;
- STDMETHOD_(ASIOError,start)(THIS) PURE;
- STDMETHOD_(ASIOError,stop)(THIS) PURE;
- STDMETHOD_(ASIOError,getChannels)(THIS_ long *numInputChannels, long *numOutputChannels) PURE;
- STDMETHOD_(ASIOError,getLatencies)(THIS_ long *inputLatency, long *outputLatency) PURE;
- STDMETHOD_(ASIOError,getBufferSize)(THIS_ long *minSize, long *maxSize, long *preferredSize, long *granularity) PURE;
- STDMETHOD_(ASIOError,canSampleRate)(THIS_ ASIOSampleRate sampleRate) PURE;
- STDMETHOD_(ASIOError,getSampleRate)(THIS_ ASIOSampleRate *sampleRate) PURE;
- STDMETHOD_(ASIOError,setSampleRate)(THIS_ ASIOSampleRate sampleRate) PURE;
- STDMETHOD_(ASIOError,getClockSources)(THIS_ ASIOClockSource *clocks, long *numSources) PURE;
- STDMETHOD_(ASIOError,setClockSource)(THIS_ long reference) PURE;
- STDMETHOD_(ASIOError,getSamplePosition)(THIS_ ASIOSamples *sPos, ASIOTimeStamp *tStamp) PURE;
- STDMETHOD_(ASIOError,getChannelInfo)(THIS_ ASIOChannelInfo *info) PURE;
- STDMETHOD_(ASIOError,createBuffers)(THIS_ ASIOBufferInfo *bufferInfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks) PURE;
- STDMETHOD_(ASIOError,disposeBuffers)(THIS) PURE;
- STDMETHOD_(ASIOError,controlPanel)(THIS) PURE;
- STDMETHOD_(ASIOError,future)(THIS_ long selector,void *opt) PURE;
- STDMETHOD_(ASIOError,outputReady)(THIS) PURE;
- };
- #undef INTERFACE
-
- typedef struct IWineASIO *LPWINEASIO, **LPLPWINEASIO;
-
- enum
- {
- Init,
- Run,
- Exit
- };
-
- struct IWineASIOImpl
- {
- /* COM stuff */
- const IWineASIOVtbl *lpVtbl;
- LONG ref;
-
- /* ASIO stuff */
- HWND hwnd;
- ASIOSampleRate sample_rate;
- long input_latency;
- long output_latency;
- long block_frames;
- ASIOTime asio_time;
- long miliseconds;
- ASIOTimeStamp system_time;
- double sample_position;
- ASIOBufferInfo *bufferInfos;
- ASIOCallbacks *callbacks;
- char error_message[256];
- long in_map[MAX_INPUTS];
- long out_map[MAX_OUTPUTS];
- long num_inputs;
- long num_outputs;
- short *input_buffers[MAX_INPUTS][2];
- short *output_buffers[MAX_OUTPUTS][2];
- long active_inputs;
- long active_outputs;
- BOOL time_info_mode;
- BOOL tc_read;
-
- /* JACK stuff */
- jack_port_t *input_port[MAX_INPUTS];
- jack_port_t *output_port[MAX_OUTPUTS];
- jack_client_t *client;
- long client_state;
- long toggle;
- };
-
- typedef struct IWineASIOImpl IWineASIOImpl;
-
- static ULONG WINAPI IWineASIOImpl_AddRef(LPWINEASIO iface)
- {
- IWineASIOImpl *This = (IWineASIOImpl *)iface;
- ULONG ref = InterlockedIncrement(&(This->ref));
- TRACE("(%p) ref was %ld\n", This, ref - 1);
- return ref;
- }
-
- static ULONG WINAPI IWineASIOImpl_Release(LPWINEASIO iface)
- {
- IWineASIOImpl *This = (IWineASIOImpl *)iface;
- ULONG ref = InterlockedDecrement(&(This->ref));
- TRACE("(%p) ref was %ld\n", This, ref + 1);
-
- if (!ref) {
- jack_client_close(This->client);
- TRACE("JACK client closed\n");
-
- HeapFree(GetProcessHeap(),0,This);
- TRACE("(%p) released\n", This);
- }
- return ref;
- }
-
- static HRESULT WINAPI IWineASIOImpl_QueryInterface(LPWINEASIO iface, REFIID riid, void** ppvObject)
- {
- IWineASIOImpl * This = (IWineASIOImpl*)iface;
- TRACE("(%p, %s, %p)\n", iface, debugstr_guid(riid), ppvObject);
-
- if (ppvObject == NULL)
- return E_INVALIDARG;
-
- if (IsEqualIID(&CLSID_WineASIO, riid))
- {
- IWineASIOImpl_AddRef(iface);
-
- *ppvObject = This;
-
- return S_OK;
- }
-
- return E_NOINTERFACE;
- }
-
- WRAP_THISCALL( ASIOBool __stdcall, IWineASIOImpl_init, (LPWINEASIO iface, void *sysHandle))
- {
- IWineASIOImpl * This = (IWineASIOImpl*)iface;
- jack_status_t status;
- int i;
- TRACE("(%p, %p)\n", iface, sysHandle);
-
- This->sample_rate = 48000;
- This->block_frames = 1024;
- This->input_latency = This->block_frames;
- This->output_latency = This->block_frames * 2;
- This->miliseconds = (long)((double)(This->block_frames * 1000) / This->sample_rate);
- This->callbacks = NULL;
- This->sample_position = 0;
- strcpy(This->error_message, "No Error");
- This->num_inputs = 0;
- This->num_outputs = 0;
- This->active_inputs = 0;
- This->active_outputs = 0;
- This->toggle = 0;
- This->client_state = Init;
- This->time_info_mode = FALSE;
- This->tc_read = FALSE;
-
- for (i = 0; i < MAX_INPUTS; i++)
- {
- This->in_map[i] = 0;
- }
-
- for (i = 0; i < MAX_OUTPUTS; i++)
- {
- This->out_map[i] = 0;
- }
-
- This->client = jack_client_open("Wine_ASIO_Jack_Client", JackNullOption, &status, NULL);
- if (This->client == NULL)
- {
- WARN("failed ot open jack server\n");
- return ASIOFalse;
- }
-
- TRACE("JACK client opened\n");
-
- if (status & JackServerStarted)
- TRACE("JACK server started\n");
-
- jack_set_process_callback(This->client, jack_process, This);
-
- This->sample_rate = jack_get_sample_rate(This->client);
- This->miliseconds = (long)((double)(This->block_frames * 1000) / This->sample_rate);
-
- TRACE("sample rate: %f\n", This->sample_rate);
-
- for (i = 0; i < MAX_INPUTS; i++)
- {
- char name[32];
- snprintf(name, sizeof(name), "Input%d", i);
- This->input_port[i] = jack_port_register(This->client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, i);
- if (This->input_port[i] == 0)
- break;
-
- This->num_inputs++;
- }
-
- TRACE("found %ld inputs\n", This->num_inputs);
-
- for (i = 0; i < MAX_OUTPUTS; i++)
- {
- char name[32];
- snprintf(name, sizeof(name), "Output%d", i);
- This->output_port[i] = jack_port_register(This->client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, i);
- if (This->output_port[i] == 0)
- break;
-
- This->num_outputs++;
- }
-
- TRACE("found %ld outputs\n", This->num_outputs);
-
- return ASIOTrue;
- }
-
- WRAP_THISCALL( void __stdcall, IWineASIOImpl_getDriverName, (LPWINEASIO iface, char *name))
- {
- TRACE("(%p, %p)\n", iface, name);
- strcpy(name, "Wine ASIO");
- }
-
- WRAP_THISCALL( long __stdcall, IWineASIOImpl_getDriverVersion, (LPWINEASIO iface))
- {
- TRACE("(%p)\n", iface);
- return 1;
- }
-
- WRAP_THISCALL( void __stdcall, IWineASIOImpl_getErrorMessage, (LPWINEASIO iface, char *string))
- {
- IWineASIOImpl * This = (IWineASIOImpl*)iface;
- TRACE("(%p, %p)\n", iface, string);
- strcpy(string, This->error_message);
- }
-
- WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_start, (LPWINEASIO iface))
- {
- IWineASIOImpl * This = (IWineASIOImpl*)iface;
- const char ** ports;
- int i;
- TRACE("(%p)\n", iface);
-
- if (This->callbacks)
- {
- This->sample_position = 0;
- This->system_time.lo = 0;
- This->system_time.hi = 0;
-
- if (jack_activate(This->client))
- {
- WARN("couldn't activate client\n");
- return ASE_NotPresent;
- }
-
- ports = jack_get_ports(This->client, NULL, NULL, JackPortIsPhysical | JackPortIsOutput);
-
- if (ports == NULL)
- {
- WARN("couldn't get input ports\n");
- return ASE_NotPresent;
- }
-
- for (i = 0; i < This->active_inputs; i++)
- {
- if (jack_connect(This->client, ports[i], jack_port_name(This->input_port[i])))
- {
- WARN("input %d connect failed\n", i);
- free(ports);
- return ASE_NotPresent;
- }
- }
-
- free(ports);
-
- ports = jack_get_ports(This->client, NULL, NULL, JackPortIsPhysical | JackPortIsInput);
-
- if (ports == NULL)
- {
- WARN("couldn't get output ports\n");
- return ASE_NotPresent;
- }
-
- for (i = 0; i < This->active_outputs; i++)
- {
- if (jack_connect(This->client, jack_port_name(This->output_port[i]), ports[i]))
- {
- WARN("output %d connect failed\n", i);
- free(ports);
- return ASE_NotPresent;
- }
- }
-
- free(ports);
-
- TRACE("started\n");
-
- return ASE_OK;
- }
-
- return ASE_NotPresent;
- }
-
- WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_stop, (LPWINEASIO iface))
- {
- TRACE("(%p) stub!\n", iface);
-
- return ASE_OK;
- }
-
- WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_getChannels, (LPWINEASIO iface, long *numInputChannels, long *numOutputChannels))
- {
- IWineASIOImpl * This = (IWineASIOImpl*)iface;
- TRACE("(%p, %p, %p)\n", iface, numInputChannels, numOutputChannels);
-
- if (numInputChannels)
- *numInputChannels = This->num_inputs;
-
- if (numOutputChannels)
- *numOutputChannels = This->num_outputs;
-
- return ASE_OK;
- }
-
- WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_getLatencies, (LPWINEASIO iface, long *inputLatency, long *outputLatency))
- {
- IWineASIOImpl * This = (IWineASIOImpl*)iface;
- TRACE("(%p, %p, %p)\n", iface, inputLatency, outputLatency);
-
- if (inputLatency)
- *inputLatency = This->input_latency;
-
- if (outputLatency)
- *outputLatency = This->output_latency;
-
- return ASE_OK;
- }
-
- WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_getBufferSize, (LPWINEASIO iface, long *minSize, long *maxSize, long *preferredSize, long *granularity))
- {
- IWineASIOImpl * This = (IWineASIOImpl*)iface;
- TRACE("(%p, %p, %p, %p, %p)\n", iface, minSize, maxSize, preferredSize, granularity);
-
- if (minSize)
- *minSize = This->block_frames;
-
- if (maxSize)
- *maxSize = This->block_frames;
-
- if (preferredSize)
- *preferredSize = This->block_frames;
-
- if (granularity)
- *granularity = 0;
-
- return ASE_OK;
- }
-
- WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_canSampleRate, (LPWINEASIO iface, ASIOSampleRate sampleRate))
- {
- IWineASIOImpl * This = (IWineASIOImpl*)iface;
- TRACE("(%p, %f)\n", iface, sampleRate);
-
- if (sampleRate == This->sample_rate)
- return ASE_OK;
-
- return ASE_NoClock;
- }
-
- WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_getSampleRate, (LPWINEASIO iface, ASIOSampleRate *sampleRate))
- {
- IWineASIOImpl * This = (IWineASIOImpl*)iface;
- TRACE("(%p, %p)\n", iface, sampleRate);
-
- if (sampleRate)
- *sampleRate = This->sample_rate;
-
- return ASE_OK;
- }
-
- WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_setSampleRate, (LPWINEASIO iface, ASIOSampleRate sampleRate))
- {
- IWineASIOImpl * This = (IWineASIOImpl*)iface;
- TRACE("(%p, %f)\n", iface, sampleRate);
-
- if (sampleRate != This->sample_rate)
- return ASE_NoClock;
-
- if (sampleRate != This->sample_rate)
- {
- This->sample_rate = sampleRate;
- This->asio_time.timeInfo.sampleRate = sampleRate;
- This->asio_time.timeInfo.flags |= kSampleRateChanged;
- This->miliseconds = (long)((double)(This->block_frames * 1000) / This->sample_rate);
-
- if (This->callbacks && This->callbacks->sampleRateDidChange)
- This->callbacks->sampleRateDidChange(This->sample_rate);
- }
-
- return ASE_OK;
- }
-
- WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_getClockSources, (LPWINEASIO iface, ASIOClockSource *clocks, long *numSources))
- {
- TRACE("(%p, %p, %p)\n", iface, clocks, numSources);
-
- if (clocks && numSources)
- {
- clocks->index = 0;
- clocks->associatedChannel = -1;
- clocks->associatedGroup = -1;
- clocks->isCurrentSource = ASIOTrue;
- strcpy(clocks->name, "Internal");
-
- *numSources = 1;
- return ASE_OK;
- }
-
- return ASE_InvalidParameter;
- }
-
- WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_setClockSource, (LPWINEASIO iface, long reference))
- {
- IWineASIOImpl * This = (IWineASIOImpl*)iface;
- TRACE("(%p, %ld)\n", iface, reference);
-
- if (reference == 0)
- {
- This->asio_time.timeInfo.flags |= kClockSourceChanged;
-
- return ASE_OK;
- }
-
- return ASE_NotPresent;
- }
-
- WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_getSamplePosition, (LPWINEASIO iface, ASIOSamples *sPos, ASIOTimeStamp *tStamp))
- {
- IWineASIOImpl * This = (IWineASIOImpl*)iface;
- TRACE("(%p, %p, %p)\n", iface, sPos, tStamp);
-
- tStamp->lo = This->system_time.lo;
- tStamp->hi = This->system_time.hi;
-
- if (This->sample_position >= twoRaisedTo32)
- {
- sPos->hi = (unsigned long)(This->sample_position * twoRaisedTo32Reciprocal);
- sPos->lo = (unsigned long)(This->sample_position - (sPos->hi * twoRaisedTo32));
- }
- else
- {
- sPos->hi = 0;
- sPos->lo = (unsigned long)This->sample_position;
- }
-
- return ASE_OK;
- }
-
- WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_getChannelInfo, (LPWINEASIO iface, ASIOChannelInfo *info))
- {
- IWineASIOImpl * This = (IWineASIOImpl*)iface;
- int i;
- char name[32];
- TRACE("(%p, %p)\n", iface, info);
-
- if (info->channel < 0 || (info->isInput ? info->channel >= MAX_INPUTS : info->channel >= MAX_OUTPUTS))
- return ASE_InvalidParameter;
-
- info->type = ASIOSTInt16LSB;
- info->channelGroup = 0;
- info->isActive = ASIOFalse;
-
- if (info->isInput)
- {
- for (i = 0; i < This->active_inputs; i++)
- {
- if (This->in_map[i] == info->channel)
- {
- info->isActive = ASIOTrue;
- break;
- }
- }
-
- snprintf(name, sizeof(name), "Input %ld", info->channel);
- }
- else
- {
- for (i = 0; i < This->active_outputs; i++)
- {
- if (This->out_map[i] == info->channel)
- {
- info->isActive = ASIOTrue;
- break;
- }
- }
-
- snprintf(name, sizeof(name), "Output %ld", info->channel);
- }
-
- strcpy(info->name, name);
-
- return ASE_OK;
- }
-
- WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_disposeBuffers, (LPWINEASIO iface))
- {
- int i;
- IWineASIOImpl * This = (IWineASIOImpl*)iface;
- TRACE("(%p)\n", iface);
-
- This->callbacks = NULL;
- __wrapped_IWineASIOImpl_stop(iface);
-
- for (i = 0; i < This->active_inputs; i++)
- {
- HeapFree(GetProcessHeap(), 0, This->input_buffers[i][0]);
- HeapFree(GetProcessHeap(), 0, This->input_buffers[i][1]);
- }
-
- This->active_inputs = 0;
-
- for (i = 0; i < This->active_outputs; i++)
- {
- HeapFree(GetProcessHeap(), 0, This->output_buffers[i][0]);
- HeapFree(GetProcessHeap(), 0, This->output_buffers[i][1]);
- }
-
- This->active_outputs = 0;
-
- return ASE_OK;
- }
-
- WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_createBuffers, (LPWINEASIO iface, ASIOBufferInfo *bufferInfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks))
- {
- IWineASIOImpl * This = (IWineASIOImpl*)iface;
- ASIOBufferInfo * info = bufferInfos;
- int i;
- TRACE("(%p, %p, %ld, %ld, %p)\n", iface, bufferInfos, numChannels, bufferSize, callbacks);
-
- This->active_inputs = 0;
- This->active_outputs = 0;
- This->block_frames = bufferSize;
- This->miliseconds = (long)((double)(This->block_frames * 1000) / This->sample_rate);
-
- for (i = 0; i < numChannels; i++, info++)
- {
- if (info->isInput)
- {
- if (info->channelNum < 0 || info->channelNum >= This->num_inputs)
- {
- WARN("invalid input channel: %ld\n", info->channelNum);
- goto ERROR_PARAM;
- }
-
- if (This->active_inputs >= This->num_inputs)
- {
- WARN("too many inputs\n");
- goto ERROR_PARAM;
- }
-
- This->in_map[This->active_inputs] = info->channelNum;
- This->input_buffers[This->active_inputs][0] = HeapAlloc(GetProcessHeap(), 0, This->block_frames * sizeof(short));
- This->input_buffers[This->active_inputs][1] = HeapAlloc(GetProcessHeap(), 0, This->block_frames * sizeof(short));
- if (This->input_buffers[This->active_inputs][0] && This->input_buffers[This->active_inputs][1])
- {
- info->buffers[0] = This->input_buffers[This->active_inputs][0];
- info->buffers[1] = This->input_buffers[This->active_inputs][1];
- }
- else
- {
- HeapFree(GetProcessHeap(), 0, This->input_buffers[This->active_inputs][0]);
- info->buffers[0] = 0;
- info->buffers[1] = 0;
- WARN("no input buffer memory\n");
- goto ERROR_MEM;
- }
- This->active_inputs++;
- }
- else
- {
- if (info->channelNum < 0 || info->channelNum >= This->num_outputs)
- {
- WARN("invalid output channel: %ld\n", info->channelNum);
- goto ERROR_PARAM;
- }
-
- if (This->active_outputs >= This->num_outputs)
- {
- WARN("too many outputs\n");
- goto ERROR_PARAM;
- }
-
- This->out_map[This->active_outputs] = info->channelNum;
- This->output_buffers[This->active_outputs][0] = HeapAlloc(GetProcessHeap(), 0, This->block_frames * sizeof(short));
- This->output_buffers[This->active_outputs][1] = HeapAlloc(GetProcessHeap(), 0, This->block_frames * sizeof(short));
- if (This->output_buffers[This->active_outputs][0] && This->output_buffers[This->active_outputs][1])
- {
- info->buffers[0] = This->output_buffers[This->active_outputs][0];
- info->buffers[1] = This->output_buffers[This->active_outputs][1];
- }
- else
- {
- HeapFree(GetProcessHeap(), 0, This->output_buffers[This->active_outputs][0]);
- info->buffers[0] = 0;
- info->buffers[1] = 0;
- WARN("no output buffer memory\n");
- goto ERROR_MEM;
- }
- This->active_outputs++;
- }
- }
-
- This->callbacks = callbacks;
-
- if (This->callbacks->asioMessage)
- {
- if (This->callbacks->asioMessage(kAsioSupportsTimeInfo, 0, 0, 0))
- {
- This->time_info_mode = TRUE;
- This->asio_time.timeInfo.speed = 1;
- This->asio_time.timeInfo.systemTime.hi = 0;
- This->asio_time.timeInfo.systemTime.lo = 0;
- This->asio_time.timeInfo.samplePosition.hi = 0;
- This->asio_time.timeInfo.samplePosition.lo = 0;
- This->asio_time.timeInfo.sampleRate = This->sample_rate;
- This->asio_time.timeInfo. flags = kSystemTimeValid | kSamplePositionValid | kSampleRateValid;
-
- This->asio_time.timeCode.speed = 1;
- This->asio_time.timeCode.timeCodeSamples.hi = 0;
- This->asio_time.timeCode.timeCodeSamples.lo = 0;
- This->asio_time.timeCode.flags = kTcValid | kTcRunning;
- }
- else
- This->time_info_mode = FALSE;
- }
- else
- {
- This->time_info_mode = FALSE;
- WARN("asioMessage callback not supplied\n");
- goto ERROR_PARAM;
- }
-
- return ASE_OK;
-
- ERROR_MEM:
- __wrapped_IWineASIOImpl_disposeBuffers(iface);
- WARN("no memory\n");
- return ASE_NoMemory;
-
- ERROR_PARAM:
- __wrapped_IWineASIOImpl_disposeBuffers(iface);
- WARN("invalid parameter\n");
- return ASE_InvalidParameter;
- }
-
- WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_controlPanel, (LPWINEASIO iface))
- {
- TRACE("(%p) stub!\n", iface);
-
- return ASE_OK;
- }
-
- WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_future, (LPWINEASIO iface, long selector, void *opt))
- {
- IWineASIOImpl * This = (IWineASIOImpl*)iface;
- TRACE("(%p, %ld, %p)\n", iface, selector, opt);
-
- switch (selector)
- {
- case kAsioEnableTimeCodeRead:
- This->tc_read = TRUE;
- return ASE_SUCCESS;
- case kAsioDisableTimeCodeRead:
- This->tc_read = FALSE;
- return ASE_SUCCESS;
- case kAsioSetInputMonitor:
- return ASE_SUCCESS;
- case kAsioCanInputMonitor:
- return ASE_SUCCESS;
- case kAsioCanTimeInfo:
- return ASE_SUCCESS;
- case kAsioCanTimeCode:
- return ASE_SUCCESS;
- }
-
- return ASE_NotPresent;
- }
-
- WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_outputReady, (LPWINEASIO iface))
- {
- TRACE("(%p)\n", iface);
-
- return ASE_NotPresent;
- }
-
- static const IWineASIOVtbl WineASIO_Vtbl =
- {
- IWineASIOImpl_QueryInterface,
- IWineASIOImpl_AddRef,
- IWineASIOImpl_Release,
- IWineASIOImpl_init,
- IWineASIOImpl_getDriverName,
- IWineASIOImpl_getDriverVersion,
- IWineASIOImpl_getErrorMessage,
- IWineASIOImpl_start,
- IWineASIOImpl_stop,
- IWineASIOImpl_getChannels,
- IWineASIOImpl_getLatencies,
- IWineASIOImpl_getBufferSize,
- IWineASIOImpl_canSampleRate,
- IWineASIOImpl_getSampleRate,
- IWineASIOImpl_setSampleRate,
- IWineASIOImpl_getClockSources,
- IWineASIOImpl_setClockSource,
- IWineASIOImpl_getSamplePosition,
- IWineASIOImpl_getChannelInfo,
- IWineASIOImpl_createBuffers,
- IWineASIOImpl_disposeBuffers,
- IWineASIOImpl_controlPanel,
- IWineASIOImpl_future,
- IWineASIOImpl_outputReady,
- };
-
- HRESULT asioCreateInstance(REFIID riid, LPVOID *ppobj)
- {
- IWineASIOImpl * pobj;
- TRACE("(%s, %p)\n", debugstr_guid(riid), ppobj);
-
- pobj = HeapAlloc(GetProcessHeap(), 0, sizeof(*pobj));
- if (pobj == NULL) {
- WARN("out of memory\n");
- return E_OUTOFMEMORY;
- }
-
- pobj->lpVtbl = &WineASIO_Vtbl;
- pobj->ref = 1;
- TRACE("pobj = %p\n", pobj);
- *ppobj = pobj;
- TRACE("return %p\n", *ppobj);
- return S_OK;
- }
-
- static void getNanoSeconds(ASIOTimeStamp* ts)
- {
- double nanoSeconds = (double)((unsigned long)timeGetTime ()) * 1000000.;
- ts->hi = (unsigned long)(nanoSeconds / twoRaisedTo32);
- ts->lo = (unsigned long)(nanoSeconds - (ts->hi * twoRaisedTo32));
- }
-
- static int jack_process(jack_nframes_t nframes, void * arg)
- {
- IWineASIOImpl * This = (IWineASIOImpl*)arg;
- int i, j;
- jack_default_audio_sample_t * in, *out;
- jack_transport_state_t ts = jack_transport_query(This->client, NULL);
-
- if (ts == JackTransportRolling)
- {
- if (This->client_state == Init)
- This->client_state = Run;
-
- This->sample_position += nframes;
-
- /* get the input data from JACK and copy it to the ASIO buffers */
- for (i = 0; i < This->active_inputs; i++)
- {
- short * buffer = This->input_buffers[i][This->toggle];
-
- in = jack_port_get_buffer(This->input_port[i], nframes);
-
- for (j = 0; j < nframes; j++)
- buffer[j] = in[j] * 32767.0f;
- }
-
- /* call the ASIO user callback to read the input data and fill the output data */
- getNanoSeconds(&This->system_time);
-
- if (This->time_info_mode)
- {
- __wrapped_IWineASIOImpl_getSamplePosition((LPWINEASIO)This, &This->asio_time.timeInfo.samplePosition, &This->asio_time.timeInfo.systemTime);
- if (This->tc_read)
- {
- /* FIXME */
- This->asio_time.timeCode.timeCodeSamples.lo = This->asio_time.timeInfo.samplePosition.lo;
- This->asio_time.timeCode.timeCodeSamples.hi = 0;
- }
- This->callbacks->bufferSwitchTimeInfo(&This->asio_time, This->toggle, ASIOFalse);
- This->asio_time.timeInfo.flags &= ~(kSampleRateChanged | kClockSourceChanged);
- }
- else
- This->callbacks->bufferSwitch(This->toggle, ASIOFalse);
-
- /* copy the ASIO data to JACK */
- for (i = 0; i < This->active_outputs; i++)
- {
- short * buffer = This->output_buffers[i][This->toggle];
-
- out = jack_port_get_buffer(This->output_port[i], nframes);
-
- for (j = 0; j < nframes; j++)
- out[j] = buffer[j] / 32767.0f;
- }
-
- This->toggle = This->toggle ? 0 : 1;
- }
- else if (ts == JackTransportStopped)
- {
- if (This->client_state == Run)
- This->client_state = Exit;
-
- /* FIXME why is this needed ? */
- jack_transport_start(This->client);
- }
-
- return 0;
- }
|