git-svn-id: http://subversion.jackaudio.org/jack/jack2/branches/libjacknet@3421 0c269be4-1314-0410-8aa9-9f06e86f4224tags/1.9.8
| @@ -17,12 +17,21 @@ Nedko Arnaudov | |||||
| Fernando Lopez-Lezcano | Fernando Lopez-Lezcano | ||||
| Romain Moret | Romain Moret | ||||
| Florian Faber | Florian Faber | ||||
| Michael Voigt | |||||
| Michael Voigt | |||||
| Torben Hohn | |||||
| --------------------------- | --------------------------- | ||||
| Jackdmp changes log | 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> | 2009-03-05 Stephane Letz <letz@grame.fr> | ||||
| * Support for BIG_ENDIAN machines in NetJack2 for transport data. | * Support for BIG_ENDIAN machines in NetJack2 for transport data. | ||||
| @@ -58,6 +58,7 @@ namespace Jack | |||||
| } | } | ||||
| fclose(file); | fclose(file); | ||||
| /* No used for now | |||||
| // Adapter timing 1 | // Adapter timing 1 | ||||
| file = fopen("AdapterTiming1.plot", "w"); | file = fopen("AdapterTiming1.plot", "w"); | ||||
| fprintf(file, "set multiplot\n"); | fprintf(file, "set multiplot\n"); | ||||
| @@ -88,6 +89,7 @@ namespace Jack | |||||
| fprintf(file, buffer); | fprintf(file, buffer); | ||||
| fclose(file); | fclose(file); | ||||
| */ | |||||
| // Adapter timing 2 | // Adapter timing 2 | ||||
| file = fopen("AdapterTiming2.plot", "w"); | file = fopen("AdapterTiming2.plot", "w"); | ||||
| @@ -162,30 +164,7 @@ namespace Jack | |||||
| fPlaybackRingBuffer[i]->Reset(); | 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(); | ResetRingBuffers(); | ||||
| fRunning = false; | fRunning = false; | ||||
| @@ -226,25 +205,31 @@ namespace Jack | |||||
| int JackAudioAdapterInterface::PushAndPull(float** inputBuffer, float** outputBuffer, unsigned int frames) | int JackAudioAdapterInterface::PushAndPull(float** inputBuffer, float** outputBuffer, unsigned int frames) | ||||
| { | { | ||||
| bool failure = false; | 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 | // Push/pull from ringbuffer | ||||
| for (int i = 0; i < fCaptureChannels; i++) { | for (int i = 0; i < fCaptureChannels; i++) { | ||||
| fCaptureRingBuffer[i]->SetRatio(time1, time2); | |||||
| fCaptureRingBuffer[i]->SetRatio(ratio); | |||||
| if (fCaptureRingBuffer[i]->WriteResample(inputBuffer[i], frames) < frames) | if (fCaptureRingBuffer[i]->WriteResample(inputBuffer[i], frames) < frames) | ||||
| failure = true; | failure = true; | ||||
| } | } | ||||
| for (int i = 0; i < fPlaybackChannels; i++) { | 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) | if (fPlaybackRingBuffer[i]->ReadResample(outputBuffer[i], frames) < frames) | ||||
| failure = true; | failure = true; | ||||
| } | } | ||||
| #ifdef JACK_MONITOR | #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 | #endif | ||||
| // Reset all ringbuffers in case of failure | // Reset all ringbuffers in case of failure | ||||
| @@ -260,8 +245,8 @@ namespace Jack | |||||
| int JackAudioAdapterInterface::PullAndPush(float** inputBuffer, float** outputBuffer, unsigned int frames) | int JackAudioAdapterInterface::PullAndPush(float** inputBuffer, float** outputBuffer, unsigned int frames) | ||||
| { | { | ||||
| bool failure = false; | bool failure = false; | ||||
| fHostDLL.IncFrame(GetMicroSeconds()); | |||||
| fPullAndPushTime = GetMicroSeconds(); | |||||
| // Push/pull from ringbuffer | // Push/pull from ringbuffer | ||||
| for (int i = 0; i < fCaptureChannels; i++) { | for (int i = 0; i < fCaptureChannels; i++) { | ||||
| if (fCaptureRingBuffer[i]->Read(inputBuffer[i], frames) < frames) | if (fCaptureRingBuffer[i]->Read(inputBuffer[i], frames) < frames) | ||||
| @@ -82,36 +82,34 @@ namespace Jack | |||||
| jack_nframes_t fAdaptedBufferSize; | jack_nframes_t fAdaptedBufferSize; | ||||
| jack_nframes_t fAdaptedSampleRate; | jack_nframes_t fAdaptedSampleRate; | ||||
| //delay locked loop | |||||
| JackAtomicDelayLockedLoop fHostDLL; | |||||
| JackAtomicDelayLockedLoop fAdaptedDLL; | |||||
| //PI controler | |||||
| JackPIControler fPIControler; | |||||
| JackResampler** fCaptureRingBuffer; | JackResampler** fCaptureRingBuffer; | ||||
| JackResampler** fPlaybackRingBuffer; | JackResampler** fPlaybackRingBuffer; | ||||
| unsigned int fQuality; | unsigned int fQuality; | ||||
| unsigned int fRingbufferSize; | unsigned int fRingbufferSize; | ||||
| jack_time_t fPullAndPushTime; | |||||
| bool fRunning; | bool fRunning; | ||||
| void ResetRingBuffers(); | void ResetRingBuffers(); | ||||
| void ResampleFactor ( jack_time_t& frame1, jack_time_t& frame2 ); | |||||
| public: | 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, | JackAudioAdapterInterface ( jack_nframes_t host_buffer_size, | ||||
| jack_nframes_t host_sample_rate, | jack_nframes_t host_sample_rate, | ||||
| @@ -123,10 +121,10 @@ namespace Jack | |||||
| fHostSampleRate ( host_sample_rate ), | fHostSampleRate ( host_sample_rate ), | ||||
| fAdaptedBufferSize ( adapted_buffer_size), | fAdaptedBufferSize ( adapted_buffer_size), | ||||
| fAdaptedSampleRate ( adapted_sample_rate ), | 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), | fQuality(0), | ||||
| fRingbufferSize(DEFAULT_RB_SIZE), | fRingbufferSize(DEFAULT_RB_SIZE), | ||||
| fPullAndPushTime(0), | |||||
| fRunning ( false ) | fRunning ( false ) | ||||
| {} | {} | ||||
| @@ -156,14 +154,12 @@ namespace Jack | |||||
| virtual int SetHostBufferSize ( jack_nframes_t buffer_size ) | virtual int SetHostBufferSize ( jack_nframes_t buffer_size ) | ||||
| { | { | ||||
| fHostBufferSize = buffer_size; | fHostBufferSize = buffer_size; | ||||
| fHostDLL.Init ( fHostBufferSize, fHostSampleRate ); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| virtual int SetAdaptedBufferSize ( jack_nframes_t buffer_size ) | virtual int SetAdaptedBufferSize ( jack_nframes_t buffer_size ) | ||||
| { | { | ||||
| fAdaptedBufferSize = buffer_size; | fAdaptedBufferSize = buffer_size; | ||||
| fAdaptedDLL.Init ( fAdaptedBufferSize, fAdaptedSampleRate ); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -177,14 +173,14 @@ namespace Jack | |||||
| virtual int SetHostSampleRate ( jack_nframes_t sample_rate ) | virtual int SetHostSampleRate ( jack_nframes_t sample_rate ) | ||||
| { | { | ||||
| fHostSampleRate = sample_rate; | fHostSampleRate = sample_rate; | ||||
| fHostDLL.Init ( fHostBufferSize, fHostSampleRate ); | |||||
| fPIControler.Init(double(fHostSampleRate) / double(fAdaptedSampleRate)); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| virtual int SetAdaptedSampleRate ( jack_nframes_t sample_rate ) | virtual int SetAdaptedSampleRate ( jack_nframes_t sample_rate ) | ||||
| { | { | ||||
| fAdaptedSampleRate = sample_rate; | fAdaptedSampleRate = sample_rate; | ||||
| fAdaptedDLL.Init ( fAdaptedBufferSize, fAdaptedSampleRate ); | |||||
| fPIControler.Init(double(fHostSampleRate) / double(fAdaptedSampleRate)); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -28,7 +28,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||||
| namespace Jack | namespace Jack | ||||
| { | { | ||||
| #define TIME_POINTS 250000 | |||||
| #define TIME_POINTS 125000 | |||||
| #define FAILURE_TIME_POINTS 10000 | #define FAILURE_TIME_POINTS 10000 | ||||
| #define FAILURE_WINDOW 10 | #define FAILURE_WINDOW 10 | ||||
| #define MEASURED_CLIENTS 32 | #define MEASURED_CLIENTS 32 | ||||
| @@ -23,6 +23,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||||
| #include "jack.h" | #include "jack.h" | ||||
| #include "JackAtomicState.h" | #include "JackAtomicState.h" | ||||
| #include <math.h> | #include <math.h> | ||||
| #include <stdlib.h> | |||||
| namespace Jack | namespace Jack | ||||
| { | { | ||||
| @@ -201,6 +202,117 @@ namespace Jack | |||||
| return res; | 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); | jack_error("JackGraphManager::Connect failed port_src = %ld port_dst = %ld", port_src, port_dst); | ||||
| goto end; | goto end; | ||||
| } | } | ||||
| manager->Connect(port_dst, port_src); | |||||
| res = manager->Connect(port_dst, port_src); | |||||
| if (res < 0) { | if (res < 0) { | ||||
| jack_error("JackGraphManager::Connect failed port_dst = %ld port_src = %ld", port_dst, port_src); | jack_error("JackGraphManager::Connect failed port_dst = %ld port_src = %ld", port_dst, port_src); | ||||
| goto end; | goto end; | ||||
| @@ -583,12 +583,12 @@ int JackGraphManager::Disconnect(jack_port_id_t port_src, jack_port_id_t port_ds | |||||
| goto end; | goto end; | ||||
| } | } | ||||
| manager->Disconnect(port_src, port_dst); | |||||
| res = manager->Disconnect(port_src, port_dst); | |||||
| if (res < 0) { | if (res < 0) { | ||||
| jack_error("JackGraphManager::Disconnect failed port_src = %ld port_dst = %ld", port_src, port_dst); | jack_error("JackGraphManager::Disconnect failed port_src = %ld port_dst = %ld", port_src, port_dst); | ||||
| goto end; | goto end; | ||||
| } | } | ||||
| manager->Disconnect(port_dst, port_src); | |||||
| res = manager->Disconnect(port_dst, port_src); | |||||
| if (res < 0) { | if (res < 0) { | ||||
| jack_error("JackGraphManager::Disconnect failed port_dst = %ld port_src = %ld", port_dst, port_src); | jack_error("JackGraphManager::Disconnect failed port_dst = %ld port_src = %ld", port_dst, port_src); | ||||
| goto end; | goto end; | ||||
| @@ -23,7 +23,7 @@ namespace Jack | |||||
| { | { | ||||
| JackLibSampleRateResampler::JackLibSampleRateResampler() | JackLibSampleRateResampler::JackLibSampleRateResampler() | ||||
| :JackResampler(),fRatio(1) | |||||
| :JackResampler() | |||||
| { | { | ||||
| int error; | int error; | ||||
| fResampler = src_new(SRC_LINEAR, 1, &error); | fResampler = src_new(SRC_LINEAR, 1, &error); | ||||
| @@ -32,7 +32,7 @@ JackLibSampleRateResampler::JackLibSampleRateResampler() | |||||
| } | } | ||||
| JackLibSampleRateResampler::JackLibSampleRateResampler(unsigned int quality, unsigned int ringbuffer_size) | JackLibSampleRateResampler::JackLibSampleRateResampler(unsigned int quality, unsigned int ringbuffer_size) | ||||
| :JackResampler(ringbuffer_size),fRatio(1) | |||||
| :JackResampler(ringbuffer_size) | |||||
| { | { | ||||
| switch (quality) { | switch (quality) { | ||||
| case 0: | case 0: | ||||
| @@ -26,11 +26,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||||
| namespace Jack | 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/). | \brief Resampler using "libsamplerate" (http://www.mega-nerd.com/SRC/). | ||||
| */ | */ | ||||
| @@ -41,7 +36,6 @@ class JackLibSampleRateResampler : public JackResampler | |||||
| private: | private: | ||||
| SRC_STATE* fResampler; | SRC_STATE* fResampler; | ||||
| double fRatio; | |||||
| public: | public: | ||||
| @@ -51,12 +45,6 @@ class JackLibSampleRateResampler : public JackResampler | |||||
| unsigned int ReadResample(float* buffer, unsigned int frames); | unsigned int ReadResample(float* buffer, unsigned int frames); | ||||
| unsigned int WriteResample(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(); | void Reset(); | ||||
| @@ -95,6 +95,9 @@ namespace Jack | |||||
| case 'q': | case 'q': | ||||
| fQuality = param->value.ui; | fQuality = param->value.ui; | ||||
| break; | break; | ||||
| case 'g': | |||||
| fRingbufferSize = param->value.ui; | |||||
| break; | |||||
| } | } | ||||
| } | } | ||||
| @@ -151,6 +154,10 @@ namespace Jack | |||||
| { | { | ||||
| jack_log ( "JackNetAdapter::Close" ); | jack_log ( "JackNetAdapter::Close" ); | ||||
| #ifdef JACK_MONITOR | |||||
| fTable.Save(fHostBufferSize, fHostSampleRate, fAdaptedSampleRate, fAdaptedBufferSize); | |||||
| #endif | |||||
| switch ( fThread.GetStatus() ) | switch ( fThread.GetStatus() ) | ||||
| { | { | ||||
| // Kill the thread in Init phase | // 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->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 | 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 ) ); | desc->params = ( jack_driver_param_desc_t* ) calloc ( desc->nparams, sizeof ( jack_driver_param_desc_t ) ); | ||||
| int i = 0; | int i = 0; | ||||
| @@ -414,7 +421,7 @@ extern "C" | |||||
| strcpy ( desc->params[i].long_desc, desc->params[i].short_desc ); | strcpy ( desc->params[i].long_desc, desc->params[i].short_desc ); | ||||
| i++; | i++; | ||||
| strcpy ( desc->params[i].name, "input_ports" ); | |||||
| strcpy ( desc->params[i].name, "input-ports" ); | |||||
| desc->params[i].character = 'C'; | desc->params[i].character = 'C'; | ||||
| desc->params[i].type = JackDriverParamInt; | desc->params[i].type = JackDriverParamInt; | ||||
| desc->params[i].value.i = 2; | desc->params[i].value.i = 2; | ||||
| @@ -422,7 +429,7 @@ extern "C" | |||||
| strcpy ( desc->params[i].long_desc, desc->params[i].short_desc ); | strcpy ( desc->params[i].long_desc, desc->params[i].short_desc ); | ||||
| i++; | i++; | ||||
| strcpy ( desc->params[i].name, "output_ports" ); | |||||
| strcpy ( desc->params[i].name, "output-ports" ); | |||||
| desc->params[i].character = 'P'; | desc->params[i].character = 'P'; | ||||
| desc->params[i].type = JackDriverParamInt; | desc->params[i].type = JackDriverParamInt; | ||||
| desc->params[i].value.i = 2; | desc->params[i].value.i = 2; | ||||
| @@ -430,7 +437,7 @@ extern "C" | |||||
| strcpy ( desc->params[i].long_desc, desc->params[i].short_desc ); | strcpy ( desc->params[i].long_desc, desc->params[i].short_desc ); | ||||
| i++; | i++; | ||||
| strcpy ( desc->params[i].name, "client_name" ); | |||||
| strcpy ( desc->params[i].name, "client-name" ); | |||||
| desc->params[i].character = 'n'; | desc->params[i].character = 'n'; | ||||
| desc->params[i].type = JackDriverParamString; | desc->params[i].type = JackDriverParamString; | ||||
| strcpy ( desc->params[i].value.str, "'hostname'" ); | strcpy ( desc->params[i].value.str, "'hostname'" ); | ||||
| @@ -438,7 +445,7 @@ extern "C" | |||||
| strcpy ( desc->params[i].long_desc, desc->params[i].short_desc ); | strcpy ( desc->params[i].long_desc, desc->params[i].short_desc ); | ||||
| i++; | i++; | ||||
| strcpy ( desc->params[i].name, "transport_sync" ); | |||||
| strcpy ( desc->params[i].name, "transport-sync" ); | |||||
| desc->params[i].character = 't'; | desc->params[i].character = 't'; | ||||
| desc->params[i].type = JackDriverParamUInt; | desc->params[i].type = JackDriverParamUInt; | ||||
| desc->params[i].value.ui = 1U; | desc->params[i].value.ui = 1U; | ||||
| @@ -462,13 +469,21 @@ extern "C" | |||||
| strcpy(desc->params[i].long_desc, desc->params[i].short_desc); | strcpy(desc->params[i].long_desc, desc->params[i].short_desc); | ||||
| i++; | 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].character = 'c'; | ||||
| desc->params[i].type = JackDriverParamBool; | desc->params[i].type = JackDriverParamBool; | ||||
| desc->params[i].value.i = false; | desc->params[i].value.i = false; | ||||
| strcpy ( desc->params[i].short_desc, "Auto connect netmaster to system ports" ); | strcpy ( desc->params[i].short_desc, "Auto connect netmaster to system ports" ); | ||||
| strcpy ( desc->params[i].long_desc, desc->params[i].short_desc ); | strcpy ( desc->params[i].long_desc, desc->params[i].short_desc ); | ||||
| return desc; | return desc; | ||||
| } | } | ||||
| @@ -421,14 +421,14 @@ namespace Jack | |||||
| dst_params->fPosition.beat = htonl(src_params->fPosition.beat); | dst_params->fPosition.beat = htonl(src_params->fPosition.beat); | ||||
| dst_params->fPosition.tick = htonl(src_params->fPosition.tick); | 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.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.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.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.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.next_time = htonll((uint64_t)src_params->fPosition.next_time); | ||||
| dst_params->fPosition.bbt_offset = htonl(src_params->fPosition.bbt_offset); | 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.video_offset = htonl(src_params->fPosition.video_offset); | ||||
| dst_params->fPosition.unique_2 = htonll(src_params->fPosition.unique_2); | 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.beat = ntohl(src_params->fPosition.beat); | ||||
| dst_params->fPosition.tick = ntohl(src_params->fPosition.tick); | 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.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.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.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.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.next_time = ntohll((uint64_t)src_params->fPosition.next_time); | ||||
| dst_params->fPosition.bbt_offset = ntohl(src_params->fPosition.bbt_offset); | 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.video_offset = ntohl(src_params->fPosition.video_offset); | ||||
| dst_params->fPosition.unique_2 = ntohll(src_params->fPosition.unique_2); | 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 | 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); | fRingBuffer = jack_ringbuffer_create(sizeof(float) * fRingBufferSize); | ||||
| jack_ringbuffer_read_advance(fRingBuffer, (sizeof(float) * fRingBufferSize) / 2); | jack_ringbuffer_read_advance(fRingBuffer, (sizeof(float) * fRingBufferSize) / 2); | ||||
| @@ -26,8 +26,13 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||||
| namespace Jack | 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. | \brief Base class for Resampler. | ||||
| */ | */ | ||||
| @@ -38,8 +43,7 @@ class JackResampler | |||||
| protected: | protected: | ||||
| jack_ringbuffer_t* fRingBuffer; | jack_ringbuffer_t* fRingBuffer; | ||||
| unsigned int fNum; | |||||
| unsigned int fDenom; | |||||
| double fRatio; | |||||
| unsigned int fRingBufferSize; | unsigned int fRingBufferSize; | ||||
| public: | public: | ||||
| @@ -58,16 +62,20 @@ class JackResampler | |||||
| virtual unsigned int ReadSpace(); | virtual unsigned int ReadSpace(); | ||||
| virtual unsigned int WriteSpace(); | 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; | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -342,7 +342,7 @@ void sample_move_dS_s32u24 (jack_default_audio_sample_t *dst, char *src, unsigne | |||||
| int i4 = *((int *) src); | int i4 = *((int *) src); | ||||
| src+= src_skip; | src+= src_skip; | ||||
| __m128i src = _mm_set_epi32(i1, i2, i3, i4); | |||||
| __m128i src = _mm_set_epi32(i4, i3, i2, i1); | |||||
| __m128i shifted = _mm_srai_epi32(src, 8); | __m128i shifted = _mm_srai_epi32(src, 8); | ||||
| __m128 as_float = _mm_cvtepi32_ps(shifted); | __m128 as_float = _mm_cvtepi32_ps(shifted); | ||||
| @@ -287,7 +287,7 @@ extern "C" | |||||
| desc->params[i].character = 'g'; | desc->params[i].character = 'g'; | ||||
| desc->params[i].type = JackDriverParamInt; | desc->params[i].type = JackDriverParamInt; | ||||
| desc->params[i].value.ui = 0; | desc->params[i].value.ui = 0; | ||||
| strcpy(desc->params[i].short_desc, "Resampling ringbuffer size in frames (default = 32768)"); | |||||
| strcpy(desc->params[i].short_desc, "Resampling ringbuffer size in frames (default = 16384)"); | |||||
| strcpy(desc->params[i].long_desc, desc->params[i].short_desc); | strcpy(desc->params[i].long_desc, desc->params[i].short_desc); | ||||
| return desc; | return desc; | ||||
| @@ -377,7 +377,7 @@ JackCoreAudioAdapter::JackCoreAudioAdapter(jack_nframes_t buffer_size, jack_nfra | |||||
| fQuality = param->value.ui; | fQuality = param->value.ui; | ||||
| break; | break; | ||||
| case 'g': | |||||
| case 'g': | |||||
| fRingbufferSize = param->value.ui; | fRingbufferSize = param->value.ui; | ||||
| break; | break; | ||||
| } | } | ||||
| @@ -1081,7 +1081,7 @@ extern "C" | |||||
| desc->params[i].character = 'g'; | desc->params[i].character = 'g'; | ||||
| desc->params[i].type = JackDriverParamInt; | desc->params[i].type = JackDriverParamInt; | ||||
| desc->params[i].value.ui = 0; | desc->params[i].value.ui = 0; | ||||
| strcpy(desc->params[i].short_desc, "Resampling ringbuffer size in frames (default = 32768)"); | |||||
| strcpy(desc->params[i].short_desc, "Resampling ringbuffer size in frames (default = 16384)"); | |||||
| strcpy(desc->params[i].long_desc, desc->params[i].short_desc); | strcpy(desc->params[i].long_desc, desc->params[i].short_desc); | ||||
| return desc; | return desc; | ||||
| @@ -743,7 +743,7 @@ extern "C" | |||||
| desc->params[i].character = 'g'; | desc->params[i].character = 'g'; | ||||
| desc->params[i].type = JackDriverParamInt; | desc->params[i].type = JackDriverParamInt; | ||||
| desc->params[i].value.ui = 0; | desc->params[i].value.ui = 0; | ||||
| strcpy(desc->params[i].short_desc, "Resampling ringbuffer size in frames (default = 32768)"); | |||||
| strcpy(desc->params[i].short_desc, "Resampling ringbuffer size in frames (default = 16384)"); | |||||
| strcpy(desc->params[i].long_desc, desc->params[i].short_desc); | strcpy(desc->params[i].long_desc, desc->params[i].short_desc); | ||||
| return desc; | return desc; | ||||
| @@ -286,7 +286,13 @@ namespace Jack | |||||
| //local loop********************************************************************************************************* | //local loop********************************************************************************************************* | ||||
| int JackNetWinSocket::SetLocalLoop() | int JackNetWinSocket::SetLocalLoop() | ||||
| { | { | ||||
| char disable = 0; | |||||
| //char disable = 0; | |||||
| /* | |||||
| see http://msdn.microsoft.com/en-us/library/aa916098.aspx | |||||
| Default value is TRUE. When TRUE, data that is sent from the local interface to the multicast group to | |||||
| which the socket is joined, including data sent from the same socket, will be echoed to its receive buffer. | |||||
| */ | |||||
| char disable = 1; | |||||
| return SetOption ( IPPROTO_IP, IP_MULTICAST_LOOP, &disable, sizeof ( disable ) ); | return SetOption ( IPPROTO_IP, IP_MULTICAST_LOOP, &disable, sizeof ( disable ) ); | ||||
| } | } | ||||
| @@ -50,10 +50,10 @@ JackRouter is an ASIO driver that allows any ASIO compatible application to beco | |||||
| ============================================= | ============================================= | ||||
| Known problems: | |||||
| Known problems | |||||
| ============================================= | ============================================= | ||||
| - starting/stopping the server several times in QJACKCTL does not work correctly. You'll have to quit qjacckctl and launch it again. | |||||
| - starting/stopping the server several times in QJACKCTL does not work correctly. You'll have to quit qjackctl and launch it again. | |||||
| ============================================= | ============================================= | ||||
| @@ -299,7 +299,7 @@ extern "C" | |||||
| desc->params[i].character = 'g'; | desc->params[i].character = 'g'; | ||||
| desc->params[i].type = JackDriverParamInt; | desc->params[i].type = JackDriverParamInt; | ||||
| desc->params[i].value.ui = 0; | desc->params[i].value.ui = 0; | ||||
| strcpy(desc->params[i].short_desc, "Resampling ringbuffer size in frames (default = 32768)"); | |||||
| strcpy(desc->params[i].short_desc, "Resampling ringbuffer size in frames (default = 16384)"); | |||||
| strcpy(desc->params[i].long_desc, desc->params[i].short_desc); | strcpy(desc->params[i].long_desc, desc->params[i].short_desc); | ||||
| return desc; | return desc; | ||||