Jack2  1.9.10
JackFilters.h
1 /*
2 Copyright (C) 2008 Grame
3 
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.
8 
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.
13 
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.
17 
18 */
19 
20 #ifndef __JackFilters__
21 #define __JackFilters__
22 
23 #ifdef __APPLE__
24 #include <TargetConditionals.h>
25 #endif
26 
27 #include "jack.h"
28 #ifndef MY_TARGET_OS_IPHONE
29 #include "JackAtomicState.h"
30 #endif
31 #include <math.h>
32 #include <stdlib.h>
33 
34 namespace Jack
35 {
36 
37 #ifndef TARGET_OS_IPHONE
38 
39  #define MAX_SIZE 64
40 
41  PRE_PACKED_STRUCTURE
42  struct JackFilter
43  {
44 
45  jack_time_t fTable[MAX_SIZE];
46 
47  JackFilter()
48  {
49  for (int i = 0; i < MAX_SIZE; i++) {
50  fTable[i] = 0;
51  }
52  }
53 
54  void AddValue(jack_time_t val)
55  {
56  memcpy(&fTable[1], &fTable[0], sizeof(jack_time_t) * (MAX_SIZE - 1));
57  fTable[0] = val;
58  }
59 
60  jack_time_t GetVal()
61  {
62  jack_time_t mean = 0;
63  for (int i = 0; i < MAX_SIZE; i++) {
64  mean += fTable[i];
65  }
66  return mean / MAX_SIZE;
67  }
68 
69  } POST_PACKED_STRUCTURE;
70 
71  PRE_PACKED_STRUCTURE
73  {
74 
75  private:
76 
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 */
86  bool fUpdating;
87 
88  public:
89 
91  {}
92 
93  JackDelayLockedLoop(jack_nframes_t buffer_size, jack_nframes_t sample_rate)
94  {
95  Init(buffer_size, sample_rate);
96  }
97 
98  void Init(jack_nframes_t buffer_size, jack_nframes_t sample_rate)
99  {
100  fFrames = 0;
101  fCurrentWakeup = 0;
102  fCurrentCallback = 0;
103  fNextWakeUp = 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
109  }
110 
111  void Init(jack_time_t callback_usecs)
112  {
113  fFrames = 0;
114  fCurrentWakeup = 0;
115  fSecondOrderIntegrator = 0.0f;
116  fCurrentCallback = callback_usecs;
117  fNextWakeUp = callback_usecs + fPeriodUsecs;
118  }
119 
120  void IncFrame(jack_time_t callback_usecs)
121  {
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)));
128  }
129 
130  jack_nframes_t Time2Frames(jack_time_t time)
131  {
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);
134  }
135 
136  jack_time_t Frames2Time(jack_nframes_t frames)
137  {
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);
140  }
141 
142  jack_nframes_t CurFrame()
143  {
144  return fFrames;
145  }
146 
147  jack_time_t CurTime()
148  {
149  return fCurrentWakeup;
150  }
151 
152  } POST_PACKED_STRUCTURE;
153 
154  PRE_PACKED_STRUCTURE
155  class JackAtomicDelayLockedLoop : public JackAtomicState<JackDelayLockedLoop>
156  {
157  public:
158 
159  JackAtomicDelayLockedLoop(jack_nframes_t buffer_size, jack_nframes_t sample_rate)
160  {
161  fState[0].Init(buffer_size, sample_rate);
162  fState[1].Init(buffer_size, sample_rate);
163  }
164 
165  void Init(jack_time_t callback_usecs)
166  {
168  dll->Init(callback_usecs);
170  TrySwitchState(); // always succeed since there is only one writer
171  }
172 
173  void Init(jack_nframes_t buffer_size, jack_nframes_t sample_rate)
174  {
176  dll->Init(buffer_size, sample_rate);
178  TrySwitchState(); // always succeed since there is only one writer
179  }
180 
181  void IncFrame(jack_time_t callback_usecs)
182  {
184  dll->IncFrame(callback_usecs);
186  TrySwitchState(); // always succeed since there is only one writer
187  }
188 
189  jack_nframes_t Time2Frames(jack_time_t time)
190  {
191  UInt16 next_index = GetCurrentIndex();
192  UInt16 cur_index;
193  jack_nframes_t res;
194 
195  do {
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
200 
201  return res;
202  }
203 
204  jack_time_t Frames2Time(jack_nframes_t frames)
205  {
206  UInt16 next_index = GetCurrentIndex();
207  UInt16 cur_index;
208  jack_time_t res;
209 
210  do {
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
215 
216  return res;
217  }
218  } POST_PACKED_STRUCTURE;
219 
220 #endif
221 
222  /*
223  Torben Hohn PI controler from JACK1
224  */
225 
227 
228  double resample_mean;
229  double static_resample_factor;
230 
231  double* offset_array;
232  double* window_array;
233  int offset_differential_index;
234 
235  double offset_integral;
236 
237  double catch_factor;
238  double catch_factor2;
239  double pclamp;
240  double controlquant;
241  int smooth_size;
242 
243  double hann(double x)
244  {
245  return 0.5 * (1.0 - cos(2 * M_PI * x));
246  }
247 
248  JackPIControler(double resample_factor, int fir_size)
249  {
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;
257 
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));
261  }
262 
263  // These values could be configurable
264  catch_factor = 100000;
265  catch_factor2 = 10000;
266  pclamp = 15.0;
267  controlquant = 10000.0;
268  }
269 
270  ~JackPIControler()
271  {
272  delete[] offset_array;
273  delete[] window_array;
274  }
275 
276  void Init(double resample_factor)
277  {
278  resample_mean = resample_factor;
279  static_resample_factor = resample_factor;
280  }
281 
282  /*
283  double GetRatio(int fill_level)
284  {
285  double offset = fill_level;
286 
287  // Save offset.
288  offset_array[(offset_differential_index++) % smooth_size] = offset;
289 
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];
294  }
295  smooth_offset /= double(smooth_size);
296 
297  // This is the integral of the smoothed_offset
298  offset_integral += smooth_offset;
299 
300  // Clamp offset : the smooth offset still contains unwanted noise which would go straigth 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)
303  smooth_offset = 0.0;
304 
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;
310 
311  // Now quantize this value around resample_mean, so that the noise which is in the integral component doesnt hurt.
312  current_resample_factor = floor((current_resample_factor - resample_mean) * controlquant + 0.5) / controlquant + resample_mean;
313 
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;
317  }
318  */
319 
320  double GetRatio(int error)
321  {
322  double smooth_offset = error;
323 
324  // This is the integral of the smoothed_offset
325  offset_integral += smooth_offset;
326 
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;
331  }
332 
333  void OurOfBounds()
334  {
335  int i;
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;
343  }
344  }
345 
346  };
347 
348 }
349 
350 #endif