From 2fccddba626833278a4a3891a1a98855e57dbd63 Mon Sep 17 00:00:00 2001 From: Oona Date: Mon, 14 Jan 2013 23:21:15 +0200 Subject: [PATCH] reworked sync detection, now based on convolution etc --- common.c | 30 ++++++++++++++++++++++++++++++ common.h | 4 ++++ gui.c | 8 ++++---- slowrx.c | 12 +++++++++--- slowrx.ui | 35 +++++++++++++++++++++-------------- sync.c | 51 +++++++++++++++++++++++++++------------------------ video.c | 17 ++++++++++------- vis.c | 8 ++++---- 8 files changed, 109 insertions(+), 56 deletions(-) diff --git a/common.c b/common.c index cf4f2c1..d789d30 100644 --- a/common.c +++ b/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; + } + } +} diff --git a/common.h b/common.h index 165fafc..39011e7 100644 --- a/common.h +++ b/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 (); diff --git a/gui.c b/gui.c index 8b12c69..d29a173 100644 --- a/gui.c +++ b/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; diff --git a/slowrx.c b/slowrx.c index ab93a15..37564a7 100644 --- a/slowrx.c +++ b/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 (); + } } diff --git a/slowrx.ui b/slowrx.ui index 5fccfec..fc5bcc8 100644 --- a/slowrx.ui +++ b/slowrx.ui @@ -8,6 +8,14 @@ 10 100 + + + + + + + + False slowrx @@ -145,12 +153,20 @@ False vertical - - 500 - 375 + True False - gtk-missing-image + GDK_BUTTON_PRESS_MASK | GDK_STRUCTURE_MASK + False + + + 500 + 375 + True + False + gtk-missing-image + + False @@ -478,7 +494,7 @@ - Clear + Clear image True False True @@ -530,7 +546,6 @@ True - False False 0 in @@ -1102,12 +1117,4 @@ - - - - - - - - diff --git a/sync.c b/sync.c index d0845f3..37c1081 100644 --- a/sync.c +++ b/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; y0 || 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 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; diff --git a/video.c b/video.c index 98dd763..bad10de 100644 --- a/video.c +++ b/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= 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 ++; } diff --git a/vis.c b/vis.c index b7f103f..5e15fb4 100644 --- a/vis.c +++ b/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");