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"
|
|
|
|
|
2011-08-12 20:06:23 +00:00
|
|
|
/* Find the slant angle of the sync singnal and adjust sample rate to cancel it out
|
2011-07-07 14:09:57 +00:00
|
|
|
* 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-08-12 20:06:23 +00:00
|
|
|
int LineWidth = ModeSpec[Mode].LineLen / ModeSpec[Mode].SyncLen * 4;
|
|
|
|
int x,y,xmid,x0;
|
|
|
|
int q, d, qMost, dMost;
|
|
|
|
int maxsy = 0;
|
|
|
|
guint s, TotPix, xmax;
|
|
|
|
gushort xAcc[700] = {0};
|
|
|
|
gushort lines[600][(MAXSLANT-MINSLANT)*2];
|
|
|
|
gushort cy, cx;
|
|
|
|
gushort Retries = 0;
|
|
|
|
guchar SyncImg[700][630];
|
|
|
|
double NextImgSample;
|
|
|
|
double t=0, slantAngle;
|
2011-07-07 14:09:57 +00:00
|
|
|
|
2011-07-19 19:29:14 +00:00
|
|
|
|
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
|
|
|
return (Rate);
|
|
|
|
|
|
|
|
}
|