Browse Source

Use Torben Hohn PI controler code for adapters (in progress).

git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@3417 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/1.9.2
sletz 16 years ago
parent
commit
d55eddb4e2
8 changed files with 168 additions and 71 deletions
  1. +6
    -1
      ChangeLog
  2. +18
    -33
      common/JackAudioAdapterInterface.cpp
  3. +7
    -10
      common/JackAudioAdapterInterface.h
  4. +112
    -0
      common/JackFilters.h
  5. +2
    -2
      common/JackLibSampleRateResampler.cpp
  6. +0
    -12
      common/JackLibSampleRateResampler.h
  7. +6
    -4
      common/JackResampler.cpp
  8. +17
    -9
      common/JackResampler.h

+ 6
- 1
ChangeLog View File

@@ -17,12 +17,17 @@ Nedko Arnaudov
Fernando Lopez-Lezcano
Romain Moret
Florian Faber
Michael Voigt
Michael Voigt
Torben Hohn
---------------------------
Jackdmp changes log
---------------------------

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.


+ 18
- 33
common/JackAudioAdapterInterface.cpp View File

@@ -53,6 +53,7 @@ namespace Jack
}
fclose(file);

/* No used for now
// Adapter timing 1
file = fopen("AdapterTiming1.plot", "w");
fprintf(file, "set multiplot\n");
@@ -83,6 +84,7 @@ namespace Jack
fprintf(file, buffer);
fclose(file);
*/

// Adapter timing 2
file = fopen("AdapterTiming2.plot", "w");
@@ -157,30 +159,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;
@@ -216,25 +195,31 @@ namespace Jack
int JackAudioAdapterInterface::PushAndPull(float** inputBuffer, float** outputBuffer, unsigned int inNumberFrames)
{
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], inNumberFrames) < inNumberFrames)
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], inNumberFrames) < inNumberFrames)
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
@@ -250,8 +235,8 @@ namespace Jack
int JackAudioAdapterInterface::PullAndPush(float** inputBuffer, float** outputBuffer, unsigned int inNumberFrames)
{
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], inNumberFrames) < inNumberFrames)


+ 7
- 10
common/JackAudioAdapterInterface.h View File

@@ -82,20 +82,19 @@ 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:

@@ -106,10 +105,10 @@ namespace Jack
fHostSampleRate ( sample_rate ),
fAdaptedBufferSize ( buffer_size),
fAdaptedSampleRate ( sample_rate ),
fHostDLL ( buffer_size, sample_rate ),
fAdaptedDLL ( buffer_size, sample_rate ),
fPIControler(sample_rate / sample_rate, 256),
fCaptureRingBuffer(NULL), fPlaybackRingBuffer(NULL),
fQuality(0), fRingbufferSize(DEFAULT_RB_SIZE),
fPullAndPushTime(0),
fRunning(false)
{}

@@ -139,14 +138,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;
}

@@ -160,14 +157,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;
}



+ 112
- 0
common/JackFilters.h View File

@@ -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;
}
}
};

}



+ 2
- 2
common/JackLibSampleRateResampler.cpp View File

@@ -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:


+ 0
- 12
common/JackLibSampleRateResampler.h View File

@@ -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();


+ 6
- 4
common/JackResampler.cpp View File

@@ -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);


+ 17
- 9
common/JackResampler.h View File

@@ -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);
}

virtual void SetRatio(unsigned int num, unsigned int denom)
void SetRatio(double ratio)
{
fNum = num;
fDenom = denom;
fRatio = Range(0.25, 4.0, ratio);
}
virtual void GetRatio(unsigned int& num, unsigned int& denom)
double GetRatio()
{
num = fNum;
denom = fDenom;
return fRatio;
}
};


Loading…
Cancel
Save