X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=decode.c;h=923913dea5a317ecca934ce59a0978959fc1534c;hb=f7953a166b871c47d0c3a602142b8e498f9ce278;hp=7e4c84b182bcea56530cda7bedcb9c3e334e3dd0;hpb=64f186d68c59fe7cd21fa02fa5f910f60644b8a7;p=c64tapwav diff --git a/decode.c b/decode.c index 7e4c84b..923913d 100644 --- a/decode.c +++ b/decode.c @@ -2,10 +2,15 @@ #include #include #include +#include #include #define LANCZOS_RADIUS 30 -#define LEN 813440 +#define BUFSIZE 4096 +#define HYSTERESIS_LIMIT 1000 +#define SAMPLE_RATE 44100 +#define C64_FREQUENCY 985248 +#define TAP_RESOLUTION 8 double sinc(double x) { @@ -34,38 +39,36 @@ double weight(double x) } #endif -double interpolate(const short *in, double i) +double interpolate(const std::vector &pcm, double i) { - int lower = std::max(int(ceil(i - LANCZOS_RADIUS)), 0); - int upper = std::min(int(floor(i + LANCZOS_RADIUS)), LEN - 1); + int lower = std::max(ceil(i - LANCZOS_RADIUS), 0); + int upper = std::min(floor(i + LANCZOS_RADIUS), pcm.size() - 1); double sum = 0.0f; for (int x = lower; x <= upper; ++x) { - sum += in[x] * weight(i - x); + sum += pcm[x] * weight(i - x); } return sum; } -short in[LEN]; - // between [x,x+1] -double find_zerocrossing(int x) +double find_zerocrossing(const std::vector &pcm, int x) { - if (in[x] == 0) { + if (pcm[x] == 0) { return x; } - if (in[x + 1] == 0) { + if (pcm[x + 1] == 0) { return x + 1; } - assert(in[x + 1] > 0); - assert(in[x] < 0); + assert(pcm[x + 1] > 0); + assert(pcm[x] < 0); double lower = x; double upper = x + 1; while (upper - lower > 1e-6) { double mid = 0.5f * (upper + lower); - if (interpolate(in, mid) > 0) { + if (interpolate(pcm, mid) > 0) { upper = mid; } else { lower = mid; @@ -77,7 +80,15 @@ double find_zerocrossing(int x) int main(int argc, char **argv) { - fread(in, LEN*2, 1, stdin); + std::vector pcm; + + while (!feof(stdin)) { + short buf[BUFSIZE]; + ssize_t ret = fread(buf, 2, BUFSIZE, stdin); + if (ret >= 0) { + pcm.insert(pcm.end(), buf, buf + ret); + } + } #if 0 for (int i = 0; i < LEN; ++i) { @@ -90,20 +101,46 @@ int main(int argc, char **argv) printf("%d\n", in[i]); } #endif + + std::vector pulse_lengths; // in seconds + + // Find the flanks. int last_bit = -1; double last_upflank = -1; - for (int i = 0; i < LEN; ++i) { - int bit = (in[i] > 0) ? 1 : 0; - if (bit == 1 && last_bit == 0) { + int last_max_level = 0; + for (int i = 0; i < pcm.size(); ++i) { + int bit = (pcm[i] > 0) ? 1 : 0; + if (bit == 1 && last_bit == 0 && last_max_level > HYSTERESIS_LIMIT) { // up-flank! - double t = find_zerocrossing(i - 1) * (123156.0/44100.0); + double t = find_zerocrossing(pcm, i - 1) * (1.0 / SAMPLE_RATE); if (last_upflank > 0) { -// fprintf(stderr, "length: %f (0x%x)\n", t - last_upflank, lrintf(t - last_upflank)); - int len = lrintf(t - last_upflank); - printf("0x%x\n", len); + pulse_lengths.push_back(t - last_upflank); } last_upflank = t; + last_max_level = 0; } + last_max_level = std::max(last_max_level, abs(pcm[i])); last_bit = bit; } + + // Calibrate on the first ~15k pulses (skip a few, just to be sure). + float calibration_factor = 1.0f; + if (pulse_lengths.size() < 20000) { + fprintf(stderr, "Too few pulses, not calibrating!\n"); + } else { + double sum = 0.0; + for (int i = 1000; i < 16000; ++i) { + sum += pulse_lengths[i]; + } + double mean_length = C64_FREQUENCY * sum / 15000.0f; + calibration_factor = 380.0 / mean_length; + fprintf(stderr, "Cycle length: %.2f -> 380.0 (change %+.2f%%)\n", + mean_length, 100.0 * (calibration_factor - 1.0)); + } + + for (int i = 0; i < pulse_lengths.size(); ++i) { + int len = lrintf(pulse_lengths[i] * calibration_factor * C64_FREQUENCY / TAP_RESOLUTION); + //fprintf(stderr, "length: %f (0x%x)\n", t - last_upflank, len); + printf("0x%x\n", len); + } }