kopia lustrzana https://github.com/windytan/slowrx
reworked sync detection, now based on convolution etc
rodzic
83c10ffd0d
commit
2fccddba62
30
common.c
30
common.c
|
@ -58,6 +58,11 @@ double deg2rad (double Deg) {
|
|||
return (Deg / 180) * M_PI;
|
||||
}
|
||||
|
||||
// Convert radians -> degrees
|
||||
double rad2deg (double rad) {
|
||||
return (180 / M_PI) * rad;
|
||||
}
|
||||
|
||||
|
||||
/*** Gtk+ event handlers ***/
|
||||
|
||||
|
@ -126,3 +131,28 @@ void evt_clearPix() {
|
|||
gtk_label_set_markup (GTK_LABEL(gui.label_utc), "");
|
||||
gtk_label_set_markup (GTK_LABEL(gui.label_lastmode), "");
|
||||
}
|
||||
|
||||
// Manual slant adjust
|
||||
void evt_clickimg(GtkWidget *widget, GdkEventButton* event, GdkWindowEdge edge) {
|
||||
static double prevx=0,prevy=0;
|
||||
static bool secondpress=false;
|
||||
double dx,dy,a;
|
||||
|
||||
if (event->type == GDK_BUTTON_PRESS && event->button == 1 && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(gui.tog_setedge))) {
|
||||
if (secondpress) {
|
||||
printf(":) %.1f,%.1f -> %.1f,%.1f\n",prevx,prevy,event->x,event->y);
|
||||
dx = event->x - prevx;
|
||||
dy = event->y - prevy;
|
||||
a = rad2deg(M_PI/2 - asin(dx/sqrt(pow(dx,2) + pow(dy,2))));
|
||||
if (event->y < prevy) a = fabs(a-180);
|
||||
printf("%.3f\n",a);
|
||||
|
||||
secondpress=false;
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(gui.tog_setedge),false);
|
||||
} else {
|
||||
prevx = event->x;
|
||||
prevy = event->y;
|
||||
secondpress = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
4
common.h
4
common.h
|
@ -4,6 +4,7 @@
|
|||
#define MINSLANT 30
|
||||
#define MAXSLANT 150
|
||||
#define BUFLEN 4096
|
||||
#define SYNCPIXLEN 1.5e-3
|
||||
|
||||
extern bool Abort;
|
||||
extern bool Adaptive;
|
||||
|
@ -29,7 +30,9 @@ struct _GuiObjs {
|
|||
GtkWidget *combo_card;
|
||||
GtkWidget *combo_mode;
|
||||
GtkWidget *entry_picdir;
|
||||
GtkWidget *eventbox_img;
|
||||
GtkWidget *frame_manual;
|
||||
GtkWidget *frame_slant;
|
||||
GtkWidget *grid_vu;
|
||||
GtkWidget *iconview;
|
||||
GtkWidget *image_devstatus;
|
||||
|
@ -118,6 +121,7 @@ void evt_AbortRx ();
|
|||
void evt_changeDevices ();
|
||||
void evt_chooseDir ();
|
||||
void evt_clearPix ();
|
||||
void evt_clickimg ();
|
||||
void evt_deletewindow ();
|
||||
void evt_GetAdaptive ();
|
||||
void evt_ManualStart ();
|
||||
|
|
8
gui.c
8
gui.c
|
@ -23,7 +23,9 @@ void createGUI() {
|
|||
gui.combo_card = GTK_WIDGET(gtk_builder_get_object(builder,"combo_card"));
|
||||
gui.combo_mode = GTK_WIDGET(gtk_builder_get_object(builder,"combo_mode"));
|
||||
gui.entry_picdir = GTK_WIDGET(gtk_builder_get_object(builder,"entry_picdir"));
|
||||
gui.eventbox_img = GTK_WIDGET(gtk_builder_get_object(builder,"eventbox_img"));
|
||||
gui.frame_manual = GTK_WIDGET(gtk_builder_get_object(builder,"frame_manual"));
|
||||
gui.frame_slant = GTK_WIDGET(gtk_builder_get_object(builder,"frame_slant"));
|
||||
gui.grid_vu = GTK_WIDGET(gtk_builder_get_object(builder,"grid_vu"));
|
||||
gui.iconview = GTK_WIDGET(gtk_builder_get_object(builder,"SavedIconView"));
|
||||
gui.image_devstatus = GTK_WIDGET(gtk_builder_get_object(builder,"image_devstatus"));
|
||||
|
@ -51,6 +53,7 @@ void createGUI() {
|
|||
g_signal_connect (gui.button_clear, "clicked", G_CALLBACK(evt_clearPix), NULL);
|
||||
g_signal_connect (gui.button_start, "clicked", G_CALLBACK(evt_ManualStart), NULL);
|
||||
g_signal_connect (gui.combo_card, "changed", G_CALLBACK(evt_changeDevices), NULL);
|
||||
g_signal_connect (gui.eventbox_img, "button-press-event",G_CALLBACK(evt_clickimg), NULL);
|
||||
g_signal_connect (gui.menuitem_quit, "activate", G_CALLBACK(evt_deletewindow), NULL);
|
||||
g_signal_connect (gui.menuitem_about,"activate", G_CALLBACK(evt_show_about), NULL);
|
||||
g_signal_connect_swapped(gui.tog_adapt, "toggled", G_CALLBACK(evt_GetAdaptive), NULL);
|
||||
|
@ -87,7 +90,6 @@ void setVU (short int PcmValue, double SNRdB) {
|
|||
int PWRdB = (int)round(10 * log10(pow(PcmValue/32767.0,2)));
|
||||
guchar *pixelsPWR, *pixelsSNR, *pPWR, *pSNR;
|
||||
unsigned int rowstridePWR,rowstrideSNR;
|
||||
int SNRdBthresh[10] = {30, 15, 10, 5, 3, 0, -3, -5, -10, -15};
|
||||
|
||||
rowstridePWR = gdk_pixbuf_get_rowstride (pixbuf_PWR);
|
||||
pixelsPWR = gdk_pixbuf_get_pixels (pixbuf_PWR);
|
||||
|
@ -101,9 +103,7 @@ void setVU (short int PcmValue, double SNRdB) {
|
|||
pPWR = pixelsPWR + y * rowstridePWR + (99-x) * 3;
|
||||
pSNR = pixelsSNR + y * rowstrideSNR + (99-x) * 3;
|
||||
|
||||
if (y > 1 && y < 18 &&
|
||||
x % 10 > 1 && x % 10 < 9 &&
|
||||
x % 2 == 0 && y % 2 == 0) {
|
||||
if (y > 1 && y < 18 && x % 2 == 0) {
|
||||
|
||||
if (PWRdB >= -0.0075*pow(x,2)-3) {
|
||||
pPWR[0] = 0x89;
|
||||
|
|
12
slowrx.c
12
slowrx.c
|
@ -108,7 +108,7 @@ void *Listen() {
|
|||
}
|
||||
|
||||
// Allocate space for sync signal
|
||||
HasSync = calloc((int)(ModeSpec[Mode].LineLen * ModeSpec[Mode].ImgHeight / 1.5e-3 +1), sizeof(bool));
|
||||
HasSync = calloc((int)(ModeSpec[Mode].LineLen * ModeSpec[Mode].ImgHeight / SYNCPIXLEN +1), sizeof(bool));
|
||||
if (HasSync == NULL) {
|
||||
perror("Listen: Unable to allocate memory for sync signal");
|
||||
exit(EXIT_FAILURE);
|
||||
|
@ -119,9 +119,11 @@ void *Listen() {
|
|||
gdk_threads_enter ();
|
||||
gtk_label_set_text (GTK_LABEL(gui.label_fskid), "");
|
||||
gtk_widget_set_sensitive (gui.frame_manual, false);
|
||||
gtk_widget_set_sensitive (gui.frame_slant, false);
|
||||
gtk_widget_set_sensitive (gui.combo_card, false);
|
||||
gtk_widget_set_sensitive (gui.button_abort, true);
|
||||
gtk_widget_set_sensitive (gui.button_clear, false);
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(gui.tog_setedge), false);
|
||||
gtk_statusbar_push (GTK_STATUSBAR(gui.statusbar), 0, "Receiving video..." );
|
||||
gtk_label_set_markup (GTK_LABEL(gui.label_lastmode), ModeSpec[Mode].Name);
|
||||
gtk_label_set_markup (GTK_LABEL(gui.label_utc), rctime);
|
||||
|
@ -132,8 +134,6 @@ void *Listen() {
|
|||
|
||||
gdk_threads_enter ();
|
||||
gtk_widget_set_sensitive (gui.button_abort, false);
|
||||
gtk_widget_set_sensitive (gui.frame_manual, true);
|
||||
gtk_widget_set_sensitive (gui.combo_card, true);
|
||||
gdk_threads_leave ();
|
||||
|
||||
id[0] = '\0';
|
||||
|
@ -214,6 +214,12 @@ void *Listen() {
|
|||
free(StoredLum);
|
||||
StoredLum = NULL;
|
||||
|
||||
gdk_threads_enter ();
|
||||
gtk_widget_set_sensitive (gui.frame_slant, true);
|
||||
gtk_widget_set_sensitive (gui.frame_manual, true);
|
||||
gtk_widget_set_sensitive (gui.combo_card, true);
|
||||
gdk_threads_leave ();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
35
slowrx.ui
35
slowrx.ui
|
@ -8,6 +8,14 @@
|
|||
<property name="step_increment">10</property>
|
||||
<property name="page_increment">100</property>
|
||||
</object>
|
||||
<object class="GtkListStore" id="savedstore">
|
||||
<columns>
|
||||
<!-- column-name GdkPixbuf1 -->
|
||||
<column type="GdkPixbuf"/>
|
||||
<!-- column-name gchararray1 -->
|
||||
<column type="gchararray"/>
|
||||
</columns>
|
||||
</object>
|
||||
<object class="GtkWindow" id="window_main">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="title" translatable="yes">slowrx</property>
|
||||
|
@ -145,12 +153,20 @@
|
|||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="image_rx">
|
||||
<property name="width_request">500</property>
|
||||
<property name="height_request">375</property>
|
||||
<object class="GtkEventBox" id="eventbox_img">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-missing-image</property>
|
||||
<property name="events">GDK_BUTTON_PRESS_MASK | GDK_STRUCTURE_MASK</property>
|
||||
<property name="visible_window">False</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="image_rx">
|
||||
<property name="width_request">500</property>
|
||||
<property name="height_request">375</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-missing-image</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
|
@ -478,7 +494,7 @@
|
|||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="button_clear">
|
||||
<property name="label" translatable="yes">Clear</property>
|
||||
<property name="label" translatable="yes">Clear image</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">True</property>
|
||||
|
@ -530,7 +546,6 @@
|
|||
<child>
|
||||
<object class="GtkFrame" id="frame_slant">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label_xalign">0</property>
|
||||
<property name="shadow_type">in</property>
|
||||
|
@ -1102,12 +1117,4 @@
|
|||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkListStore" id="savedstore">
|
||||
<columns>
|
||||
<!-- column-name GdkPixbuf1 -->
|
||||
<column type="GdkPixbuf"/>
|
||||
<!-- column-name gchararray1 -->
|
||||
<column type="gchararray"/>
|
||||
</columns>
|
||||
</object>
|
||||
</interface>
|
||||
|
|
51
sync.c
51
sync.c
|
@ -19,25 +19,26 @@
|
|||
double FindSync (guchar Mode, double Rate, int *Skip) {
|
||||
|
||||
int LineWidth = ModeSpec[Mode].LineLen / ModeSpec[Mode].SyncLen * 4;
|
||||
int x,y,xmid,x0;
|
||||
int x,y;
|
||||
int q, d, qMost, dMost, s;
|
||||
gushort xAcc[700] = {0}, xmax;
|
||||
gushort xAcc[700] = {0};
|
||||
gushort lines[600][(MAXSLANT-MINSLANT)*2];
|
||||
gushort cy, cx, Retries = 0;
|
||||
bool SyncImg[700][630] = {{false}};
|
||||
double t=0, slantAngle;
|
||||
|
||||
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].ImgHeight; y++) {
|
||||
for (x=0; x<LineWidth; x++) {
|
||||
t = (y + 1.0*x/LineWidth) * ModeSpec[Mode].LineLen;
|
||||
// Center sync pulse horizontally
|
||||
if (y>0 || x>=LineWidth/2) SyncImg[x][y] = HasSync[ (int)( (t-ModeSpec[Mode].LineLen/2) / 1.5e-3 * Rate/44100) ];
|
||||
SyncImg[x][y] = HasSync[ (int)( t / SYNCPIXLEN * Rate/44100) ];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,35 +94,37 @@ double FindSync (guchar Mode, double Rate, int *Skip) {
|
|||
Retries ++;
|
||||
}
|
||||
|
||||
// find abscissa at higher resolution
|
||||
// accumulate a 1-dim array of the position of the sync pulse
|
||||
memset(xAcc, 0, sizeof(xAcc[0]) * 700);
|
||||
xmax = 0;
|
||||
|
||||
for (y=0; y<ModeSpec[Mode].ImgHeight; y++) {
|
||||
for (x=0; x<700; x++) {
|
||||
t = y * ModeSpec[Mode].LineLen + x/700.0 * ModeSpec[Mode].LineLen;
|
||||
xAcc[x] += HasSync[ (int)(t / 1.5e-3 * Rate/44100) ];
|
||||
if (xAcc[x] > xAcc[xmax]) xmax = x;
|
||||
xAcc[x] += HasSync[ (int)(t / SYNCPIXLEN * Rate/44100) ];
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// skip until the start of the sync pulse
|
||||
s = (xmid / 700.0 * ModeSpec[Mode].LineLen - ModeSpec[Mode].SyncLen/2) * Rate;
|
||||
// If pulse is on the right side, it just probably slipped out the left edge
|
||||
if (xmax > 350) xmax -= 350;
|
||||
|
||||
// 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 until the start of the line.
|
||||
// (Scottie modes don't start lines with sync)
|
||||
if (Mode == S1 || Mode == S2 || Mode == SDX) {
|
||||
s = (xmax / 700.0 * ModeSpec[Mode].LineLen - ModeSpec[Mode].SyncLen -
|
||||
2*ModeSpec[Mode].SeparatorLen - 2*ModeSpec[Mode].PixelLen*ModeSpec[Mode].ImgWidth)
|
||||
* Rate;
|
||||
} else {
|
||||
s = (xmax / 700.0 * ModeSpec[Mode].LineLen - ModeSpec[Mode].SyncLen) * Rate;
|
||||
}
|
||||
|
||||
*Skip = s;
|
||||
|
||||
|
|
17
video.c
17
video.c
|
@ -99,7 +99,7 @@ bool GetVideo(guchar Mode, double Rate, int Skip, bool Redraw) {
|
|||
|
||||
Length = ModeSpec[Mode].LineLen * ModeSpec[Mode].ImgHeight * 44100;
|
||||
SyncTargetBin = GetBin(1200+HedrShift, FFTLen);
|
||||
LopassBin = GetBin(3000, FFTLen);
|
||||
LopassBin = GetBin(5000, FFTLen);
|
||||
Abort = false;
|
||||
SyncSampleNum = 0;
|
||||
|
||||
|
@ -132,19 +132,22 @@ bool GetVideo(guchar Mode, double Rate, int Skip, bool Redraw) {
|
|||
fftw_execute(Plan1024);
|
||||
|
||||
for (i=0;i<LopassBin;i++) {
|
||||
Praw += pow(out[i], 2) + pow(out[FFTLen-i], 2);
|
||||
if (i >= SyncTargetBin-1 && i <= SyncTargetBin+1) Psync += pow(out[i], 2) + pow(out[FFTLen-i], 2);
|
||||
if (i >= GetBin(1500+HedrShift, FFTLen) && i <= GetBin(2300+HedrShift, FFTLen))
|
||||
Praw += pow(out[i], 2) + pow(out[FFTLen-i], 2);
|
||||
|
||||
if (i >= SyncTargetBin-1 && i <= SyncTargetBin+1)
|
||||
Psync += (pow(out[i], 2) + pow(out[FFTLen-i], 2)) * (1- .5*abs(SyncTargetBin-i));
|
||||
}
|
||||
|
||||
Praw /= (FFTLen/2.0) * ( LopassBin/(FFTLen/2.0));
|
||||
Psync /= 3.0;
|
||||
Praw /= (GetBin(2300+HedrShift, FFTLen) - GetBin(1500+HedrShift, FFTLen));
|
||||
Psync /= 2.0;
|
||||
|
||||
// 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
|
||||
// sync band than in the video band, we have a sync signal here
|
||||
if (Psync > 2*Praw) HasSync[SyncSampleNum] = true;
|
||||
else HasSync[SyncSampleNum] = false;
|
||||
|
||||
NextSyncTime += 1.5e-3;
|
||||
NextSyncTime += SYNCPIXLEN;
|
||||
SyncSampleNum ++;
|
||||
|
||||
}
|
||||
|
|
8
vis.c
8
vis.c
|
@ -171,10 +171,10 @@ guchar GetVIS () {
|
|||
PcmPointer += 20e-3 * 44100;
|
||||
|
||||
// In case of Scottie, skip first sync pulse
|
||||
if (VISmap[VIS] == S1 || VISmap[VIS] == S2 || VISmap[VIS] == SDX) {
|
||||
readPcm(9e-3 * 44100);
|
||||
PcmPointer += 9e-3 * 44100;
|
||||
}
|
||||
/*if (VISmap[VIS] == S1 || VISmap[VIS] == S2 || VISmap[VIS] == SDX) {
|
||||
readPcm(ModeSpec[VISmap[VIS]].SyncLen * 44100);
|
||||
PcmPointer += ModeSpec[VISmap[VIS]].SyncLen * 44100;
|
||||
}*/
|
||||
|
||||
if (VISmap[VIS] != UNKNOWN) return VISmap[VIS];
|
||||
else printf(" No VIS found\n");
|
||||
|
|
Ładowanie…
Reference in New Issue