kopia lustrzana https://github.com/windytan/slowrx
sync improvements ... and a lot more
rodzic
c3248524ba
commit
f60ec21e6b
2
common.h
2
common.h
|
@ -3,7 +3,7 @@
|
|||
|
||||
#define MINSLANT 30
|
||||
#define MAXSLANT 150
|
||||
#define SYNCW 350
|
||||
#define SYNCW 400
|
||||
#define SNRSIZE 2048
|
||||
|
||||
extern int VISmap[128];
|
||||
|
|
|
@ -92,7 +92,7 @@ ModeSpecDef ModeSpec[] = {
|
|||
.ShortName = "S1",
|
||||
.SyncLen = 9e-3,
|
||||
.PorchLen = 1.5e-3,
|
||||
.SeparatorLen = 1.7e-3,
|
||||
.SeparatorLen = 1.5e-3,
|
||||
.PixelLen = 0.4320e-3,
|
||||
.LineLen = 428.38e-3,
|
||||
.ImgWidth = 320,
|
||||
|
|
20
slowrx.c
20
slowrx.c
|
@ -44,7 +44,7 @@ void *Cam() {
|
|||
while (1) {
|
||||
|
||||
//PcmInStream = popen( "sox -q -t alsa hw:0 -t .raw -b 16 -c 1 -e signed-integer -r 44100 -L - 2>/dev/null", "r");
|
||||
PcmInStream = popen( "sox -q iss.ogg -t raw -b 16 -c 1 -e signed-integer -r 44100 -L - 2>/dev/null", "r");
|
||||
PcmInStream = popen( "sox -q iss2.ogg -t raw -b 16 -c 1 -e signed-integer -r 44100 -L - 2>/dev/null", "r");
|
||||
|
||||
if (PcmInStream == NULL) {
|
||||
perror("Unable to open sox pipe");
|
||||
|
@ -93,7 +93,7 @@ void *Cam() {
|
|||
gtk_statusbar_push( GTK_STATUSBAR(statusbar), 0, "Receiving video" );
|
||||
gtk_label_set_markup(GTK_LABEL(infolabel), infostr);
|
||||
gdk_threads_leave();
|
||||
PcmPointer = 0;
|
||||
PcmPointer = 2048;
|
||||
Sample = 0;
|
||||
Rate = 44100;
|
||||
Skip = 0;
|
||||
|
@ -116,15 +116,13 @@ void *Cam() {
|
|||
free(PCM);
|
||||
PCM = NULL;
|
||||
|
||||
if (Rate != 44100) {
|
||||
// Final image
|
||||
gdk_threads_enter();
|
||||
gtk_statusbar_push( GTK_STATUSBAR(statusbar), 0, "Redrawing" );
|
||||
gdk_threads_leave();
|
||||
printf(" getvideo @ %.02f Hz, Skip %d, HedrShift %.0f Hz\n", Rate, Skip, HedrShift);
|
||||
GetVideo(Mode, Rate, Skip, TRUE, TRUE);
|
||||
}
|
||||
|
||||
// Final image
|
||||
gdk_threads_enter();
|
||||
gtk_statusbar_push( GTK_STATUSBAR(statusbar), 0, "Redrawing" );
|
||||
gdk_threads_leave();
|
||||
printf(" getvideo @ %.02f Hz, Skip %d, HedrShift %.0f Hz\n", Rate, Skip, HedrShift);
|
||||
GetVideo(Mode, Rate, Skip, TRUE, TRUE);
|
||||
|
||||
gdk_threads_enter();
|
||||
gtk_statusbar_push( GTK_STATUSBAR(statusbar), 0, "Saving" );
|
||||
gdk_threads_leave();
|
||||
|
|
106
sync.c
106
sync.c
|
@ -14,10 +14,14 @@
|
|||
*/
|
||||
double FindSync (unsigned int Length, int Mode, double Rate, int *Skip) {
|
||||
|
||||
int LineWidth = ModeSpec[Mode].LineLen / ModeSpec[Mode].SyncLen * 4;
|
||||
|
||||
printf("LineWidth %d\n",LineWidth);
|
||||
|
||||
unsigned int i, s, TotPix;
|
||||
double NextImgSample;
|
||||
double t=0, slantAngle;
|
||||
unsigned char SyncImg[SYNCW][630];
|
||||
unsigned char SyncImg[450][630];
|
||||
int x,y;
|
||||
|
||||
double Praw, Psync;
|
||||
|
@ -27,8 +31,9 @@ double FindSync (unsigned int Length, int Mode, double Rate, int *Skip) {
|
|||
perror("FindSync: Unable to allocate memory for sync signal");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
memset(HasSync,0,Length * sizeof(char));
|
||||
|
||||
unsigned short int lines[SYNCW+SYNCW/4][(MAXSLANT-MINSLANT)*2];
|
||||
unsigned short int lines[600][(MAXSLANT-MINSLANT)*2];
|
||||
|
||||
unsigned short int cy, cx;
|
||||
int q, d, qMost, dMost;
|
||||
|
@ -36,9 +41,6 @@ double FindSync (unsigned int Length, int Mode, double Rate, int *Skip) {
|
|||
int maxsy = 0;
|
||||
FILE *GrayFile;
|
||||
char PixBuf[1] = {0};
|
||||
unsigned short int xAcc[SYNCW] = {0};
|
||||
unsigned short int xMax = 0;
|
||||
unsigned short int Leftmost;
|
||||
double Pwr[2048];
|
||||
|
||||
// FFT plan
|
||||
|
@ -74,6 +76,7 @@ double FindSync (unsigned int Length, int Mode, double Rate, int *Skip) {
|
|||
printf("power est.\n");
|
||||
|
||||
// Power estimation
|
||||
|
||||
for (s = 0; s < Length; s+=50) {
|
||||
|
||||
// Hann window
|
||||
|
@ -97,8 +100,8 @@ double FindSync (unsigned int Length, int Mode, double Rate, int *Skip) {
|
|||
|
||||
// If there is more than twice the amount of Power per Hz in the
|
||||
// sync band than in the rest of the band, we have a sync signal here
|
||||
if (Psync > 2*Praw) HasSync[s] = TRUE;
|
||||
else HasSync[s] = FALSE;
|
||||
if (Psync > 2*Praw) HasSync[s] = TRUE;
|
||||
else HasSync[s] = FALSE;
|
||||
|
||||
for (i = 0; i < 50; i++) {
|
||||
if (s+i >= Length) break;
|
||||
|
@ -112,19 +115,13 @@ double FindSync (unsigned int Length, int Mode, double Rate, int *Skip) {
|
|||
// Repeat until slant < 0.5° or until we give up
|
||||
while (1) {
|
||||
|
||||
/*GrayFile = fopen("sync.gray","w");
|
||||
if (GrayFile == NULL) {
|
||||
perror("Unable to open sync.gray for writing");
|
||||
exit(EXIT_FAILURE);
|
||||
}*/
|
||||
|
||||
TotPix = 0;
|
||||
TotPix = LineWidth/2; // Start at the middle of the picture
|
||||
NextImgSample = 0;
|
||||
t = 0;
|
||||
maxsy = 0;
|
||||
|
||||
memset(SyncImg, 0, sizeof(SyncImg[0][0]) * SYNCW * 500);
|
||||
|
||||
memset(SyncImg, 0, sizeof(SyncImg[0][0]) * LineWidth * 500);
|
||||
|
||||
// Draw the sync signal into memory
|
||||
for (s = 0; s < Length; s++) {
|
||||
|
||||
|
@ -133,42 +130,52 @@ double FindSync (unsigned int Length, int Mode, double Rate, int *Skip) {
|
|||
|
||||
if (t >= NextImgSample) {
|
||||
|
||||
x = TotPix % SYNCW;
|
||||
y = TotPix / SYNCW;
|
||||
x = TotPix % LineWidth;
|
||||
y = TotPix / LineWidth;
|
||||
|
||||
SyncImg[x][y] = HasSync[s];
|
||||
|
||||
if (y > maxsy) maxsy = y;
|
||||
|
||||
//PixBuf[0] = (SyncImg[x][y] ? 255 : 0);
|
||||
//fwrite(PixBuf, 1, 1, GrayFile);
|
||||
|
||||
TotPix++;
|
||||
|
||||
NextImgSample += ModeSpec[Mode].LineLen / (1.0 * SYNCW);
|
||||
NextImgSample += ModeSpec[Mode].LineLen / (1.0 * LineWidth);
|
||||
}
|
||||
}
|
||||
//fclose(GrayFile);
|
||||
|
||||
// write sync.gray
|
||||
GrayFile = fopen("sync.gray","w");
|
||||
if (GrayFile == NULL) {
|
||||
perror("Unable to open sync.gray for writing");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
for (y=0;y<maxsy;y++) {
|
||||
for (x=0;x<LineWidth;x++) {
|
||||
PixBuf[0] = (SyncImg[x][y] ? 255 : 0);
|
||||
fwrite(PixBuf, 1, 1, GrayFile);
|
||||
}
|
||||
}
|
||||
fclose(GrayFile);
|
||||
|
||||
/** Linear Hough transform **/
|
||||
|
||||
// zero arrays
|
||||
dMost = qMost = 0;
|
||||
for (d=0; d<SYNCW+SYNCW/4; d++)
|
||||
for (d=0; d<LineWidth+LineWidth/4; d++)
|
||||
for (q=MINSLANT*2; q < MAXSLANT * 2; q++)
|
||||
lines[d][q-MINSLANT*2] = 0;
|
||||
|
||||
// Find white pixels
|
||||
for (cy = 0; cy < TotPix / SYNCW; cy++) {
|
||||
for (cx = 0; cx < SYNCW; cx++) {
|
||||
for (cy = 0; cy < TotPix / LineWidth; 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 = SYNCW + round( -cx * sin(deg2rad(q/2.0)) + cy * cos(deg2rad(q/2.0)) );
|
||||
if (d > 0 && d < SYNCW+SYNCW/4) {
|
||||
d = LineWidth + round( -cx * sin(deg2rad(q/2.0)) + cy * cos(deg2rad(q/2.0)) );
|
||||
if (d > 0 && d < LineWidth+LineWidth/4) {
|
||||
lines[d][q-MINSLANT*2] ++;
|
||||
if (lines[d][q-MINSLANT*2] > lines[dMost][qMost-MINSLANT*2]) {
|
||||
dMost = d;
|
||||
|
@ -188,18 +195,12 @@ double FindSync (unsigned int Length, int Mode, double Rate, int *Skip) {
|
|||
slantAngle = qMost / 2.0;
|
||||
|
||||
//printf(" most (%d occurrences): d=%d q=%f\n", LineAcc[dMost][ (int)(qMost * 10) ], dMost, qMost);
|
||||
printf(" %.1f° @ %.2f Hz", slantAngle, Rate);
|
||||
printf(" %.1f° (d=%d) @ %.2f Hz", slantAngle, dMost, Rate);
|
||||
|
||||
Rate = Rate + tan(deg2rad(90 - slantAngle)) / (1.0 * SYNCW) * Rate;
|
||||
|
||||
if (Rate < 40000 || Rate > 50000) {
|
||||
printf(" unrealistic receiving conditions; giving up.\n");
|
||||
Rate = 44100;
|
||||
break;
|
||||
}
|
||||
Rate = Rate + tan(deg2rad(90 - slantAngle)) / (1.0 * LineWidth) * Rate;
|
||||
|
||||
if (slantAngle > 89 && slantAngle < 91) {
|
||||
printf(" -> %.2f slant OK :)\n", Rate);
|
||||
printf(" slant OK :)\n");
|
||||
break;
|
||||
} else if (Retries == 3) {
|
||||
printf(" still slanted; giving up\n");
|
||||
|
@ -212,32 +213,13 @@ double FindSync (unsigned int Length, int Mode, double Rate, int *Skip) {
|
|||
}
|
||||
}
|
||||
|
||||
printf(" gray = %dx%d\n", SYNCW, maxsy);
|
||||
printf(" gray = %dx%d\n", LineWidth, maxsy);
|
||||
|
||||
// Find the abscissa of the now vertical sync pulse
|
||||
for (i=0;i<SYNCW;i++) xAcc[i] = 0;
|
||||
xMax = 0;
|
||||
for (cy = 0; cy < TotPix / SYNCW; cy++) {
|
||||
for (cx = 1; cx < SYNCW; cx++) {
|
||||
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
|
||||
Leftmost = SYNCW;
|
||||
for (i = 0; i < SYNCW; i++)
|
||||
if (xAcc[i] == xAcc[xMax] && i < Leftmost)
|
||||
Leftmost = i;
|
||||
|
||||
if (Rate == 44100) Leftmost = 0;
|
||||
|
||||
printf(" abscissa = %d (%d occurrences)", Leftmost, xAcc[Leftmost]);
|
||||
Leftmost = Leftmost * (ModeSpec[Mode].LineLen / (1.0 * SYNCW)) * Rate;
|
||||
printf(" (need to skip %d samples)\n", Leftmost);
|
||||
|
||||
*Skip = Leftmost;
|
||||
//s = (LineWidth/2 - dMost) * (ModeSpec[Mode].LineLen / (1.0 * LineWidth)) * Rate;
|
||||
//s -= ModeSpec[Mode].SyncLen / 2.0 * Rate;
|
||||
//*Skip = s;
|
||||
|
||||
*Skip = 0;
|
||||
|
||||
free(HasSync);
|
||||
fftw_destroy_plan(Plan);
|
||||
|
|
97
video.c
97
video.c
|
@ -32,7 +32,7 @@ int GetVideo(int Mode, double Rate, int Skip, int Adaptive, int Redraw) {
|
|||
double Pvideo_plus_noise=0, Pnoise_only=0, Pnoise=0, Psignal=0;
|
||||
double SNR = 0;
|
||||
double CurLineTime = 0;
|
||||
double ChanStart[3] = {0}, ChanLen[3] = {0};
|
||||
double ChanStart[4] = {0}, ChanLen[4] = {0};
|
||||
unsigned char Lum=0, Image[800][616][3] = {{{0}}};
|
||||
unsigned char Channel = 0;
|
||||
fftw_plan Plan, BigPlan, SNRPlan;
|
||||
|
@ -75,21 +75,10 @@ int GetVideo(int Mode, double Rate, int Skip, int Adaptive, int Redraw) {
|
|||
0.2673747, 0.2122111, 0.1631808, 0.1206692, 0.1569882 };
|
||||
|
||||
|
||||
// Starting times of video channels on every line, counted from beginning of sync pulse
|
||||
// Starting times of video channels on every line, counted from beginning of line
|
||||
|
||||
switch (Mode) {
|
||||
|
||||
case R72:
|
||||
case R24BW:
|
||||
case R12BW:
|
||||
case R8BW:
|
||||
ChanLen[0] = ModeSpec[Mode].PixelLen * ModeSpec[Mode].ImgWidth;
|
||||
ChanLen[1] = ChanLen[2] = ChanLen[0];
|
||||
ChanStart[0] = ModeSpec[Mode].SyncLen + ModeSpec[Mode].PorchLen;
|
||||
ChanStart[1] = ChanStart[0] + ChanLen[0] + ModeSpec[Mode].SeparatorLen;
|
||||
ChanStart[2] = ChanStart[1] + ChanLen[1] + ModeSpec[Mode].SeparatorLen;
|
||||
break;
|
||||
|
||||
case R36:
|
||||
case R24:
|
||||
ChanLen[0] = ModeSpec[Mode].PixelLen * ModeSpec[Mode].ImgWidth * 2;
|
||||
|
@ -99,6 +88,15 @@ int GetVideo(int Mode, double Rate, int Skip, int Adaptive, int Redraw) {
|
|||
ChanStart[2] = ChanStart[1];
|
||||
break;
|
||||
|
||||
case S1:
|
||||
case S2:
|
||||
case SDX:
|
||||
ChanLen[0] = ChanLen[1] = ChanLen[2] = ModeSpec[Mode].PixelLen * ModeSpec[Mode].ImgWidth;
|
||||
ChanStart[0] = ModeSpec[Mode].SeparatorLen;
|
||||
ChanStart[1] = ChanStart[0] + ChanLen[0] + ModeSpec[Mode].SeparatorLen;
|
||||
ChanStart[2] = ChanStart[1] + ChanLen[1] + ModeSpec[Mode].SyncLen + ModeSpec[Mode].PorchLen;
|
||||
break;
|
||||
|
||||
default:
|
||||
ChanLen[0] = ChanLen[1] = ChanLen[2] = ModeSpec[Mode].PixelLen * ModeSpec[Mode].ImgWidth;
|
||||
ChanStart[0] = ModeSpec[Mode].SyncLen + ModeSpec[Mode].PorchLen;
|
||||
|
@ -141,7 +139,7 @@ int GetVideo(int Mode, double Rate, int Skip, int Adaptive, int Redraw) {
|
|||
} else {
|
||||
|
||||
// Read 2048 samples
|
||||
if (Sample >= PcmPointer - 2048) {
|
||||
if (Sample == 0 || Sample >= PcmPointer - 2048) {
|
||||
if (!PcmInStream || feof (PcmInStream) || PcmPointer > Length-2048) break;
|
||||
|
||||
samplesread = fread(PcmBuffer, 2, 2048, PcmInStream);
|
||||
|
@ -317,7 +315,7 @@ int GetVideo(int Mode, double Rate, int Skip, int Adaptive, int Redraw) {
|
|||
case PD180:
|
||||
case PD240:
|
||||
case PD290:
|
||||
if (CurLineTime >= ChanStart[2] + ChanLen[2]) Channel = 4; // ch 0 of even line
|
||||
if (CurLineTime >= ChanStart[2] + ChanLen[2]) Channel = 3; // ch 0 of even line
|
||||
else if (CurLineTime >= ChanStart[2]) Channel = 2;
|
||||
else if (CurLineTime >= ChanStart[1]) Channel = 1;
|
||||
else Channel = 0;
|
||||
|
@ -332,71 +330,18 @@ int GetVideo(int Mode, double Rate, int Skip, int Adaptive, int Redraw) {
|
|||
}
|
||||
|
||||
// X coordinate of this pixel
|
||||
switch(Mode) {
|
||||
|
||||
case S1:
|
||||
case S2:
|
||||
case SDX:
|
||||
x = fmod(CurLineTime - ModeSpec[Mode].SyncLen - ModeSpec[Mode].PorchLen, ChanLen[Channel] +
|
||||
ModeSpec[Mode].SeparatorLen) / ChanLen[Channel] * ModeSpec[Mode].ImgWidth;
|
||||
break;
|
||||
|
||||
default:
|
||||
x = (CurLineTime - ChanStart[Channel]) / ChanLen[Channel] * ModeSpec[Mode].ImgWidth;
|
||||
break;
|
||||
|
||||
}
|
||||
x = (CurLineTime - ChanStart[Channel]) / ChanLen[Channel] * ModeSpec[Mode].ImgWidth;
|
||||
|
||||
// Y coordinate of this pixel
|
||||
switch(Mode) {
|
||||
|
||||
case S1:
|
||||
case S2:
|
||||
case SDX:
|
||||
switch(Channel) {
|
||||
|
||||
case 0:
|
||||
y = LineNum;
|
||||
Channel = 2;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
y = LineNum + 1;
|
||||
Channel = 0;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
y = LineNum + 1;
|
||||
Channel = 1;
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case PD50:
|
||||
case PD90:
|
||||
case PD120:
|
||||
case PD160:
|
||||
case PD180:
|
||||
case PD240:
|
||||
case PD290:
|
||||
switch(Channel) {
|
||||
case 4:
|
||||
y = LineNum + 1;
|
||||
Channel = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
y = LineNum;
|
||||
break;
|
||||
|
||||
}
|
||||
switch(Channel) {
|
||||
case 3:
|
||||
y = LineNum + 1;
|
||||
Channel = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
y = LineNum;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// Luminance from frequency
|
||||
|
@ -454,9 +399,9 @@ int GetVideo(int Mode, double Rate, int Skip, int Adaptive, int Redraw) {
|
|||
}
|
||||
|
||||
if (!Redraw || LineNum % 5 == 0 || LineNum == ModeSpec[Mode].ImgHeight-1) {
|
||||
gdk_threads_enter();
|
||||
gtk_image_set_from_pixbuf(GTK_IMAGE(CamImage), CamPixbuf);
|
||||
gdk_threads_leave();
|
||||
gdk_threads_enter();
|
||||
gtk_image_set_from_pixbuf(GTK_IMAGE(CamImage), CamPixbuf);
|
||||
gdk_threads_leave();
|
||||
}
|
||||
}
|
||||
prevline = LineNum;
|
||||
|
|
16
vis.c
16
vis.c
|
@ -83,7 +83,7 @@ int GetVIS () {
|
|||
// Zero padding, if necessary
|
||||
for (i = 882; i < FFTLen; i++) in[i] = 0;
|
||||
|
||||
// FFT
|
||||
// FFT of last 20 ms
|
||||
fftw_execute(VISPlan);
|
||||
|
||||
MaxBin = 0;
|
||||
|
@ -101,14 +101,14 @@ int GetVIS () {
|
|||
HedrBuf[HedrPtr] = MaxBin + (log( Power[MaxBin + 1] / Power[MaxBin - 1] )) /
|
||||
(2 * log( pow(Power[MaxBin], 2) / (Power[MaxBin + 1] * Power[MaxBin - 1])));
|
||||
} else {
|
||||
HedrBuf[HedrPtr] = HedrBuf[(HedrPtr-1)%100];
|
||||
HedrBuf[HedrPtr] = HedrBuf[(HedrPtr-1)%50];
|
||||
}
|
||||
|
||||
// Header buffer holds 50 * 10 = 500 msec
|
||||
// Header buffer holds 50 * 10 msec = 500 msec
|
||||
HedrPtr = (HedrPtr + 1) % 50;
|
||||
|
||||
for (i = 0; i < 50; i++) {
|
||||
tone[i] = HedrBuf[(i + HedrPtr) % 50];
|
||||
tone[i] = HedrBuf[(HedrPtr + i) % 50];
|
||||
tone[i] = 1.0 * tone[i] / FFTLen * 44100;
|
||||
}
|
||||
|
||||
|
@ -186,8 +186,12 @@ int GetVIS () {
|
|||
|
||||
free(PCM);
|
||||
|
||||
// Skip 20 ms
|
||||
samplesread = fread(PcmBuffer, 2, 441*2, PcmInStream);
|
||||
// Skip 10 ms
|
||||
samplesread = fread(PcmBuffer, 2, 441, PcmInStream);
|
||||
|
||||
// In case of Scottie, skip another 9 ms
|
||||
if (VISmap[VIS] == S1 || VISmap[VIS] == S2 || VISmap[VIS] == SDX)
|
||||
samplesread = fread(PcmBuffer, 2, 397, PcmInStream);
|
||||
|
||||
if (feof(PcmInStream)) perror("unable to read from dsp");
|
||||
else if (VISmap[VIS] != UNKNOWN) return VISmap[VIS];
|
||||
|
|
Ładowanie…
Reference in New Issue