jack2 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

336 lines
11KB

  1. /*
  2. Copyright (C) 2008 Grame
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14. */
  15. #ifndef __JackFilters__
  16. #define __JackFilters__
  17. #include "jack.h"
  18. #include "JackAtomicState.h"
  19. #include <math.h>
  20. #include <stdlib.h>
  21. namespace Jack
  22. {
  23. #define MAX_SIZE 64
  24. struct JackFilter
  25. {
  26. jack_time_t fTable[MAX_SIZE];
  27. JackFilter()
  28. {
  29. for (int i = 0; i < MAX_SIZE; i++)
  30. fTable[i] = 0;
  31. }
  32. void AddValue(jack_time_t val)
  33. {
  34. memcpy(&fTable[1], &fTable[0], sizeof(jack_time_t) * (MAX_SIZE - 1));
  35. fTable[0] = val;
  36. }
  37. jack_time_t GetVal()
  38. {
  39. jack_time_t mean = 0;
  40. for (int i = 0; i < MAX_SIZE; i++)
  41. mean += fTable[i];
  42. return mean / MAX_SIZE;
  43. }
  44. } POST_PACKED_STRUCTURE;
  45. class JackDelayLockedLoop
  46. {
  47. private:
  48. jack_nframes_t fFrames;
  49. jack_time_t fCurrentWakeup;
  50. jack_time_t fCurrentCallback;
  51. jack_time_t fNextWakeUp;
  52. float fSecondOrderIntegrator;
  53. jack_nframes_t fBufferSize;
  54. jack_nframes_t fSampleRate;
  55. jack_time_t fPeriodUsecs;
  56. float fFilterCoefficient; /* set once, never altered */
  57. bool fUpdating;
  58. public:
  59. JackDelayLockedLoop()
  60. {}
  61. JackDelayLockedLoop(jack_nframes_t buffer_size, jack_nframes_t sample_rate)
  62. {
  63. Init(buffer_size, sample_rate);
  64. }
  65. void Init(jack_nframes_t buffer_size, jack_nframes_t sample_rate)
  66. {
  67. fFrames = 0;
  68. fCurrentWakeup = 0;
  69. fCurrentCallback = 0;
  70. fNextWakeUp = 0;
  71. fFilterCoefficient = 0.01f;
  72. fSecondOrderIntegrator = 0.0f;
  73. fBufferSize = buffer_size;
  74. fSampleRate = sample_rate;
  75. fPeriodUsecs = jack_time_t(1000000.f / fSampleRate * fBufferSize); // in microsec
  76. }
  77. void Init(jack_time_t callback_usecs)
  78. {
  79. fFrames = 0;
  80. fCurrentWakeup = 0;
  81. fSecondOrderIntegrator = 0.0f;
  82. fCurrentCallback = callback_usecs;
  83. fNextWakeUp = callback_usecs + fPeriodUsecs;
  84. }
  85. void IncFrame(jack_time_t callback_usecs)
  86. {
  87. float delta = (int64_t)callback_usecs - (int64_t)fNextWakeUp;
  88. fCurrentWakeup = fNextWakeUp;
  89. fCurrentCallback = callback_usecs;
  90. fFrames += fBufferSize;
  91. fSecondOrderIntegrator += 0.5f * fFilterCoefficient * delta;
  92. fNextWakeUp = fCurrentWakeup + fPeriodUsecs + (int64_t) floorf((fFilterCoefficient * (delta + fSecondOrderIntegrator)));
  93. }
  94. jack_nframes_t Time2Frames(jack_time_t time)
  95. {
  96. long delta = (long) rint(((double) ((long long)(time - fCurrentWakeup)) / ((long long)(fNextWakeUp - fCurrentWakeup))) * fBufferSize);
  97. return (delta < 0) ? ((fFrames > 0) ? fFrames : 1) : (fFrames + delta);
  98. }
  99. jack_time_t Frames2Time(jack_nframes_t frames)
  100. {
  101. long delta = (long) rint(((double) ((long long)(frames - fFrames)) * ((long long)(fNextWakeUp - fCurrentWakeup))) / fBufferSize);
  102. return (delta < 0) ? ((fCurrentWakeup > 0) ? fCurrentWakeup : 1) : (fCurrentWakeup + delta);
  103. }
  104. jack_nframes_t CurFrame()
  105. {
  106. return fFrames;
  107. }
  108. jack_time_t CurTime()
  109. {
  110. return fCurrentWakeup;
  111. }
  112. } POST_PACKED_STRUCTURE;
  113. class JackAtomicDelayLockedLoop : public JackAtomicState<JackDelayLockedLoop>
  114. {
  115. public:
  116. JackAtomicDelayLockedLoop(jack_nframes_t buffer_size, jack_nframes_t sample_rate)
  117. {
  118. fState[0].Init(buffer_size, sample_rate);
  119. fState[1].Init(buffer_size, sample_rate);
  120. }
  121. void Init(jack_time_t callback_usecs)
  122. {
  123. JackDelayLockedLoop* dll = WriteNextStateStart();
  124. dll->Init(callback_usecs);
  125. WriteNextStateStop();
  126. TrySwitchState(); // always succeed since there is only one writer
  127. }
  128. void Init(jack_nframes_t buffer_size, jack_nframes_t sample_rate)
  129. {
  130. JackDelayLockedLoop* dll = WriteNextStateStart();
  131. dll->Init(buffer_size, sample_rate);
  132. WriteNextStateStop();
  133. TrySwitchState(); // always succeed since there is only one writer
  134. }
  135. void IncFrame(jack_time_t callback_usecs)
  136. {
  137. JackDelayLockedLoop* dll = WriteNextStateStart();
  138. dll->IncFrame(callback_usecs);
  139. WriteNextStateStop();
  140. TrySwitchState(); // always succeed since there is only one writer
  141. }
  142. jack_nframes_t Time2Frames(jack_time_t time)
  143. {
  144. UInt16 next_index = GetCurrentIndex();
  145. UInt16 cur_index;
  146. jack_nframes_t res;
  147. do {
  148. cur_index = next_index;
  149. res = ReadCurrentState()->Time2Frames(time);
  150. next_index = GetCurrentIndex();
  151. } while (cur_index != next_index); // Until a coherent state has been read
  152. return res;
  153. }
  154. jack_time_t Frames2Time(jack_nframes_t frames)
  155. {
  156. UInt16 next_index = GetCurrentIndex();
  157. UInt16 cur_index;
  158. jack_time_t res;
  159. do {
  160. cur_index = next_index;
  161. res = ReadCurrentState()->Frames2Time(frames);
  162. next_index = GetCurrentIndex();
  163. } while (cur_index != next_index); // Until a coherent state has been read
  164. return res;
  165. }
  166. } POST_PACKED_STRUCTURE;
  167. /*
  168. Torben Hohn PI controler from JACK1
  169. */
  170. struct JackPIControler {
  171. double resample_mean;
  172. double static_resample_factor;
  173. double* offset_array;
  174. double* window_array;
  175. int offset_differential_index;
  176. double offset_integral;
  177. double catch_factor;
  178. double catch_factor2;
  179. double pclamp;
  180. double controlquant;
  181. int smooth_size;
  182. double hann(double x)
  183. {
  184. return 0.5 * (1.0 - cos(2 * M_PI * x));
  185. }
  186. JackPIControler(double resample_factor, int fir_size)
  187. {
  188. resample_mean = resample_factor;
  189. static_resample_factor = resample_factor;
  190. offset_array = new double[fir_size];
  191. window_array = new double[fir_size];
  192. offset_differential_index = 0;
  193. offset_integral = 0.0;
  194. smooth_size = fir_size;
  195. for (int i = 0; i < fir_size; i++) {
  196. offset_array[i] = 0.0;
  197. window_array[i] = hann(double(i) / (double(fir_size) - 1.0));
  198. }
  199. // These values could be configurable
  200. catch_factor = 100000;
  201. catch_factor2 = 10000;
  202. pclamp = 15.0;
  203. controlquant = 10000.0;
  204. }
  205. ~JackPIControler()
  206. {
  207. delete[] offset_array;
  208. delete[] window_array;
  209. }
  210. void Init(double resample_factor)
  211. {
  212. resample_mean = resample_factor;
  213. static_resample_factor = resample_factor;
  214. }
  215. /*
  216. double GetRatio(int fill_level)
  217. {
  218. double offset = fill_level;
  219. // Save offset.
  220. offset_array[(offset_differential_index++) % smooth_size] = offset;
  221. // Build the mean of the windowed offset array basically fir lowpassing.
  222. double smooth_offset = 0.0;
  223. for (int i = 0; i < smooth_size; i++) {
  224. smooth_offset += offset_array[(i + offset_differential_index - 1) % smooth_size] * window_array[i];
  225. }
  226. smooth_offset /= double(smooth_size);
  227. // This is the integral of the smoothed_offset
  228. offset_integral += smooth_offset;
  229. // Clamp offset : the smooth offset still contains unwanted noise which would go straigth onto the resample coeff.
  230. // It only used in the P component and the I component is used for the fine tuning anyways.
  231. if (fabs(smooth_offset) < pclamp)
  232. smooth_offset = 0.0;
  233. // Ok, now this is the PI controller.
  234. // u(t) = K * (e(t) + 1/T \int e(t') dt')
  235. // Kp = 1/catch_factor and T = catch_factor2 Ki = Kp/T
  236. double current_resample_factor
  237. = static_resample_factor - smooth_offset / catch_factor - offset_integral / catch_factor / catch_factor2;
  238. // Now quantize this value around resample_mean, so that the noise which is in the integral component doesnt hurt.
  239. current_resample_factor = floor((current_resample_factor - resample_mean) * controlquant + 0.5) / controlquant + resample_mean;
  240. // Calculate resample_mean so we can init ourselves to saner values.
  241. resample_mean = 0.9999 * resample_mean + 0.0001 * current_resample_factor;
  242. return current_resample_factor;
  243. }
  244. */
  245. double GetRatio(int error)
  246. {
  247. double smooth_offset = error;
  248. // This is the integral of the smoothed_offset
  249. offset_integral += smooth_offset;
  250. // Ok, now this is the PI controller.
  251. // u(t) = K * (e(t) + 1/T \int e(t') dt')
  252. // Kp = 1/catch_factor and T = catch_factor2 Ki = Kp/T
  253. return static_resample_factor - smooth_offset/catch_factor - offset_integral/catch_factor/catch_factor2;
  254. }
  255. void OurOfBounds()
  256. {
  257. int i;
  258. // Set the resample_rate... we need to adjust the offset integral, to do this.
  259. // first look at the PI controller, this code is just a special case, which should never execute once
  260. // everything is swung in.
  261. offset_integral = - (resample_mean - static_resample_factor) * catch_factor * catch_factor2;
  262. // Also clear the array. we are beginning a new control cycle.
  263. for (i = 0; i < smooth_size; i++) {
  264. offset_array[i] = 0.0;
  265. }
  266. }
  267. };
  268. }
  269. #endif