Jack2 1.9.6

JackFilters.h

00001 /*
00002 Copyright (C) 2008 Grame
00003 
00004 This program is free software; you can redistribute it and/or modify
00005 it under the terms of the GNU General Public License as published by
00006 the Free Software Foundation; either version 2 of the License, or
00007 (at your option) any later version.
00008 
00009 This program is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 GNU General Public License for more details.
00013 
00014 You should have received a copy of the GNU General Public License
00015 along with this program; if not, write to the Free Software
00016 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017 
00018 */
00019 
00020 #ifndef __JackFilters__
00021 #define __JackFilters__
00022 
00023 #include "jack.h"
00024 #include "JackAtomicState.h"
00025 #include <math.h>
00026 #include <stdlib.h>
00027 
00028 namespace Jack
00029 {
00030 
00031     #define MAX_SIZE 64
00032     
00033         struct JackFilter 
00034     {
00035     
00036         jack_time_t fTable[MAX_SIZE];
00037         
00038         JackFilter()
00039         {
00040             for (int i = 0; i < MAX_SIZE; i++)
00041                 fTable[i] = 0;
00042         }
00043         
00044         void AddValue(jack_time_t val)
00045         {
00046             memcpy(&fTable[1], &fTable[0], sizeof(jack_time_t) * (MAX_SIZE - 1));
00047             fTable[0] = val;
00048         }
00049         
00050         jack_time_t GetVal()
00051         {
00052             jack_time_t mean = 0;
00053             for (int i = 0; i < MAX_SIZE; i++)
00054                 mean += fTable[i];
00055             return mean / MAX_SIZE;
00056         }
00057         
00058     } POST_PACKED_STRUCTURE;
00059     
00060     class JackDelayLockedLoop
00061     {
00062     
00063         private:
00064         
00065             jack_nframes_t fFrames;
00066             jack_time_t fCurrentWakeup;
00067             jack_time_t fCurrentCallback;
00068             jack_time_t fNextWakeUp;
00069             float fSecondOrderIntegrator;
00070             jack_nframes_t fBufferSize;
00071             jack_nframes_t fSampleRate;
00072             jack_time_t fPeriodUsecs;
00073             float fFilterCoefficient;   /* set once, never altered */
00074             bool fUpdating;
00075         
00076         public:
00077         
00078             JackDelayLockedLoop()
00079             {}
00080             
00081             JackDelayLockedLoop(jack_nframes_t buffer_size, jack_nframes_t sample_rate)
00082             {
00083                 Init(buffer_size, sample_rate);
00084             }
00085             
00086             void Init(jack_nframes_t buffer_size, jack_nframes_t sample_rate)
00087             {
00088                 fFrames = 0;
00089                 fCurrentWakeup = 0;
00090                 fCurrentCallback = 0;
00091                 fNextWakeUp = 0;
00092                 fFilterCoefficient = 0.01f;
00093                 fSecondOrderIntegrator = 0.0f;
00094                 fBufferSize = buffer_size;
00095                 fSampleRate = sample_rate;
00096                 fPeriodUsecs = jack_time_t(1000000.f / fSampleRate * fBufferSize);      // in microsec
00097             }
00098         
00099             void Init(jack_time_t callback_usecs)
00100             {
00101                 fFrames = 0;
00102                 fCurrentWakeup = 0;
00103                 fSecondOrderIntegrator = 0.0f;
00104                 fCurrentCallback = callback_usecs;
00105                 fNextWakeUp = callback_usecs + fPeriodUsecs;
00106             }
00107             
00108             void IncFrame(jack_time_t callback_usecs)
00109             {
00110                 float delta = (int64_t)callback_usecs - (int64_t)fNextWakeUp;
00111                 fCurrentWakeup = fNextWakeUp;
00112                 fCurrentCallback = callback_usecs;
00113                 fFrames += fBufferSize;
00114                 fSecondOrderIntegrator += 0.5f * fFilterCoefficient * delta;
00115                 fNextWakeUp = fCurrentWakeup + fPeriodUsecs + (int64_t) floorf((fFilterCoefficient * (delta + fSecondOrderIntegrator)));
00116             }
00117             
00118             jack_nframes_t Time2Frames(jack_time_t time)
00119             {
00120                 long delta = (long) rint(((double) ((long long)(time - fCurrentWakeup)) / ((long long)(fNextWakeUp - fCurrentWakeup))) * fBufferSize);
00121                 return (delta < 0) ? ((fFrames > 0) ? fFrames : 1) : (fFrames + delta);
00122             }
00123             
00124             jack_time_t Frames2Time(jack_nframes_t frames)
00125             {
00126                 long delta = (long) rint(((double) ((long long)(frames - fFrames)) * ((long long)(fNextWakeUp - fCurrentWakeup))) / fBufferSize);
00127                 return (delta < 0) ? ((fCurrentWakeup > 0) ? fCurrentWakeup : 1) : (fCurrentWakeup + delta);
00128             }
00129             
00130             jack_nframes_t CurFrame()
00131             {
00132                 return fFrames;
00133             }
00134                  
00135             jack_time_t CurTime()
00136             {
00137                 return fCurrentWakeup;
00138             }
00139   
00140     } POST_PACKED_STRUCTURE;
00141     
00142     class JackAtomicDelayLockedLoop : public JackAtomicState<JackDelayLockedLoop>
00143     {
00144          public:
00145          
00146             JackAtomicDelayLockedLoop(jack_nframes_t buffer_size, jack_nframes_t sample_rate)
00147             {
00148                 fState[0].Init(buffer_size, sample_rate);
00149                 fState[1].Init(buffer_size, sample_rate);
00150             }
00151             
00152             void Init(jack_time_t callback_usecs)
00153             {
00154                 JackDelayLockedLoop* dll = WriteNextStateStart();
00155                 dll->Init(callback_usecs);
00156                 WriteNextStateStop();
00157                 TrySwitchState(); // always succeed since there is only one writer
00158             }
00159             
00160             void Init(jack_nframes_t buffer_size, jack_nframes_t sample_rate)
00161             {
00162                 JackDelayLockedLoop* dll = WriteNextStateStart();
00163                 dll->Init(buffer_size, sample_rate);
00164                 WriteNextStateStop();
00165                 TrySwitchState(); // always succeed since there is only one writer
00166             }
00167             
00168             void IncFrame(jack_time_t callback_usecs)
00169             {
00170                 JackDelayLockedLoop* dll = WriteNextStateStart();
00171                 dll->IncFrame(callback_usecs);
00172                 WriteNextStateStop();
00173                 TrySwitchState(); // always succeed since there is only one writer
00174             }
00175             
00176             jack_nframes_t Time2Frames(jack_time_t time)
00177             {
00178                 UInt16 next_index = GetCurrentIndex();
00179                 UInt16 cur_index;
00180                 jack_nframes_t res;
00181                 
00182                 do {
00183                     cur_index = next_index;
00184                     res = ReadCurrentState()->Time2Frames(time);
00185                     next_index = GetCurrentIndex();
00186                 } while (cur_index != next_index); // Until a coherent state has been read
00187                 
00188                 return res;
00189             }
00190              
00191             jack_time_t Frames2Time(jack_nframes_t frames)
00192             {
00193                 UInt16 next_index = GetCurrentIndex();
00194                 UInt16 cur_index;
00195                 jack_time_t res;
00196                 
00197                 do {
00198                     cur_index = next_index;
00199                     res = ReadCurrentState()->Frames2Time(frames);
00200                     next_index = GetCurrentIndex();
00201                 } while (cur_index != next_index); // Until a coherent state has been read
00202                 
00203                 return res;
00204             }
00205     } POST_PACKED_STRUCTURE;
00206     
00207     /*
00208     Torben Hohn PI controler from JACK1
00209     */
00210     
00211     struct JackPIControler {
00212     
00213         double resample_mean;
00214         double static_resample_factor;
00215 
00216         double* offset_array;
00217         double* window_array;
00218         int offset_differential_index;
00219 
00220         double offset_integral;
00221 
00222         double catch_factor;
00223         double catch_factor2;
00224         double pclamp;
00225         double controlquant;
00226         int smooth_size;
00227     
00228         double hann(double x)
00229         {
00230             return 0.5 * (1.0 - cos(2 * M_PI * x));
00231         }
00232         
00233         JackPIControler(double resample_factor, int fir_size)
00234         {
00235             resample_mean = resample_factor;
00236             static_resample_factor = resample_factor;
00237             offset_array = new double[fir_size];
00238             window_array = new double[fir_size];
00239             offset_differential_index = 0;
00240             offset_integral = 0.0;
00241             smooth_size = fir_size;
00242             
00243             for (int i = 0; i < fir_size; i++) {
00244                 offset_array[i] = 0.0;
00245                 window_array[i] = hann(double(i) / (double(fir_size) - 1.0));
00246             }
00247 
00248             // These values could be configurable
00249             catch_factor = 100000;
00250             catch_factor2 = 10000;
00251             pclamp = 15.0;
00252             controlquant = 10000.0;
00253         }
00254         
00255         ~JackPIControler()
00256         {
00257             delete[] offset_array;
00258             delete[] window_array;
00259         }
00260         
00261         void Init(double resample_factor)
00262         {
00263             resample_mean = resample_factor;
00264             static_resample_factor = resample_factor;
00265         }
00266         
00267         /*
00268         double GetRatio(int fill_level)
00269         {
00270             double offset = fill_level;
00271 
00272             // Save offset.
00273             offset_array[(offset_differential_index++) % smooth_size] = offset;
00274             
00275             // Build the mean of the windowed offset array basically fir lowpassing.
00276             double smooth_offset = 0.0;
00277             for (int i = 0; i < smooth_size; i++) {
00278                 smooth_offset += offset_array[(i + offset_differential_index - 1) % smooth_size] * window_array[i];
00279             }
00280             smooth_offset /= double(smooth_size);
00281         
00282             // This is the integral of the smoothed_offset
00283             offset_integral += smooth_offset;
00284 
00285             // Clamp offset : the smooth offset still contains unwanted noise which would go straigth onto the resample coeff.
00286             // It only used in the P component and the I component is used for the fine tuning anyways.
00287             if (fabs(smooth_offset) < pclamp)
00288                 smooth_offset = 0.0;
00289          
00290             // Ok, now this is the PI controller. 
00291             // u(t) = K * (e(t) + 1/T \int e(t') dt')
00292             // Kp = 1/catch_factor and T = catch_factor2  Ki = Kp/T 
00293             double current_resample_factor 
00294                 = static_resample_factor - smooth_offset / catch_factor - offset_integral / catch_factor / catch_factor2;
00295             
00296             // Now quantize this value around resample_mean, so that the noise which is in the integral component doesnt hurt.
00297             current_resample_factor = floor((current_resample_factor - resample_mean) * controlquant + 0.5) / controlquant + resample_mean;
00298 
00299             // Calculate resample_mean so we can init ourselves to saner values.
00300             resample_mean = 0.9999 * resample_mean + 0.0001 * current_resample_factor;
00301             return current_resample_factor;
00302         }
00303         */
00304 
00305         double GetRatio(int error)
00306         {
00307             double smooth_offset = error;
00308 
00309             // This is the integral of the smoothed_offset
00310             offset_integral += smooth_offset;
00311 
00312             // Ok, now this is the PI controller. 
00313             // u(t) = K * (e(t) + 1/T \int e(t') dt')
00314             // Kp = 1/catch_factor and T = catch_factor2 Ki = Kp/T 
00315             return static_resample_factor - smooth_offset/catch_factor - offset_integral/catch_factor/catch_factor2;
00316         }
00317         
00318         void OurOfBounds()
00319         {
00320             int i;
00321             // Set the resample_rate... we need to adjust the offset integral, to do this.
00322             // first look at the PI controller, this code is just a special case, which should never execute once
00323             // everything is swung in. 
00324             offset_integral = - (resample_mean - static_resample_factor) * catch_factor * catch_factor2;
00325             // Also clear the array. we are beginning a new control cycle.
00326             for (i = 0; i < smooth_size; i++) {
00327                 offset_array[i] = 0.0;
00328             }
00329         }
00330     
00331     };
00332 
00333 }
00334 
00335 #endif