slowrx/sync.c

134 wiersze
3.7 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"
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-20 05:51:27 +00:00
*
2011-07-07 14:09:57 +00:00
*/
2011-08-18 00:04:28 +00:00
double FindSync (guchar Mode, double Rate, int *Skip) {
2011-07-07 14:09:57 +00:00
2015-07-17 07:43:32 +00:00
int LineWidth = ModeSpec[Mode].LineTime / ModeSpec[Mode].SyncTime * 4;
int x,y;
2013-01-17 10:15:46 +00:00
int q, d, qMost, dMost;
gushort xAcc[700] = {0};
2011-08-13 12:26:49 +00:00
gushort lines[600][(MAXSLANT-MINSLANT)*2];
gushort cy, cx, Retries = 0;
2013-01-20 17:59:43 +00:00
gboolean SyncImg[700][630] = {{FALSE}};
2013-01-17 10:15:46 +00:00
double t=0, slantAngle, s;
double ConvoFilter[8] = { 1,1,1,1,-1,-1,-1,-1 };
double convd, maxconvd=0;
int xmax=0;
2011-08-20 05:51:27 +00:00
2011-07-07 14:09:57 +00:00
// Repeat until slant < 0.5° or until we give up
2013-01-19 09:51:29 +00:00
while (TRUE) {
2011-08-18 00:04:28 +00:00
2011-08-17 16:33:04 +00:00
// Draw the 2D sync signal at current rate
for (y=0; y<ModeSpec[Mode].NumLines; y++) {
2011-08-17 16:33:04 +00:00
for (x=0; x<LineWidth; x++) {
2015-07-17 07:43:32 +00:00
t = (y + 1.0*x/LineWidth) * ModeSpec[Mode].LineTime;
2013-01-20 17:59:43 +00:00
SyncImg[x][y] = HasSync[ (int)( t * Rate / 13.0) ];
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 **/
dMost = qMost = 0;
2011-08-13 12:26:49 +00:00
memset(lines, 0, sizeof(lines[0][0]) * (MAXSLANT-MINSLANT)*2 * 600);
2011-07-07 14:09:57 +00:00
2011-07-17 23:12:42 +00:00
// Find white pixels
for (cy = 0; cy < ModeSpec[Mode].NumLines; cy++) {
2011-07-25 22:41:04 +00:00
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;
2011-08-18 00:04:28 +00:00
printf(" %.1f° (d=%d) @ %.1f Hz", slantAngle, dMost, Rate);
2011-07-07 14:09:57 +00:00
2011-08-18 00:04:28 +00:00
// Adjust sample rate
Rate += tan(deg2rad(90 - slantAngle)) / 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-08-16 21:29:38 +00:00
Rate = 44100;
printf(" -> 44100\n");
2011-07-07 14:09:57 +00:00
break;
}
2011-08-18 00:04:28 +00:00
printf(" -> %.1f recalculating\n", Rate);
Retries ++;
2011-07-07 14:09:57 +00:00
}
2011-08-20 05:51:27 +00:00
// accumulate a 1-dim array of the position of the sync pulse
2011-07-28 12:45:37 +00:00
memset(xAcc, 0, sizeof(xAcc[0]) * 700);
for (y=0; y<ModeSpec[Mode].NumLines; y++) {
2011-08-18 00:04:28 +00:00
for (x=0; x<700; x++) {
2015-07-17 07:43:32 +00:00
t = y * ModeSpec[Mode].LineTime + x/700.0 * ModeSpec[Mode].LineTime;
2013-01-20 17:59:43 +00:00
xAcc[x] += HasSync[ (int)(t / (13.0/44100) * Rate/44100) ];
2011-07-28 12:45:37 +00:00
}
}
// find falling edge of the sync pulse by 8-point convolution
for (x=0;x<700-8;x++) {
convd = 0;
for (int i=0;i<8;i++) convd += xAcc[x+i] * ConvoFilter[i];
if (convd > maxconvd) {
maxconvd = convd;
2013-01-20 00:17:38 +00:00
xmax = x+4;
2011-07-28 12:45:37 +00:00
}
}
2013-01-17 10:15:46 +00:00
// If pulse is near the right edge of the image, it just probably slipped
// out the left edge
if (xmax > 350) xmax -= 350;
2013-01-17 10:15:46 +00:00
// Skip until the start of the line
2015-07-17 07:43:32 +00:00
s = xmax / 700.0 * ModeSpec[Mode].LineTime - ModeSpec[Mode].SyncTime;
2013-01-17 10:15:46 +00:00
// (Scottie modes don't start lines with sync)
2013-01-17 10:15:46 +00:00
if (Mode == S1 || Mode == S2 || Mode == SDX)
2015-07-17 07:43:32 +00:00
s = s - ModeSpec[Mode].PixelTime * ModeSpec[Mode].ImgWidth / 2.0
+ ModeSpec[Mode].PorchTime * 2;
2011-07-28 12:45:37 +00:00
2013-01-17 10:15:46 +00:00
*Skip = s * Rate;
2013-01-20 17:59:43 +00:00
printf("will return %.2f\n",Rate);
2011-07-28 12:45:37 +00:00
2011-07-07 14:09:57 +00:00
return (Rate);
}