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>
|
|
|
|
#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
|
|
|
|
*/
|
|
|
|
double FindSync (unsigned int Length, int Mode, double Rate, int *Skip) {
|
|
|
|
|
2011-07-20 17:54:00 +00:00
|
|
|
unsigned int i, s, TotPix;
|
2011-07-07 14:09:57 +00:00
|
|
|
double NextImgSample;
|
|
|
|
double t=0, slantAngle;
|
2011-07-20 17:54:00 +00:00
|
|
|
unsigned char SyncImg[SYNCW][630];
|
2011-07-07 14:09:57 +00:00
|
|
|
int x,y;
|
|
|
|
|
|
|
|
double Praw, Psync;
|
2011-07-19 19:29:14 +00:00
|
|
|
unsigned char *HasSync;
|
2011-07-07 14:09:57 +00:00
|
|
|
HasSync = malloc(Length * sizeof(char));
|
|
|
|
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-07-17 23:12:42 +00:00
|
|
|
unsigned short int lines[SYNCW+SYNCW/4][(MAXSLANT-MINSLANT)*2];
|
2011-07-07 14:09:57 +00:00
|
|
|
|
|
|
|
unsigned short int cy, cx;
|
|
|
|
int q, d, qMost, dMost;
|
|
|
|
unsigned short int Retries = 0;
|
|
|
|
int maxsy = 0;
|
|
|
|
FILE *GrayFile;
|
|
|
|
char PixBuf[1] = {0};
|
2011-07-17 23:12:42 +00:00
|
|
|
unsigned short int xAcc[SYNCW] = {0};
|
2011-07-07 14:09:57 +00:00
|
|
|
unsigned short int xMax = 0;
|
|
|
|
unsigned short int Leftmost;
|
2011-07-20 17:54:00 +00:00
|
|
|
double Pwr[2048];
|
2011-07-07 14:09:57 +00:00
|
|
|
|
|
|
|
// FFT plan
|
|
|
|
fftw_plan Plan;
|
|
|
|
double *in;
|
|
|
|
double *out;
|
|
|
|
unsigned int FFTLen = 1024;
|
|
|
|
|
|
|
|
in = fftw_malloc(sizeof(double) * FFTLen);
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
out = fftw_malloc(sizeof(double) * FFTLen);
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
Plan = fftw_plan_r2r_1d(FFTLen, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
|
|
|
|
|
|
|
|
// Create 50-point Hann window
|
2011-07-20 17:54:00 +00:00
|
|
|
double Hann[50];
|
2011-07-07 14:09:57 +00:00
|
|
|
for (i = 0; i < 50; i++) Hann[i] = 0.5 * (1 - cos( 2 * M_PI * i / 49.0) );
|
|
|
|
|
|
|
|
// Zero fill input array
|
2011-07-20 17:54:00 +00:00
|
|
|
memset(in, 0, FFTLen * sizeof(in[0]));
|
|
|
|
|
2011-07-25 12:05:03 +00:00
|
|
|
unsigned int LopassBin = GetBin(3000, FFTLen);
|
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
|
|
|
|
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-07 14:09:57 +00:00
|
|
|
if (Psync > 2*Praw) HasSync[s] = TRUE;
|
|
|
|
else HasSync[s] = FALSE;
|
|
|
|
|
|
|
|
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-19 19:29:14 +00:00
|
|
|
/*GrayFile = fopen("sync.gray","w");
|
2011-07-17 23:12:42 +00:00
|
|
|
if (GrayFile == NULL) {
|
|
|
|
perror("Unable to open sync.gray for writing");
|
|
|
|
exit(EXIT_FAILURE);
|
2011-07-19 19:29:14 +00:00
|
|
|
}*/
|
2011-07-07 14:09:57 +00:00
|
|
|
|
|
|
|
TotPix = 0;
|
|
|
|
NextImgSample = 0;
|
|
|
|
t = 0;
|
|
|
|
maxsy = 0;
|
|
|
|
|
2011-07-19 19:29:14 +00:00
|
|
|
memset(SyncImg, 0, sizeof(SyncImg[0][0]) * SYNCW * 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) {
|
|
|
|
|
2011-07-17 23:12:42 +00:00
|
|
|
x = TotPix % SYNCW;
|
|
|
|
y = TotPix / SYNCW;
|
2011-07-07 14:09:57 +00:00
|
|
|
|
|
|
|
SyncImg[x][y] = HasSync[s];
|
|
|
|
|
|
|
|
if (y > maxsy) maxsy = y;
|
|
|
|
|
2011-07-19 19:29:14 +00:00
|
|
|
//PixBuf[0] = (SyncImg[x][y] ? 255 : 0);
|
|
|
|
//fwrite(PixBuf, 1, 1, GrayFile);
|
2011-07-07 14:09:57 +00:00
|
|
|
|
|
|
|
TotPix++;
|
|
|
|
|
2011-07-17 23:12:42 +00:00
|
|
|
NextImgSample += ModeSpec[Mode].LineLen / (1.0 * SYNCW);
|
2011-07-07 14:09:57 +00:00
|
|
|
}
|
|
|
|
}
|
2011-07-19 19:29:14 +00:00
|
|
|
//fclose(GrayFile);
|
2011-07-07 14:09:57 +00:00
|
|
|
|
|
|
|
/** Linear Hough transform **/
|
|
|
|
|
|
|
|
// zero arrays
|
|
|
|
dMost = qMost = 0;
|
2011-07-17 23:12:42 +00:00
|
|
|
for (d=0; d<SYNCW+SYNCW/4; d++)
|
|
|
|
for (q=MINSLANT*2; q < MAXSLANT * 2; q++)
|
|
|
|
lines[d][q-MINSLANT*2] = 0;
|
2011-07-07 14:09:57 +00:00
|
|
|
|
2011-07-17 23:12:42 +00:00
|
|
|
// Find white pixels
|
|
|
|
for (cy = 0; cy < TotPix / SYNCW; cy++) {
|
|
|
|
for (cx = 0; cx < SYNCW; cx++) {
|
|
|
|
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
|
|
|
|
d = SYNCW + round( -cx * sin(deg2rad(q/2.0)) + cy * cos(deg2rad(q/2.0)) );
|
|
|
|
if (d > 0 && d < SYNCW+SYNCW/4) {
|
|
|
|
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-07-19 19:29:14 +00:00
|
|
|
printf(" %.1f° @ %.2f Hz", slantAngle, Rate);
|
2011-07-07 14:09:57 +00:00
|
|
|
|
2011-07-17 23:12:42 +00:00
|
|
|
Rate = Rate + tan(deg2rad(90 - slantAngle)) / (1.0 * SYNCW) * Rate;
|
2011-07-07 14:09:57 +00:00
|
|
|
|
|
|
|
if (Rate < 40000 || Rate > 50000) {
|
|
|
|
printf(" unrealistic receiving conditions; giving up.\n");
|
|
|
|
Rate = 44100;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (slantAngle > 89 && slantAngle < 91) {
|
|
|
|
printf(" -> %.2f slant OK :)\n", Rate);
|
|
|
|
break;
|
|
|
|
} else if (Retries == 3) {
|
|
|
|
printf(" still slanted; giving up\n");
|
|
|
|
Rate = 44100;
|
|
|
|
printf(" -> 44100\n");
|
|
|
|
break;
|
|
|
|
} else {
|
2011-07-19 19:29:14 +00:00
|
|
|
printf(" -> %.2f recalculating\n", Rate);
|
2011-07-07 14:09:57 +00:00
|
|
|
Retries ++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-17 23:12:42 +00:00
|
|
|
printf(" gray = %dx%d\n", SYNCW, maxsy);
|
2011-07-07 14:09:57 +00:00
|
|
|
|
|
|
|
// Find the abscissa of the now vertical sync pulse
|
2011-07-17 23:12:42 +00:00
|
|
|
for (i=0;i<SYNCW;i++) xAcc[i] = 0;
|
2011-07-07 14:09:57 +00:00
|
|
|
xMax = 0;
|
2011-07-17 23:12:42 +00:00
|
|
|
for (cy = 0; cy < TotPix / SYNCW; cy++) {
|
|
|
|
for (cx = 1; cx < SYNCW; cx++) {
|
2011-07-07 14:09:57 +00:00
|
|
|
if (!SyncImg[cx - 1][cy] && SyncImg[cx][cy]) {
|
|
|
|
xAcc[cx]++;
|
|
|
|
if (xAcc[cx] > xAcc[xMax]) xMax = cx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Now, find the leftmost one of those vertical lines with the maximum occurrences
|
2011-07-17 23:12:42 +00:00
|
|
|
Leftmost = SYNCW;
|
|
|
|
for (i = 0; i < SYNCW; i++)
|
|
|
|
if (xAcc[i] == xAcc[xMax] && i < Leftmost)
|
|
|
|
Leftmost = i;
|
2011-07-07 14:09:57 +00:00
|
|
|
|
|
|
|
if (Rate == 44100) Leftmost = 0;
|
|
|
|
|
|
|
|
printf(" abscissa = %d (%d occurrences)", Leftmost, xAcc[Leftmost]);
|
2011-07-17 23:12:42 +00:00
|
|
|
Leftmost = Leftmost * (ModeSpec[Mode].LineLen / (1.0 * SYNCW)) * Rate;
|
2011-07-07 14:09:57 +00:00
|
|
|
printf(" (need to skip %d samples)\n", Leftmost);
|
|
|
|
|
|
|
|
*Skip = Leftmost;
|
|
|
|
|
|
|
|
free(HasSync);
|
|
|
|
fftw_destroy_plan(Plan);
|
|
|
|
fftw_free(in);
|
|
|
|
fftw_free(out);
|
|
|
|
|
|
|
|
return (Rate);
|
|
|
|
|
|
|
|
}
|