Revision
| Source/ClockSync.cpp | ||
|---|---|---|
| 44 | 44 |
((myClock_t*)((char*)buffer+sizeof(int)))[0]=timestamp; |
| 45 | 45 |
} |
| 46 | 46 |
void ClockSync::print(){
|
| 47 |
printf("type: %d, timestamp: %lld\n",*((int*)buffer),*((myClock_t*)(((int*)buffer)+1)));
|
|
| 47 |
//printf("type: %d, timestamp: %lld\n",*((int*)buffer),*((myClock_t*)(((int*)buffer)+1)));
|
|
| 48 | 48 |
} |
| 49 | 49 |
void ClockSync::setPort(int aPort){
|
| 50 | 50 |
if(aPort>0){
|
| ... | ... | |
| 52 | 52 |
int outPort=isSlave() ? aPort+1: aPort; |
| 53 | 53 |
server.bindToPort(inPort); |
| 54 | 54 |
client.setPort(outPort); |
| 55 |
printf("Receiving on port %d\n", inPort);
|
|
| 56 |
printf("Sending to port %d\n", outPort);
|
|
| 55 |
//printf("Receiving on port %d\n", inPort);
|
|
| 56 |
//printf("Sending to port %d\n", outPort);
|
|
| 57 | 57 |
} |
| 58 | 58 |
} |
| 59 | 59 |
/** |
| ... | ... | |
| 89 | 89 |
ret=server.read(buffer, bufferLength, false); |
| 90 | 90 |
myClock_t timestamp=(myClock_t)virtualClock->getNow(); |
| 91 | 91 |
if(timestamp==0){
|
| 92 |
printf("The virtualClock period is <=0\n");
|
|
| 92 |
//printf("The virtualClock period is <=0\n");
|
|
| 93 | 93 |
return -3; |
| 94 | 94 |
} |
| 95 | 95 |
if(ret==-1){
|
| ... | ... | |
| 97 | 97 |
return -1; |
| 98 | 98 |
} |
| 99 | 99 |
if(ret!=bufferLength){
|
| 100 |
printf("Received a clockSync of the wrong size: %d\n", ret);
|
|
| 100 |
//printf("Received a clockSync of the wrong size: %d\n", ret);
|
|
| 101 | 101 |
return -2; |
| 102 | 102 |
} |
| 103 | 103 |
// print(); |
| ... | ... | |
| 106 | 106 |
|
| 107 | 107 |
int ClockSync::masterSendSync(){
|
| 108 | 108 |
//let's send a sync clockSync! |
| 109 |
printf("Sending a sync clockSync\n");
|
|
| 109 |
//printf("Sending a sync clockSync\n");
|
|
| 110 | 110 |
setType(kSync); |
| 111 | 111 |
setTimestamp(-1);//do not care about sending the timestamp, a more accurate one will be sent in the follow up |
| 112 | 112 |
localTimestamp=send(); |
| 113 | 113 |
if(localTimestamp<0){
|
| 114 |
printf("Could not send sync clockSync\n");
|
|
| 114 |
//printf("Could not send sync clockSync\n");
|
|
| 115 | 115 |
return -1; //error, don't retry, start over |
| 116 | 116 |
} |
| 117 | 117 |
//let's send a followUp |
| 118 |
printf("sent a sync clockSync\n");
|
|
| 118 |
//printf("sent a sync clockSync\n");
|
|
| 119 | 119 |
setType(kFollowUp); |
| 120 | 120 |
setTimestamp(localTimestamp); |
| 121 | 121 |
if(localTimestamp<0){
|
| 122 |
printf("Could not send followup clockSync\n");
|
|
| 122 |
//printf("Could not send followup clockSync\n");
|
|
| 123 | 123 |
return -2; //error, don't retry, start over |
| 124 | 124 |
} |
| 125 | 125 |
int ret=send(); |
| 126 | 126 |
if(ret<0){
|
| 127 |
printf("Error while sending followup\n");
|
|
| 127 |
//printf("Error while sending followup\n");
|
|
| 128 | 128 |
return -3; |
| 129 | 129 |
} |
| 130 |
printf("sent a followUp clockSync\n");
|
|
| 130 |
//printf("sent a followUp clockSync\n");
|
|
| 131 | 131 |
expectedClockSyncType=kDelayReq; |
| 132 | 132 |
return 1; |
| 133 | 133 |
} |
| 134 |
#ifdef USE_JUCE |
|
| 135 |
#define NOTGSHOULDSTOP 1 |
|
| 136 |
#else |
|
| 137 |
extern bool gShouldStop; |
|
| 138 |
#define NOTGSHOULDSTOP (!gShouldStop) |
|
| 139 |
#endif /* USE_JUCE */ |
|
| 134 | 140 |
int ClockSync::receiveLoop(){
|
| 135 | 141 |
int receiveLoopElapsed=0; |
| 136 |
while(isSlave() || (receiveLoopElapsed<receiveLoopTimeout)){ //when slave, does not timeout!
|
|
| 142 |
while( NOTGSHOULDSTOP && (isSlave() || (receiveLoopElapsed<receiveLoopTimeout))){ //when slave, does not timeout!
|
|
| 137 | 143 |
receiveLoopElapsed+=receiveLoopSleepUs; |
| 138 | 144 |
usleep(receiveLoopSleepUs); //how often to check for new clockSyncs; |
| 139 |
// printf("waiting for clockSyncs\n");
|
|
| 145 |
// //printf("waiting for clockSyncs\n");
|
|
| 140 | 146 |
localTimestamp=receive(); |
| 141 | 147 |
if(localTimestamp<=0){
|
| 142 | 148 |
if(localTimestamp==0){
|
| 143 |
// printf("Socket not ready to be read: %lld\n", localTimestamp);
|
|
| 149 |
// //printf("Socket not ready to be read: %lld\n", localTimestamp);
|
|
| 144 | 150 |
} |
| 145 |
else if(localTimestamp==-1) |
|
| 146 |
printf("Error while receiving: %lld\n", localTimestamp);
|
|
| 151 |
else if(localTimestamp==-1){
|
|
| 152 |
//printf("Error while receiving: %lld\n", localTimestamp);
|
|
| 153 |
} |
|
| 147 | 154 |
else if(localTimestamp==-2){
|
| 148 |
// printf("Wrong size of the received clockSync: %lld\n", localTimestamp);
|
|
| 155 |
// //printf("Wrong size of the received clockSync: %lld\n", localTimestamp);
|
|
| 149 | 156 |
} |
| 150 | 157 |
continue ; //keep waiting |
| 151 | 158 |
} |
| 152 | 159 |
clockSyncType=getType(); |
| 153 | 160 |
clockSyncTimestamp=getTimestamp(); |
| 154 | 161 |
if(clockSyncType!=expectedClockSyncType){
|
| 155 |
printf("Wrong clockSync type: %d, expected: %d\n",clockSyncType, expectedClockSyncType);
|
|
| 162 |
//printf("Wrong clockSync type: %d, expected: %d\n",clockSyncType, expectedClockSyncType);
|
|
| 156 | 163 |
return -2; //start over |
| 157 | 164 |
} |
| 158 |
printf("Received clockSync type: %d, clockSyncTimestamp: %lld\n", clockSyncType, clockSyncTimestamp);
|
|
| 165 |
//printf("Received clockSync type: %d, clockSyncTimestamp: %lld\n", clockSyncType, clockSyncTimestamp);
|
|
| 159 | 166 |
if(isSlave()==true){
|
| 160 | 167 |
int ret=slaveHandleMessage(); |
| 161 | 168 |
if(ret==1 && clockSyncType==kDelayResp){ //we are done, end of a cycle!
|
| ... | ... | |
| 175 | 182 |
} |
| 176 | 183 |
} |
| 177 | 184 |
} |
| 178 |
printf("Receive loop timeout\n");
|
|
| 185 |
//printf("Receive loop timeout\n");
|
|
| 179 | 186 |
return -1; |
| 180 | 187 |
} |
| 181 | 188 |
|
| ... | ... | |
| 192 | 199 |
setTimestamp(-1); |
| 193 | 200 |
T2=send(); |
| 194 | 201 |
if(T2<0){
|
| 195 |
printf("Error while sending delayReq\n");
|
|
| 202 |
//printf("Error while sending delayReq\n");
|
|
| 196 | 203 |
return -1; |
| 197 | 204 |
} |
| 198 | 205 |
expectedClockSyncType=kDelayResp; |
| ... | ... | |
| 206 | 213 |
break; |
| 207 | 214 |
} |
| 208 | 215 |
default: |
| 209 |
printf("Unexpected message type\n"); // we should never get here
|
|
| 216 |
//printf("Unexpected message type\n"); // we should never get here
|
|
| 210 | 217 |
return -1; |
| 211 | 218 |
} |
| 212 | 219 |
return 1; |
| ... | ... | |
| 227 | 234 |
|
| 228 | 235 |
int ClockSync::sendReceiveLoop(){
|
| 229 | 236 |
if(isSlave()==true){
|
| 230 |
printf("Waiting for a sync clockSync\n");
|
|
| 237 |
//printf("Waiting for a sync clockSync\n");
|
|
| 231 | 238 |
} else { //if this is master
|
| 232 |
usleep(1000000); //this times (roughly) how often sync clockSyncs are being sent.
|
|
| 239 |
usleep(100000); //this times (roughly) how often sync clockSyncs are being sent. |
|
| 233 | 240 |
int ret=masterSendSync(); |
| 234 | 241 |
if(ret<=0) |
| 235 | 242 |
return -1; |
| Source/ClockSyncThread.cpp | ||
|---|---|---|
| 1 | 1 |
#include "ClockSyncThread.h" |
| 2 |
|
|
| 2 |
#ifdef USE_JUCE |
|
| 3 |
#else //declare static members TODO: rather refactor this similar to other threads so that only run and clockSyncTask are static |
|
| 4 |
myClock_t ClockSyncThread::lastTime; // Used for clock synchronization |
|
| 5 |
bool ClockSyncThread::listening; |
|
| 6 |
ClockSync ClockSyncThread::clockSync; |
|
| 7 |
VirtualClock* ClockSyncThread::virtualClock; |
|
| 8 |
bool ClockSyncThread::threadIsExiting; |
|
| 9 |
AuxiliaryTask ClockSyncThread::clockSyncTask; |
|
| 10 |
#endif |
|
| 3 | 11 |
#ifdef USE_JUCE |
| 4 | 12 |
ClockSyncThread::ClockSyncThread(const String &threadName) : |
| 5 | 13 |
Thread(threadName) |
| ... | ... | |
| 15 | 23 |
stopThread(); |
| 16 | 24 |
#endif /* USE_JUCE */ |
| 17 | 25 |
} |
| 18 |
void ClockSyncThread::init(int aPort, int aBlockSize, VirtualClock &aVirtualClock){
|
|
| 26 |
void ClockSyncThread::init(bool isSlave, int aPort, VirtualClock &aVirtualClock){
|
|
| 19 | 27 |
setVirtualClock(aVirtualClock); |
| 20 | 28 |
listening=false; |
| 21 |
clockSync.init(false, aPort, *virtualClock);
|
|
| 29 |
clockSync.init(isSlave, aPort, *virtualClock);
|
|
| 22 | 30 |
#ifdef USE_JUCE |
| 23 | 31 |
startThread(5); |
| 24 | 32 |
#else |
| 33 |
threadIsExiting=false; |
|
| 34 |
clockSyncTask=BeagleRT_createAuxiliaryTask(&ClockSyncThread::run,98, "clockSyncTask"); |
|
| 25 | 35 |
//TODO: the thread cannot be started here at the moment because init() is called in setup(), where tasks cannot be scheduled |
| 26 | 36 |
#endif /* USE_JUCE */ |
| 27 | 37 |
} |
| ... | ... | |
| 29 | 39 |
#ifdef USE_JUCE |
| 30 | 40 |
#else |
| 31 | 41 |
void ClockSyncThread::startThread(){
|
| 32 |
BeagleRT_scheduleAuxiliaryTask(receiveDataTask); |
|
| 42 |
printf("starting\n");
|
|
| 43 |
BeagleRT_scheduleAuxiliaryTask(clockSyncTask); |
|
| 44 |
printf("started\n");
|
|
| 33 | 45 |
} |
| 34 | 46 |
void ClockSyncThread::stopThread(){
|
| 35 | 47 |
threadIsExiting=true; |
| ... | ... | |
| 45 | 57 |
|
| 46 | 58 |
void ClockSyncThread::run(){
|
| 47 | 59 |
while(!threadShouldExit()){
|
| 48 |
// usleep(100000); |
|
| 49 | 60 |
clockSync.sendReceiveLoop(); |
| 50 |
double now=virtualClock->getNow(); |
|
| 51 |
// printf("now: %f\n", now*blockSize/44100.0f);
|
|
| 61 |
usleep(5000); |
|
| 62 |
// double now=virtualClock->getNow(); |
|
| 63 |
// printf("th(end+1)=%f;\n", now/44100.0f);
|
|
| 64 |
// printf("act(end+1)=%lld;\n", Clock::getTimeUs());
|
|
| 52 | 65 |
} |
| 53 | 66 |
printf("Thread is not running \n");
|
| 54 |
} |
|
| 67 |
} |
|
| Source/ClockSyncThread.h | ||
|---|---|---|
| 3 | 3 |
|
| 4 | 4 |
#ifdef USE_JUCE |
| 5 | 5 |
#include <JuceHeader.h> |
| 6 |
#define IS_STATIC |
|
| 6 | 7 |
#else |
| 8 |
#define IS_STATIC static |
|
| 9 |
#include <BeagleRT.h> |
|
| 7 | 10 |
#endif /*USE_JUCE*/ |
| 8 | 11 |
|
| 9 | 12 |
#include "ClockSync.h" |
| ... | ... | |
| 14 | 17 |
class ClockSyncThread {
|
| 15 | 18 |
#endif /* USE_JUCE */ |
| 16 | 19 |
private: |
| 17 |
myClock_t lastTime; // Used for clock synchronization |
|
| 18 |
bool listening; |
|
| 19 |
ClockSync clockSync; |
|
| 20 |
int blockSize; |
|
| 21 |
VirtualClock *virtualClock; |
|
| 20 |
IS_STATIC myClock_t lastTime; // Used for clock synchronization |
|
| 21 |
IS_STATIC bool listening; |
|
| 22 |
IS_STATIC ClockSync clockSync; |
|
| 23 |
IS_STATIC VirtualClock *virtualClock; |
|
| 24 |
#ifdef USE_JUCE |
|
| 25 |
#else |
|
| 26 |
IS_STATIC bool threadIsExiting; |
|
| 27 |
IS_STATIC AuxiliaryTask clockSyncTask; |
|
| 28 |
#endif /* USE_JUCE */ |
|
| 29 |
|
|
| 22 | 30 |
public: |
| 23 | 31 |
#ifdef USE_JUCE |
| 24 | 32 |
ClockSyncThread(const String &threadName); |
| 25 | 33 |
#else |
| 26 | 34 |
ClockSyncThread(); |
| 27 |
#endif |
|
| 35 |
#endif /* USE_JUCE */
|
|
| 28 | 36 |
~ClockSyncThread(); |
| 29 |
void init(int aPort, int aBlockSize, VirtualClock &aVirtualClock);
|
|
| 30 |
void setVirtualClock(VirtualClock &aVirtualClock);
|
|
| 37 |
IS_STATIC void init(bool isSlave, int aPort, VirtualClock &aVirtualClock);
|
|
| 38 |
IS_STATIC void setVirtualClock(VirtualClock &aVirtualClock);
|
|
| 31 | 39 |
|
| 32 |
void run(); |
|
| 40 |
IS_STATIC void run();
|
|
| 33 | 41 |
#ifdef USE_JUCE |
| 34 | 42 |
#else |
| 35 |
void startThread(); |
|
| 36 |
void stopThread(); |
|
| 43 |
IS_STATIC void startThread(); |
|
| 44 |
IS_STATIC void stopThread(); |
|
| 45 |
IS_STATIC bool threadShouldExit(); |
|
| 37 | 46 |
#endif // USE_JUCE |
| 38 | 47 |
}; |
| 39 | 48 |
#endif // CLOCK_SYNC_THREAD_H_INCLUDED |
| Source/PluginProcessor.cpp | ||
|---|---|---|
| 130 | 130 |
// Use this method as the place to do any pre-playback |
| 131 | 131 |
// initialisation that you need.. |
| 132 | 132 |
virtualClock.init(); |
| 133 |
clockSyncThread.init(5000, samplesPerBlock, virtualClock); |
|
| 133 |
clockSyncThread.init(false, 5000, virtualClock); |
|
| 134 |
_samplesPerBlock=samplesPerBlock; |
|
| 134 | 135 |
} |
| 135 | 136 |
|
| 136 | 137 |
void ClockSyncAudioProcessor::releaseResources() |
| ... | ... | |
| 142 | 143 |
void ClockSyncAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages) |
| 143 | 144 |
{
|
| 144 | 145 |
// printf("period: %lld\n",virtualClock.getPeriod());
|
| 145 |
virtualClock.sync(); |
|
| 146 |
virtualClock.sync(_samplesPerBlock); |
|
| 147 |
double now=virtualClock.getNow(); |
|
| 148 |
// printf("now(end+1)=%f;\n", now);
|
|
| 146 | 149 |
// In case we have more outputs than inputs, this code clears any output |
| 147 | 150 |
// channels that didn't contain input data, (because these aren't |
| 148 | 151 |
// guaranteed to be empty - they may contain garbage). |
| Source/PluginProcessor.h | ||
|---|---|---|
| 66 | 66 |
void getStateInformation (MemoryBlock& destData) override; |
| 67 | 67 |
void setStateInformation (const void* data, int sizeInBytes) override; |
| 68 | 68 |
private: |
| 69 |
int _samplesPerBlock; |
|
| 69 | 70 |
VirtualClock virtualClock; |
| 70 | 71 |
ClockSyncThread clockSyncThread; |
| 71 | 72 |
//============================================================================== |
| Source/VirtualClock.cpp | ||
|---|---|---|
| 9 | 9 |
init(); |
| 10 | 10 |
} |
| 11 | 11 |
void VirtualClock::sync(){
|
| 12 |
sync(1); |
|
| 13 |
} |
|
| 14 |
void VirtualClock::sync(double count){
|
|
| 12 | 15 |
myClock_t currentTime=Clock::getTimeUs(); |
| 13 | 16 |
if(firstRun==true){
|
| 14 | 17 |
firstRun=false; |
| 15 | 18 |
startTime=currentTime; |
| 16 | 19 |
} else {
|
| 17 |
period=movingAverage.add(currentTime-lastSync); //TODO: replace with Kalman filter
|
|
| 20 |
period=movingAverage.add((currentTime-lastSync)/count); //TODO: replace with Kalman filter
|
|
| 18 | 21 |
} |
| 19 |
// printf("lastPeriod(end+1)= %lld;\n", currentTime-lastSync);
|
|
| 20 | 22 |
lastSync=currentTime; |
| 21 | 23 |
} |
| 22 | 24 |
|
| 23 | 25 |
double VirtualClock::getNow(){
|
| 24 |
myClock_t now=Clock::getTimeUs();
|
|
| 26 |
myClock_t now=Clock::getTimeUs(); |
|
| 25 | 27 |
if(period<=0){
|
| 26 | 28 |
return now; |
| 27 | 29 |
} |
| 28 |
double beginningOfPeriod=lastSync; // TODO: if sync() does not get called every time (but e.g. only every so often), |
|
| 30 |
// double beginningOfPeriod=lastSync; // TODO: if sync() does not get called every time (but e.g. only every so often),
|
|
| 29 | 31 |
// then this line (and the class) needs editing |
| 30 | 32 |
myClock_t elapsed=(now-startTime); |
| 31 | 33 |
double frac=elapsed/(double)period; |
| ... | ... | |
| 33 | 35 |
return frac; |
| 34 | 36 |
} |
| 35 | 37 |
|
| 36 |
myClock_t VirtualClock::getPeriod(){
|
|
| 38 |
double VirtualClock::getPeriod(){
|
|
| 37 | 39 |
return period; |
| 38 |
} |
|
| 40 |
} |
|
| Source/VirtualClock.h | ||
|---|---|---|
| 9 | 9 |
myClock_t startTime; |
| 10 | 10 |
myClock_t lastSync; |
| 11 | 11 |
bool firstRun; |
| 12 |
myClock_t period;
|
|
| 13 |
MovingAverage<myClock_t> movingAverage;
|
|
| 12 |
double period;
|
|
| 13 |
MovingAverage<double> movingAverage;
|
|
| 14 | 14 |
public: |
| 15 | 15 |
void init(); |
| 16 | 16 |
VirtualClock(); |
| ... | ... | |
| 21 | 21 |
/** |
| 22 | 22 |
Call this method asynchronously, passing a number of equally spaced events that have elapsed since the last call. |
| 23 | 23 |
*/ |
| 24 |
void sync(long long int count);
|
|
| 24 |
void sync(double count);
|
|
| 25 | 25 |
/** |
| 26 | 26 |
Get the current time according to the VirtualClock. |
| 27 | 27 |
|
| ... | ... | |
| 33 | 33 |
|
| 34 | 34 |
Get the length of the period (difference between calls to sync() after various filtering operations) |
| 35 | 35 |
*/ |
| 36 |
myClock_t getPeriod();
|
|
| 36 |
double getPeriod();
|
|
| 37 | 37 |
}; |
| 38 | 38 |
|
| 39 |
#endif /* VIRTUAL_CLOCK_H_INCLUDED */ |
|
| 39 |
#endif /* VIRTUAL_CLOCK_H_INCLUDED */ |
|
Also available in: Unified diff