-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy pathsync.c
More file actions
133 lines (108 loc) · 3.72 KB
/
sync.c
File metadata and controls
133 lines (108 loc) · 3.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <fftw3.h>
#include <gtk/gtk.h>
#include <alsa/asoundlib.h>
#include "common.h"
/* Find the slant angle of the sync singnal and adjust sample rate to cancel it out
* 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 (guchar Mode, double Rate, int *Skip) {
int LineWidth = ModeSpec[Mode].LineTime / ModeSpec[Mode].SyncTime * 4;
int x,y;
int q, d, qMost, dMost;
gushort xAcc[700] = {0};
gushort lines[600][(MAXSLANT-MINSLANT)*2];
gushort cy, cx, Retries = 0;
gboolean SyncImg[700][630] = {{FALSE}};
double t=0, slantAngle, s;
double ConvoFilter[8] = { 1,1,1,1,-1,-1,-1,-1 };
double convd, maxconvd=0;
int xmax=0;
// Repeat until slant < 0.5° or until we give up
while (TRUE) {
// Draw the 2D sync signal at current rate
for (y=0; y<ModeSpec[Mode].NumLines; y++) {
for (x=0; x<LineWidth; x++) {
t = (y + 1.0*x/LineWidth) * ModeSpec[Mode].LineTime;
SyncImg[x][y] = HasSync[ (int)( t * Rate / 13.0) ];
}
}
/** Linear Hough transform **/
dMost = qMost = 0;
memset(lines, 0, sizeof(lines[0][0]) * (MAXSLANT-MINSLANT)*2 * 600);
// Find white pixels
for (cy = 0; cy < ModeSpec[Mode].NumLines; cy++) {
for (cx = 0; cx < LineWidth; cx++) {
if (SyncImg[cx][cy]) {
// Slant angles to consider
for (q = MINSLANT*2; q < MAXSLANT*2; q ++) {
// Line accumulator
d = LineWidth + round( -cx * sin(deg2rad(q/2.0)) + cy * cos(deg2rad(q/2.0)) );
if (d > 0 && d < LineWidth) {
lines[d][q-MINSLANT*2] ++;
if (lines[d][q-MINSLANT*2] > lines[dMost][qMost-MINSLANT*2]) {
dMost = d;
qMost = q;
}
}
}
}
}
}
if ( qMost == 0) {
printf(" no sync signal; giving up\n");
break;
}
slantAngle = qMost / 2.0;
printf(" %.1f° (d=%d) @ %.1f Hz", slantAngle, dMost, Rate);
// Adjust sample rate
Rate += tan(deg2rad(90 - slantAngle)) / LineWidth * Rate;
if (slantAngle > 89 && slantAngle < 91) {
printf(" slant OK :)\n");
break;
} else if (Retries == 3) {
printf(" still slanted; giving up\n");
Rate = 44100;
printf(" -> 44100\n");
break;
}
printf(" -> %.1f recalculating\n", Rate);
Retries ++;
}
// accumulate a 1-dim array of the position of the sync pulse
memset(xAcc, 0, sizeof(xAcc[0]) * 700);
for (y=0; y<ModeSpec[Mode].NumLines; y++) {
for (x=0; x<700; x++) {
t = y * ModeSpec[Mode].LineTime + x/700.0 * ModeSpec[Mode].LineTime;
xAcc[x] += HasSync[ (int)(t / (13.0/44100) * Rate/44100) ];
}
}
// 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;
xmax = x+4;
}
}
// If pulse is near the right edge of the image, it just probably slipped
// out the left edge
if (xmax > 350) xmax -= 350;
// Skip until the start of the line
s = xmax / 700.0 * ModeSpec[Mode].LineTime - ModeSpec[Mode].SyncTime;
// (Scottie modes don't start lines with sync)
if (Mode == S1 || Mode == S2 || Mode == SDX)
s = s - ModeSpec[Mode].PixelTime * ModeSpec[Mode].ImgWidth / 2.0
+ ModeSpec[Mode].PorchTime * 2;
*Skip = s * Rate;
printf("will return %.2f\n",Rate);
return (Rate);
}