]> git.sesse.net Git - audiosync/blob - estimate-skew.cpp
2e6aff241b53f1f41c2c2361d82721884d8f3869
[audiosync] / estimate-skew.cpp
1 #include <stdio.h>
2 #include <string.h>
3 #include <math.h>
4 #include <stdlib.h>
5
6 double frac(double x)
7 {
8         return x - (int)x;
9 }
10
11 class FlankDetector
12 {
13 private:
14         static const unsigned NUM_SAMPLES = 10;
15         static const int MIN_LEVEL = 8192;
16
17         bool status, flag;  // high/low
18         unsigned counter;
19
20 public:
21         FlankDetector() : status(false), flag(false), counter(0) {}
22         void update(short x)
23         {
24                 if (abs(x) < MIN_LEVEL) {
25                         counter = 0;
26                         return;
27                 }
28
29                 if (!status) {
30                         // low
31                         if (x >= MIN_LEVEL) {
32                                 ++counter;
33                         } else {
34                                 counter = 0;
35                         }
36                 } else {
37                         // high
38                         if (x <= -MIN_LEVEL) {
39                                 ++counter;
40                         } else {
41                                 counter = 0;
42                         }
43                 }
44
45                 if (counter >= NUM_SAMPLES) {
46                         status = !status;
47                         counter = 0;
48                         flag = true;
49                 }
50         }
51
52         bool check_flag()
53         {
54                 bool ret = flag;
55                 flag = false;
56                 return ret;
57         }
58
59         bool get_status() const
60         {
61                 return status;
62         }
63 };
64
65 class InterpolatingReader
66 {
67 private:
68         FILE *f;
69         double speed;
70         double p;
71         int in_pos;
72         short prev_sample;
73
74 public:
75         InterpolatingReader(FILE *f) : f(f), speed(1.0), p(0.0), in_pos(-1) {}
76
77         void update_speed(double speed)
78         {
79                 this->speed = speed;
80         }
81
82         double read_sample()
83         {
84                 short sample;
85
86                 p += speed;
87                 while ((int)(ceil(p)) > in_pos) {
88                         prev_sample = sample;
89                         if (fread(&sample, sizeof(short), 1, f) != 1) {
90                                 exit(0);
91                         }
92                         ++in_pos;
93                 }
94
95                 // linear interpolation (works OK since delta_p varies so slowly)
96                 double t = frac(p);
97                 return prev_sample * (1.0 - t) + sample * t;
98         }
99 };
100
101 double filter(double x)
102 {
103         static double l;
104         static bool init = false;
105
106         if (init) {
107                 l = 0.05 * x + 0.95 * l;
108         } else {
109                 init = true;
110                 l = x;
111         }
112         return l;
113 }
114
115 int main(int argc, char **argv)
116 {
117         FILE *in1, *in2, *skew;
118
119         // open input1 (reference)
120         if (strcmp(argv[1], "-") == 0) {
121                 in1 = stdin;
122         } else {
123                 in1 = fopen(argv[1], "rb");
124                 if (in1 == NULL) {
125                         perror(argv[1]);
126                         exit(1);
127                 }
128         }
129
130         // open input2
131         if (strcmp(argv[2], "-") == 0) {
132                 in2 = stdin;
133         } else {
134                 in2 = fopen(argv[2], "rb");
135                 if (in2 == NULL) {
136                         perror(argv[2]);
137                         exit(1);
138                 }
139         }
140
141         // open (estimated) skew
142         if (strcmp(argv[3], "-") == 0) {
143                 skew = stderr;
144         } else {
145                 skew = fopen(argv[3], "wb");
146                 if (skew == NULL) {
147                         perror(argv[3]);
148                         exit(1);
149                 }
150         }
151
152         FlankDetector f1, f2;
153
154         // initial sync, reference
155         do {
156                 short s;
157                 if (fread(&s, sizeof(short), 1, in1) != 1) {
158                         exit(0);
159                 }
160
161                 f1.update(s);
162         } while (!f1.check_flag() || !f1.get_status());
163         
164         // initial sync, input
165         do {
166                 short s;
167                 if (fread(&s, sizeof(short), 1, in2) != 1) {
168                         exit(0);
169                 }
170
171                 f2.update(s);
172         } while (!f2.check_flag() || !f2.get_status());
173
174         double speed = 1.000;
175
176         InterpolatingReader intp(in2);
177         intp.update_speed(speed);  // test to see if we can resync OK
178
179         while (!feof(in1) && !feof(in2)) {
180                 short refs;
181
182                 // read reference until the next triggering
183                 unsigned num_ref = 0;
184                 while (!feof(in1) && !f1.check_flag()) {
185                         if (fread(&refs, sizeof(short), 1, in1) != 1) {
186                                 exit(0);
187                         }
188                         f1.update(refs);
189                         ++num_ref;
190                 }
191
192                 // same here
193                 unsigned num_inp = 0;
194                 while (!feof(in2) && !f2.check_flag()) {
195                         double s = intp.read_sample();
196                         f2.update((short)s);
197                         ++num_inp;
198                 }
199
200                 double ns = filter(speed * double(num_inp) / double(num_ref));
201                 printf("%u vs. %u -- ratio %.3f, speed %.3f, filtered speed %.3f\n", num_inp, num_ref,
202                         double(num_inp) / double(num_ref), speed * double(num_inp) / double(num_ref), ns);
203                 speed = ns;
204                 intp.update_speed(ns);
205         }
206 }