slowrx/common.c

216 wiersze
6.1 KiB
C
Czysty Zwykły widok Historia

2011-07-07 14:09:57 +00:00
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/stat.h>
#include <sys/types.h>
2011-07-07 14:09:57 +00:00
2011-07-29 20:09:42 +00:00
#include <gtk/gtk.h>
#include <alsa/asoundlib.h>
2012-12-25 20:43:26 +00:00
2011-08-16 21:29:38 +00:00
#include <fftw3.h>
2011-07-29 20:09:42 +00:00
2011-07-07 14:09:57 +00:00
#include "common.h"
2013-01-19 09:51:29 +00:00
gboolean Abort = FALSE;
gboolean Adaptive = TRUE;
gboolean *HasSync = NULL;
2011-08-11 11:48:35 +00:00
gshort HedrShift = 0;
2013-01-19 09:51:29 +00:00
gboolean ManualActivated = FALSE;
gboolean ManualResync = FALSE;
guchar *StoredLum = NULL;
2011-08-08 21:36:47 +00:00
2013-01-09 19:02:41 +00:00
pthread_t thread1;
FFTStuff fft;
2013-01-09 19:46:39 +00:00
GuiObjs gui;
PicMeta CurrentPic;
PcmData pcm;
2013-01-09 19:46:39 +00:00
GdkPixbuf *pixbuf_rx = NULL;
GdkPixbuf *pixbuf_disp = NULL;
GdkPixbuf *pixbuf_PWR = NULL;
GdkPixbuf *pixbuf_SNR = NULL;
2011-08-13 12:26:49 +00:00
GtkListStore *savedstore = NULL;
GKeyFile *config = NULL;
2013-01-09 19:02:41 +00:00
2011-08-20 05:51:27 +00:00
// Return the FFT bin index matching the given frequency
guint GetBin (double Freq, guint FFTLen) {
2011-08-16 21:29:38 +00:00
return (Freq / 44100 * FFTLen);
2011-07-07 14:09:57 +00:00
}
// Sinusoid power from complex DFT coefficients
double power (fftw_complex coeff) {
return pow(coeff[0],2) + pow(coeff[1],2);
}
2011-07-07 14:09:57 +00:00
// Clip to [0..255]
2011-08-11 11:48:35 +00:00
guchar clip (double a) {
2011-07-07 14:09:57 +00:00
if (a < 0) return 0;
else if (a > 255) return 255;
2011-08-20 05:51:27 +00:00
return (guchar)round(a);
2011-07-07 14:09:57 +00:00
}
2011-08-12 09:33:49 +00:00
// Convert degrees -> radians
2011-07-07 14:09:57 +00:00
double deg2rad (double Deg) {
2011-08-10 20:43:17 +00:00
return (Deg / 180) * M_PI;
2011-07-07 14:09:57 +00:00
}
2011-08-02 23:42:56 +00:00
// Convert radians -> degrees
double rad2deg (double rad) {
return (180 / M_PI) * rad;
}
void ensure_dir_exists(const char *dir) {
struct stat buf;
int i = stat(dir, &buf);
if (i != 0) {
if (mkdir(dir, 0777) != 0) {
perror("Unable to create directory for output file");
exit(EXIT_FAILURE);
}
}
}
// Save current picture as PNG
void saveCurrentPic() {
GdkPixbuf *scaledpb;
GString *pngfilename;
pngfilename = g_string_new(g_key_file_get_string(config,"slowrx","rxdir",NULL));
g_string_append_printf(pngfilename, "/%s_%s.png", CurrentPic.timestr, ModeSpec[CurrentPic.Mode].ShortName);
printf(" Saving to %s\n", pngfilename->str);
scaledpb = gdk_pixbuf_scale_simple (pixbuf_rx, ModeSpec[CurrentPic.Mode].ImgWidth,
ModeSpec[CurrentPic.Mode].NumLines * ModeSpec[CurrentPic.Mode].LineHeight, GDK_INTERP_HYPER);
ensure_dir_exists(g_key_file_get_string(config,"slowrx","rxdir",NULL));
gdk_pixbuf_savev(scaledpb, pngfilename->str, "png", NULL, NULL, NULL);
g_object_unref(scaledpb);
2013-01-19 09:51:29 +00:00
g_string_free(pngfilename, TRUE);
}
/*** Gtk+ event handlers ***/
2011-08-12 09:33:49 +00:00
// Quit
void evt_deletewindow() {
2011-08-02 23:42:56 +00:00
gtk_main_quit ();
}
2011-08-10 20:43:17 +00:00
2011-08-12 09:33:49 +00:00
// Transform the NoiseAdapt toggle state into a variable
void evt_GetAdaptive() {
Adaptive = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(gui.tog_adapt));
2011-08-10 20:43:17 +00:00
}
2011-08-12 09:33:49 +00:00
// Manual Start clicked
void evt_ManualStart() {
2013-01-19 09:51:29 +00:00
ManualActivated = TRUE;
2011-08-11 11:48:35 +00:00
}
2013-01-09 19:02:41 +00:00
// Abort clicked during rx
void evt_AbortRx() {
2013-01-19 09:51:29 +00:00
Abort = TRUE;
2011-08-10 20:43:17 +00:00
}
2013-01-09 19:02:41 +00:00
// Another device selected from list
void evt_changeDevices() {
2013-01-09 19:02:41 +00:00
int status;
2013-01-19 09:51:29 +00:00
pcm.BufferDrop = FALSE;
Abort = TRUE;
2013-01-09 19:02:41 +00:00
2015-02-13 09:59:01 +00:00
static int init;
if (init)
pthread_join(thread1, NULL);
init = 1;
2013-01-09 19:02:41 +00:00
if (pcm.handle != NULL) snd_pcm_close(pcm.handle);
2013-01-09 19:02:41 +00:00
status = initPcmDevice(gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(gui.combo_card)));
2013-01-09 19:02:41 +00:00
switch(status) {
case 0:
gtk_image_set_from_stock(GTK_IMAGE(gui.image_devstatus),GTK_STOCK_YES,GTK_ICON_SIZE_SMALL_TOOLBAR);
gtk_widget_set_tooltip_text(gui.image_devstatus, "Device successfully opened");
2013-01-09 19:02:41 +00:00
break;
case -1:
gtk_image_set_from_stock(GTK_IMAGE(gui.image_devstatus),GTK_STOCK_DIALOG_WARNING,GTK_ICON_SIZE_SMALL_TOOLBAR);
gtk_widget_set_tooltip_text(gui.image_devstatus, "Device was opened, but doesn't support 44100 Hz");
2013-01-09 19:02:41 +00:00
break;
case -2:
gtk_image_set_from_stock(GTK_IMAGE(gui.image_devstatus),GTK_STOCK_DIALOG_ERROR,GTK_ICON_SIZE_SMALL_TOOLBAR);
gtk_widget_set_tooltip_text(gui.image_devstatus, "Failed to open device");
2013-01-09 19:02:41 +00:00
break;
}
g_key_file_set_string(config,"slowrx","device",gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(gui.combo_card)));
2013-01-09 19:02:41 +00:00
pthread_create (&thread1, NULL, Listen, NULL);
}
2013-01-13 18:49:42 +00:00
// Clear received picture & metadata
void evt_clearPix() {
2013-01-13 19:52:31 +00:00
gdk_pixbuf_fill (pixbuf_disp, 0);
gtk_image_set_from_pixbuf(GTK_IMAGE(gui.image_rx), pixbuf_disp);
gtk_label_set_markup (GTK_LABEL(gui.label_fskid), "");
gtk_label_set_markup (GTK_LABEL(gui.label_utc), "");
gtk_label_set_markup (GTK_LABEL(gui.label_lastmode), "");
2013-01-13 18:49:42 +00:00
}
// Manual slant adjust
void evt_clickimg(GtkWidget *widget, GdkEventButton* event, GdkWindowEdge edge) {
static double prevx=0,prevy=0,newrate;
2013-01-19 09:51:29 +00:00
static gboolean secondpress=FALSE;
double x,y,dx,dy,xic;
(void)widget;
(void)edge;
if (event->type == GDK_BUTTON_PRESS && event->button == 1 && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(gui.tog_setedge))) {
x = event->x * (ModeSpec[CurrentPic.Mode].ImgWidth / 500.0);
y = event->y * (ModeSpec[CurrentPic.Mode].ImgWidth / 500.0) / ModeSpec[CurrentPic.Mode].LineHeight;
if (secondpress) {
2013-01-19 09:51:29 +00:00
secondpress=FALSE;
dx = x - prevx;
dy = y - prevy;
2013-01-19 09:51:29 +00:00
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(gui.tog_setedge),FALSE);
// Adjust sample rate, if in sensible limits
2015-07-17 07:43:32 +00:00
newrate = CurrentPic.Rate + CurrentPic.Rate * (dx * ModeSpec[CurrentPic.Mode].PixelTime) / (dy * ModeSpec[CurrentPic.Mode].LineHeight * ModeSpec[CurrentPic.Mode].LineTime);
if (newrate > 32000 && newrate < 56000) {
CurrentPic.Rate = newrate;
// Find x-intercept and adjust skip
xic = fmod( (x - (y / (dy/dx))), ModeSpec[CurrentPic.Mode].ImgWidth);
if (xic < 0) xic = ModeSpec[CurrentPic.Mode].ImgWidth - xic;
2015-07-17 07:43:32 +00:00
CurrentPic.Skip = fmod(CurrentPic.Skip + xic * ModeSpec[CurrentPic.Mode].PixelTime * CurrentPic.Rate,
ModeSpec[CurrentPic.Mode].LineTime * CurrentPic.Rate);
if (CurrentPic.Skip > ModeSpec[CurrentPic.Mode].LineTime * CurrentPic.Rate / 2.0)
CurrentPic.Skip -= ModeSpec[CurrentPic.Mode].LineTime * CurrentPic.Rate;
// Signal the listener to exit from GetVIS() and re-process the pic
2013-01-19 09:51:29 +00:00
ManualResync = TRUE;
}
} else {
2013-01-19 09:51:29 +00:00
secondpress = TRUE;
prevx = x;
prevy = y;
}
} else {
2013-01-19 09:51:29 +00:00
secondpress=FALSE;
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(gui.tog_setedge), FALSE);
}
}