Commit b63e6a8f authored by sletz's avatar sletz
Browse files

rebase from trunk 3401:3420

git-svn-id: http://subversion.jackaudio.org/jack/jack2/branches/libjacknet@3421 0c269be4-1314-0410-8aa9-9f06e86f4224
parent 62966c28
......@@ -17,12 +17,21 @@ Nedko Arnaudov
Fernando Lopez-Lezcano
Romain Moret
Florian Faber
Michael Voigt
Michael Voigt
Torben Hohn
---------------------------
Jackdmp changes log
---------------------------
2009-03-10 Stephane Letz <letz@grame.fr>
* Add -g (ring-buffer) parameter to netadapter.
2009-03-09 Stephane Letz <letz@grame.fr>
* Use Torben Hohn PI controler code for adapters (in progress).
2009-03-05 Stephane Letz <letz@grame.fr>
* Support for BIG_ENDIAN machines in NetJack2 for transport data.
......
......@@ -58,6 +58,7 @@ namespace Jack
}
fclose(file);
/* No used for now
// Adapter timing 1
file = fopen("AdapterTiming1.plot", "w");
fprintf(file, "set multiplot\n");
......@@ -88,6 +89,7 @@ namespace Jack
fprintf(file, buffer);
fclose(file);
*/
// Adapter timing 2
file = fopen("AdapterTiming2.plot", "w");
......@@ -162,30 +164,7 @@ namespace Jack
fPlaybackRingBuffer[i]->Reset();
}
void JackAudioAdapterInterface::ResampleFactor ( jack_time_t& frame1, jack_time_t& frame2 )
{
jack_time_t time = GetMicroSeconds();
if (!fRunning) {
// Init DLL
fRunning = true;
fHostDLL.Init(time);
fAdaptedDLL.Init(time);
frame1 = 1;
frame2 = 1;
} else {
// DLL
fAdaptedDLL.IncFrame(time);
jack_nframes_t time1 = fHostDLL.Time2Frames(time);
jack_nframes_t time2 = fAdaptedDLL.Time2Frames(time);
frame1 = time1;
frame2 = time2;
jack_log("JackAudioAdapterInterface::ResampleFactor time1 = %ld time2 = %ld src_ratio_input = %f src_ratio_output = %f",
long(time1), long(time2), double(time1) / double(time2), double(time2) / double(time1));
}
}
void JackAudioAdapterInterface::Reset()
void JackAudioAdapterInterface::Reset()
{
ResetRingBuffers();
fRunning = false;
......@@ -226,25 +205,31 @@ namespace Jack
int JackAudioAdapterInterface::PushAndPull(float** inputBuffer, float** outputBuffer, unsigned int frames)
{
bool failure = false;
jack_time_t time1, time2;
ResampleFactor(time1, time2);
fRunning = true;
/*
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());
// Push/pull from ringbuffer
for (int i = 0; i < fCaptureChannels; i++) {
fCaptureRingBuffer[i]->SetRatio(time1, time2);
fCaptureRingBuffer[i]->SetRatio(ratio);
if (fCaptureRingBuffer[i]->WriteResample(inputBuffer[i], frames) < frames)
failure = true;
}
for (int i = 0; i < fPlaybackChannels; i++) {
fPlaybackRingBuffer[i]->SetRatio(time2, time1);
fPlaybackRingBuffer[i]->SetRatio(1 / ratio);
if (fPlaybackRingBuffer[i]->ReadResample(outputBuffer[i], frames) < frames)
failure = true;
}
#ifdef JACK_MONITOR
fTable.Write(time1, time2, double(time1) / double(time2), double(time2) / double(time1),
fCaptureRingBuffer[0]->ReadSpace(), fPlaybackRingBuffer[0]->WriteSpace());
fTable.Write(0, 0, ratio, 1/ratio, fCaptureRingBuffer[0]->ReadSpace(), fPlaybackRingBuffer[0]->WriteSpace());
#endif
// Reset all ringbuffers in case of failure
......@@ -260,8 +245,8 @@ namespace Jack
int JackAudioAdapterInterface::PullAndPush(float** inputBuffer, float** outputBuffer, unsigned int frames)
{
bool failure = false;
fHostDLL.IncFrame(GetMicroSeconds());
fPullAndPushTime = GetMicroSeconds();
// Push/pull from ringbuffer
for (int i = 0; i < fCaptureChannels; i++) {
if (fCaptureRingBuffer[i]->Read(inputBuffer[i], frames) < frames)
......
......@@ -82,36 +82,34 @@ namespace Jack
jack_nframes_t fAdaptedBufferSize;
jack_nframes_t fAdaptedSampleRate;
//delay locked loop
JackAtomicDelayLockedLoop fHostDLL;
JackAtomicDelayLockedLoop fAdaptedDLL;
//PI controler
JackPIControler fPIControler;
JackResampler** fCaptureRingBuffer;
JackResampler** fPlaybackRingBuffer;
unsigned int fQuality;
unsigned int fRingbufferSize;
jack_time_t fPullAndPushTime;
bool fRunning;
void ResetRingBuffers();
void ResampleFactor ( jack_time_t& frame1, jack_time_t& frame2 );
public:
JackAudioAdapterInterface ( jack_nframes_t host_buffer_size,
jack_nframes_t host_sample_rate) :
fCaptureChannels ( 0 ),
fPlaybackChannels ( 0 ),
fHostBufferSize ( host_buffer_size ),
fHostSampleRate ( host_sample_rate ),
fAdaptedBufferSize ( host_buffer_size),
fAdaptedSampleRate ( host_sample_rate ),
fHostDLL ( host_buffer_size, host_sample_rate ),
fAdaptedDLL ( host_buffer_size, host_sample_rate ),
fQuality(0),
fRingbufferSize(DEFAULT_RB_SIZE),
fRunning ( false )
JackAudioAdapterInterface ( jack_nframes_t buffer_size, jack_nframes_t sample_rate ):
fCaptureChannels ( 0 ),
fPlaybackChannels ( 0 ),
fHostBufferSize ( buffer_size ),
fHostSampleRate ( sample_rate ),
fAdaptedBufferSize ( buffer_size),
fAdaptedSampleRate ( sample_rate ),
fPIControler(sample_rate / sample_rate, 256),
fCaptureRingBuffer(NULL), fPlaybackRingBuffer(NULL),
fQuality(0), fRingbufferSize(DEFAULT_RB_SIZE),
fPullAndPushTime(0),
fRunning(false)
{}
JackAudioAdapterInterface ( jack_nframes_t host_buffer_size,
jack_nframes_t host_sample_rate,
......@@ -123,10 +121,10 @@ namespace Jack
fHostSampleRate ( host_sample_rate ),
fAdaptedBufferSize ( adapted_buffer_size),
fAdaptedSampleRate ( adapted_sample_rate ),
fHostDLL ( host_buffer_size, host_sample_rate ),
fAdaptedDLL ( adapted_buffer_size, adapted_sample_rate ),
fPIControler(host_sample_rate / host_sample_rate, 256),
fQuality(0),
fRingbufferSize(DEFAULT_RB_SIZE),
fPullAndPushTime(0),
fRunning ( false )
{}
......@@ -156,14 +154,12 @@ namespace Jack
virtual int SetHostBufferSize ( jack_nframes_t buffer_size )
{
fHostBufferSize = buffer_size;
fHostDLL.Init ( fHostBufferSize, fHostSampleRate );
return 0;
}
virtual int SetAdaptedBufferSize ( jack_nframes_t buffer_size )
{
fAdaptedBufferSize = buffer_size;
fAdaptedDLL.Init ( fAdaptedBufferSize, fAdaptedSampleRate );
return 0;
}
......@@ -177,14 +173,14 @@ namespace Jack
virtual int SetHostSampleRate ( jack_nframes_t sample_rate )
{
fHostSampleRate = sample_rate;
fHostDLL.Init ( fHostBufferSize, fHostSampleRate );
fPIControler.Init(double(fHostSampleRate) / double(fAdaptedSampleRate));
return 0;
}
virtual int SetAdaptedSampleRate ( jack_nframes_t sample_rate )
{
fAdaptedSampleRate = sample_rate;
fAdaptedDLL.Init ( fAdaptedBufferSize, fAdaptedSampleRate );
fPIControler.Init(double(fHostSampleRate) / double(fAdaptedSampleRate));
return 0;
}
......
......@@ -28,7 +28,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
namespace Jack
{
#define TIME_POINTS 250000
#define TIME_POINTS 125000
#define FAILURE_TIME_POINTS 10000
#define FAILURE_WINDOW 10
#define MEASURED_CLIENTS 32
......
......@@ -23,6 +23,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include "jack.h"
#include "JackAtomicState.h"
#include <math.h>
#include <stdlib.h>
namespace Jack
{
......@@ -201,6 +202,117 @@ namespace Jack
return res;
}
};
/*
Torben Hohn PI controler from JACK1
*/
struct JackPIControler {
double resample_mean;
double static_resample_factor;
double* offset_array;
double* window_array;
int offset_differential_index;
double offset_integral;
double catch_factor;
double catch_factor2;
double pclamp;
double controlquant;
int smooth_size;
double hann(double x)
{
return 0.5 * (1.0 - cos(2 * M_PI * x));
}
JackPIControler(double resample_factor, int fir_size)
{
resample_mean = resample_factor;
static_resample_factor = resample_factor;
offset_array = new double[fir_size];
window_array = new double[fir_size];
offset_differential_index = 0;
offset_integral = 0.0;
smooth_size = fir_size;
for (int i = 0; i < fir_size; i++) {
offset_array[i] = 0.0;
window_array[i] = hann(double(i) / (double(fir_size) - 1.0));
}
// These values could be configurable
catch_factor = 100000;
catch_factor2 = 10000;
pclamp = 15.0;
controlquant = 10000.0;
}
~JackPIControler()
{
delete[] offset_array;
delete[] window_array;
}
void Init(double resample_factor)
{
resample_mean = resample_factor;
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;
// Clamp offset : the smooth offset still contains unwanted noise which would go straigth onto the resample coeff.
// 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;
// Calculate resample_mean so we can init ourselves to saner values.
resample_mean = 0.9999 * resample_mean + 0.0001 * current_resample_factor;
return current_resample_factor;
}
void OurOfBounds()
{
int i;
// Set the resample_rate... we need to adjust the offset integral, to do this.
// first look at the PI controller, this code is just a special case, which should never execute once
// everything is swung in.
offset_integral = - (resample_mean - static_resample_factor) * catch_factor * catch_factor2;
// Also clear the array. we are beginning a new control cycle.
for (i = 0; i < smooth_size; i++) {
offset_array[i] = 0.0;
}
}
};
}
......
......@@ -542,7 +542,7 @@ int JackGraphManager::Connect(jack_port_id_t port_src, jack_port_id_t port_dst)
jack_error("JackGraphManager::Connect failed port_src = %ld port_dst = %ld", port_src, port_dst);
goto end;
}
manager->Connect(port_dst, port_src);
res = manager->Connect(port_dst, port_src);
if (res < 0) {
jack_error("JackGraphManager::Connect failed port_dst = %ld port_src = %ld", port_dst, port_src);
goto end;
......@@ -583,12 +583,12 @@ int JackGraphManager::Disconnect(jack_port_id_t port_src, jack_port_id_t port_ds
goto end;
}
manager->Disconnect(port_src, port_dst);
res = manager->Disconnect(port_src, port_dst);
if (res < 0) {
jack_error("JackGraphManager::Disconnect failed port_src = %ld port_dst = %ld", port_src, port_dst);
goto end;
}
manager->Disconnect(port_dst, port_src);
res = manager->Disconnect(port_dst, port_src);
if (res < 0) {
jack_error("JackGraphManager::Disconnect failed port_dst = %ld port_src = %ld", port_dst, port_src);
goto end;
......
......@@ -23,7 +23,7 @@ namespace Jack
{
JackLibSampleRateResampler::JackLibSampleRateResampler()
:JackResampler(),fRatio(1)
:JackResampler()
{
int error;
fResampler = src_new(SRC_LINEAR, 1, &error);
......@@ -32,7 +32,7 @@ JackLibSampleRateResampler::JackLibSampleRateResampler()
}
JackLibSampleRateResampler::JackLibSampleRateResampler(unsigned int quality, unsigned int ringbuffer_size)
:JackResampler(ringbuffer_size),fRatio(1)
:JackResampler(ringbuffer_size)
{
switch (quality) {
case 0:
......
......@@ -26,11 +26,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
namespace Jack
{
inline float Range(float min, float max, float val)
{
return (val < min) ? min : ((val > max) ? max : val);
}
/*!
\brief Resampler using "libsamplerate" (http://www.mega-nerd.com/SRC/).
*/
......@@ -41,7 +36,6 @@ class JackLibSampleRateResampler : public JackResampler
private:
SRC_STATE* fResampler;
double fRatio;
public:
......@@ -51,12 +45,6 @@ class JackLibSampleRateResampler : public JackResampler
unsigned int ReadResample(float* buffer, unsigned int frames);
unsigned int WriteResample(float* buffer, unsigned int frames);
void SetRatio(unsigned int num, unsigned int denom)
{
JackResampler::SetRatio(num, denom);
fRatio = Range(0.25, 4.0, (double(num) / double(denom)));
}
void Reset();
......
......@@ -95,6 +95,9 @@ namespace Jack
case 'q':
fQuality = param->value.ui;
break;
case 'g':
fRingbufferSize = param->value.ui;
break;
}
}
......@@ -151,6 +154,10 @@ namespace Jack
{
jack_log ( "JackNetAdapter::Close" );
#ifdef JACK_MONITOR
fTable.Save(fHostBufferSize, fHostSampleRate, fAdaptedSampleRate, fAdaptedBufferSize);
#endif
switch ( fThread.GetStatus() )
{
// Kill the thread in Init phase
......@@ -386,7 +393,7 @@ extern "C"
strcpy(desc->name, "netadapter"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1
strcpy(desc->desc, "netjack net <==> audio backend adapter"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1
desc->nparams = 10;
desc->nparams = 11;
desc->params = ( jack_driver_param_desc_t* ) calloc ( desc->nparams, sizeof ( jack_driver_param_desc_t ) );
int i = 0;
......@@ -414,7 +421,7 @@ extern "C"
strcpy ( desc->params[i].long_desc, desc->params[i].short_desc );
i++;
strcpy ( desc->params[i].name, "input_ports" );
strcpy ( desc->params[i].name, "input-ports" );
desc->params[i].character = 'C';
desc->params[i].type = JackDriverParamInt;
desc->params[i].value.i = 2;
......@@ -422,7 +429,7 @@ extern "C"
strcpy ( desc->params[i].long_desc, desc->params[i].short_desc );
i++;
strcpy ( desc->params[i].name, "output_ports" );
strcpy ( desc->params[i].name, "output-ports" );
desc->params[i].character = 'P';
desc->params[i].type = JackDriverParamInt;
desc->params[i].value.i = 2;
......@@ -430,7 +437,7 @@ extern "C"
strcpy ( desc->params[i].long_desc, desc->params[i].short_desc );
i++;
strcpy ( desc->params[i].name, "client_name" );
strcpy ( desc->params[i].name, "client-name" );
desc->params[i].character = 'n';
desc->params[i].type = JackDriverParamString;
strcpy ( desc->params[i].value.str, "'hostname'" );
......@@ -438,7 +445,7 @@ extern "C"
strcpy ( desc->params[i].long_desc, desc->params[i].short_desc );
i++;
strcpy ( desc->params[i].name, "transport_sync" );
strcpy ( desc->params[i].name, "transport-sync" );
desc->params[i].character = 't';
desc->params[i].type = JackDriverParamUInt;
desc->params[i].value.ui = 1U;
......@@ -462,13 +469,21 @@ extern "C"
strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
i++;
strcpy ( desc->params[i].name, "auto_connect" );
strcpy(desc->params[i].name, "ring-buffer");
desc->params[i].character = 'g';
desc->params[i].type = JackDriverParamInt;
desc->params[i].value.ui = 0;
strcpy(desc->params[i].short_desc, "Resampling ringbuffer size in frames (default = 16384)");
strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
i++;
strcpy ( desc->params[i].name, "auto-connect" );
desc->params[i].character = 'c';
desc->params[i].type = JackDriverParamBool;
desc->params[i].value.i = false;
strcpy ( desc->params[i].short_desc, "Auto connect netmaster to system ports" );
strcpy ( desc->params[i].long_desc, desc->params[i].short_desc );
return desc;
}
......
......@@ -421,14 +421,14 @@ namespace Jack
dst_params->fPosition.beat = htonl(src_params->fPosition.beat);
dst_params->fPosition.tick = htonl(src_params->fPosition.tick);
dst_params->fPosition.bar_start_tick = htonll((uint64_t)src_params->fPosition.bar_start_tick);
dst_params->fPosition.beats_per_bar = htonl(src_params->fPosition.beats_per_bar);
dst_params->fPosition.beat_type = htonl(src_params->fPosition.beat_type);
dst_params->fPosition.beats_per_bar = htonl((uint32_t)src_params->fPosition.beats_per_bar);
dst_params->fPosition.beat_type = htonl((uint32_t)src_params->fPosition.beat_type);
dst_params->fPosition.ticks_per_beat = htonll((uint64_t)src_params->fPosition.ticks_per_beat);
dst_params->fPosition.beats_per_minute = htonll((uint64_t)src_params->fPosition.beats_per_minute);
dst_params->fPosition.frame_time = htonll((uint64_t)src_params->fPosition.frame_time);
dst_params->fPosition.next_time = htonll((uint64_t)src_params->fPosition.next_time);
dst_params->fPosition.bbt_offset = htonl(src_params->fPosition.bbt_offset);
dst_params->fPosition.audio_frames_per_video_frame = htonl(src_params->fPosition.audio_frames_per_video_frame);
dst_params->fPosition.audio_frames_per_video_frame = htonl((uint32_t)src_params->fPosition.audio_frames_per_video_frame);
dst_params->fPosition.video_offset = htonl(src_params->fPosition.video_offset);
dst_params->fPosition.unique_2 = htonll(src_params->fPosition.unique_2);
}
......@@ -446,14 +446,14 @@ namespace Jack
dst_params->fPosition.beat = ntohl(src_params->fPosition.beat);
dst_params->fPosition.tick = ntohl(src_params->fPosition.tick);
dst_params->fPosition.bar_start_tick = ntohll((uint64_t)src_params->fPosition.bar_start_tick);
dst_params->fPosition.beats_per_bar = ntohl(src_params->fPosition.beats_per_bar);
dst_params->fPosition.beat_type = ntohl(src_params->fPosition.beat_type);
dst_params->fPosition.beats_per_bar = ntohl((uint32_t)src_params->fPosition.beats_per_bar);
dst_params->fPosition.beat_type = ntohl((uint32_t)src_params->fPosition.beat_type);
dst_params->fPosition.ticks_per_beat = ntohll((uint64_t)src_params->fPosition.ticks_per_beat);
dst_params->fPosition.beats_per_minute = ntohll((uint64_t)src_params->fPosition.beats_per_minute);
dst_params->fPosition.frame_time = ntohll((uint64_t)src_params->fPosition.frame_time);
dst_params->fPosition.next_time = ntohll((uint64_t)src_params->fPosition.next_time);
dst_params->fPosition.bbt_offset = ntohl(src_params->fPosition.bbt_offset);
dst_params->fPosition.audio_frames_per_video_frame = ntohl(src_params->fPosition.audio_frames_per_video_frame);
dst_params->fPosition.audio_frames_per_video_frame = ntohl((uint32_t)src_params->fPosition.audio_frames_per_video_frame);
dst_params->fPosition.video_offset = ntohl(src_params->fPosition.video_offset);
dst_params->fPosition.unique_2 = ntohll(src_params->fPosition.unique_2);
}
......
......@@ -23,13 +23,15 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
namespace Jack
{
JackResampler::JackResampler():fNum(1),fDenom(1)
JackResampler::JackResampler()
:fRatio(1),fRingBufferSize(DEFAULT_RB_SIZE)
{
fRingBuffer = jack_ringbuffer_create(sizeof(float) * DEFAULT_RB_SIZE);
jack_ringbuffer_read_advance(fRingBuffer, (sizeof(float) * DEFAULT_RB_SIZE) / 2);
fRingBuffer = jack_ringbuffer_create(sizeof(float) * fRingBufferSize);
jack_ringbuffer_read_advance(fRingBuffer, (sizeof(float) * fRingBufferSize) / 2);
}
JackResampler::JackResampler(unsigned int ringbuffer_size):fNum(1),fDenom(1),fRingBufferSize(ringbuffer_size)
JackResampler::JackResampler(unsigned int ringbuffer_size)
:fRatio(1),fRingBufferSize(ringbuffer_size)
{
fRingBuffer = jack_ringbuffer_create(sizeof(float) * fRingBufferSize);
jack_ringbuffer_read_advance(fRingBuffer, (sizeof(float) * fRingBufferSize) / 2);
......
......@@ -26,8 +26,13 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
namespace Jack
{
#define DEFAULT_RB_SIZE 16384 * 2
#define DEFAULT_RB_SIZE 16384
inline float Range(float min, float max, float val)
{
return (val < min) ? min : ((val > max) ? max : val);
}
/*!
\brief Base class for Resampler.
*/
......@@ -38,8 +43,7 @@ class JackResampler
protected:
jack_ringbuffer_t* fRingBuffer;
unsigned int fNum;
unsigned int fDenom;
double fRatio;
unsigned int fRingBufferSize;
public:
......@@ -58,16 +62,20 @@ class JackResampler
virtual unsigned int ReadSpace();
virtual unsigned int WriteSpace();
unsigned int GetOffset()
{
return (jack_ringbuffer_read_space(fRingBuffer) / sizeof(float)) - (fRingBufferSize / 2);
}