git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@3428 0c269be4-1314-0410-8aa9-9f06e86f4224tags/1.9.2
@@ -23,10 +23,14 @@ Torben Hohn | |||
--------------------------- | |||
Jackdmp changes log | |||
--------------------------- | |||
2009-03-12 Stephane Letz <letz@grame.fr> | |||
* Try automatic adaptative mode in adapters. | |||
2009-03-11 Stephane Letz <letz@grame.fr> | |||
* Client incorrect re-naming fixed: now done at socket level also. | |||
* Client incorrect re-naming fixed : now done at socket level also. | |||
2009-03-10 Stephane Letz <letz@grame.fr> | |||
@@ -36,19 +36,22 @@ namespace Jack | |||
int JackAudioAdapter::Process (jack_nframes_t frames, void* arg) | |||
{ | |||
JackAudioAdapter* adapter = static_cast<JackAudioAdapter*>(arg); | |||
if (!adapter->fAudioAdapter->IsRunning()) | |||
return 0; | |||
float* inputBuffer[adapter->fAudioAdapter->GetInputs()]; | |||
float* outputBuffer[adapter->fAudioAdapter->GetOutputs()]; | |||
// Always clear output | |||
for (int i = 0; i < adapter->fAudioAdapter->GetInputs(); i++) { | |||
inputBuffer[i] = (float*)jack_port_get_buffer(adapter->fCapturePortList[i], frames); | |||
memset(inputBuffer[i], 0, frames * sizeof(float)); | |||
} | |||
for (int i = 0; i < adapter->fAudioAdapter->GetOutputs(); i++) { | |||
outputBuffer[i] = (float*)jack_port_get_buffer(adapter->fPlaybackPortList[i], frames); | |||
} | |||
adapter->fAudioAdapter->PullAndPush(inputBuffer, outputBuffer, frames); | |||
if (adapter->fAudioAdapter->IsRunning()) { | |||
for (int i = 0; i < adapter->fAudioAdapter->GetOutputs(); i++) { | |||
outputBuffer[i] = (float*)jack_port_get_buffer(adapter->fPlaybackPortList[i], frames); | |||
} | |||
adapter->fAudioAdapter->PullAndPush(inputBuffer, outputBuffer, frames); | |||
} | |||
return 0; | |||
} | |||
@@ -81,7 +84,7 @@ namespace Jack | |||
param = (const jack_driver_param_t*) node->data; | |||
switch (param->character) { | |||
case 'c': | |||
fAutoConnect = param->value.i; | |||
fAutoConnect = true; | |||
break; | |||
} | |||
} | |||
@@ -47,13 +47,12 @@ namespace Jack | |||
for (int i = 1; i < max; i++) | |||
{ | |||
fprintf(file, "%d \t %d \t %d \t %f \t %f \t %d \t %d \n", | |||
fTable[i].delta, fTable[i+1].time1 - fTable[i].time1, | |||
fTable[i+1].time2 - fTable[i].time2, | |||
fTable[i].delta, fTable[i].time1, fTable[i].time2, | |||
fTable[i].r1, fTable[i].r2, fTable[i].pos1, fTable[i].pos2); | |||
} | |||
fclose(file); | |||
/* No used for now | |||
// No used for now | |||
// Adapter timing 1 | |||
file = fopen("AdapterTiming1.plot", "w"); | |||
fprintf(file, "set multiplot\n"); | |||
@@ -63,9 +62,9 @@ namespace Jack | |||
fprintf(file, "set xlabel \"audio cycles\"\n"); | |||
fprintf(file, "set ylabel \"frames\"\n"); | |||
fprintf(file, "plot "); | |||
sprintf(buffer, "\"JackAudioAdapter.log\" using 2 title \"Consumer interrupt period\" with lines,"); | |||
sprintf(buffer, "\"JackAudioAdapter.log\" using 2 title \"Ringbuffer error\" with lines,"); | |||
fprintf(file, buffer); | |||
sprintf(buffer, "\"JackAudioAdapter.log\" using 3 title \"Producer interrupt period\" with lines"); | |||
sprintf(buffer, "\"JackAudioAdapter.log\" using 3 title \"Ringbuffer error with timing correction\" with lines"); | |||
fprintf(file, buffer); | |||
fprintf(file, "\n unset multiplot\n"); | |||
@@ -84,8 +83,7 @@ namespace Jack | |||
fprintf(file, buffer); | |||
fclose(file); | |||
*/ | |||
// Adapter timing 2 | |||
file = fopen("AdapterTiming2.plot", "w"); | |||
fprintf(file, "set multiplot\n"); | |||
@@ -150,22 +148,32 @@ namespace Jack | |||
} | |||
#endif | |||
void JackAudioAdapterInterface::GrowRingBufferSize() | |||
{ | |||
fRingbufferCurSize *= 2; | |||
} | |||
void JackAudioAdapterInterface::AdaptRingBufferSize() | |||
{ | |||
if (fHostBufferSize > fAdaptedBufferSize) | |||
fRingbufferCurSize = 4 * fHostBufferSize; | |||
else | |||
fRingbufferCurSize = 4 * fAdaptedBufferSize; | |||
} | |||
void JackAudioAdapterInterface::ResetRingBuffers() | |||
{ | |||
if (fRingbufferSize == 0) { | |||
fRingbufferCurSize *= 2; | |||
if (fRingbufferCurSize > DEFAULT_RB_SIZE) | |||
fRingbufferCurSize = DEFAULT_RB_SIZE; | |||
} | |||
if (fRingbufferCurSize > DEFAULT_RB_SIZE) | |||
fRingbufferCurSize = DEFAULT_RB_SIZE; | |||
for (int i = 0; i < fCaptureChannels; i++) | |||
fCaptureRingBuffer[i]->Reset(fRingbufferCurSize); | |||
for (int i = 0; i < fPlaybackChannels; i++) | |||
fPlaybackRingBuffer[i]->Reset(fRingbufferCurSize); | |||
} | |||
void JackAudioAdapterInterface::Reset() | |||
void JackAudioAdapterInterface::Reset() | |||
{ | |||
ResetRingBuffers(); | |||
fRunning = false; | |||
@@ -177,10 +185,11 @@ namespace Jack | |||
fCaptureRingBuffer = new JackResampler*[fCaptureChannels]; | |||
fPlaybackRingBuffer = new JackResampler*[fPlaybackChannels]; | |||
fRingbufferCurSize = (fRingbufferSize == 0) ? DEFAULT_ADAPTATIVE_SIZE : DEFAULT_RB_SIZE; | |||
if (fRingbufferSize == 0) { | |||
if (fAdaptative) { | |||
jack_info("Ringbuffer automatic adaptative mode"); | |||
} else { | |||
fRingbufferCurSize = DEFAULT_RB_SIZE; | |||
jack_info("Fixed ringbuffer size = %d frames", fRingbufferCurSize); | |||
} | |||
for (int i = 0; i < fCaptureChannels; i++ ) { | |||
@@ -213,14 +222,14 @@ namespace Jack | |||
{ | |||
bool failure = false; | |||
fRunning = true; | |||
// Finer estimation of the position in the ringbuffer | |||
int delta_frames = (fPullAndPushTime > 0) ? (int)((float(long(GetMicroSeconds() - fPullAndPushTime)) * float(fAdaptedSampleRate)) / 1000000.f) : 0; | |||
double ratio = fPIControler.GetRatio(fCaptureRingBuffer[0]->GetError() - delta_frames); | |||
/* | |||
Finer estimation of the position in the ringbuffer ?? | |||
int delta_frames = (int)(float(long(GetMicroSeconds() - fPullAndPushTime)) * float(fAdaptedSampleRate)) / 1000000.f; | |||
double ratio = fPIControler.GetRatio(fCaptureRingBuffer[0]->GetOffset() - delta_frames); | |||
*/ | |||
double ratio = fPIControler.GetRatio(fCaptureRingBuffer[0]->GetOffset()); | |||
#ifdef JACK_MONITOR | |||
fTable.Write(fCaptureRingBuffer[0]->GetError(), fCaptureRingBuffer[0]->GetError() - delta_frames, ratio, 1/ratio, fCaptureRingBuffer[0]->ReadSpace(), fCaptureRingBuffer[0]->ReadSpace()); | |||
#endif | |||
// Push/pull from ringbuffer | |||
for (int i = 0; i < fCaptureChannels; i++) { | |||
@@ -234,14 +243,10 @@ namespace Jack | |||
if (fPlaybackRingBuffer[i]->ReadResample(outputBuffer[i], frames) < frames) | |||
failure = true; | |||
} | |||
#ifdef JACK_MONITOR | |||
fTable.Write(0, 0, ratio, 1/ratio, fCaptureRingBuffer[0]->ReadSpace(), fPlaybackRingBuffer[0]->WriteSpace()); | |||
#endif | |||
// Reset all ringbuffers in case of failure | |||
if (failure) { | |||
jack_error("JackAudioAdapterInterface::PushAndPull ringbuffer failure... reset"); | |||
GrowRingBufferSize(); | |||
ResetRingBuffers(); | |||
return -1; | |||
} else { | |||
@@ -251,28 +256,21 @@ namespace Jack | |||
int JackAudioAdapterInterface::PullAndPush(float** inputBuffer, float** outputBuffer, unsigned int frames) | |||
{ | |||
bool failure = false; | |||
int res = 0; | |||
fPullAndPushTime = GetMicroSeconds(); | |||
// Push/pull from ringbuffer | |||
for (int i = 0; i < fCaptureChannels; i++) { | |||
if (fCaptureRingBuffer[i]->Read(inputBuffer[i], frames) < frames) | |||
failure = true; | |||
res = -1; | |||
} | |||
for (int i = 0; i < fPlaybackChannels; i++) { | |||
if (fPlaybackRingBuffer[i]->Write(outputBuffer[i], frames) < frames) | |||
failure = true; | |||
} | |||
// Reset all ringbuffers in case of failure | |||
if (failure) { | |||
jack_error("JackCallbackAudioAdapter::PullAndPush ringbuffer failure... reset"); | |||
Reset(); | |||
return -1; | |||
} else { | |||
return 0; | |||
res = -1; | |||
} | |||
return res; | |||
} | |||
} // namespace |
@@ -23,6 +23,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
#include "JackResampler.h" | |||
#include "JackFilters.h" | |||
#include "JackConstants.h" | |||
#include <stdio.h> | |||
namespace Jack | |||
{ | |||
@@ -89,13 +90,15 @@ namespace Jack | |||
JackResampler** fPlaybackRingBuffer; | |||
unsigned int fQuality; | |||
unsigned int fRingbufferSize; | |||
unsigned int fRingbufferCurSize; | |||
jack_time_t fPullAndPushTime; | |||
bool fRunning; | |||
bool fAdaptative; | |||
void ResetRingBuffers(); | |||
void AdaptRingBufferSize(); | |||
void GrowRingBufferSize(); | |||
public: | |||
@@ -108,10 +111,11 @@ namespace Jack | |||
fAdaptedSampleRate ( sample_rate ), | |||
fPIControler(sample_rate / sample_rate, 256), | |||
fCaptureRingBuffer(NULL), fPlaybackRingBuffer(NULL), | |||
fQuality(0), fRingbufferSize(DEFAULT_RB_SIZE), | |||
fRingbufferCurSize(0), | |||
fQuality(0), | |||
fRingbufferCurSize(DEFAULT_ADAPTATIVE_SIZE), | |||
fPullAndPushTime(0), | |||
fRunning(false) | |||
fRunning(false), | |||
fAdaptative(true) | |||
{} | |||
virtual ~JackAudioAdapterInterface() | |||
@@ -140,12 +144,20 @@ namespace Jack | |||
virtual int SetHostBufferSize ( jack_nframes_t buffer_size ) | |||
{ | |||
fHostBufferSize = buffer_size; | |||
if (fAdaptative) { | |||
AdaptRingBufferSize(); | |||
ResetRingBuffers(); | |||
} | |||
return 0; | |||
} | |||
virtual int SetAdaptedBufferSize ( jack_nframes_t buffer_size ) | |||
{ | |||
fAdaptedBufferSize = buffer_size; | |||
if (fAdaptative) { | |||
AdaptRingBufferSize(); | |||
ResetRingBuffers(); | |||
} | |||
return 0; | |||
} | |||
@@ -203,7 +215,7 @@ namespace Jack | |||
int PushAndPull(float** inputBuffer, float** outputBuffer, unsigned int inNumberFrames); | |||
int PullAndPush(float** inputBuffer, float** outputBuffer, unsigned int inNumberFrames); | |||
}; | |||
} | |||
@@ -263,20 +263,21 @@ namespace Jack | |||
static_resample_factor = resample_factor; | |||
} | |||
/* | |||
double GetRatio(int fill_level) | |||
{ | |||
double offset = fill_level; | |||
// Save offset. | |||
offset_array[(offset_differential_index++) % smooth_size] = offset; | |||
// Build the mean of the windowed offset array basically fir lowpassing. | |||
double smooth_offset = 0.0; | |||
for (int i = 0; i < smooth_size; i++) { | |||
smooth_offset += offset_array[(i + offset_differential_index - 1) % smooth_size] * window_array[i]; | |||
} | |||
smooth_offset /= double(smooth_size); | |||
// This is the integral of the smoothed_offset | |||
offset_integral += smooth_offset; | |||
@@ -284,13 +285,13 @@ namespace Jack | |||
// It only used in the P component and the I component is used for the fine tuning anyways. | |||
if (fabs(smooth_offset) < pclamp) | |||
smooth_offset = 0.0; | |||
// Ok, now this is the PI controller. | |||
// u(t) = K * (e(t) + 1/T \int e(t') dt') | |||
// Kp = 1/catch_factor and T = catch_factor2 Ki = Kp/T | |||
double current_resample_factor | |||
= static_resample_factor - smooth_offset / catch_factor - offset_integral / catch_factor / catch_factor2; | |||
// Now quantize this value around resample_mean, so that the noise which is in the integral component doesnt hurt. | |||
current_resample_factor = floor((current_resample_factor - resample_mean) * controlquant + 0.5) / controlquant + resample_mean; | |||
@@ -298,6 +299,21 @@ namespace Jack | |||
resample_mean = 0.9999 * resample_mean + 0.0001 * current_resample_factor; | |||
return current_resample_factor; | |||
} | |||
*/ | |||
double GetRatio(int error) | |||
{ | |||
double smooth_offset = error; | |||
// This is the integral of the smoothed_offset | |||
offset_integral += smooth_offset; | |||
// Ok, now this is the PI controller. | |||
// u(t) = K * (e(t) + 1/T \int e(t') dt') | |||
// Kp = 1/catch_factor and T = catch_factor2 Ki = Kp/T | |||
return static_resample_factor - smooth_offset/catch_factor - offset_integral/catch_factor/catch_factor2; | |||
} | |||
void OurOfBounds() | |||
{ | |||
@@ -96,7 +96,7 @@ namespace Jack | |||
fQuality = param->value.ui; | |||
break; | |||
case 'g': | |||
fRingbufferSize = param->value.ui; | |||
fAdaptative = false; | |||
break; | |||
} | |||
} | |||
@@ -242,27 +242,24 @@ namespace Jack | |||
bool JackNetAdapter::Execute() | |||
{ | |||
try | |||
{ | |||
try { | |||
// Keep running even in case of error | |||
while ( fThread.GetStatus() == JackThread::kRunning ) | |||
if ( Process() == SOCKET_ERROR ) | |||
while (fThread.GetStatus() == JackThread::kRunning) | |||
if (Process() == SOCKET_ERROR) | |||
return false; | |||
return false; | |||
} | |||
catch ( JackNetException& e ) | |||
{ | |||
} catch (JackNetException& e) { | |||
e.PrintMessage(); | |||
jack_log ( "NetAdapter is restarted." ); | |||
jack_info("NetAdapter is restarted."); | |||
Reset(); | |||
fThread.DropRealTime(); | |||
fThread.SetStatus ( JackThread::kIniting ); | |||
if ( Init() ) | |||
{ | |||
fThread.SetStatus ( JackThread::kRunning ); | |||
fThread.SetStatus(JackThread::kIniting); | |||
if (Init()) { | |||
fThread.SetStatus(JackThread::kRunning); | |||
return true; | |||
} | |||
else | |||
} else { | |||
return false; | |||
} | |||
} | |||
} | |||
@@ -471,10 +468,10 @@ extern "C" | |||
i++; | |||
strcpy(desc->params[i].name, "ring-buffer"); | |||
desc->params[i].character = 'g'; | |||
desc->params[i].type = JackDriverParamInt; | |||
desc->params[i].value.ui = 32768; | |||
strcpy(desc->params[i].short_desc, "Resampling ringbuffer size in frames"); | |||
strcpy(desc->params[i].long_desc, "Resampling ringbuffer size in frames (default = 32768, 0 for automatic mode)"); | |||
desc->params[i].type = JackDriverParamBool; | |||
desc->params[i].value.i = false; | |||
strcpy(desc->params[i].short_desc, "Fixed ringbuffer size"); | |||
strcpy(desc->params[i].long_desc, "Fixed ringbuffer size (false = automatic adaptative)"); | |||
i++; | |||
strcpy ( desc->params[i].name, "auto-connect" ); | |||
@@ -63,7 +63,7 @@ class JackResampler | |||
virtual unsigned int ReadSpace(); | |||
virtual unsigned int WriteSpace(); | |||
unsigned int GetOffset() | |||
unsigned int GetError() | |||
{ | |||
return (jack_ringbuffer_read_space(fRingBuffer) / sizeof(float)) - (fRingBufferSize / 2); | |||
} | |||
@@ -61,7 +61,7 @@ bool JackWaitThreadedDriver::Execute() | |||
return false; | |||
} catch (JackNetException& e) { | |||
e.PrintMessage(); | |||
jack_log("Driver is restarted"); | |||
jack_info("Driver is restarted"); | |||
fThread.DropRealTime(); | |||
// Thread in kIniting status again... | |||
fThread.SetStatus(JackThread::kIniting); | |||
@@ -77,7 +77,7 @@ namespace Jack | |||
fQuality = param->value.ui; | |||
break; | |||
case 'g': | |||
fRingbufferSize = param->value.ui; | |||
fAdaptative = false; | |||
break; | |||
} | |||
} | |||
@@ -251,7 +251,7 @@ extern "C" | |||
strcpy ( desc->params[i].name, "duplex" ); | |||
desc->params[i].character = 'D'; | |||
desc->params[i].type = JackDriverParamBool; | |||
desc->params[i].value.i = 1; | |||
desc->params[i].value.i = true; | |||
strcpy ( desc->params[i].short_desc, | |||
"Provide both capture and playback ports" ); | |||
strcpy ( desc->params[i].long_desc, desc->params[i].short_desc ); | |||
@@ -285,10 +285,10 @@ extern "C" | |||
i++; | |||
strcpy(desc->params[i].name, "ring-buffer"); | |||
desc->params[i].character = 'g'; | |||
desc->params[i].type = JackDriverParamInt; | |||
desc->params[i].value.ui = 32768; | |||
strcpy(desc->params[i].short_desc, "Resampling ringbuffer size in frames"); | |||
strcpy(desc->params[i].long_desc, "Resampling ringbuffer size in frames (default = 32768, 0 for automatic mode)"); | |||
desc->params[i].type = JackDriverParamBool; | |||
desc->params[i].value.i = false; | |||
strcpy(desc->params[i].short_desc, "Fixed ringbuffer size"); | |||
strcpy(desc->params[i].long_desc, "Fixed ringbuffer size (false = automatic adaptative)"); | |||
return desc; | |||
} | |||
@@ -378,7 +378,7 @@ JackCoreAudioAdapter::JackCoreAudioAdapter(jack_nframes_t buffer_size, jack_nfra | |||
break; | |||
case 'g': | |||
fRingbufferSize = param->value.ui; | |||
fAdaptative = false; | |||
break; | |||
} | |||
} | |||
@@ -1079,10 +1079,10 @@ extern "C" | |||
i++; | |||
strcpy(desc->params[i].name, "ring-buffer"); | |||
desc->params[i].character = 'g'; | |||
desc->params[i].type = JackDriverParamInt; | |||
desc->params[i].value.ui = 32768; | |||
strcpy(desc->params[i].short_desc, "Resampling ringbuffer size in frames"); | |||
strcpy(desc->params[i].long_desc, "Resampling ringbuffer size in frames (default = 32768, 0 for automatic mode)"); | |||
desc->params[i].type = JackDriverParamBool; | |||
desc->params[i].value.i = false; | |||
strcpy(desc->params[i].short_desc, "Fixed ringbuffer size"); | |||
strcpy(desc->params[i].long_desc, "Fixed ringbuffer size (false = automatic adaptative)"); | |||
return desc; | |||
} | |||
@@ -183,7 +183,7 @@ JackOSSAdapter::JackOSSAdapter(jack_nframes_t buffer_size, jack_nframes_t sample | |||
break; | |||
case 'g': | |||
fRingbufferSize = param->value.ui; | |||
fAdaptative = false; | |||
break; | |||
} | |||
@@ -741,11 +741,11 @@ extern "C" | |||
i++; | |||
strcpy(desc->params[i].name, "ring-buffer"); | |||
desc->params[i].character = 'g'; | |||
desc->params[i].type = JackDriverParamInt; | |||
desc->params[i].value.ui = 32768; | |||
strcpy(desc->params[i].short_desc, "Resampling ringbuffer size in frames (default = 32768, 0 for automatic mode)"); | |||
strcpy(desc->params[i].long_desc, "Resampling ringbuffer size in frames (default = 32768, 0 for automatic mode)"); | |||
desc->params[i].type = JackDriverParamBool; | |||
desc->params[i].value.i = false; | |||
strcpy(desc->params[i].short_desc, "Fixed ringbuffer size"); | |||
strcpy(desc->params[i].long_desc, "Fixed ringbuffer size (false = automatic adaptative)"); | |||
return desc; | |||
} | |||
@@ -97,7 +97,7 @@ namespace Jack | |||
fQuality = param->value.ui; | |||
break; | |||
case 'g': | |||
fRingbufferSize = param->value.ui; | |||
fAdaptative = false; | |||
break; | |||
} | |||
} | |||
@@ -282,7 +282,7 @@ extern "C" | |||
strcpy(desc->params[i].name, "list-devices"); | |||
desc->params[i].character = 'l'; | |||
desc->params[i].type = JackDriverParamBool; | |||
desc->params[i].value.i = TRUE; | |||
desc->params[i].value.i = true; | |||
strcpy(desc->params[i].short_desc, "Display available PortAudio devices"); | |||
strcpy(desc->params[i].long_desc, desc->params[i].short_desc); | |||
@@ -297,10 +297,10 @@ extern "C" | |||
i++; | |||
strcpy(desc->params[i].name, "ring-buffer"); | |||
desc->params[i].character = 'g'; | |||
desc->params[i].type = JackDriverParamInt; | |||
desc->params[i].value.ui = 32768; | |||
strcpy(desc->params[i].short_desc, "Resampling ringbuffer size in frames"); | |||
strcpy(desc->params[i].long_desc, "Resampling ringbuffer size in frames (default = 32768, 0 for automatic mode)"); | |||
desc->params[i].type = JackDriverParamBool; | |||
desc->params[i].value.i = false; | |||
strcpy(desc->params[i].short_desc, "Fixed ringbuffer size"); | |||
strcpy(desc->params[i].long_desc, "Fixed ringbuffer size (false = automatic adaptative)"); | |||
return desc; | |||
} | |||