Init engine fields, cleanup.
[jack2.git] / common / JackFrameTimer.cpp
blobbd6d9b5397699c0c5d335bd0baec92e9cafbaa00
1 /*
2 Copyright (C) 2001 Paul Davis
3 Copyright (C) 2004-2008 Grame
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 #include "JackFrameTimer.h"
22 #include "JackError.h"
23 #include <math.h>
24 #include <stdio.h>
26 namespace Jack
29 #if defined(WIN32) && !defined(__MINGW32__)
30 /* missing on Windows : see http://bugs.mysql.com/bug.php?id=15936 */
31 inline double rint(double nr)
33 double f = floor(nr);
34 double c = ceil(nr);
35 return (((c -nr) >= (nr - f)) ? f : c);
37 #endif
39 JackTimer::JackTimer()
41 fInitialized = false;
42 fFrames = 0;
43 fCurrentWakeup = 0;
44 fCurrentCallback = 0;
45 fNextWakeUp = 0;
46 fFilterCoefficient = 0.01f;
47 fSecondOrderIntegrator = 0.0f;
50 jack_nframes_t JackTimer::Time2Frames(jack_time_t time, jack_nframes_t buffer_size)
52 if (fInitialized) {
53 return fFrames + (long)rint(((double) ((long long)(time - fCurrentWakeup)) / ((long long)(fNextWakeUp - fCurrentWakeup))) * buffer_size);
54 } else {
55 return 0;
59 jack_time_t JackTimer::Frames2Time(jack_nframes_t frames, jack_nframes_t buffer_size)
61 if (fInitialized) {
62 return fCurrentWakeup + (long)rint(((double) ((long long)(frames - fFrames)) * ((long long)(fNextWakeUp - fCurrentWakeup))) / buffer_size);
63 } else {
64 return 0;
68 jack_nframes_t JackTimer::FramesSinceCycleStart(jack_time_t cur_time, jack_nframes_t frames_rate)
70 return (jack_nframes_t) floor((((float)frames_rate) / 1000000.0f) * (cur_time - fCurrentCallback));
73 void JackFrameTimer::InitFrameTime()
75 fFirstWakeUp = true;
78 void JackFrameTimer::IncFrameTime(jack_nframes_t buffer_size, jack_time_t callback_usecs, jack_time_t period_usecs)
80 if (fFirstWakeUp) {
81 InitFrameTimeAux(callback_usecs, period_usecs);
82 fFirstWakeUp = false;
83 } else {
84 IncFrameTimeAux(buffer_size, callback_usecs, period_usecs);
88 void JackFrameTimer::ResetFrameTime(jack_nframes_t frames_rate, jack_time_t callback_usecs, jack_time_t period_usecs)
90 if (!fFirstWakeUp) { // ResetFrameTime may be called by a xrun/delayed wakeup on the first cycle
91 JackTimer* timer = WriteNextStateStart();
92 jack_nframes_t period_size_guess = (jack_nframes_t)(frames_rate * ((timer->fNextWakeUp - timer->fCurrentWakeup) / 1000000.0));
93 timer->fFrames += ((callback_usecs - timer->fNextWakeUp) / period_size_guess) * period_size_guess;
94 timer->fCurrentWakeup = callback_usecs;
95 timer->fCurrentCallback = callback_usecs;
96 timer->fNextWakeUp = callback_usecs + period_usecs;
97 WriteNextStateStop();
98 TrySwitchState(); // always succeed since there is only one writer
103 Use the state returned by ReadCurrentState and check that the state was not changed during the read operation.
104 The operation is lock-free since there is no intermediate state in the write operation that could cause the
105 read to loop forever.
107 void JackFrameTimer::ReadFrameTime(JackTimer* timer)
109 UInt16 next_index = GetCurrentIndex();
110 UInt16 cur_index;
111 do {
112 cur_index = next_index;
113 memcpy(timer, ReadCurrentState(), sizeof(JackTimer));
114 next_index = GetCurrentIndex();
115 } while (cur_index != next_index); // Until a coherent state has been read
118 // Internal
120 void JackFrameTimer::InitFrameTimeAux(jack_time_t callback_usecs, jack_time_t period_usecs)
122 JackTimer* timer = WriteNextStateStart();
123 timer->fSecondOrderIntegrator = 0.0f;
124 timer->fCurrentCallback = callback_usecs;
125 timer->fNextWakeUp = callback_usecs + period_usecs;
126 WriteNextStateStop();
127 TrySwitchState(); // always succeed since there is only one writer
130 void JackFrameTimer::IncFrameTimeAux(jack_nframes_t buffer_size, jack_time_t callback_usecs, jack_time_t period_usecs)
132 JackTimer* timer = WriteNextStateStart();
133 float delta = (int64_t)callback_usecs - (int64_t)timer->fNextWakeUp;
134 timer->fCurrentWakeup = timer->fNextWakeUp;
135 timer->fCurrentCallback = callback_usecs;
136 timer->fFrames += buffer_size;
137 timer->fSecondOrderIntegrator += 0.5f * timer->fFilterCoefficient * delta;
138 timer->fNextWakeUp = timer->fCurrentWakeup + period_usecs + (int64_t) floorf((timer->fFilterCoefficient * (delta + timer->fSecondOrderIntegrator)));
139 timer->fInitialized = true;
140 WriteNextStateStop();
141 TrySwitchState(); // always succeed since there is only one writer
144 } // end of namespace