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.

112 lines
3.8KB

  1. /*
  2. Copyright (C) 2001 Paul Davis
  3. Copyright (C) 2004-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.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. */
  16. #include "JackFrameTimer.h"
  17. #include "JackError.h"
  18. #include <math.h>
  19. namespace Jack
  20. {
  21. JackTimer::JackTimer()
  22. {
  23. fInitialized = false;
  24. fFrames = 0;
  25. fCurrentWakeup = 0;
  26. fCurrentCallback = 0;
  27. fNextWakeUp = 0;
  28. fFilterCoefficient = 0.01f;
  29. fSecondOrderIntegrator = 0.0f;
  30. }
  31. void JackFrameTimer::InitFrameTime()
  32. {
  33. fFirstWakeUp = true;
  34. }
  35. void JackFrameTimer::IncFrameTime(jack_nframes_t nframes, jack_time_t callback_usecs, jack_time_t period_usecs)
  36. {
  37. if (fFirstWakeUp) {
  38. InitFrameTimeAux(callback_usecs, period_usecs);
  39. fFirstWakeUp = false;
  40. } else {
  41. IncFrameTimeAux(nframes, callback_usecs, period_usecs);
  42. }
  43. }
  44. void JackFrameTimer::ResetFrameTime(jack_nframes_t frames_rate, jack_time_t callback_usecs, jack_time_t period_usecs)
  45. {
  46. if (!fFirstWakeUp) { // ResetFrameTime may be called by a xrun/delayed wakeup on the first cycle
  47. JackTimer* timer = WriteNextStateStart();
  48. jack_nframes_t period_size_guess = (jack_nframes_t)(frames_rate * ((timer->fNextWakeUp - timer->fCurrentWakeup) / 1000000.0));
  49. timer->fFrames += ((callback_usecs - timer->fNextWakeUp) / period_size_guess) * period_size_guess;
  50. timer->fCurrentWakeup = callback_usecs;
  51. timer->fCurrentCallback = callback_usecs;
  52. timer->fNextWakeUp = callback_usecs + period_usecs;
  53. WriteNextStateStop();
  54. TrySwitchState(); // always succeed since there is only one writer
  55. }
  56. }
  57. /*
  58. Use the state returned by ReadCurrentState and check that the state was not changed during the read operation.
  59. The operation is lock-free since there is no intermediate state in the write operation that could cause the
  60. read to loop forever.
  61. */
  62. void JackFrameTimer::ReadFrameTime(JackTimer* timer)
  63. {
  64. UInt16 next_index = GetCurrentIndex();
  65. UInt16 cur_index;
  66. do {
  67. cur_index = next_index;
  68. memcpy(timer, ReadCurrentState(), sizeof(JackTimer));
  69. next_index = GetCurrentIndex();
  70. } while (cur_index != next_index); // Until a coherent state has been read
  71. }
  72. // Internal
  73. void JackFrameTimer::InitFrameTimeAux(jack_time_t callback_usecs, jack_time_t period_usecs)
  74. {
  75. JackTimer* timer = WriteNextStateStart();
  76. timer->fSecondOrderIntegrator = 0.0f;
  77. timer->fCurrentCallback = callback_usecs;
  78. timer->fNextWakeUp = callback_usecs + period_usecs;
  79. WriteNextStateStop();
  80. TrySwitchState(); // always succeed since there is only one writer
  81. }
  82. void JackFrameTimer::IncFrameTimeAux(jack_nframes_t nframes, jack_time_t callback_usecs, jack_time_t period_usecs)
  83. {
  84. JackTimer* timer = WriteNextStateStart();
  85. float delta = (int64_t)callback_usecs - (int64_t)timer->fNextWakeUp;
  86. timer->fCurrentWakeup = timer->fNextWakeUp;
  87. timer->fCurrentCallback = callback_usecs;
  88. timer->fFrames += nframes;
  89. timer->fSecondOrderIntegrator += 0.5f * timer->fFilterCoefficient * delta;
  90. timer->fNextWakeUp = timer->fCurrentWakeup + period_usecs + (int64_t) floorf((timer->fFilterCoefficient * (delta + timer->fSecondOrderIntegrator)));
  91. timer->fInitialized = true;
  92. WriteNextStateStop();
  93. TrySwitchState(); // always succeed since there is only one writer
  94. }
  95. } // end of namespace