root/jack2/branches/libjacknet/common/JackFilters.h

Revision 3900, 11.5 kB (checked in by sletz, 7 months ago)

rebase from trunk 3813:3899

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