From e6372863fe387ff438865eaaafc142b228f2d031 Mon Sep 17 00:00:00 2001 From: sletz Date: Wed, 2 Jul 2008 12:48:55 +0000 Subject: [PATCH] New JackLibSampleRateResampler class git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@2594 0c269be4-1314-0410-8aa9-9f06e86f4224 --- common/JackFilters.h | 20 ++-- common/JackIOAdapter.h | 2 +- common/JackLibSampleRateResampler.cpp | 132 ++++++++++++++++++++++++++ common/JackLibSampleRateResampler.h | 54 +++++++++++ common/JackResampler.cpp | 96 +------------------ common/JackResampler.h | 33 ++++--- common/wscript | 4 +- macosx/JackCoreAudioIOAdapter.cpp | 5 +- windows/JackPortAudioIOAdapter.cpp | 28 +++--- windows/JackPortAudioIOAdapter.h | 2 +- 10 files changed, 234 insertions(+), 142 deletions(-) create mode 100644 common/JackLibSampleRateResampler.cpp create mode 100644 common/JackLibSampleRateResampler.h diff --git a/common/JackFilters.h b/common/JackFilters.h index 806f49e0..645009b5 100644 --- a/common/JackFilters.h +++ b/common/JackFilters.h @@ -106,31 +106,27 @@ namespace Jack jack_nframes_t Time2Frames(jack_time_t time) { - /* - long val = (long) rint(((double) (long(time - fCurrentWakeup)) / ((jack_time_t)(fNextWakeUp - fCurrentWakeup))) * fBufferSize); - if (val < 0) { - printf("Time2Frames %ld\n", val); - printf("time %ld\n", time); - printf("fCurrentWakeup %ld\n", fCurrentWakeup); - printf("fNextWakeUp %ld\n", fNextWakeUp); - } - */ return fFrames + (long) rint(((double) (long(time - fCurrentWakeup)) / ((jack_time_t)(fNextWakeUp - fCurrentWakeup))) * fBufferSize); } jack_time_t Frames2Time(jack_nframes_t frames) { - return fCurrentWakeup + (long) rint(((double) ((frames - fFrames)) * ((jack_time_t)(fNextWakeUp - fCurrentWakeup))) / fBufferSize); + return fCurrentWakeup + (long) rint(((double) (long(frames - fFrames)) * ((jack_time_t)(fNextWakeUp - fCurrentWakeup))) / fBufferSize); } jack_time_t CurFrame2Time() { - return fCurrentWakeup; + return fCurrentWakeup; + } + + jack_nframes_t CurTime2Frame() + { + return fFrames; } }; - + inline float Range(float min, float max, float val) { return (val < min) ? min : ((val > max) ? max : val); diff --git a/common/JackIOAdapter.h b/common/JackIOAdapter.h index ef204f6b..3a064d5a 100644 --- a/common/JackIOAdapter.h +++ b/common/JackIOAdapter.h @@ -50,8 +50,8 @@ namespace Jack JackFilter fConsumerFilter; // DLL - JackDelayLockedLoop fConsumerDLL; JackDelayLockedLoop fProducerDLL; + JackDelayLockedLoop fConsumerDLL; jack_time_t fCurFrames; JackResampler* fCaptureRingBuffer; diff --git a/common/JackLibSampleRateResampler.cpp b/common/JackLibSampleRateResampler.cpp new file mode 100644 index 00000000..826d5bef --- /dev/null +++ b/common/JackLibSampleRateResampler.cpp @@ -0,0 +1,132 @@ +/* +Copyright (C) 2008 Grame + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "JackLibSampleRateResampler.h" + +namespace Jack +{ + +JackLibSampleRateResampler::JackLibSampleRateResampler():JackResampler(),fRatio(1) +{ + int error; + fResampler = src_new(SRC_LINEAR, 1, &error); + if (error != 0) + jack_error("JackLibSampleRateResampler::JackLibSampleRateResampler err = %s", src_strerror(error)); +} + +JackLibSampleRateResampler::~JackLibSampleRateResampler() +{ + src_delete(fResampler); +} + +int JackLibSampleRateResampler::ReadResample(float* buffer, unsigned int frames) +{ + jack_ringbuffer_data_t ring_buffer_data[2]; + SRC_DATA src_data; + unsigned int frames_to_write = frames; + unsigned int written_frames = 0; + int res; + + jack_ringbuffer_get_read_vector(fRingBuffer, ring_buffer_data); + unsigned int available_frames = (ring_buffer_data[0].len + ring_buffer_data[1].len) / sizeof(float); + jack_log("OUPUT available = %ld", available_frames); + + for (int j = 0; j < 2; j++) { + + if (ring_buffer_data[j].len > 0) { + + src_data.data_in = (float*)ring_buffer_data[j].buf; + src_data.data_out = &buffer[written_frames]; + src_data.input_frames = ring_buffer_data[j].len / sizeof(float); + src_data.output_frames = frames_to_write; + src_data.end_of_input = 0; + src_data.src_ratio = fRatio; + + res = src_process(fResampler, &src_data); + if (res != 0) + jack_error("JackLibSampleRateResampler::ReadResample err = %s", src_strerror(res)); + + frames_to_write -= src_data.output_frames_gen; + written_frames += src_data.output_frames_gen; + + if ((src_data.input_frames_used == 0 || src_data.output_frames_gen == 0) && j == 0) { + jack_error("OUTPUT : j = %d input_frames_used = %ld output_frames_gen = %ld", j, src_data.input_frames_used, src_data.output_frames_gen); + } + + jack_log("OUTPUT : j = %d input_frames_used = %ld output_frames_gen = %ld", j, src_data.input_frames_used, src_data.output_frames_gen); + jack_ringbuffer_read_advance(fRingBuffer, src_data.input_frames_used * sizeof(float)); + } + } + + if (written_frames < frames) { + jack_error("OUPUT available = %ld", available_frames); + jack_error("JackLibSampleRateResampler::ReadResample error written_frames = %ld", written_frames); + } + + return written_frames; +} + +int JackLibSampleRateResampler::WriteResample(float* buffer, unsigned int frames) +{ + jack_ringbuffer_data_t ring_buffer_data[2]; + SRC_DATA src_data; + unsigned int frames_to_read = frames; + unsigned int read_frames = 0; + int res; + + jack_ringbuffer_get_write_vector(fRingBuffer, ring_buffer_data); + unsigned int available_frames = (ring_buffer_data[0].len + ring_buffer_data[1].len) / sizeof(float); + jack_log("INPUT available = %ld", available_frames); + + for (int j = 0; j < 2; j++) { + + if (ring_buffer_data[j].len > 0) { + + src_data.data_in = &buffer[read_frames]; + src_data.data_out = (float*)ring_buffer_data[j].buf; + src_data.input_frames = frames_to_read; + src_data.output_frames = (ring_buffer_data[j].len / sizeof(float)); + src_data.end_of_input = 0; + src_data.src_ratio = fRatio; + + res = src_process(fResampler, &src_data); + if (res != 0) + jack_error("JackLibSampleRateResampler::ReadResample err = %s", src_strerror(res)); + + frames_to_read -= src_data.input_frames_used; + read_frames += src_data.input_frames_used; + + if ((src_data.input_frames_used == 0 || src_data.output_frames_gen == 0) && j == 0) { + jack_error("INPUT : j = %d input_frames_used = %ld output_frames_gen = %ld", j, src_data.input_frames_used, src_data.output_frames_gen); + } + + jack_log("INPUT : j = %d input_frames_used = %ld output_frames_gen = %ld", j, src_data.input_frames_used, src_data.output_frames_gen); + jack_ringbuffer_write_advance(fRingBuffer, src_data.output_frames_gen * sizeof(float)); + } + } + + if (read_frames < frames) { + jack_error("INPUT available = %ld", available_frames); + jack_error("JackLibSampleRateResampler::ReadResample error read_frames = %ld", read_frames); + } + + return read_frames; +} + +} diff --git a/common/JackLibSampleRateResampler.h b/common/JackLibSampleRateResampler.h new file mode 100644 index 00000000..4a655da9 --- /dev/null +++ b/common/JackLibSampleRateResampler.h @@ -0,0 +1,54 @@ +/* +Copyright (C) 2008 Grame + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __JackLibSampleRateResampler__ +#define __JackLibSampleRateResampler__ + +#include "JackResampler.h" +#include + +namespace Jack +{ + + class JackLibSampleRateResampler : public JackResampler + { + + private: + + SRC_STATE* fResampler; + double fRatio; + + public: + + JackLibSampleRateResampler(); + virtual ~JackLibSampleRateResampler(); + + int ReadResample(float* buffer, unsigned int frames); + int WriteResample(float* buffer, unsigned int frames); + + virtual void SetRatio(unsigned int num, unsigned int denom) + { + JackResampler::SetRatio(num, denom); + fRatio = double(num) / double(denom); + } + + }; +} + +#endif diff --git a/common/JackResampler.cpp b/common/JackResampler.cpp index 9183cf8a..02ceaeaf 100644 --- a/common/JackResampler.cpp +++ b/common/JackResampler.cpp @@ -22,19 +22,15 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. namespace Jack { -JackResampler::JackResampler():fRatio(0) +JackResampler::JackResampler() + :fNum(1),fDenom(1) { - int error; - fResampler = src_new(SRC_LINEAR, 1, &error); - if (error != 0) - jack_error("JackResampler::JackResampler err = %s", src_strerror(error)); fRingBuffer = jack_ringbuffer_create(sizeof(float) * DEFAULT_RB_SIZE); jack_ringbuffer_read_advance(fRingBuffer, (sizeof(float) * DEFAULT_RB_SIZE) / 2); } JackResampler::~JackResampler() { - src_delete(fResampler); if (fRingBuffer) jack_ringbuffer_free(fRingBuffer); } @@ -81,96 +77,12 @@ int JackResampler::Write(float* buffer, unsigned int frames) int JackResampler::ReadResample(float* buffer, unsigned int frames) { - jack_ringbuffer_data_t ring_buffer_data[2]; - SRC_DATA src_data; - unsigned int frames_to_write = frames; - unsigned int written_frames = 0; - int res; - - jack_ringbuffer_get_read_vector(fRingBuffer, ring_buffer_data); - unsigned int available_frames = (ring_buffer_data[0].len + ring_buffer_data[1].len) / sizeof(float); - jack_log("OUPUT available = %ld", available_frames); - - for (int j = 0; j < 2; j++) { - - if (ring_buffer_data[j].len > 0) { - - src_data.data_in = (float*)ring_buffer_data[j].buf; - src_data.data_out = &buffer[written_frames]; - src_data.input_frames = ring_buffer_data[j].len / sizeof(float); - src_data.output_frames = frames_to_write; - src_data.end_of_input = 0; - src_data.src_ratio = fRatio; - - res = src_process(fResampler, &src_data); - if (res != 0) - jack_error("JackResampler::ReadResample err = %s", src_strerror(res)); - - frames_to_write -= src_data.output_frames_gen; - written_frames += src_data.output_frames_gen; - - if ((src_data.input_frames_used == 0 || src_data.output_frames_gen == 0) && j == 0) { - jack_error("OUTPUT : j = %d input_frames_used = %ld output_frames_gen = %ld", j, src_data.input_frames_used, src_data.output_frames_gen); - } - - jack_log("OUTPUT : j = %d input_frames_used = %ld output_frames_gen = %ld", j, src_data.input_frames_used, src_data.output_frames_gen); - jack_ringbuffer_read_advance(fRingBuffer, src_data.input_frames_used * sizeof(float)); - } - } - - if (written_frames < frames) { - jack_error("OUPUT available = %ld", available_frames); - jack_error("JackResampler::ReadResample error written_frames = %ld", written_frames); - } - - return written_frames; + return Read(buffer, frames); } int JackResampler::WriteResample(float* buffer, unsigned int frames) { - jack_ringbuffer_data_t ring_buffer_data[2]; - SRC_DATA src_data; - unsigned int frames_to_read = frames; - unsigned int read_frames = 0; - int res; - - jack_ringbuffer_get_write_vector(fRingBuffer, ring_buffer_data); - unsigned int available_frames = (ring_buffer_data[0].len + ring_buffer_data[1].len) / sizeof(float); - jack_log("INPUT available = %ld", available_frames); - - for (int j = 0; j < 2; j++) { - - if (ring_buffer_data[j].len > 0) { - - src_data.data_in = &buffer[read_frames]; - src_data.data_out = (float*)ring_buffer_data[j].buf; - src_data.input_frames = frames_to_read; - src_data.output_frames = (ring_buffer_data[j].len / sizeof(float)); - src_data.end_of_input = 0; - src_data.src_ratio = fRatio; - - res = src_process(fResampler, &src_data); - if (res != 0) - jack_error("JackResampler::ReadResample err = %s", src_strerror(res)); - - frames_to_read -= src_data.input_frames_used; - read_frames += src_data.input_frames_used; - - if ((src_data.input_frames_used == 0 || src_data.output_frames_gen == 0) && j == 0) { - jack_error("INPUT : j = %d input_frames_used = %ld output_frames_gen = %ld", j, src_data.input_frames_used, src_data.output_frames_gen); - } - - jack_log("INPUT : j = %d input_frames_used = %ld output_frames_gen = %ld", j, src_data.input_frames_used, src_data.output_frames_gen); - jack_ringbuffer_write_advance(fRingBuffer, src_data.output_frames_gen * sizeof(float)); - } - } - - if (read_frames < frames) { - jack_error("INPUT available = %ld", available_frames); - jack_error("JackResampler::ReadResample error read_frames = %ld", read_frames); - } - - return read_frames; + return Write(buffer, frames); } } diff --git a/common/JackResampler.h b/common/JackResampler.h index e3fd9b25..7ad8fdc6 100644 --- a/common/JackResampler.h +++ b/common/JackResampler.h @@ -22,45 +22,48 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #include "ringbuffer.h" #include "JackError.h" -#include + namespace Jack { - #define DEFAULT_RB_SIZE 16384 + #define DEFAULT_RB_SIZE 16384 * 4 class JackResampler { protected: - SRC_STATE* fResampler; jack_ringbuffer_t* fRingBuffer; - double fRatio; + unsigned int fNum; + unsigned int fDenom; public: JackResampler(); virtual ~JackResampler(); - int ReadResample(float* buffer, unsigned int frames); - int WriteResample(float* buffer, unsigned int frames); + virtual int ReadResample(float* buffer, unsigned int frames); + virtual int WriteResample(float* buffer, unsigned int frames); - int Read(float* buffer, unsigned int frames); - int Write(float* buffer, unsigned int frames); + virtual int Read(float* buffer, unsigned int frames); + virtual int Write(float* buffer, unsigned int frames); - unsigned int ReadSpace(); - unsigned int WriteSpace(); + virtual unsigned int ReadSpace(); + virtual unsigned int WriteSpace(); - void SetRatio(double ratio) + virtual void SetRatio(unsigned int num, unsigned int denom) { - fRatio = ratio; + fNum = num; + fDenom = denom; } - double GetRatio() + virtual void GetRatio(unsigned int& num, unsigned int& denom) { - return fRatio; + num = fNum; + denom = fDenom; } - }; + + }; } #endif diff --git a/common/wscript b/common/wscript index 2faab4fe..f07b169d 100644 --- a/common/wscript +++ b/common/wscript @@ -194,8 +194,8 @@ def build(bld): create_jack_process_obj(bld, 'netmanager', 'JackNetManager.cpp', serverlib) - #process = create_jack_process_obj(bld, 'netioadapter', 'JackResampler.cpp JackIOAdapter.cpp JackNetIOAdapter.cpp JackCallbackNetIOAdapter.cpp ../macosx/JackCoreAudioIOAdapter.cpp', serverlib) - process = create_jack_process_obj(bld, 'netioadapter', 'JackResampler.cpp JackIOAdapter.cpp JackNetIOAdapter.cpp JackCallbackNetIOAdapter.cpp ../windows/JackPortAudioIOAdapter.cpp', serverlib) + #process = create_jack_process_obj(bld, 'netioadapter', 'JackResampler.cpp ackLibSampleRateResampler.cpp JackIOAdapter.cpp JackNetIOAdapter.cpp JackCallbackNetIOAdapter.cpp ../macosx/JackCoreAudioIOAdapter.cpp', serverlib) + process = create_jack_process_obj(bld, 'netioadapter', 'JackResampler.cpp JackLibSampleRateResampler.cpp JackIOAdapter.cpp JackNetIOAdapter.cpp JackCallbackNetIOAdapter.cpp ../windows/JackPortAudioIOAdapter.cpp', serverlib) process.env.append_value("LINKFLAGS", "-lsamplerate") if bld.env()['IS_MACOSX']: diff --git a/macosx/JackCoreAudioIOAdapter.cpp b/macosx/JackCoreAudioIOAdapter.cpp index 385f303d..893692e8 100644 --- a/macosx/JackCoreAudioIOAdapter.cpp +++ b/macosx/JackCoreAudioIOAdapter.cpp @@ -151,7 +151,6 @@ OSStatus JackCoreAudioIOAdapter::Render(void *inRefCon, jack_time_t time = jack_get_time(); adapter->fProducerDLL.IncFrame(time); - adapter->fCurFrames += inNumberFrames; /* jack_time_t time1 = adapter->fConsumerDLL.CurFrame2Time(); jack_time_t time2 = adapter->fProducerDLL.CurFrame2Time(); @@ -190,13 +189,13 @@ OSStatus JackCoreAudioIOAdapter::Render(void *inRefCon, printf("Callback resampler src_ratio_input = %f src_ratio_output = %f\n", src_ratio_input, src_ratio_output); for (int i = 0; i < adapter->fCaptureChannels; i++) { - adapter->fCaptureRingBuffer[i].SetRatio(src_ratio_input); + adapter->fCaptureRingBuffer[i].SetRatio(time1, time2); adapter->fCaptureRingBuffer[i].WriteResample((float*)adapter->fInputData->mBuffers[i].mData, inNumberFrames); // adapter->fCaptureRingBuffer[i].Write((float*)adapter->fInputData->mBuffers[i].mData, inNumberFrames); } for (int i = 0; i < adapter->fPlaybackChannels; i++) { - adapter->fPlaybackRingBuffer[i].SetRatio(src_ratio_output); + adapter->fPlaybackRingBuffer[i].SetRatio(time2, time1); adapter->fPlaybackRingBuffer[i].ReadResample((float*)ioData->mBuffers[i].mData, inNumberFrames); // adapter->fPlaybackRingBuffer[i].Read((float*)ioData->mBuffers[i].mData, inNumberFrames); } diff --git a/windows/JackPortAudioIOAdapter.cpp b/windows/JackPortAudioIOAdapter.cpp index 5873a612..402b2d5b 100644 --- a/windows/JackPortAudioIOAdapter.cpp +++ b/windows/JackPortAudioIOAdapter.cpp @@ -44,7 +44,7 @@ int JackPortAudioIOAdapter::Render(const void* inputBuffer, void* outputBuffer, if (!adapter->fRunning) { adapter->fRunning = true; - jack_time_t time = jack_get_time(); + jack_time_t time = jack_get_time(); adapter->fProducerDLL.Init(time); adapter->fConsumerDLL.Init(time); adapter->fCurFrames = 0; @@ -59,21 +59,15 @@ int JackPortAudioIOAdapter::Render(const void* inputBuffer, void* outputBuffer, //adapter->fConsumerDLL.IncFrame(adapter->fConsumerTime); jack_time_t time = jack_get_time(); adapter->fProducerDLL.IncFrame(time); - - adapter->fCurFrames += framesPerBuffer; - /* - jack_time_t time1 = adapter->fConsumerDLL.CurFrame2Time(); - jack_time_t time2 = adapter->fProducerDLL.CurFrame2Time(); - */ - + jack_nframes_t time1 = adapter->fConsumerDLL.Time2Frames(time); jack_nframes_t time2 = adapter->fProducerDLL.Time2Frames(time); - printf("time1 %ld time2 %ld\n",time1, time2); + //printf("time1 %ld time2 %ld\n",time1, time2); double src_ratio_output = double(time2) / double(time1); double src_ratio_input = double(time1) / double(time2); - + /* jack_time_t val2 = adapter->fConsumerFilter.GetVal(); jack_time_t val1 = adapter->fProducerFilter.GetVal(); @@ -86,7 +80,6 @@ int JackPortAudioIOAdapter::Render(const void* inputBuffer, void* outputBuffer, src_ratio_input = 1; } - if (src_ratio_output < 0.8f || src_ratio_output > 1.2f) { jack_error("src_ratio_output = %f", src_ratio_output); src_ratio_output = 1; @@ -95,24 +88,27 @@ int JackPortAudioIOAdapter::Render(const void* inputBuffer, void* outputBuffer, src_ratio_output = Range(0.8f, 1.2f, src_ratio_output); //jack_log("Callback resampler src_ratio_input = %f src_ratio_output = %f", src_ratio_input, src_ratio_output); - printf("Callback resampler src_ratio_input = %f src_ratio_output = %f\n", src_ratio_input, src_ratio_output); - + paBuffer = (float**)inputBuffer; for (int i = 0; i < adapter->fCaptureChannels; i++) { buffer = (float*)paBuffer[i]; - adapter->fCaptureRingBuffer[i].SetRatio(src_ratio_input); + adapter->fCaptureRingBuffer[i].SetRatio(time1, time2); //adapter->fCaptureRingBuffer[i].WriteResample(buffer, framesPerBuffer); + //adapter->fCaptureRingBuffer[i].SetRatio(double(adapter->fNum) * adapter->fError1, adapter->fDenom); adapter->fCaptureRingBuffer[i].Write(buffer, framesPerBuffer); } paBuffer = (float**)outputBuffer; for (int i = 0; i < adapter->fPlaybackChannels; i++) { buffer = (float*)paBuffer[i]; - adapter->fPlaybackRingBuffer[i].SetRatio(src_ratio_output); + adapter->fPlaybackRingBuffer[i].SetRatio(time2, time1); //adapter->fPlaybackRingBuffer[i].ReadResample(buffer, framesPerBuffer); + //adapter->fCaptureRingBuffer[i].SetRatio(double(adapter->fDenom) * adapter->fError1, adapter->fNum); adapter->fPlaybackRingBuffer[i].Read(buffer, framesPerBuffer); } - + + printf("Callback resampler src_ratio_input = %f src_ratio_output = %f\n", double(time1) / double(time2), double(time2) / double(time1)); + return paContinue; } diff --git a/windows/JackPortAudioIOAdapter.h b/windows/JackPortAudioIOAdapter.h index 732e9d8c..35b16b4f 100644 --- a/windows/JackPortAudioIOAdapter.h +++ b/windows/JackPortAudioIOAdapter.h @@ -40,7 +40,7 @@ namespace Jack const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void* userData); - + public: JackPortAudioIOAdapter(int input, int output, int buffer_size, float sample_rate)