andrewm@0: /* andrewm@0: TouchKeys: multi-touch musical keyboard control software andrewm@0: Copyright (c) 2013 Andrew McPherson andrewm@0: andrewm@0: This program is free software: you can redistribute it and/or modify andrewm@0: it under the terms of the GNU General Public License as published by andrewm@0: the Free Software Foundation, either version 3 of the License, or andrewm@0: (at your option) any later version. andrewm@0: andrewm@0: This program is distributed in the hope that it will be useful, andrewm@0: but WITHOUT ANY WARRANTY; without even the implied warranty of andrewm@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the andrewm@0: GNU General Public License for more details. andrewm@0: andrewm@0: You should have received a copy of the GNU General Public License andrewm@0: along with this program. If not, see . andrewm@0: andrewm@0: ===================================================================== andrewm@0: andrewm@0: TimerNode.cpp: creates a Node object which runs its own thread to generate andrewm@0: timestamps. andrewm@0: */ andrewm@0: andrewm@0: #include "TimerNode.h" andrewm@0: andrewm@0: using std::cout; andrewm@0: using std::endl; andrewm@0: andrewm@0: // Start the timer, if it isn't already running. The update rate is set elsewhere. andrewm@0: void TimerNode::start(timestamp_type where) { andrewm@0: if(isRunning_) andrewm@0: return; andrewm@0: startingTimestamp_ = where; andrewm@0: startThread(); andrewm@0: isRunning_ = true; andrewm@0: } andrewm@0: andrewm@0: // Stop the timer if it is currently running. This kills the associated thread. andrewm@0: void TimerNode::stop() { andrewm@0: if(!isRunning_) andrewm@0: return; andrewm@0: signalThreadShouldExit(); andrewm@0: notify(); andrewm@0: stopThread(-1); // Ask the thread to stop; no timeout andrewm@0: isRunning_ = false; andrewm@0: } andrewm@0: andrewm@0: // This function runs in its own thread, as managed by the Juce Thread parent class. It produces andrewm@0: // data points approximately separated in time by intervalMicros_. The resolution of the system andrewm@0: // timer affects how precise the spacing will be. Though the ticks may jitter, there shouldn't andrewm@0: // be any systematic drift unless intervalMicros_ is smaller than the execution time of the loop. andrewm@0: // (For example, 1000 will be fine; 1 is too short) andrewm@0: andrewm@0: void TimerNode::run() { andrewm@0: unsigned long long targetMicros = 0; andrewm@0: andrewm@0: // Find the start time, against which our offsets will be measured. andrewm@0: double startTime = Time::getMillisecondCounterHiRes(); andrewm@0: double nextTime; andrewm@0: andrewm@0: while(!threadShouldExit()) { andrewm@0: // Get the current time relative to when we started, using it as the "official" timestamp andrewm@0: // for the data source. andrewm@0: insert(startingTimestamp_ + microseconds_to_timestamp(targetMicros), milliseconds_to_timestamp(Time::getMillisecondCounterHiRes() - startTime)); andrewm@0: targetMicros += intervalMicros_; andrewm@0: andrewm@0: // Next millisecond time according to Juce timer andrewm@0: nextTime = startTime + (double)targetMicros/1000.0; andrewm@0: andrewm@0: // Sleep until we get to the next tick. andrewm@0: // thread_.sleep(startTime + microseconds(target_micros)); andrewm@0: wait((int)(nextTime - Time::getMillisecondCounterHiRes())); andrewm@0: } andrewm@0: }