andrewm@0
|
1 /*
|
andrewm@0
|
2 TouchKeys: multi-touch musical keyboard control software
|
andrewm@0
|
3 Copyright (c) 2013 Andrew McPherson
|
andrewm@0
|
4
|
andrewm@0
|
5 This program is free software: you can redistribute it and/or modify
|
andrewm@0
|
6 it under the terms of the GNU General Public License as published by
|
andrewm@0
|
7 the Free Software Foundation, either version 3 of the License, or
|
andrewm@0
|
8 (at your option) any later version.
|
andrewm@0
|
9
|
andrewm@0
|
10 This program is distributed in the hope that it will be useful,
|
andrewm@0
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
andrewm@0
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
andrewm@0
|
13 GNU General Public License for more details.
|
andrewm@0
|
14
|
andrewm@0
|
15 You should have received a copy of the GNU General Public License
|
andrewm@0
|
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
andrewm@0
|
17
|
andrewm@0
|
18 =====================================================================
|
andrewm@0
|
19
|
andrewm@0
|
20 TimerNode.cpp: creates a Node object which runs its own thread to generate
|
andrewm@0
|
21 timestamps.
|
andrewm@0
|
22 */
|
andrewm@0
|
23
|
andrewm@0
|
24 #include "TimerNode.h"
|
andrewm@0
|
25
|
andrewm@0
|
26 using std::cout;
|
andrewm@0
|
27 using std::endl;
|
andrewm@0
|
28
|
andrewm@0
|
29 // Start the timer, if it isn't already running. The update rate is set elsewhere.
|
andrewm@0
|
30 void TimerNode::start(timestamp_type where) {
|
andrewm@0
|
31 if(isRunning_)
|
andrewm@0
|
32 return;
|
andrewm@0
|
33 startingTimestamp_ = where;
|
andrewm@0
|
34 startThread();
|
andrewm@0
|
35 isRunning_ = true;
|
andrewm@0
|
36 }
|
andrewm@0
|
37
|
andrewm@0
|
38 // Stop the timer if it is currently running. This kills the associated thread.
|
andrewm@0
|
39 void TimerNode::stop() {
|
andrewm@0
|
40 if(!isRunning_)
|
andrewm@0
|
41 return;
|
andrewm@0
|
42 signalThreadShouldExit();
|
andrewm@0
|
43 notify();
|
andrewm@0
|
44 stopThread(-1); // Ask the thread to stop; no timeout
|
andrewm@0
|
45 isRunning_ = false;
|
andrewm@0
|
46 }
|
andrewm@0
|
47
|
andrewm@0
|
48 // This function runs in its own thread, as managed by the Juce Thread parent class. It produces
|
andrewm@0
|
49 // data points approximately separated in time by intervalMicros_. The resolution of the system
|
andrewm@0
|
50 // timer affects how precise the spacing will be. Though the ticks may jitter, there shouldn't
|
andrewm@0
|
51 // be any systematic drift unless intervalMicros_ is smaller than the execution time of the loop.
|
andrewm@0
|
52 // (For example, 1000 will be fine; 1 is too short)
|
andrewm@0
|
53
|
andrewm@0
|
54 void TimerNode::run() {
|
andrewm@0
|
55 unsigned long long targetMicros = 0;
|
andrewm@0
|
56
|
andrewm@0
|
57 // Find the start time, against which our offsets will be measured.
|
andrewm@0
|
58 double startTime = Time::getMillisecondCounterHiRes();
|
andrewm@0
|
59 double nextTime;
|
andrewm@0
|
60
|
andrewm@0
|
61 while(!threadShouldExit()) {
|
andrewm@0
|
62 // Get the current time relative to when we started, using it as the "official" timestamp
|
andrewm@0
|
63 // for the data source.
|
andrewm@0
|
64 insert(startingTimestamp_ + microseconds_to_timestamp(targetMicros), milliseconds_to_timestamp(Time::getMillisecondCounterHiRes() - startTime));
|
andrewm@0
|
65 targetMicros += intervalMicros_;
|
andrewm@0
|
66
|
andrewm@0
|
67 // Next millisecond time according to Juce timer
|
andrewm@0
|
68 nextTime = startTime + (double)targetMicros/1000.0;
|
andrewm@0
|
69
|
andrewm@0
|
70 // Sleep until we get to the next tick.
|
andrewm@0
|
71 // thread_.sleep(startTime + microseconds(target_micros));
|
andrewm@0
|
72 wait((int)(nextTime - Time::getMillisecondCounterHiRes()));
|
andrewm@0
|
73 }
|
andrewm@0
|
74 } |