2 Copyright (C) 2008 Grame
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #ifndef __JackFilters__
21 #define __JackFilters__
24 #include <TargetConditionals.h>
28 #ifndef MY_TARGET_OS_IPHONE
29 #include "JackAtomicState.h"
37 #ifndef TARGET_OS_IPHONE
45 jack_time_t fTable
[MAX_SIZE
];
49 for (int i
= 0; i
< MAX_SIZE
; i
++) {
54 void AddValue(jack_time_t val
)
56 memcpy(&fTable
[1], &fTable
[0], sizeof(jack_time_t
) * (MAX_SIZE
- 1));
63 for (int i
= 0; i
< MAX_SIZE
; i
++) {
66 return mean
/ MAX_SIZE
;
69 } POST_PACKED_STRUCTURE
;
72 class JackDelayLockedLoop
77 jack_nframes_t fFrames
;
78 jack_time_t fCurrentWakeup
;
79 jack_time_t fCurrentCallback
;
80 jack_time_t fNextWakeUp
;
81 float fSecondOrderIntegrator
;
82 jack_nframes_t fBufferSize
;
83 jack_nframes_t fSampleRate
;
84 jack_time_t fPeriodUsecs
;
85 float fFilterCoefficient
; /* set once, never altered */
93 JackDelayLockedLoop(jack_nframes_t buffer_size
, jack_nframes_t sample_rate
)
95 Init(buffer_size
, sample_rate
);
98 void Init(jack_nframes_t buffer_size
, jack_nframes_t sample_rate
)
102 fCurrentCallback
= 0;
104 fFilterCoefficient
= 0.01f
;
105 fSecondOrderIntegrator
= 0.0f
;
106 fBufferSize
= buffer_size
;
107 fSampleRate
= sample_rate
;
108 fPeriodUsecs
= jack_time_t(1000000.f
/ fSampleRate
* fBufferSize
); // in microsec
111 void Init(jack_time_t callback_usecs
)
115 fSecondOrderIntegrator
= 0.0f
;
116 fCurrentCallback
= callback_usecs
;
117 fNextWakeUp
= callback_usecs
+ fPeriodUsecs
;
120 void IncFrame(jack_time_t callback_usecs
)
122 float delta
= (int64_t)callback_usecs
- (int64_t)fNextWakeUp
;
123 fCurrentWakeup
= fNextWakeUp
;
124 fCurrentCallback
= callback_usecs
;
125 fFrames
+= fBufferSize
;
126 fSecondOrderIntegrator
+= 0.5f
* fFilterCoefficient
* delta
;
127 fNextWakeUp
= fCurrentWakeup
+ fPeriodUsecs
+ (int64_t) floorf((fFilterCoefficient
* (delta
+ fSecondOrderIntegrator
)));
130 jack_nframes_t
Time2Frames(jack_time_t time
)
132 long delta
= (long) rint(((double) ((long long)(time
- fCurrentWakeup
)) / ((long long)(fNextWakeUp
- fCurrentWakeup
))) * fBufferSize
);
133 return (delta
< 0) ? ((fFrames
> 0) ? fFrames
: 1) : (fFrames
+ delta
);
136 jack_time_t
Frames2Time(jack_nframes_t frames
)
138 long delta
= (long) rint(((double) ((long long)(frames
- fFrames
)) * ((long long)(fNextWakeUp
- fCurrentWakeup
))) / fBufferSize
);
139 return (delta
< 0) ? ((fCurrentWakeup
> 0) ? fCurrentWakeup
: 1) : (fCurrentWakeup
+ delta
);
142 jack_nframes_t
CurFrame()
147 jack_time_t
CurTime()
149 return fCurrentWakeup
;
152 } POST_PACKED_STRUCTURE
;
155 class JackAtomicDelayLockedLoop
: public JackAtomicState
<JackDelayLockedLoop
>
159 JackAtomicDelayLockedLoop(jack_nframes_t buffer_size
, jack_nframes_t sample_rate
)
161 fState
[0].Init(buffer_size
, sample_rate
);
162 fState
[1].Init(buffer_size
, sample_rate
);
165 void Init(jack_time_t callback_usecs
)
167 JackDelayLockedLoop
* dll
= WriteNextStateStart();
168 dll
->Init(callback_usecs
);
169 WriteNextStateStop();
170 TrySwitchState(); // always succeed since there is only one writer
173 void Init(jack_nframes_t buffer_size
, jack_nframes_t sample_rate
)
175 JackDelayLockedLoop
* dll
= WriteNextStateStart();
176 dll
->Init(buffer_size
, sample_rate
);
177 WriteNextStateStop();
178 TrySwitchState(); // always succeed since there is only one writer
181 void IncFrame(jack_time_t callback_usecs
)
183 JackDelayLockedLoop
* dll
= WriteNextStateStart();
184 dll
->IncFrame(callback_usecs
);
185 WriteNextStateStop();
186 TrySwitchState(); // always succeed since there is only one writer
189 jack_nframes_t
Time2Frames(jack_time_t time
)
191 UInt16 next_index
= GetCurrentIndex();
196 cur_index
= next_index
;
197 res
= ReadCurrentState()->Time2Frames(time
);
198 next_index
= GetCurrentIndex();
199 } while (cur_index
!= next_index
); // Until a coherent state has been read
204 jack_time_t
Frames2Time(jack_nframes_t frames
)
206 UInt16 next_index
= GetCurrentIndex();
211 cur_index
= next_index
;
212 res
= ReadCurrentState()->Frames2Time(frames
);
213 next_index
= GetCurrentIndex();
214 } while (cur_index
!= next_index
); // Until a coherent state has been read
218 } POST_PACKED_STRUCTURE
;
223 Torben Hohn PI controller from JACK1
226 struct JackPIControler
{
228 double resample_mean
;
229 double static_resample_factor
;
231 double* offset_array
;
232 double* window_array
;
233 int offset_differential_index
;
235 double offset_integral
;
238 double catch_factor2
;
243 double hann(double x
)
245 return 0.5 * (1.0 - cos(2 * M_PI
* x
));
248 JackPIControler(double resample_factor
, int fir_size
)
250 resample_mean
= resample_factor
;
251 static_resample_factor
= resample_factor
;
252 offset_array
= new double[fir_size
];
253 window_array
= new double[fir_size
];
254 offset_differential_index
= 0;
255 offset_integral
= 0.0;
256 smooth_size
= fir_size
;
258 for (int i
= 0; i
< fir_size
; i
++) {
259 offset_array
[i
] = 0.0;
260 window_array
[i
] = hann(double(i
) / (double(fir_size
) - 1.0));
263 // These values could be configurable
264 catch_factor
= 100000;
265 catch_factor2
= 10000;
267 controlquant
= 10000.0;
272 delete[] offset_array
;
273 delete[] window_array
;
276 void Init(double resample_factor
)
278 resample_mean
= resample_factor
;
279 static_resample_factor
= resample_factor
;
283 double GetRatio(int fill_level)
285 double offset = fill_level;
288 offset_array[(offset_differential_index++) % smooth_size] = offset;
290 // Build the mean of the windowed offset array basically fir lowpassing.
291 double smooth_offset = 0.0;
292 for (int i = 0; i < smooth_size; i++) {
293 smooth_offset += offset_array[(i + offset_differential_index - 1) % smooth_size] * window_array[i];
295 smooth_offset /= double(smooth_size);
297 // This is the integral of the smoothed_offset
298 offset_integral += smooth_offset;
300 // Clamp offset : the smooth offset still contains unwanted noise which would go straight onto the resample coeff.
301 // It only used in the P component and the I component is used for the fine tuning anyways.
302 if (fabs(smooth_offset) < pclamp)
305 // Ok, now this is the PI controller.
306 // u(t) = K * (e(t) + 1/T \int e(t') dt')
307 // Kp = 1/catch_factor and T = catch_factor2 Ki = Kp/T
308 double current_resample_factor
309 = static_resample_factor - smooth_offset / catch_factor - offset_integral / catch_factor / catch_factor2;
311 // Now quantize this value around resample_mean, so that the noise which is in the integral component doesn't hurt.
312 current_resample_factor = floor((current_resample_factor - resample_mean) * controlquant + 0.5) / controlquant + resample_mean;
314 // Calculate resample_mean so we can init ourselves to saner values.
315 resample_mean = 0.9999 * resample_mean + 0.0001 * current_resample_factor;
316 return current_resample_factor;
320 double GetRatio(int error
)
322 double smooth_offset
= error
;
324 // This is the integral of the smoothed_offset
325 offset_integral
+= smooth_offset
;
327 // Ok, now this is the PI controller.
328 // u(t) = K * (e(t) + 1/T \int e(t') dt')
329 // Kp = 1/catch_factor and T = catch_factor2 Ki = Kp/T
330 return static_resample_factor
- smooth_offset
/catch_factor
- offset_integral
/catch_factor
/catch_factor2
;
336 // Set the resample_rate... we need to adjust the offset integral, to do this.
337 // first look at the PI controller, this code is just a special case, which should never execute once
338 // everything is swung in.
339 offset_integral
= - (resample_mean
- static_resample_factor
) * catch_factor
* catch_factor2
;
340 // Also clear the array. we are beginning a new control cycle.
341 for (i
= 0; i
< smooth_size
; i
++) {
342 offset_array
[i
] = 0.0;