+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+
+double frac(double x)
+{
+ return x - (int)x;
+}
+
+class FlankDetector
+{
+private:
+ static const unsigned NUM_SAMPLES = 10;
+ static const int MIN_LEVEL = 8192;
+
+ bool status, flag; // high/low
+ unsigned counter;
+
+public:
+ FlankDetector() : status(false), flag(false), counter(0) {}
+ void update(short x)
+ {
+ if (abs(x) < MIN_LEVEL) {
+ counter = 0;
+ return;
+ }
+
+ if (!status) {
+ // low
+ if (x >= MIN_LEVEL) {
+ ++counter;
+ } else {
+ counter = 0;
+ }
+ } else {
+ // high
+ if (x <= -MIN_LEVEL) {
+ ++counter;
+ } else {
+ counter = 0;
+ }
+ }
+
+ if (counter >= NUM_SAMPLES) {
+ status = !status;
+ counter = 0;
+ flag = true;
+ }
+ }
+
+ bool check_flag()
+ {
+ bool ret = flag;
+ flag = false;
+ return ret;
+ }
+
+ bool get_status() const
+ {
+ return status;
+ }
+};
+
+class InterpolatingReader
+{
+private:
+ FILE *f;
+ double speed;
+ double p;
+ int in_pos;
+ short prev_sample;
+
+public:
+ InterpolatingReader(FILE *f) : f(f), speed(1.0), p(0.0), in_pos(-1) {}
+
+ void update_speed(double speed)
+ {
+ this->speed = speed;
+ }
+
+ double read_sample()
+ {
+ short sample;
+
+ p += speed;
+ while ((int)(ceil(p)) > in_pos) {
+ prev_sample = sample;
+ if (fread(&sample, sizeof(short), 1, f) != 1) {
+ exit(0);
+ }
+ ++in_pos;
+ }
+
+ // linear interpolation (works OK since delta_p varies so slowly)
+ double t = frac(p);
+ return prev_sample * (1.0 - t) + sample * t;
+ }
+};
+
+double filter(double x)
+{
+ static double l = 1.0;
+ l = 0.01 * x + 0.99 * l;
+ return l;
+}
+
+int main(int argc, char **argv)
+{
+ FILE *in1, *in2, *skew;
+
+ // open input1 (reference)
+ if (strcmp(argv[1], "-") == 0) {
+ in1 = stdin;
+ } else {
+ in1 = fopen(argv[1], "rb");
+ if (in1 == NULL) {
+ perror(argv[1]);
+ exit(1);
+ }
+ }
+
+ // open input2
+ if (strcmp(argv[2], "-") == 0) {
+ in2 = stdin;
+ } else {
+ in2 = fopen(argv[2], "rb");
+ if (in2 == NULL) {
+ perror(argv[2]);
+ exit(1);
+ }
+ }
+
+ // open (estimated) skew
+ if (strcmp(argv[3], "-") == 0) {
+ skew = stderr;
+ } else {
+ skew = fopen(argv[3], "wb");
+ if (skew == NULL) {
+ perror(argv[3]);
+ exit(1);
+ }
+ }
+
+ FlankDetector f1, f2;
+
+ // initial sync, reference
+ do {
+ short s;
+ if (fread(&s, sizeof(short), 1, in1) != 1) {
+ exit(0);
+ }
+
+ f1.update(s);
+ } while (!f1.check_flag() || !f1.get_status());
+
+ // initial sync, input
+ do {
+ short s;
+ if (fread(&s, sizeof(short), 1, in2) != 1) {
+ exit(0);
+ }
+
+ f2.update(s);
+ } while (!f2.check_flag() || !f2.get_status());
+
+ double speed = 1.000;
+
+ InterpolatingReader intp(in2);
+ intp.update_speed(speed); // test to see if we can resync OK
+
+ while (!feof(in1) && !feof(in2)) {
+ short refs;
+
+ // read reference until the next triggering
+ unsigned num_ref = 0;
+ while (!feof(in1) && !f1.check_flag()) {
+ if (fread(&refs, sizeof(short), 1, in1) != 1) {
+ exit(0);
+ }
+ f1.update(refs);
+ ++num_ref;
+ }
+
+ // same here
+ unsigned num_inp = 0;
+ while (!feof(in2) && !f2.check_flag()) {
+ double s = intp.read_sample();
+ f2.update((short)s);
+ ++num_inp;
+ }
+
+ double ns = filter(speed * double(num_inp) / double(num_ref));
+ printf("%u vs. %u -- ratio %f, speed %f, filtered speed %f\n", num_inp, num_ref,
+ double(num_inp) / double(num_ref), speed * double(num_inp) / double(num_ref), ns);
+ speed = ns;
+ intp.update_speed(ns);
+ }
+}