JackFrameTimer.cpp

00001 /*
00002 Copyright (C) 2001 Paul Davis 
00003 Copyright (C) 2004-2008 Grame
00004 
00005 This program is free software; you can redistribute it and/or modify
00006 it under the terms of the GNU General Public License as published by
00007 the Free Software Foundation; either version 2 of the License, or
00008 (at your option) any later version.
00009 
00010 This program is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 GNU General Public License for more details.
00014 
00015 You should have received a copy of the GNU General Public License
00016 along with this program; if not, write to the Free Software
00017 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00018 
00019 */
00020 
00021 #include "JackFrameTimer.h"
00022 #include "JackError.h"
00023 #include <math.h>
00024 
00025 namespace Jack
00026 {
00027 
00028 JackTimer::JackTimer()
00029 {
00030     fInitialized = false;
00031     fFrames = 0;
00032     fCurrentWakeup = 0;
00033     fCurrentCallback = 0;
00034     fNextWakeUp = 0;
00035     fFilterCoefficient = 0.01f;
00036     fSecondOrderIntegrator = 0.0f;
00037 }
00038 
00039 void JackFrameTimer::InitFrameTime()
00040 {
00041     fFirstWakeUp = true;
00042 }
00043 
00044 void JackFrameTimer::IncFrameTime(jack_nframes_t nframes, jack_time_t callback_usecs, jack_time_t period_usecs)
00045 {
00046     if (fFirstWakeUp) {
00047         InitFrameTimeAux(callback_usecs, period_usecs);
00048         fFirstWakeUp = false;
00049     } else {
00050         IncFrameTimeAux(nframes, callback_usecs, period_usecs);
00051     }
00052 }
00053 
00054 void JackFrameTimer::ResetFrameTime(jack_nframes_t frames_rate, jack_time_t callback_usecs, jack_time_t period_usecs)
00055 {
00056     if (!fFirstWakeUp) { // ResetFrameTime may be called by a xrun/delayed wakeup on the first cycle
00057         JackTimer* timer = WriteNextStateStart();
00058         jack_nframes_t period_size_guess = (jack_nframes_t)(frames_rate * ((timer->fNextWakeUp - timer->fCurrentWakeup) / 1000000.0));
00059         timer->fFrames += ((callback_usecs - timer->fNextWakeUp) / period_size_guess) * period_size_guess;
00060         timer->fCurrentWakeup = callback_usecs;
00061         timer->fCurrentCallback = callback_usecs;
00062         timer->fNextWakeUp = callback_usecs + period_usecs;
00063         WriteNextStateStop();
00064         TrySwitchState(); // always succeed since there is only one writer
00065     }
00066 }
00067 
00068 /*
00069         Use the state returned by ReadCurrentState and check that the state was not changed during the read operation.
00070         The operation is lock-free since there is no intermediate state in the write operation that could cause the
00071         read to loop forever.
00072 */
00073 void JackFrameTimer::ReadFrameTime(JackTimer* timer)
00074 {
00075     UInt16 next_index = GetCurrentIndex();
00076     UInt16 cur_index;
00077     do {
00078         cur_index = next_index;
00079         memcpy(timer, ReadCurrentState(), sizeof(JackTimer));
00080         next_index = GetCurrentIndex();
00081     } while (cur_index != next_index); // Until a coherent state has been read
00082 }
00083 
00084 // Internal
00085 
00086 void JackFrameTimer::InitFrameTimeAux(jack_time_t callback_usecs, jack_time_t period_usecs)
00087 {
00088     JackTimer* timer = WriteNextStateStart();
00089     timer->fSecondOrderIntegrator = 0.0f;
00090     timer->fCurrentCallback = callback_usecs;
00091     timer->fNextWakeUp = callback_usecs + period_usecs;
00092     WriteNextStateStop();
00093     TrySwitchState(); // always succeed since there is only one writer
00094 }
00095 
00096 void JackFrameTimer::IncFrameTimeAux(jack_nframes_t nframes, jack_time_t callback_usecs, jack_time_t period_usecs)
00097 {
00098     JackTimer* timer = WriteNextStateStart();
00099     float delta = (int64_t)callback_usecs - (int64_t)timer->fNextWakeUp;
00100     timer->fCurrentWakeup = timer->fNextWakeUp;
00101     timer->fCurrentCallback = callback_usecs;
00102     timer->fFrames += nframes;
00103     timer->fSecondOrderIntegrator += 0.5f * timer->fFilterCoefficient * delta;
00104     timer->fNextWakeUp = timer->fCurrentWakeup + period_usecs + (int64_t) floorf((timer->fFilterCoefficient * (delta + timer->fSecondOrderIntegrator)));
00105     timer->fInitialized = true;
00106     WriteNextStateStop();
00107     TrySwitchState(); // always succeed since there is only one writer
00108 }
00109 
00110 } // end of namespace
00111 

Generated on Thu Feb 14 11:16:01 2008 for Jackdmp by  doxygen 1.5.1