Jack2 1.9.6
|
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 Lesser General Public License as published by 00007 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. 00014 00015 You should have received a copy of the GNU Lesser General Public License 00016 along with this program; if not, write to the Free Software 00017 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00018 00019 */ 00020 00021 #include "JackFrameTimer.h" 00022 #include "JackError.h" 00023 #include <math.h> 00024 #include <stdio.h> 00025 00026 namespace Jack 00027 { 00028 00029 #if defined(WIN32) && !defined(__MINGW32__) 00030 /* missing on Windows : see http://bugs.mysql.com/bug.php?id=15936 */ 00031 inline double rint(double nr) 00032 { 00033 double f = floor(nr); 00034 double c = ceil(nr); 00035 return (((c -nr) >= (nr - f)) ? f : c); 00036 } 00037 #endif 00038 00039 JackTimer::JackTimer() 00040 { 00041 fInitialized = false; 00042 fFrames = 0; 00043 fCurrentWakeup = 0; 00044 fCurrentCallback = 0; 00045 fNextWakeUp = 0; 00046 fFilterCoefficient = 0.01f; 00047 fSecondOrderIntegrator = 0.0f; 00048 } 00049 00050 jack_nframes_t JackTimer::Time2Frames(jack_time_t time, jack_nframes_t buffer_size) 00051 { 00052 if (fInitialized) { 00053 return fFrames + (long)rint(((double) ((long long)(time - fCurrentWakeup)) / ((long long)(fNextWakeUp - fCurrentWakeup))) * buffer_size); 00054 } else { 00055 return 0; 00056 } 00057 } 00058 00059 jack_time_t JackTimer::Frames2Time(jack_nframes_t frames, jack_nframes_t buffer_size) 00060 { 00061 if (fInitialized) { 00062 return fCurrentWakeup + (long)rint(((double) ((long long)(frames - fFrames)) * ((long long)(fNextWakeUp - fCurrentWakeup))) / buffer_size); 00063 } else { 00064 return 0; 00065 } 00066 } 00067 00068 jack_nframes_t JackTimer::FramesSinceCycleStart(jack_time_t cur_time, jack_nframes_t frames_rate) 00069 { 00070 return (jack_nframes_t) floor((((float)frames_rate) / 1000000.0f) * (cur_time - fCurrentCallback)); 00071 } 00072 00073 void JackFrameTimer::InitFrameTime() 00074 { 00075 fFirstWakeUp = true; 00076 } 00077 00078 void JackFrameTimer::IncFrameTime(jack_nframes_t buffer_size, jack_time_t callback_usecs, jack_time_t period_usecs) 00079 { 00080 if (fFirstWakeUp) { 00081 InitFrameTimeAux(callback_usecs, period_usecs); 00082 fFirstWakeUp = false; 00083 } else { 00084 IncFrameTimeAux(buffer_size, callback_usecs, period_usecs); 00085 } 00086 } 00087 00088 void JackFrameTimer::ResetFrameTime(jack_nframes_t frames_rate, jack_time_t callback_usecs, jack_time_t period_usecs) 00089 { 00090 if (!fFirstWakeUp) { // ResetFrameTime may be called by a xrun/delayed wakeup on the first cycle 00091 JackTimer* timer = WriteNextStateStart(); 00092 jack_nframes_t period_size_guess = (jack_nframes_t)(frames_rate * ((timer->fNextWakeUp - timer->fCurrentWakeup) / 1000000.0)); 00093 timer->fFrames += ((callback_usecs - timer->fNextWakeUp) / period_size_guess) * period_size_guess; 00094 timer->fCurrentWakeup = callback_usecs; 00095 timer->fCurrentCallback = callback_usecs; 00096 timer->fNextWakeUp = callback_usecs + period_usecs; 00097 WriteNextStateStop(); 00098 TrySwitchState(); // always succeed since there is only one writer 00099 } 00100 } 00101 00102 /* 00103 Use the state returned by ReadCurrentState and check that the state was not changed during the read operation. 00104 The operation is lock-free since there is no intermediate state in the write operation that could cause the 00105 read to loop forever. 00106 */ 00107 void JackFrameTimer::ReadFrameTime(JackTimer* timer) 00108 { 00109 UInt16 next_index = GetCurrentIndex(); 00110 UInt16 cur_index; 00111 do { 00112 cur_index = next_index; 00113 memcpy(timer, ReadCurrentState(), sizeof(JackTimer)); 00114 next_index = GetCurrentIndex(); 00115 } while (cur_index != next_index); // Until a coherent state has been read 00116 } 00117 00118 // Internal 00119 00120 void JackFrameTimer::InitFrameTimeAux(jack_time_t callback_usecs, jack_time_t period_usecs) 00121 { 00122 JackTimer* timer = WriteNextStateStart(); 00123 timer->fSecondOrderIntegrator = 0.0f; 00124 timer->fCurrentCallback = callback_usecs; 00125 timer->fNextWakeUp = callback_usecs + period_usecs; 00126 WriteNextStateStop(); 00127 TrySwitchState(); // always succeed since there is only one writer 00128 } 00129 00130 void JackFrameTimer::IncFrameTimeAux(jack_nframes_t buffer_size, jack_time_t callback_usecs, jack_time_t period_usecs) 00131 { 00132 JackTimer* timer = WriteNextStateStart(); 00133 float delta = (int64_t)callback_usecs - (int64_t)timer->fNextWakeUp; 00134 timer->fCurrentWakeup = timer->fNextWakeUp; 00135 timer->fCurrentCallback = callback_usecs; 00136 timer->fFrames += buffer_size; 00137 timer->fSecondOrderIntegrator += 0.5f * timer->fFilterCoefficient * delta; 00138 timer->fNextWakeUp = timer->fCurrentWakeup + period_usecs + (int64_t) floorf((timer->fFilterCoefficient * (delta + timer->fSecondOrderIntegrator))); 00139 timer->fInitialized = true; 00140 WriteNextStateStop(); 00141 TrySwitchState(); // always succeed since there is only one writer 00142 } 00143 00144 } // end of namespace 00145