Browse Source

WineASIO 0.0.3

tags/v1.0.0
Joakim B Hernberg 14 years ago
parent
commit
4e17843f71
1 changed files with 215 additions and 74 deletions
  1. +215
    -74
      asio.c

+ 215
- 74
asio.c View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2006 Robert Reif
* Copyright (C) 2006,2007 Robert Reif
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -70,6 +70,7 @@ MAKE_FUNCPTR(jack_port_get_buffer);
MAKE_FUNCPTR(jack_get_ports);
MAKE_FUNCPTR(jack_port_name);
MAKE_FUNCPTR(jack_get_buffer_size);
MAKE_FUNCPTR(jack_port_unregister);
#undef MAKE_FUNCPTR

void *jackhandle = NULL;
@@ -87,8 +88,8 @@ static GUID const CLSID_WineASIO = {
#define twoRaisedTo32 4294967296.0
#define twoRaisedTo32Reciprocal (1.0 / twoRaisedTo32)

#define MAX_INPUTS 2
#define MAX_OUTPUTS 2
#define MAX_INPUTS 32
#define MAX_OUTPUTS 32

/* ASIO drivers use the thiscall calling convention which only Microsoft compilers
* produce. These macros add an extra layer to fixup the registers properly for
@@ -182,19 +183,24 @@ struct IWineASIOImpl
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];
void *input_buffers[MAX_INPUTS][2];
void *output_buffers[MAX_OUTPUTS][2];
long active_inputs;
long active_outputs;
BOOL time_info_mode;
BOOL tc_read;
long state;
unsigned int sample_size;
int sample_type;

/* JACK stuff */
char client_name[64];
unsigned int num_inputs;
jack_port_t *input_port[MAX_INPUTS];
const char *input_names[MAX_INPUTS];
unsigned int num_outputs;
jack_port_t *output_port[MAX_OUTPUTS];
const char *output_names[MAX_INPUTS];
jack_client_t *client;
long client_state;
long toggle;
@@ -215,7 +221,7 @@ 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);
TRACE("(%p) ref was %d\n", This, ref - 1);
return ref;
}

@@ -223,7 +229,7 @@ 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);
TRACE("(%p) ref was %d\n", This, ref + 1);

if (!ref) {
fp_jack_client_close(This->client);
@@ -269,10 +275,25 @@ static HRESULT WINAPI IWineASIOImpl_QueryInterface(LPWINEASIO iface, REFIID riid
WRAP_THISCALL( ASIOBool __stdcall, IWineASIOImpl_init, (LPWINEASIO iface, void *sysHandle))
{
IWineASIOImpl * This = (IWineASIOImpl*)iface;
jack_port_t *input, *output;
jack_status_t status;
int i;
const char ** ports;
TRACE("(%p, %p)\n", iface, sysHandle);

strcpy(This->client_name, "Wine_ASIO_Jack_Client");
#if 0
This->sample_type = ASIOSTInt16LSB;
This->sample_size = 2;
#endif
#if 1
This->sample_type = ASIOSTInt32LSB;
This->sample_size = 4;
#endif
#if 0
This->sample_type = ASIOSTFloat32LSB;
This->sample_size = 4;
#endif
This->sample_rate = 48000.0;
This->block_frames = 1024;
This->input_latency = This->block_frames;
@@ -313,14 +334,17 @@ WRAP_THISCALL( ASIOBool __stdcall, IWineASIOImpl_init, (LPWINEASIO iface, void *
for (i = 0; i < MAX_INPUTS; i++)
{
This->in_map[i] = 0;
This->input_names[i] = 0;
}

for (i = 0; i < MAX_OUTPUTS; i++)
{
This->out_map[i] = 0;
This->output_names[i] = 0;
}

This->client = fp_jack_client_open("Wine_ASIO_Jack_Client", JackNullOption, &status, NULL);
This->client = fp_jack_client_open(This->client_name, JackNullOption, &status, NULL);

if (This->client == NULL)
{
WARN("failed to open jack server\n");
@@ -332,38 +356,91 @@ WRAP_THISCALL( ASIOBool __stdcall, IWineASIOImpl_init, (LPWINEASIO iface, void *
if (status & JackServerStarted)
TRACE("JACK server started\n");

if (status & JackNameNotUnique)
{
strcpy(This->client_name, jack_get_client_name(This->client));
TRACE("unique name `%s' assigned\n", This->client_name);
}

fp_jack_set_process_callback(This->client, jack_process, This);

This->sample_rate = fp_jack_get_sample_rate(This->client);
This->block_frames = fp_jack_get_buffer_size(This->client);

This->miliseconds = (long)((double)(This->block_frames * 1000) / This->sample_rate);
This->input_latency = This->block_frames;
This->output_latency = This->block_frames * 2;

TRACE("sample rate: %f\n", This->sample_rate);
TRACE("buffer size: %ld\n", This->block_frames);

for (i = 0; i < MAX_INPUTS; i++)
{
char name[32];
snprintf(name, sizeof(name), "Input%d", i);
This->input_port[i] = fp_jack_port_register(This->client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, i);
if (This->input_port[i] == 0)
break;
/* create two temporary ports to see what's out there */
input = fp_jack_port_register(This->client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
output = fp_jack_port_register(This->client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);

This->num_inputs++;
if ((input == NULL) || (output == NULL))
{
WARN("couldn't register ports\n");
return ASE_NotPresent;
}

TRACE("found %ld inputs\n", This->num_inputs);
/* you need to the client to find out what ports are available */
if (fp_jack_activate(This->client))
{
WARN("couldn't activate client\n");
return ASE_NotPresent;
}
/* get the list of avaliable input ports */
ports = fp_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 < MAX_OUTPUTS; i++)
for (This->num_inputs = 0; This->num_inputs < MAX_INPUTS; This->num_inputs++)
{
char name[32];
snprintf(name, sizeof(name), "Output%d", i);
This->output_port[i] = fp_jack_port_register(This->client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, i);
if (This->output_port[i] == 0)
if (ports[This->num_inputs])
{
This->input_names[This->num_inputs] = strdup(ports[This->num_inputs]);
TRACE("input port[%d] %s\n", This->num_inputs, This->input_names[This->num_inputs]);
}
else
break;
}

free(ports);

/* get the list of avaliable output ports */
ports = fp_jack_get_ports(This->client, NULL, NULL, JackPortIsPhysical | JackPortIsInput);

if (ports == NULL)
{
WARN("couldn't get output ports\n");
return ASE_NotPresent;
}

This->num_outputs++;
for (This->num_outputs = 0; This->num_outputs < MAX_OUTPUTS; This->num_outputs++)
{
if (ports[This->num_outputs])
{
This->output_names[This->num_outputs] = strdup(ports[This->num_outputs]);
TRACE("output port[%d] %s\n", This->num_outputs, This->output_names[This->num_outputs]);
}
else
break;
}

TRACE("found %ld outputs\n", This->num_outputs);
free(ports);

/* get rid of temporary ports */
fp_jack_port_unregister(This->client, input);
fp_jack_port_unregister(This->client, output);

TRACE("found %d inputs\n", This->num_inputs);
TRACE("found %d outputs\n", This->num_outputs);

return ASIOTrue;
}
@@ -390,7 +467,6 @@ WRAP_THISCALL( void __stdcall, IWineASIOImpl_getErrorMessage, (LPWINEASIO iface,
WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_start, (LPWINEASIO iface))
{
IWineASIOImpl * This = (IWineASIOImpl*)iface;
const char ** ports;
int i;
TRACE("(%p)\n", iface);

@@ -400,52 +476,44 @@ WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_start, (LPWINEASIO iface))
This->system_time.lo = 0;
This->system_time.hi = 0;

if (fp_jack_activate(This->client))
for (i = 0; i < This->active_inputs; i++)
{
WARN("couldn't activate client\n");
return ASE_NotPresent;
}
This->input_port[i] = fp_jack_port_register(This->client, This->input_names[i], JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, i);

ports = fp_jack_get_ports(This->client, NULL, NULL, JackPortIsPhysical | JackPortIsOutput);
if (This->input_port[i] == NULL)
{
WARN("input %d connect failed\n", i);
return ASE_NotPresent;
}

if (ports == NULL)
{
WARN("couldn't get input ports\n");
return ASE_NotPresent;
}
TRACE("registered input port %d: %s\n", i, This->input_names[i]);

for (i = 0; i < This->active_inputs; i++)
{
if (fp_jack_connect(This->client, ports[i], fp_jack_port_name(This->input_port[i])))
if (fp_jack_connect(This->client, This->input_names[i], fp_jack_port_name(This->input_port[i])))
{
WARN("input %d connect failed\n", i);
free(ports);
return ASE_NotPresent;
}
}

free(ports);
for (i = 0; i < This->active_outputs; i++)
{
This->output_port[i] = fp_jack_port_register(This->client, This->output_names[i], JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, i);

ports = fp_jack_get_ports(This->client, NULL, NULL, JackPortIsPhysical | JackPortIsInput);
if (This->output_port[i] == NULL)
{
WARN("output %d connect failed\n", i);
return ASE_NotPresent;
}

if (ports == NULL)
{
WARN("couldn't get output ports\n");
return ASE_NotPresent;
}
TRACE("registered output port %d: %s\n", i, This->output_names[i]);

for (i = 0; i < This->active_outputs; i++)
{
if (fp_jack_connect(This->client, fp_jack_port_name(This->output_port[i]), ports[i]))
if (fp_jack_connect(This->client, fp_jack_port_name(This->output_port[i]), This->output_names[i]))
{
WARN("output %d connect failed\n", i);
free(ports);
return ASE_NotPresent;
}
}

free(ports);

This->state = Run;
TRACE("started\n");

@@ -482,6 +550,8 @@ WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_getChannels, (LPWINEASIO iface
if (numOutputChannels)
*numOutputChannels = This->num_outputs;

TRACE("inputs: %d outputs: %d\n", This->num_inputs, This->num_outputs);

return ASE_OK;
}

@@ -516,6 +586,8 @@ WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_getBufferSize, (LPWINEASIO ifa
if (granularity)
*granularity = 0;

TRACE("min: %ld max: %ld preferred: %ld granularity: 0\n", This->block_frames, This->block_frames, This->block_frames);

return ASE_OK;
}

@@ -538,6 +610,8 @@ WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_getSampleRate, (LPWINEASIO ifa
if (sampleRate)
*sampleRate = This->sample_rate;

TRACE("rate: %f\n", This->sample_rate);

return ASE_OK;
}

@@ -560,6 +634,8 @@ WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_setSampleRate, (LPWINEASIO ifa
This->callbacks->sampleRateDidChange(This->sample_rate);
}

TRACE("rate: %f\n", This->sample_rate);

return ASE_OK;
}

@@ -623,13 +699,16 @@ WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_getChannelInfo, (LPWINEASIO if
{
IWineASIOImpl * This = (IWineASIOImpl*)iface;
int i;
char name[32];
const char * name;
TRACE("(%p, %p)\n", iface, info);

if (info->channel < 0 || (info->isInput ? info->channel >= MAX_INPUTS : info->channel >= MAX_OUTPUTS))
if (info->channel < 0 || (info->isInput ? info->channel >= This->num_inputs : info->channel >= This->num_outputs))
return ASE_InvalidParameter;

info->type = ASIOSTInt16LSB;
TRACE("info->channel = %ld\n", info->channel);
TRACE("info->isInput = %ld\n", info->isInput);

info->type = This->sample_type;
info->channelGroup = 0;
info->isActive = ASIOFalse;

@@ -644,7 +723,7 @@ WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_getChannelInfo, (LPWINEASIO if
}
}

snprintf(name, sizeof(name), "Input %ld", info->channel);
name = This->input_names[info->channel];
}
else
{
@@ -657,11 +736,16 @@ WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_getChannelInfo, (LPWINEASIO if
}
}

snprintf(name, sizeof(name), "Output %ld", info->channel);
name = This->output_names[info->channel];
}

strcpy(info->name, name);

TRACE("info->isActive = %ld\n", info->isActive);
TRACE("info->channelGroup = %ld\n", info->channelGroup);
TRACE("info->type = %ld\n", info->type);
TRACE("info->name = %s\n", info->name);

return ASE_OK;
}

@@ -722,8 +806,8 @@ WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_createBuffers, (LPWINEASIO ifa
}

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));
This->input_buffers[This->active_inputs][0] = HeapAlloc(GetProcessHeap(), 0, This->block_frames * This->sample_size);
This->input_buffers[This->active_inputs][1] = HeapAlloc(GetProcessHeap(), 0, This->block_frames * This->sample_size);
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];
@@ -754,8 +838,8 @@ WRAP_THISCALL( ASIOError __stdcall, IWineASIOImpl_createBuffers, (LPWINEASIO ifa
}

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));
This->output_buffers[This->active_outputs][0] = HeapAlloc(GetProcessHeap(), 0, This->block_frames * This->sample_size);
This->output_buffers[This->active_outputs][1] = HeapAlloc(GetProcessHeap(), 0, This->block_frames * This->sample_size);
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];
@@ -912,6 +996,7 @@ BOOL init_jack()
LOAD_FUNCPTR(jack_get_ports);
LOAD_FUNCPTR(jack_port_name);
LOAD_FUNCPTR(jack_get_buffer_size);
LOAD_FUNCPTR(jack_port_unregister);
#undef LOAD_FUNCPTR

return TRUE;
@@ -931,8 +1016,10 @@ HRESULT asioCreateInstance(REFIID riid, LPVOID *ppobj)
IWineASIOImpl * pobj;
TRACE("(%s, %p)\n", debugstr_guid(riid), ppobj);

if (!init_jack())
if (!init_jack()) {
WARN("init_jack failed!\n");
return ERROR_NOT_SUPPORTED;
}
pobj = HeapAlloc(GetProcessHeap(), 0, sizeof(*pobj));
if (pobj == NULL) {
@@ -973,14 +1060,41 @@ static int jack_process(jack_nframes_t nframes, void * arg)
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++)
switch (This->sample_type)
{
short * buffer = This->input_buffers[i][This->toggle];
case ASIOSTInt16LSB:
for (i = 0; i < This->active_inputs; i++)
{
short * buffer = This->input_buffers[i][This->toggle];

in = fp_jack_port_get_buffer(This->input_port[i], nframes);
in = fp_jack_port_get_buffer(This->input_port[i], nframes);

for (j = 0; j < nframes; j++)
buffer[j] = in[j] * 32767.0f;
for (j = 0; j < nframes; j++)
buffer[j] = in[j] * 32767.0f;
}
break;
case ASIOSTInt32LSB:
for (i = 0; i < This->active_inputs; i++)
{
int32_t * buffer = This->input_buffers[i][This->toggle];

in = fp_jack_port_get_buffer(This->input_port[i], nframes);

for (j = 0; j < nframes; j++)
buffer[j] = in[j] * 2147483647.0f;
}
break;
case ASIOSTFloat32LSB:
for (i = 0; i < This->active_inputs; i++)
{
float * buffer = This->input_buffers[i][This->toggle];

in = fp_jack_port_get_buffer(This->input_port[i], nframes);

for (j = 0; j < nframes; j++)
buffer[j] = in[j];
}
break;
}

/* call the ASIO user callback to read the input data and fill the output data */
@@ -993,14 +1107,41 @@ static int jack_process(jack_nframes_t nframes, void * arg)
sem_wait(&This->semaphore2);

/* copy the ASIO data to JACK */
for (i = 0; i < This->active_outputs; i++)
switch (This->sample_type)
{
short * buffer = This->output_buffers[i][This->toggle];
case ASIOSTInt16LSB:
for (i = 0; i < This->active_outputs; i++)
{
short * buffer = This->output_buffers[i][This->toggle];

out = fp_jack_port_get_buffer(This->output_port[i], nframes);
out = fp_jack_port_get_buffer(This->output_port[i], nframes);

for (j = 0; j < nframes; j++)
out[j] = buffer[j] / 32767.0f;
for (j = 0; j < nframes; j++)
out[j] = buffer[j] / 32767.0f;
}
break;
case ASIOSTInt32LSB:
for (i = 0; i < This->active_outputs; i++)
{
int32_t * buffer = This->output_buffers[i][This->toggle];

out = fp_jack_port_get_buffer(This->output_port[i], nframes);

for (j = 0; j < nframes; j++)
out[j] = buffer[j] / 2147483647.0f;
}
break;
case ASIOSTFloat32LSB:
for (i = 0; i < This->active_outputs; i++)
{
float * buffer = This->output_buffers[i][This->toggle];

out = fp_jack_port_get_buffer(This->output_port[i], nframes);

for (j = 0; j < nframes; j++)
out[j] = buffer[j];
}
break;
}
}
else if (ts == JackTransportStopped)


Loading…
Cancel
Save