slowrx/common.c

218 wiersze
6.2 KiB
C
Czysty Zwykły widok Historia

2011-07-07 14:09:57 +00:00
#include <stdio.h>
#include <stdlib.h>
2011-08-20 11:49:29 +00:00
#include <stdbool.h>
2011-07-07 14:09:57 +00:00
#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"
bool Abort = false;
bool Adaptive = true;
bool BufferDrop = false;
2011-08-16 21:29:38 +00:00
double *in = NULL;
bool *HasSync = NULL;
2011-08-11 11:48:35 +00:00
gshort HedrShift = 0;
2011-08-20 11:49:29 +00:00
bool ManualActivated = false;
bool ManualResync = false;
int MaxPcm = 0;
double *out = NULL;
gint16 *PcmBuffer = NULL;
int PcmPointer = 0;
guchar *StoredLum = NULL;
2011-08-08 21:36:47 +00:00
2013-01-09 19:02:41 +00:00
pthread_t thread1;
2013-01-09 19:46:39 +00:00
GuiObjs gui;
PicMeta CurrentPic;
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-08 21:36:47 +00:00
snd_pcm_t *pcm_handle = NULL;
2011-07-29 20:09:42 +00:00
2011-08-16 21:29:38 +00:00
fftw_plan Plan1024 = NULL;
fftw_plan Plan2048 = NULL;
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
}
// 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].ImgHeight * ModeSpec[CurrentPic.Mode].YScale, 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);
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() {
2011-08-20 11:49: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() {
2011-08-20 11:49: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;
BufferDrop = false;
2013-01-09 19:02:41 +00:00
Abort = true;
pthread_join(thread1, NULL);
if (pcm_handle != NULL) snd_pcm_close(pcm_handle);
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;
static bool 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].YScale;
if (secondpress) {
secondpress=false;
dx = x - prevx;
dy = y - prevy;
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(gui.tog_setedge),false);
// Adjust sample rate, if in sensible limits
newrate = CurrentPic.Rate + CurrentPic.Rate * (dx * ModeSpec[CurrentPic.Mode].PixelLen) / (dy * ModeSpec[CurrentPic.Mode].YScale * ModeSpec[CurrentPic.Mode].LineLen);
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;
CurrentPic.Skip = fmod(CurrentPic.Skip + xic * ModeSpec[CurrentPic.Mode].PixelLen * CurrentPic.Rate,
ModeSpec[CurrentPic.Mode].LineLen * CurrentPic.Rate);
if (CurrentPic.Skip > ModeSpec[CurrentPic.Mode].LineLen * CurrentPic.Rate / 2.0)
CurrentPic.Skip -= ModeSpec[CurrentPic.Mode].LineLen * CurrentPic.Rate;
// Signal the listener to exit from GetVIS() and re-process the pic
ManualResync = true;
}
} else {
secondpress = true;
prevx = x;
prevy = y;
}
} else {
secondpress=false;
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(gui.tog_setedge), false);
}
}