Jack2  1.9.9
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  void AddValue(jack_time_t val)
54  {
55  memcpy(&fTable[1], &fTable[0], sizeof(jack_time_t) * (MAX_SIZE - 1));
56  fTable[0] = val;
57  }
58 
59  jack_time_t GetVal()
60  {
61  jack_time_t mean = 0;
62  for (int i = 0; i < MAX_SIZE; i++)
63  mean += fTable[i];
64  return mean / MAX_SIZE;
65  }
66 
67  } POST_PACKED_STRUCTURE;
68 
69  PRE_PACKED_STRUCTURE
71  {
72 
73  private:
74 
75  jack_nframes_t fFrames;
76  jack_time_t fCurrentWakeup;
77  jack_time_t fCurrentCallback;
78  jack_time_t fNextWakeUp;
79  float fSecondOrderIntegrator;
80  jack_nframes_t fBufferSize;
81  jack_nframes_t fSampleRate;
82  jack_time_t fPeriodUsecs;
83  float fFilterCoefficient; /* set once, never altered */
84  bool fUpdating;
85 
86  public:
87 
89  {}
90 
91  JackDelayLockedLoop(jack_nframes_t buffer_size, jack_nframes_t sample_rate)
92  {
93  Init(buffer_size, sample_rate);
94  }
95 
96  void Init(jack_nframes_t buffer_size, jack_nframes_t sample_rate)
97  {
98  fFrames = 0;
99  fCurrentWakeup = 0;
100  fCurrentCallback = 0;
101  fNextWakeUp = 0;
102  fFilterCoefficient = 0.01f;
103  fSecondOrderIntegrator = 0.0f;
104  fBufferSize = buffer_size;
105  fSampleRate = sample_rate;
106  fPeriodUsecs = jack_time_t(1000000.f / fSampleRate * fBufferSize); // in microsec
107  }
108 
109  void Init(jack_time_t callback_usecs)
110  {
111  fFrames = 0;
112  fCurrentWakeup = 0;
113  fSecondOrderIntegrator = 0.0f;
114  fCurrentCallback = callback_usecs;
115  fNextWakeUp = callback_usecs + fPeriodUsecs;
116  }
117 
118  void IncFrame(jack_time_t callback_usecs)
119  {
120  float delta = (int64_t)callback_usecs - (int64_t)fNextWakeUp;
121  fCurrentWakeup = fNextWakeUp;
122  fCurrentCallback = callback_usecs;
123  fFrames += fBufferSize;
124  fSecondOrderIntegrator += 0.5f * fFilterCoefficient * delta;
125  fNextWakeUp = fCurrentWakeup + fPeriodUsecs + (int64_t) floorf((fFilterCoefficient * (delta + fSecondOrderIntegrator)));
126  }
127 
128  jack_nframes_t Time2Frames(jack_time_t time)
129  {
130  long delta = (long) rint(((double) ((long long)(time - fCurrentWakeup)) / ((long long)(fNextWakeUp - fCurrentWakeup))) * fBufferSize);
131  return (delta < 0) ? ((fFrames > 0) ? fFrames : 1) : (fFrames + delta);
132  }
133 
134  jack_time_t Frames2Time(jack_nframes_t frames)
135  {
136  long delta = (long) rint(((double) ((long long)(frames - fFrames)) * ((long long)(fNextWakeUp - fCurrentWakeup))) / fBufferSize);
137  return (delta < 0) ? ((fCurrentWakeup > 0) ? fCurrentWakeup : 1) : (fCurrentWakeup + delta);
138  }
139 
140  jack_nframes_t CurFrame()
141  {
142  return fFrames;
143  }
144 
145  jack_time_t CurTime()
146  {
147  return fCurrentWakeup;
148  }
149 
150  } POST_PACKED_STRUCTURE;
151 
152  PRE_PACKED_STRUCTURE
153  class JackAtomicDelayLockedLoop : public JackAtomicState<JackDelayLockedLoop>
154  {
155  public:
156 
157  JackAtomicDelayLockedLoop(jack_nframes_t buffer_size, jack_nframes_t sample_rate)
158  {
159  fState[0].Init(buffer_size, sample_rate);
160  fState[1].Init(buffer_size, sample_rate);
161  }
162 
163  void Init(jack_time_t callback_usecs)
164  {
166  dll->Init(callback_usecs);
168  TrySwitchState(); // always succeed since there is only one writer
169  }
170 
171  void Init(jack_nframes_t buffer_size, jack_nframes_t sample_rate)
172  {
174  dll->Init(buffer_size, sample_rate);
176  TrySwitchState(); // always succeed since there is only one writer
177  }
178 
179  void IncFrame(jack_time_t callback_usecs)
180  {
182  dll->IncFrame(callback_usecs);
184  TrySwitchState(); // always succeed since there is only one writer
185  }
186 
187  jack_nframes_t Time2Frames(jack_time_t time)
188  {
189  UInt16 next_index = GetCurrentIndex();
190  UInt16 cur_index;
191  jack_nframes_t res;
192 
193  do {
194  cur_index = next_index;
195  res = ReadCurrentState()->Time2Frames(time);
196  next_index = GetCurrentIndex();
197  } while (cur_index != next_index); // Until a coherent state has been read
198 
199  return res;
200  }
201 
202  jack_time_t Frames2Time(jack_nframes_t frames)
203  {
204  UInt16 next_index = GetCurrentIndex();
205  UInt16 cur_index;
206  jack_time_t res;
207 
208  do {
209  cur_index = next_index;
210  res = ReadCurrentState()->Frames2Time(frames);
211  next_index = GetCurrentIndex();
212  } while (cur_index != next_index); // Until a coherent state has been read
213 
214  return res;
215  }
216  } POST_PACKED_STRUCTURE;
217 
218 #endif
219 
220  /*
221  Torben Hohn PI controler from JACK1
222  */
223 
225 
226  double resample_mean;
227  double static_resample_factor;
228 
229  double* offset_array;
230  double* window_array;
231  int offset_differential_index;
232 
233  double offset_integral;
234 
235  double catch_factor;
236  double catch_factor2;
237  double pclamp;
238  double controlquant;
239  int smooth_size;
240 
241  double hann(double x)
242  {
243  return 0.5 * (1.0 - cos(2 * M_PI * x));
244  }
245 
246  JackPIControler(double resample_factor, int fir_size)
247  {
248  resample_mean = resample_factor;
249  static_resample_factor = resample_factor;
250  offset_array = new double[fir_size];
251  window_array = new double[fir_size];
252  offset_differential_index = 0;
253  offset_integral = 0.0;
254  smooth_size = fir_size;
255 
256  for (int i = 0; i < fir_size; i++) {
257  offset_array[i] = 0.0;
258  window_array[i] = hann(double(i) / (double(fir_size) - 1.0));
259  }
260 
261  // These values could be configurable
262  catch_factor = 100000;
263  catch_factor2 = 10000;
264  pclamp = 15.0;
265  controlquant = 10000.0;
266  }
267 
268  ~JackPIControler()
269  {
270  delete[] offset_array;
271  delete[] window_array;
272  }
273 
274  void Init(double resample_factor)
275  {
276  resample_mean = resample_factor;
277  static_resample_factor = resample_factor;
278  }
279 
280  /*
281  double GetRatio(int fill_level)
282  {
283  double offset = fill_level;
284 
285  // Save offset.
286  offset_array[(offset_differential_index++) % smooth_size] = offset;
287 
288  // Build the mean of the windowed offset array basically fir lowpassing.
289  double smooth_offset = 0.0;
290  for (int i = 0; i < smooth_size; i++) {
291  smooth_offset += offset_array[(i + offset_differential_index - 1) % smooth_size] * window_array[i];
292  }
293  smooth_offset /= double(smooth_size);
294 
295  // This is the integral of the smoothed_offset
296  offset_integral += smooth_offset;
297 
298  // Clamp offset : the smooth offset still contains unwanted noise which would go straigth onto the resample coeff.
299  // It only used in the P component and the I component is used for the fine tuning anyways.
300  if (fabs(smooth_offset) < pclamp)
301  smooth_offset = 0.0;
302 
303  // Ok, now this is the PI controller.
304  // u(t) = K * (e(t) + 1/T \int e(t') dt')
305  // Kp = 1/catch_factor and T = catch_factor2 Ki = Kp/T
306  double current_resample_factor
307  = static_resample_factor - smooth_offset / catch_factor - offset_integral / catch_factor / catch_factor2;
308 
309  // Now quantize this value around resample_mean, so that the noise which is in the integral component doesnt hurt.
310  current_resample_factor = floor((current_resample_factor - resample_mean) * controlquant + 0.5) / controlquant + resample_mean;
311 
312  // Calculate resample_mean so we can init ourselves to saner values.
313  resample_mean = 0.9999 * resample_mean + 0.0001 * current_resample_factor;
314  return current_resample_factor;
315  }
316  */
317 
318  double GetRatio(int error)
319  {
320  double smooth_offset = error;
321 
322  // This is the integral of the smoothed_offset
323  offset_integral += smooth_offset;
324 
325  // Ok, now this is the PI controller.
326  // u(t) = K * (e(t) + 1/T \int e(t') dt')
327  // Kp = 1/catch_factor and T = catch_factor2 Ki = Kp/T
328  return static_resample_factor - smooth_offset/catch_factor - offset_integral/catch_factor/catch_factor2;
329  }
330 
331  void OurOfBounds()
332  {
333  int i;
334  // Set the resample_rate... we need to adjust the offset integral, to do this.
335  // first look at the PI controller, this code is just a special case, which should never execute once
336  // everything is swung in.
337  offset_integral = - (resample_mean - static_resample_factor) * catch_factor * catch_factor2;
338  // Also clear the array. we are beginning a new control cycle.
339  for (i = 0; i < smooth_size; i++) {
340  offset_array[i] = 0.0;
341  }
342  }
343 
344  };
345 
346 }
347 
348 #endif
JackDelayLockedLoop * ReadCurrentState()
Returns the current state : only valid in the RT reader thread.
void WriteNextStateStop()
Stop write operation : make the next state ready to be used by the RT thread.
JackDelayLockedLoop * WriteNextStateStart()
Start write operation : setup and returns the next state to update, check for recursive write calls...
UInt16 GetCurrentIndex()
Returns the current state index.
JackDelayLockedLoop * TrySwitchState()
Tries to switch to the next state and returns the new current state (either the same as before if cas...
A class to handle two states (switching from one to the other) in a lock-free manner.