Mercurial > hg > beaglert
view core/ClockSynchronizer.cpp @ 152:8f98b32d0e23 ClockSync
Last commit on this branch for a while. Overall not very succesful
author | Giulio Moro <giuliomoro@yahoo.it> |
---|---|
date | Mon, 05 Oct 2015 13:06:14 +0100 |
parents | 04b1678614c9 |
children |
line wrap: on
line source
/* * ClockSynchronizer.cpp * * Created on: 26 Aug 2015 * Author: giulio */ #include "ClockSynchronizer.h" // declare static members float ClockSynchronizer::targetSamplingRate; float ClockSynchronizer::currentSamplingRate; bool ClockSynchronizer::threadRunning; int ClockSynchronizer::threadWasRunning; bool ClockSynchronizer::staticConstructed=false; AuxiliaryTask ClockSynchronizer::setClockTask; void ClockSynchronizer::staticConstructor(){ int priority=90; setClockTask=BeagleRT_createAuxiliaryTask(&ClockSynchronizer::setClock, priority, "setClockTask"); threadRunning=false; } void ClockSynchronizer::setClock(){ // rt_printf("Setting clock to %f\n",targetSamplingRate); threadRunning=true; //I2C magic gAudioCodec->setAudioSamplingRate(targetSamplingRate); threadRunning=false; threadWasRunning=1; // rt_printf("Exiting thread\n"); }; ClockSynchronizer::ClockSynchronizer() { reset(); } ClockSynchronizer::~ClockSynchronizer(){}; void ClockSynchronizer::setup(){ if(staticConstructed==false) //This should be called in the constructor, but because of the current limitations of // BeagleRT, it is here and setup() needs to be called in BeagleRT setup(); staticConstructor(); } void ClockSynchronizer::reset(){ localCounter=0; remoteCounter=0; lastTime=0; localOffset=-1; remoteOffset=-1; timeOffset=-1; currentSamplingRate=44100; } void ClockSynchronizer::update(int aLocalCounter, int aRemoteCounter, RTIME aLastTime){ if(threadRunning==true){ //do nothing if clock is being adjusted rt_printf("do nothing if clock is being adjusted\n"); return; } if(threadWasRunning > 0){ //reset variables after clock has been adjusted threadWasRunning--; // wait a few calls to make sure the clock stabilizes rt_printf("wait a few calls to make sure the clock stabilizes\n"); return; }/* if(threadWasRunning==1){ threadWasRunning=0; // reset offsets after a correction localOffset=aLocalCounter; remoteOffset=aRemoteCounter; timeOffset=aLastTime; rt_printf("reset variables after clock has been adjusted\n"); return; }*/ if (localOffset<=0 || remoteOffset<=0){ // probably this is the first run localOffset=aLocalCounter; remoteOffset=aRemoteCounter; timeOffset=aLastTime; rt_printf("First run of update(), localOffset: %d, remoteOffset: %d, timeOffset: %llu\n", localOffset, remoteOffset, timeOffset); return; } localCounter=aLocalCounter-localOffset; remoteCounter=aRemoteCounter-remoteOffset; lastTime=aLastTime-timeOffset; if (localCounter<=0 || remoteCounter<=0 || timeOffset<=0) {// did anything wrong happened? rt_printf("fourth\n"); return; } // TODO: make sure we do not get actually adjust the clock too often (e.g.: limits on the timestamp) // Should keep track of last time a change has been made, so that when a large compensation is needed // (e.g.: as the program has just started), adjustClock() is called more frequently // but gets called less often later. // Should also try to avoid drastic correction after a while that the program // has started, so to avoid glitches. But this can maybe be handled by the thread itself. // TODO: should keep a log and maybe compensate for (and prevent) overshoot according to previous changes static RTIME lastlastTime=0; // rt_printf("interval: %f, \n",(double)(remoteCounter*300.0)/lastTime*1000000000.0); lastlastTime=lastTime; currentSamplingRate=gAudioCodec->getAudioSamplingRate(); float T=1/currentSamplingRate; int elapsedSamples=remoteCounter*(NetworkBuffer::bufferLength-NetworkBuffer::headerLength); double expectedTimeUs=T*elapsedSamples*1000000; double actualTimeS=lastTime/1000000000.0; double actualTimeUs=lastTime/1000.0; static float averageBuffer[101]={0}; static int averageBufferPointer=0; static float average=0; static int bufferFull=0; average-=averageBuffer[averageBufferPointer]; averageBuffer[averageBufferPointer]=elapsedSamples/actualTimeS; average+=averageBuffer[averageBufferPointer]; averageBufferPointer++; if(averageBufferPointer==101){ averageBufferPointer=0; bufferFull++; } // rt_printf("Fs: %f, expectedTimeUs: %f, lastTime: %ul\n", expectedTimeUs, lastTime); // rt_printf("Fs: %.1f, actualTimeS: %4.6f, targetFs_ %.3f\n", if((averageBufferPointer&3)==0){ static float oldTargetSamplingRate=0; targetSamplingRate=average/101; if(bufferFull>=3 && fabsf(targetSamplingRate-oldTargetSamplingRate) < 1){ rt_printf("%.1f, %4.6f, %.3f;\n", gAudioCodec->getAudioSamplingRate(), actualTimeS, targetSamplingRate, targetSamplingRate-oldTargetSamplingRate); adjustClock(); } oldTargetSamplingRate=targetSamplingRate; } } void ClockSynchronizer::adjustClock(){ if(fabsf(currentSamplingRate-targetSamplingRate)>0.7){ //TODO: actually check that the difference is less than the quantization error in the PLL BeagleRT_scheduleAuxiliaryTask(setClockTask); } }