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 TimestampSynchronizer.h: handles aligning timestamps between multiple
|
andrewm@0
|
21 asynchronous sources, while reducing the jitter that occurs when using
|
andrewm@0
|
22 system clock time for every received sample.
|
andrewm@0
|
23 */
|
andrewm@0
|
24
|
andrewm@0
|
25 #ifndef TIMESTAMP_SYNCHRONIZER_H
|
andrewm@0
|
26 #define TIMESTAMP_SYNCHRONIZER_H
|
andrewm@0
|
27
|
andrewm@0
|
28 #include <iostream>
|
andrewm@0
|
29 #include "../JuceLibraryCode/JuceHeader.h"
|
andrewm@0
|
30 #include "Types.h"
|
andrewm@0
|
31 #include "Node.h"
|
andrewm@0
|
32
|
andrewm@0
|
33 const int kTimestampSynchronizerHistoryLength = 100;
|
andrewm@0
|
34
|
andrewm@0
|
35 /* TimestampSynchronizer
|
andrewm@0
|
36 *
|
andrewm@0
|
37 * We often want to deal with multiple independent data streams, roughly
|
andrewm@0
|
38 * synchronized in time to one another but operating on separate clocks.
|
andrewm@0
|
39 * Each data stream can be assumed to have a regular, constant frame interval
|
andrewm@0
|
40 * but the exact duration of the interval might not be known and might drift
|
andrewm@0
|
41 * with respect to the system clock.
|
andrewm@0
|
42 *
|
andrewm@0
|
43 * In this class, the self-reported frame number is compared to the current
|
andrewm@0
|
44 * system time. In any multitasking OS, the system time when we receive a
|
andrewm@0
|
45 * frame may jitter around, but in the long-term average, we want system clock
|
andrewm@0
|
46 * and frame clock to stay in sync. Thus we use the low-pass-filtered difference
|
andrewm@0
|
47 * between system clock and frame clock to adjust the reported frame rate, keeping
|
andrewm@0
|
48 * the two locked together.
|
andrewm@0
|
49 */
|
andrewm@0
|
50
|
andrewm@0
|
51 using namespace std;
|
andrewm@0
|
52
|
andrewm@0
|
53 class TimestampSynchronizer {
|
andrewm@0
|
54 public:
|
andrewm@0
|
55 // Constructor
|
andrewm@0
|
56 TimestampSynchronizer();
|
andrewm@0
|
57
|
andrewm@0
|
58 // Clear accumulated timestamps and reinitialize a relationship between clock
|
andrewm@0
|
59 // time and output timestamp.
|
andrewm@0
|
60 void initialize(double clockTimeMilliseconds, timestamp_type startingTimestamp);
|
andrewm@0
|
61
|
andrewm@0
|
62 // Return or set the expected interval between frames
|
andrewm@0
|
63 timestamp_type nominalSampleInterval() { return nominalSampleInterval_; }
|
andrewm@0
|
64 void setNominalSampleInterval(timestamp_type interval) {
|
andrewm@0
|
65 nominalSampleInterval_ = interval;
|
andrewm@0
|
66 currentSampleInterval_ = interval;
|
andrewm@0
|
67 }
|
andrewm@0
|
68
|
andrewm@0
|
69 // Return the current calculated interval between frames
|
andrewm@0
|
70 timestamp_type currentSampleInterval() { return currentSampleInterval_; }
|
andrewm@0
|
71
|
andrewm@0
|
72 // Return or set the frame modulus (at what number the frame counter wraps
|
andrewm@0
|
73 // around to 0, since it can't increase forever).
|
andrewm@0
|
74 int frameModulus() { return frameModulus_; }
|
andrewm@0
|
75 void setFrameModulus(int modulus) { frameModulus_ = modulus; }
|
andrewm@0
|
76
|
andrewm@0
|
77 // Process a new timestamp value and return the value synchronized to the
|
andrewm@0
|
78 // system clock
|
andrewm@0
|
79 timestamp_type synchronizedTimestamp(int rawFrameNumber);
|
andrewm@0
|
80
|
andrewm@0
|
81 private:
|
andrewm@0
|
82 // History buffer of clock time vs. frame time. The Node has a data type
|
andrewm@0
|
83 // (frame number and frame timestamp, respectively) and a timestamp (clock timestamp);
|
andrewm@0
|
84 // in other words, two different times are held within the buffer as well as the frame numbers.
|
andrewm@0
|
85
|
andrewm@0
|
86 Node<pair<int, timestamp_type> > history_;
|
andrewm@0
|
87
|
andrewm@0
|
88 // Expected and currently calculated frame intervals
|
andrewm@0
|
89
|
andrewm@0
|
90 timestamp_type nominalSampleInterval_;
|
andrewm@0
|
91 timestamp_type currentSampleInterval_;
|
andrewm@0
|
92
|
andrewm@0
|
93 // Modulus of frame number, i.e. the number at which the frame counter
|
andrewm@0
|
94 // wraps around back to 0.
|
andrewm@0
|
95 int frameModulus_;
|
andrewm@0
|
96
|
andrewm@0
|
97 // The time we start from (clock and output timestamp)
|
andrewm@0
|
98
|
andrewm@0
|
99 double startingClockTimeMilliseconds_;
|
andrewm@0
|
100 timestamp_type startingTimestamp_;
|
andrewm@0
|
101
|
andrewm@0
|
102 int bufferLengthCounter_;
|
andrewm@0
|
103 };
|
andrewm@0
|
104
|
andrewm@0
|
105 #endif /* TIMESTAMP_SYNCHRONIZER_H */ |