Compare commits

..

7 Commits

Author SHA1 Message Date
Derek 1fa44eb5fc More accurate latency calc (i think) 2022-12-06 22:12:39 -05:00
Derek 20543aaf5a Copy completed output buffer 2022-12-06 04:21:11 -05:00
Derek 5394c00f9f Defer bufferSwitch processing 2022-12-06 04:20:46 -05:00
Derek 2ef7259809 Organize 2022-12-06 04:20:22 -05:00
Derek 3eed43754c Use malloc/free for heap 2022-12-06 04:17:58 -05:00
Derek 45a5040d4f Prime both buffers 2022-12-06 02:19:35 -05:00
Derek 1580fa66b7 Only output silence to active channels 2022-12-06 01:29:40 -05:00
1 changed files with 57 additions and 53 deletions

110
asio.c
View File

@ -392,7 +392,7 @@ HIDDEN ULONG STDMETHODCALLTYPE Release(LPWINEASIO iface)
jack_free (This->jack_input_ports); jack_free (This->jack_input_ports);
jack_client_close(This->jack_client); jack_client_close(This->jack_client);
if (This->input_channel) if (This->input_channel)
HeapFree(GetProcessHeap(), 0, This->input_channel); free(This->input_channel);
} }
TRACE("WineASIO terminated\n\n"); TRACE("WineASIO terminated\n\n");
if (ref == 0) if (ref == 0)
@ -431,7 +431,7 @@ HIDDEN ASIOBool STDMETHODCALLTYPE Init(LPWINEASIO iface, void *sysRef)
This->asio_current_buffersize = jack_get_buffer_size(This->jack_client); This->asio_current_buffersize = jack_get_buffer_size(This->jack_client);
/* Allocate IOChannel structures */ /* Allocate IOChannel structures */
This->input_channel = HeapAlloc(GetProcessHeap(), 0, (This->wineasio_number_inputs + This->wineasio_number_outputs) * sizeof(IOChannel)); This->input_channel = malloc((This->wineasio_number_inputs + This->wineasio_number_outputs) * sizeof(IOChannel));
if (!This->input_channel) if (!This->input_channel)
{ {
jack_client_close(This->jack_client); jack_client_close(This->jack_client);
@ -475,15 +475,15 @@ HIDDEN ASIOBool STDMETHODCALLTYPE Init(LPWINEASIO iface, void *sysRef)
if (jack_set_buffer_size_callback(This->jack_client, jack_buffer_size_callback, This)) if (jack_set_buffer_size_callback(This->jack_client, jack_buffer_size_callback, This))
{ {
jack_client_close(This->jack_client); jack_client_close(This->jack_client);
HeapFree(GetProcessHeap(), 0, This->input_channel); free(This->input_channel);
ERR("Unable to register JACK buffer size change callback\n"); ERR("Unable to register JACK buffer size change callback\n");
return ASIOFalse; return ASIOFalse;
} }
if (jack_set_latency_callback(This->jack_client, jack_latency_callback, This)) if (jack_set_latency_callback(This->jack_client, jack_latency_callback, This))
{ {
jack_client_close(This->jack_client); jack_client_close(This->jack_client);
HeapFree(GetProcessHeap(), 0, This->input_channel); free(This->input_channel);
ERR("Unable to register JACK latency callback\n"); ERR("Unable to register JACK latency callback\n");
return ASIOFalse; return ASIOFalse;
} }
@ -492,7 +492,7 @@ HIDDEN ASIOBool STDMETHODCALLTYPE Init(LPWINEASIO iface, void *sysRef)
if (jack_set_process_callback(This->jack_client, jack_process_callback, This)) if (jack_set_process_callback(This->jack_client, jack_process_callback, This))
{ {
jack_client_close(This->jack_client); jack_client_close(This->jack_client);
HeapFree(GetProcessHeap(), 0, This->input_channel); free(This->input_channel);
ERR("Unable to register JACK process callback\n"); ERR("Unable to register JACK process callback\n");
return ASIOFalse; return ASIOFalse;
} }
@ -500,7 +500,7 @@ HIDDEN ASIOBool STDMETHODCALLTYPE Init(LPWINEASIO iface, void *sysRef)
if (jack_set_sample_rate_callback (This->jack_client, jack_sample_rate_callback, This)) if (jack_set_sample_rate_callback (This->jack_client, jack_sample_rate_callback, This))
{ {
jack_client_close(This->jack_client); jack_client_close(This->jack_client);
HeapFree(GetProcessHeap(), 0, This->input_channel); free(This->input_channel);
ERR("Unable to register JACK sample rate change callback\n"); ERR("Unable to register JACK sample rate change callback\n");
return ASIOFalse; return ASIOFalse;
} }
@ -570,11 +570,11 @@ HIDDEN ASIOError STDMETHODCALLTYPE Start(LPWINEASIO iface)
return ASE_NotPresent; return ASE_NotPresent;
/* Zero the audio buffer */ /* Zero the audio buffer */
This->asio_buffer_index = 0;
for (i = 0; i < (This->wineasio_number_inputs + This->wineasio_number_outputs) * 2 * This->asio_current_buffersize; i++) for (i = 0; i < (This->wineasio_number_inputs + This->wineasio_number_outputs) * 2 * This->asio_current_buffersize; i++)
This->callback_audio_buffer[i] = 0; This->callback_audio_buffer[i] = 0;
/* prime the callback by preprocessing one outbound ASIO bufffer */ /* prime the callback by preprocessing two outbound ASIO bufffers */
This->asio_buffer_index = 0;
This->asio_sample_position.hi = This->asio_sample_position.lo = 0; This->asio_sample_position.hi = This->asio_sample_position.lo = 0;
time = timeGetTime(); time = timeGetTime();
@ -596,16 +596,15 @@ HIDDEN ASIOError STDMETHODCALLTYPE Start(LPWINEASIO iface)
This->asio_time.timeCode.timeCodeSamples.hi = This->asio_time_stamp.hi; This->asio_time.timeCode.timeCodeSamples.hi = This->asio_time_stamp.hi;
This->asio_time.timeCode.flags = ~(kTcValid | kTcRunning); This->asio_time.timeCode.flags = ~(kTcValid | kTcRunning);
} }
This->asio_callbacks->bufferSwitchTimeInfo(&This->asio_time, This->asio_buffer_index, ASIOTrue); for (i=0; i<2; i++)
} This->asio_callbacks->bufferSwitchTimeInfo(&This->asio_time, i, ASIOFalse);
}
else else
{ /* use the old bufferSwitch method */ { /* use the old bufferSwitch method */
This->asio_callbacks->bufferSwitch(This->asio_buffer_index, ASIOTrue); for (i=0; i<2; i++)
This->asio_callbacks->bufferSwitch(i, ASIOFalse);
} }
/* swith asio buffer */
This->asio_buffer_index = This->asio_buffer_index ? 0 : 1;
This->asio_driver_state = Running; This->asio_driver_state = Running;
TRACE("WineASIO successfully loaded\n"); TRACE("WineASIO successfully loaded\n");
return ASE_OK; return ASE_OK;
@ -666,16 +665,17 @@ HIDDEN ASIOError STDMETHODCALLTYPE GetLatencies(LPWINEASIO iface, LONG *inputLat
IWineASIOImpl *This = (IWineASIOImpl*)iface; IWineASIOImpl *This = (IWineASIOImpl*)iface;
jack_latency_range_t range; jack_latency_range_t range;
if (!inputLatency || !outputLatency) // REVIEW: Return value is not in ASIO spec! Is there some faulty client behavior?
return ASE_InvalidParameter; // if (!inputLatency || !outputLatency)
// return ASE_InvalidParameter;
if (This->asio_driver_state == Loaded) if (This->asio_driver_state == Loaded)
return ASE_NotPresent; return ASE_NotPresent;
jack_port_get_latency_range(This->input_channel[0].port, JackCaptureLatency, &range); jack_port_get_latency_range(This->input_channel[0].port, JackCaptureLatency, &range);
*inputLatency = range.max; *inputLatency = range.max + This->asio_current_buffersize;
jack_port_get_latency_range(This->output_channel[0].port, JackPlaybackLatency, &range); jack_port_get_latency_range(This->output_channel[0].port, JackPlaybackLatency, &range);
*outputLatency = range.max; *outputLatency = range.max + (This->asio_current_buffersize * 2);
TRACE("iface: %p, input latency: %d, output latency: %d\n", iface, *inputLatency, *outputLatency); TRACE("iface: %p, input latency: %d, output latency: %d\n", iface, *inputLatency, *outputLatency);
return ASE_OK; return ASE_OK;
@ -992,7 +992,7 @@ HIDDEN ASIOError STDMETHODCALLTYPE CreateBuffers(LPWINEASIO iface, ASIOBufferInf
/* Allocate audio buffers */ /* Allocate audio buffers */
This->callback_audio_buffer = HeapAlloc(GetProcessHeap(), 0, This->callback_audio_buffer = malloc(
(This->wineasio_number_inputs + This->wineasio_number_outputs) * 2 * This->asio_current_buffersize * sizeof(jack_default_audio_sample_t)); (This->wineasio_number_inputs + This->wineasio_number_outputs) * 2 * This->asio_current_buffersize * sizeof(jack_default_audio_sample_t));
if (!This->callback_audio_buffer) if (!This->callback_audio_buffer)
{ {
@ -1097,7 +1097,7 @@ HIDDEN ASIOError STDMETHODCALLTYPE DisposeBuffers(LPWINEASIO iface)
This->asio_active_inputs = This->asio_active_outputs = 0; This->asio_active_inputs = This->asio_active_outputs = 0;
if (This->callback_audio_buffer) if (This->callback_audio_buffer)
HeapFree(GetProcessHeap(), 0, This->callback_audio_buffer); free(This->callback_audio_buffer);
This->asio_driver_state = Initialized; This->asio_driver_state = Initialized;
return ASE_OK; return ASE_OK;
@ -1227,31 +1227,6 @@ HIDDEN ASIOError STDMETHODCALLTYPE OutputReady(LPWINEASIO iface)
* JACK callbacks * JACK callbacks
*/ */
static inline int jack_buffer_size_callback(jack_nframes_t nframes, void *arg)
{
IWineASIOImpl *This = (IWineASIOImpl*)arg;
if(This->asio_driver_state != Running)
return 0;
if (This->asio_callbacks->asioMessage(kAsioSelectorSupported, kAsioResetRequest, 0 , 0))
This->asio_callbacks->asioMessage(kAsioResetRequest, 0, 0, 0);
return 0;
}
static inline void jack_latency_callback(jack_latency_callback_mode_t mode, void *arg)
{
IWineASIOImpl *This = (IWineASIOImpl*)arg;
if(This->asio_driver_state != Running)
return;
if (This->asio_callbacks->asioMessage(kAsioSelectorSupported, kAsioLatenciesChanged, 0 , 0))
This->asio_callbacks->asioMessage(kAsioLatenciesChanged, 0, 0, 0);
return;
}
static inline int jack_process_callback(jack_nframes_t nframes, void *arg) static inline int jack_process_callback(jack_nframes_t nframes, void *arg)
{ {
IWineASIOImpl *This = (IWineASIOImpl*)arg; IWineASIOImpl *This = (IWineASIOImpl*)arg;
@ -1264,8 +1239,9 @@ static inline int jack_process_callback(jack_nframes_t nframes, void *arg)
/* output silence if the ASIO callback isn't running yet */ /* output silence if the ASIO callback isn't running yet */
if (This->asio_driver_state != Running) if (This->asio_driver_state != Running)
{ {
for (i = 0; i < This->asio_active_outputs; i++) for (i = 0; i < This->wineasio_number_outputs; i++)
bzero(jack_port_get_buffer(This->output_channel[i].port, nframes), sizeof (jack_default_audio_sample_t) * nframes); if (This->output_channel[i].active == ASIOTrue)
bzero(jack_port_get_buffer(This->output_channel[i].port, nframes), sizeof (jack_default_audio_sample_t) * nframes);
return 0; return 0;
} }
@ -1300,13 +1276,16 @@ static inline int jack_process_callback(jack_nframes_t nframes, void *arg)
if (jack_transport_state == JackTransportRolling) if (jack_transport_state == JackTransportRolling)
This->asio_time.timeCode.flags |= kTcRunning; This->asio_time.timeCode.flags |= kTcRunning;
} }
This->asio_callbacks->bufferSwitchTimeInfo(&This->asio_time, This->asio_buffer_index, ASIOTrue); This->asio_callbacks->bufferSwitchTimeInfo(&This->asio_time, This->asio_buffer_index, ASIOFalse);
} }
else else
{ /* use the old bufferSwitch method */ { /* use the old bufferSwitch method */
This->asio_callbacks->bufferSwitch(This->asio_buffer_index, ASIOTrue); This->asio_callbacks->bufferSwitch(This->asio_buffer_index, ASIOFalse);
} }
/* switch asio buffer */
This->asio_buffer_index = This->asio_buffer_index ? 0 : 1;
/* copy asio to jack buffers */ /* copy asio to jack buffers */
for (i = 0; i < This->wineasio_number_outputs; i++) for (i = 0; i < This->wineasio_number_outputs; i++)
if (This->output_channel[i].active == ASIOTrue) if (This->output_channel[i].active == ASIOTrue)
@ -1314,11 +1293,35 @@ static inline int jack_process_callback(jack_nframes_t nframes, void *arg)
&This->output_channel[i].audio_buffer[nframes * This->asio_buffer_index], &This->output_channel[i].audio_buffer[nframes * This->asio_buffer_index],
sizeof (jack_default_audio_sample_t) * nframes); sizeof (jack_default_audio_sample_t) * nframes);
/* swith asio buffer */
This->asio_buffer_index = This->asio_buffer_index ? 0 : 1;
return 0; return 0;
} }
static inline int jack_buffer_size_callback(jack_nframes_t nframes, void *arg)
{
IWineASIOImpl *This = (IWineASIOImpl*)arg;
if(This->asio_driver_state != Running)
return 0;
if (This->asio_callbacks->asioMessage(kAsioSelectorSupported, kAsioResetRequest, 0 , 0))
This->asio_callbacks->asioMessage(kAsioResetRequest, 0, 0, 0);
return 0;
}
static inline void jack_latency_callback(jack_latency_callback_mode_t mode, void *arg)
{
IWineASIOImpl *This = (IWineASIOImpl*)arg;
if(This->asio_driver_state != Running)
return;
if (This->asio_callbacks->asioMessage(kAsioSelectorSupported, kAsioLatenciesChanged, 0 , 0))
This->asio_callbacks->asioMessage(kAsioLatenciesChanged, 0, 0, 0);
return;
}
static inline int jack_sample_rate_callback(jack_nframes_t nframes, void *arg) static inline int jack_sample_rate_callback(jack_nframes_t nframes, void *arg)
{ {
IWineASIOImpl *This = (IWineASIOImpl*)arg; IWineASIOImpl *This = (IWineASIOImpl*)arg;
@ -1328,6 +1331,7 @@ static inline int jack_sample_rate_callback(jack_nframes_t nframes, void *arg)
This->asio_sample_rate = nframes; This->asio_sample_rate = nframes;
This->asio_callbacks->sampleRateDidChange(nframes); This->asio_callbacks->sampleRateDidChange(nframes);
return 0; return 0;
} }
@ -1406,7 +1410,7 @@ static VOID configure_driver(IWineASIOImpl *This)
This->asio_buffer_index = 0; This->asio_buffer_index = 0;
This->asio_callbacks = NULL; This->asio_callbacks = NULL;
This->asio_can_time_code = FALSE; This->asio_can_time_code = FALSE;
This->asio_current_buffersize = 0; This->asio_current_buffersize = ASIO_PREFERRED_BUFFERSIZE;
This->asio_driver_state = Loaded; This->asio_driver_state = Loaded;
This->asio_sample_rate = 0; This->asio_sample_rate = 0;
This->asio_time_info_mode = FALSE; This->asio_time_info_mode = FALSE;