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