slowrx/sync.c

249 wiersze
6.3 KiB
C
Czysty Zwykły widok Historia

2011-07-07 14:09:57 +00:00
#include <stdlib.h>
#include <math.h>
2011-07-19 19:29:14 +00:00
#include <string.h>
2011-07-07 14:09:57 +00:00
#include <fftw3.h>
#include <gtk/gtk.h>
2011-07-29 20:09:42 +00:00
#include <alsa/asoundlib.h>
2011-07-07 14:09:57 +00:00
#include "common.h"
/* Find the horizontal sync signal and adjust sample rate to cancel out any slant.
* Length: number of PCM samples to process
* Mode: one of M1, M2, S1, S2, R72, R36 ...
* Rate: approximate sampling rate used
* Skip: pointer to variable where the skip amount will be returned
* returns adjusted sample rate
*/
2011-08-11 11:48:35 +00:00
guint FindSync (guint Length, guchar Mode, guint Rate, int *Skip) {
2011-07-07 14:09:57 +00:00
2011-07-26 07:10:43 +00:00
int LineWidth = ModeSpec[Mode].LineLen / ModeSpec[Mode].SyncLen * 4;
2011-08-11 11:48:35 +00:00
int x,y,xmid,x0;
int q, d, qMost, dMost;
int maxsy = 0;
2011-07-28 12:45:37 +00:00
unsigned int i, s, TotPix, xmax;
2011-08-11 11:48:35 +00:00
unsigned short int FFTLen = 1024;
unsigned short int LopassBin = GetBin(3000, FFTLen);
unsigned short int xAcc[700] = {0};
unsigned short int lines[600][(MAXSLANT-MINSLANT)*2];
unsigned short int cy, cx;
unsigned short int Retries = 0;
unsigned char SyncImg[700][630];
2011-07-07 14:09:57 +00:00
double NextImgSample;
double t=0, slantAngle;
2011-08-11 11:48:35 +00:00
double Praw, Psync;
double Pwr[2048];
double *in;
double *out;
double Hann[50];
gboolean *HasSync;
fftw_plan Plan;
2011-07-07 14:09:57 +00:00
2011-08-11 11:48:35 +00:00
HasSync = malloc(Length * sizeof(gboolean));
2011-07-07 14:09:57 +00:00
if (HasSync == NULL) {
2011-07-17 23:12:42 +00:00
perror("FindSync: Unable to allocate memory for sync signal");
2011-07-07 14:09:57 +00:00
exit(EXIT_FAILURE);
}
2011-08-11 11:48:35 +00:00
memset(HasSync,FALSE,Length * sizeof(gboolean));
2011-07-07 14:09:57 +00:00
2011-08-11 11:48:35 +00:00
in = fftw_malloc(sizeof(double) * FFTLen);
2011-07-07 14:09:57 +00:00
if (in == NULL) {
2011-07-17 23:12:42 +00:00
perror("FindSync: Unable to allocate memory for FFT");
2011-07-07 14:09:57 +00:00
free(HasSync);
exit(EXIT_FAILURE);
}
2011-08-11 11:48:35 +00:00
out = fftw_malloc(sizeof(double) * FFTLen);
2011-07-07 14:09:57 +00:00
if (out == NULL) {
2011-07-17 23:12:42 +00:00
perror("FindSync: Unable to allocate memory for FFT");
2011-07-07 14:09:57 +00:00
fftw_free(in);
free(HasSync);
exit(EXIT_FAILURE);
}
2011-08-11 11:48:35 +00:00
Plan = fftw_plan_r2r_1d(FFTLen, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
2011-07-07 14:09:57 +00:00
// Create 50-point Hann window
for (i = 0; i < 50; i++) Hann[i] = 0.5 * (1 - cos( 2 * M_PI * i / 49.0) );
2011-07-20 17:54:00 +00:00
memset(in, 0, FFTLen * sizeof(in[0]));
2011-07-07 14:09:57 +00:00
2011-07-19 19:29:14 +00:00
printf("power est.\n");
2011-07-07 14:09:57 +00:00
// Power estimation
2011-07-25 22:41:04 +00:00
2011-07-07 14:09:57 +00:00
for (s = 0; s < Length; s+=50) {
// Hann window
2011-07-20 17:54:00 +00:00
for (i = 0; i < 50; i++) in[i] = PCM[s+i] * Hann[i];
2011-07-07 14:09:57 +00:00
// FFT
fftw_execute(Plan);
2011-07-19 19:29:14 +00:00
// Power in the whole band
Praw = 0;
2011-07-20 17:54:00 +00:00
for (i=0;i<LopassBin;i++) {
2011-07-19 19:29:14 +00:00
Pwr[i] = pow(out[i], 2) + pow(out[FFTLen-i], 2);
Praw += Pwr[i];
}
2011-07-20 17:54:00 +00:00
Praw /= (FFTLen/2.0) * ( LopassBin/(FFTLen/2.0));
2011-07-07 14:09:57 +00:00
2011-07-19 19:29:14 +00:00
// Power around the sync band
2011-07-25 12:05:03 +00:00
i = GetBin(1200+HedrShift, FFTLen);
2011-07-19 19:29:14 +00:00
Psync = (Pwr[i-1] + Pwr[i] + Pwr[i+1]) / 3.0;
2011-07-07 14:09:57 +00:00
// If there is more than twice the amount of Power per Hz in the
2011-07-19 19:29:14 +00:00
// sync band than in the rest of the band, we have a sync signal here
2011-07-25 22:41:04 +00:00
if (Psync > 2*Praw) HasSync[s] = TRUE;
else HasSync[s] = FALSE;
2011-07-07 14:09:57 +00:00
for (i = 0; i < 50; i++) {
if (s+i >= Length) break;
HasSync[s+i] = HasSync[s];
}
}
2011-07-19 19:29:14 +00:00
printf("hough\n");
2011-07-07 14:09:57 +00:00
// Repeat until slant < 0.5° or until we give up
while (1) {
2011-07-25 22:41:04 +00:00
TotPix = LineWidth/2; // Start at the middle of the picture
2011-07-07 14:09:57 +00:00
NextImgSample = 0;
t = 0;
maxsy = 0;
2011-08-11 11:48:35 +00:00
x = y = 0;
2011-07-07 14:09:57 +00:00
2011-07-25 22:41:04 +00:00
memset(SyncImg, 0, sizeof(SyncImg[0][0]) * LineWidth * 500);
2011-07-07 14:09:57 +00:00
// Draw the sync signal into memory
for (s = 0; s < Length; s++) {
// t keeps track of time in seconds
t += 1.0/Rate;
if (t >= NextImgSample) {
SyncImg[x][y] = HasSync[s];
if (y > maxsy) maxsy = y;
TotPix++;
2011-07-28 12:45:37 +00:00
x++;
if (x >= LineWidth) {
y++;
x=0;
}
2011-07-07 14:09:57 +00:00
2011-07-25 22:41:04 +00:00
NextImgSample += ModeSpec[Mode].LineLen / (1.0 * LineWidth);
2011-07-07 14:09:57 +00:00
}
}
2011-07-25 22:41:04 +00:00
2011-07-07 14:09:57 +00:00
/** Linear Hough transform **/
// zero arrays
dMost = qMost = 0;
2011-07-29 20:09:42 +00:00
memset(lines, 0, sizeof(lines[0][0]) * (MAXSLANT-MINSLANT)*2 * LineWidth);
2011-07-07 14:09:57 +00:00
2011-07-17 23:12:42 +00:00
// Find white pixels
2011-07-25 22:41:04 +00:00
for (cy = 0; cy < TotPix / LineWidth; cy++) {
for (cx = 0; cx < LineWidth; cx++) {
2011-07-17 23:12:42 +00:00
if (SyncImg[cx][cy]) {
2011-07-07 14:09:57 +00:00
// Slant angles to consider
2011-07-17 23:12:42 +00:00
for (q = MINSLANT*2; q < MAXSLANT*2; q ++) {
// Line accumulator
2011-07-25 22:41:04 +00:00
d = LineWidth + round( -cx * sin(deg2rad(q/2.0)) + cy * cos(deg2rad(q/2.0)) );
2011-07-28 12:45:37 +00:00
if (d > 0 && d < LineWidth) {
2011-07-17 23:12:42 +00:00
lines[d][q-MINSLANT*2] ++;
if (lines[d][q-MINSLANT*2] > lines[dMost][qMost-MINSLANT*2]) {
dMost = d;
qMost = q;
}
2011-07-07 14:09:57 +00:00
}
}
}
}
}
if ( qMost == 0) {
printf(" no sync signal; giving up\n");
break;
}
slantAngle = qMost / 2.0;
//printf(" most (%d occurrences): d=%d q=%f\n", LineAcc[dMost][ (int)(qMost * 10) ], dMost, qMost);
2011-08-11 11:48:35 +00:00
printf(" %.1f° (d=%d) @ %d Hz", slantAngle, dMost, Rate);
2011-07-07 14:09:57 +00:00
2011-07-25 22:41:04 +00:00
Rate = Rate + tan(deg2rad(90 - slantAngle)) / (1.0 * LineWidth) * Rate;
2011-07-07 14:09:57 +00:00
if (slantAngle > 89 && slantAngle < 91) {
2011-07-25 22:41:04 +00:00
printf(" slant OK :)\n");
2011-07-07 14:09:57 +00:00
break;
} else if (Retries == 3) {
printf(" still slanted; giving up\n");
2011-07-29 20:09:42 +00:00
Rate = SRATE;
printf(" -> SRATE\n");
2011-07-07 14:09:57 +00:00
break;
} else {
2011-08-11 11:48:35 +00:00
printf(" -> %d recalculating\n", Rate);
2011-07-07 14:09:57 +00:00
Retries ++;
}
}
2011-07-25 22:41:04 +00:00
printf(" gray = %dx%d\n", LineWidth, maxsy);
2011-07-28 12:45:37 +00:00
// find abscissa at high granularity
t = 0;
x = 0;
xmax=0;
NextImgSample=0;
2011-07-25 22:41:04 +00:00
2011-07-28 12:45:37 +00:00
memset(xAcc, 0, sizeof(xAcc[0]) * 700);
for (s = 0; s < Length; s++) {
t += 1.0/Rate;
if (t >= NextImgSample) {
xAcc[x] += HasSync[s];
if (xAcc[x] > xAcc[xmax]) xmax = x;
if (++x >= 700) x = 0;
2011-07-07 14:09:57 +00:00
2011-07-28 12:45:37 +00:00
NextImgSample += ModeSpec[Mode].LineLen / 700.0;
}
}
// find center of sync pulse
x0 = -1;
xmid=-1;
for (x=0;x<700;x++) {
if (xAcc[x] >= xAcc[xmax]*0.5 && x0==-1) x0 = x;
if (x0 != -1 && xAcc[x] < xAcc[xmax]*0.5) {
xmid = (x + x0) / 2;
break;
}
}
// skip until the start of the sync pulse
s = (xmid / 700.0 * ModeSpec[Mode].LineLen - ModeSpec[Mode].SyncLen/2) * Rate;
// Scottie modes don't start lines with the sync pulse
if (Mode == S1 || Mode == S2 || Mode == SDX)
s -= 2 * (ModeSpec[Mode].SeparatorLen + ModeSpec[Mode].PixelLen*ModeSpec[Mode].ImgWidth) * Rate;
*Skip = s;
2011-07-07 14:09:57 +00:00
free(HasSync);
fftw_destroy_plan(Plan);
fftw_free(in);
fftw_free(out);
return (Rate);
}