kopia lustrzana https://github.com/windytan/slowrx
rodzic
657fd58940
commit
cf34bf5f45
|
@ -1,20 +1,3 @@
|
|||
slowrx
|
||||
rx
|
||||
rx-lum
|
||||
Makefile.in
|
||||
/autom4te.cache
|
||||
/aclocal.m4
|
||||
/compile
|
||||
/configure
|
||||
/depcomp
|
||||
/install-sh
|
||||
/missing
|
||||
/stamp-h1
|
||||
Makefile
|
||||
autoscan.log
|
||||
config.h
|
||||
config.h.in
|
||||
config.log
|
||||
config.status
|
||||
configure.scan
|
||||
.deps
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
AC_INIT([slowrx], [0.1], [oona@kapsi.fi])
|
||||
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
|
||||
AX_CXX_COMPILE_STDCXX_11()
|
||||
AC_PROG_CXX
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
src/uus/Makefile
|
||||
src/Makefile
|
||||
])
|
||||
PKG_CHECK_MODULES([GTKMM], [gtkmm-3.0 >= 3.8.0])
|
||||
AC_OUTPUT
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
bin_PROGRAMS = slowrx
|
||||
slowrx_CPPFLAGS = $(GTKMM_CFLAGS)
|
||||
slowrx_LDADD = $(GTKMM_LIBS)
|
||||
slowrx_SOURCES = slowrx.cc modespec.cc
|
||||
slowrx_SOURCES = slowrx.cc common.cc gui.cc fsk.cc modespec.cc pcm.cc sync.cc video.cc vis.cc
|
||||
|
|
113
src/common.h
113
src/common.h
|
@ -6,6 +6,15 @@
|
|||
#define BUFLEN 4096
|
||||
#define SYNCPIXLEN 1.5e-3
|
||||
|
||||
extern gboolean Abort;
|
||||
extern gboolean Adaptive;
|
||||
extern gboolean *HasSync;
|
||||
extern gboolean ManualActivated;
|
||||
extern gboolean ManualResync;
|
||||
extern guchar *StoredLum;
|
||||
extern pthread_t thread1;
|
||||
extern guchar VISmap[];
|
||||
|
||||
typedef struct _FFTStuff FFTStuff;
|
||||
struct _FFTStuff {
|
||||
double *in;
|
||||
|
@ -17,51 +26,49 @@ extern FFTStuff fft;
|
|||
|
||||
typedef struct _PcmData PcmData;
|
||||
struct _PcmData {
|
||||
// snd_pcm_t *handle;
|
||||
void *handle;
|
||||
snd_pcm_t *handle;
|
||||
gint16 *Buffer;
|
||||
int WindowPtr;
|
||||
gboolean BufferDrop;
|
||||
};
|
||||
//extern PcmData pcm;
|
||||
extern PcmData pcm;
|
||||
|
||||
typedef struct _GuiObjs GuiObjs;
|
||||
struct _GuiObjs {
|
||||
Gtk::Button *button_abort;
|
||||
Gtk::Button *button_browse;
|
||||
Gtk::Button *button_clear;
|
||||
Gtk::Button *button_start;
|
||||
Gtk::ComboBox *combo_card;
|
||||
Gtk::ComboBox *combo_mode;
|
||||
Gtk::Widget *entry_picdir;
|
||||
Gtk::Widget *eventbox_img;
|
||||
Gtk::Widget *frame_manual;
|
||||
Gtk::Widget *frame_slant;
|
||||
Gtk::Widget *grid_vu;
|
||||
Gtk::Widget *iconview;
|
||||
Gtk::Widget *image_devstatus;
|
||||
Gtk::Widget *image_pwr;
|
||||
Gtk::Widget *image_rx;
|
||||
Gtk::Widget *image_snr;
|
||||
Gtk::Label *label_fskid;
|
||||
Gtk::Label *label_lastmode;
|
||||
Gtk::Label *label_utc;
|
||||
Gtk::MenuItem *menuitem_about;
|
||||
Gtk::MenuItem *menuitem_quit;
|
||||
Gtk::SpinButton *spin_shift;
|
||||
Gtk::Widget *statusbar;
|
||||
Gtk::ToggleButton *tog_adapt;
|
||||
Gtk::ToggleButton *tog_fsk;
|
||||
Gtk::ToggleButton *tog_rx;
|
||||
Gtk::ToggleButton *tog_save;
|
||||
Gtk::ToggleButton *tog_setedge;
|
||||
Gtk::ToggleButton *tog_slant;
|
||||
Gtk::Window *window_about;
|
||||
Gtk::Window *window_main;
|
||||
GtkWidget *button_abort;
|
||||
GtkWidget *button_browse;
|
||||
GtkWidget *button_clear;
|
||||
GtkWidget *button_start;
|
||||
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;
|
||||
GtkWidget *image_pwr;
|
||||
GtkWidget *image_rx;
|
||||
GtkWidget *image_snr;
|
||||
GtkWidget *label_fskid;
|
||||
GtkWidget *label_lastmode;
|
||||
GtkWidget *label_utc;
|
||||
GtkWidget *menuitem_about;
|
||||
GtkWidget *menuitem_quit;
|
||||
GtkWidget *spin_shift;
|
||||
GtkWidget *statusbar;
|
||||
GtkWidget *tog_adapt;
|
||||
GtkWidget *tog_fsk;
|
||||
GtkWidget *tog_rx;
|
||||
GtkWidget *tog_save;
|
||||
GtkWidget *tog_setedge;
|
||||
GtkWidget *tog_slant;
|
||||
GtkWidget *window_about;
|
||||
GtkWidget *window_main;
|
||||
};
|
||||
extern GuiObjs gui;
|
||||
|
||||
/*
|
||||
extern GdkPixbuf *pixbuf_PWR;
|
||||
extern GdkPixbuf *pixbuf_SNR;
|
||||
extern GdkPixbuf *pixbuf_rx;
|
||||
|
@ -69,13 +76,13 @@ extern GdkPixbuf *pixbuf_disp;
|
|||
|
||||
extern GtkListStore *savedstore;
|
||||
|
||||
extern GKeyFile *config;*/
|
||||
extern GKeyFile *config;
|
||||
|
||||
|
||||
typedef struct _PicMeta PicMeta;
|
||||
struct _PicMeta {
|
||||
int HedrShift;
|
||||
int Mode;
|
||||
gshort HedrShift;
|
||||
guchar Mode;
|
||||
double Rate;
|
||||
int Skip;
|
||||
GdkPixbuf *thumbbuf;
|
||||
|
@ -100,36 +107,36 @@ enum {
|
|||
};
|
||||
|
||||
typedef struct ModeSpec {
|
||||
std::string Name;
|
||||
std::string ShortName;
|
||||
char *Name;
|
||||
char *ShortName;
|
||||
double SyncTime;
|
||||
double PorchTime;
|
||||
double SeptrTime;
|
||||
double PixelTime;
|
||||
double LineTime;
|
||||
int ImgWidth;
|
||||
int NumLines;
|
||||
int LineHeight;
|
||||
int ColorEnc;
|
||||
gushort ImgWidth;
|
||||
gushort NumLines;
|
||||
guchar LineHeight;
|
||||
guchar ColorEnc;
|
||||
} _ModeSpec;
|
||||
|
||||
extern _ModeSpec ModeSpec[];
|
||||
|
||||
double power (fftw_complex coeff);
|
||||
int clip (double a);
|
||||
double power (fftw_complex coeff);
|
||||
guchar clip (double a);
|
||||
void createGUI ();
|
||||
double deg2rad (double Deg);
|
||||
double FindSync (int Mode, double Rate, int *Skip);
|
||||
double FindSync (guchar Mode, double Rate, int *Skip);
|
||||
void GetFSK (char *dest);
|
||||
bool GetVideo (int Mode, double Rate, int Skip, bool Redraw);
|
||||
int GetVIS ();
|
||||
int GetBin (double Freq, int FFTLen);
|
||||
int initPcmDevice (char *);
|
||||
gboolean GetVideo (guchar Mode, double Rate, int Skip, gboolean Redraw);
|
||||
guchar GetVIS ();
|
||||
guint GetBin (double Freq, guint FFTLen);
|
||||
int initPcmDevice ();
|
||||
void *Listen ();
|
||||
void populateDeviceList ();
|
||||
void readPcm (int numsamples);
|
||||
void readPcm (gint numsamples);
|
||||
void saveCurrentPic();
|
||||
void setVU (double *Power, int FFTLen, int WinIdx, bool ShowWin);
|
||||
void setVU (double *Power, int FFTLen, int WinIdx, gboolean ShowWin);
|
||||
|
||||
void evt_AbortRx ();
|
||||
void evt_changeDevices ();
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
#include <gtkmm.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <alsa/asoundlib.h>
|
||||
|
||||
#include <fftw3.h>
|
||||
|
||||
|
|
265
src/slowrx.cc
265
src/slowrx.cc
|
@ -1,21 +1,256 @@
|
|||
#include <gtkmm.h>
|
||||
/*
|
||||
* slowrx - an SSTV decoder
|
||||
* * * * * * * * * * * * * *
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <alsa/asoundlib.h>
|
||||
|
||||
#include <fftw3.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
int startGui (int, char**);
|
||||
// The thread that listens to VIS headers and calls decoders etc
|
||||
void *Listen() {
|
||||
|
||||
char rctime[8];
|
||||
|
||||
guchar Mode=0;
|
||||
struct tm *timeptr = NULL;
|
||||
time_t timet;
|
||||
gboolean Finished;
|
||||
char id[20];
|
||||
GtkTreeIter iter;
|
||||
|
||||
while (TRUE) {
|
||||
|
||||
gdk_threads_enter ();
|
||||
gtk_widget_set_sensitive (gui.grid_vu, TRUE);
|
||||
gtk_widget_set_sensitive (gui.button_abort, FALSE);
|
||||
gtk_widget_set_sensitive (gui.button_clear, TRUE);
|
||||
gdk_threads_leave ();
|
||||
|
||||
pcm.WindowPtr = 0;
|
||||
snd_pcm_prepare(pcm.handle);
|
||||
snd_pcm_start (pcm.handle);
|
||||
Abort = FALSE;
|
||||
|
||||
do {
|
||||
|
||||
// Wait for VIS
|
||||
Mode = GetVIS();
|
||||
|
||||
// Stop listening on ALSA error
|
||||
if (Abort) pthread_exit(NULL);
|
||||
|
||||
// If manual resync was requested, redraw image
|
||||
if (ManualResync) {
|
||||
ManualResync = FALSE;
|
||||
snd_pcm_drop(pcm.handle);
|
||||
printf("getvideo at %.2f skip %d\n",CurrentPic.Rate,CurrentPic.Skip);
|
||||
GetVideo(CurrentPic.Mode, CurrentPic.Rate, CurrentPic.Skip, TRUE);
|
||||
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(gui.tog_save)))
|
||||
saveCurrentPic();
|
||||
pcm.WindowPtr = 0;
|
||||
snd_pcm_prepare(pcm.handle);
|
||||
snd_pcm_start (pcm.handle);
|
||||
}
|
||||
|
||||
} while (Mode == 0);
|
||||
|
||||
// Start reception
|
||||
|
||||
CurrentPic.Rate = 44100;
|
||||
CurrentPic.Mode = Mode;
|
||||
|
||||
printf(" ==== %s ====\n", ModeSpec[CurrentPic.Mode].Name);
|
||||
|
||||
// Store time of reception
|
||||
timet = time(NULL);
|
||||
timeptr = gmtime(&timet);
|
||||
strftime(CurrentPic.timestr, sizeof(CurrentPic.timestr)-1,"%Y%m%d-%H%M%Sz", timeptr);
|
||||
|
||||
|
||||
// Allocate space for cached Lum
|
||||
free(StoredLum);
|
||||
StoredLum = calloc( (int)((ModeSpec[CurrentPic.Mode].LineTime * ModeSpec[CurrentPic.Mode].NumLines + 1) * 44100), sizeof(guchar));
|
||||
if (StoredLum == NULL) {
|
||||
perror("Listen: Unable to allocate memory for Lum");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Allocate space for sync signal
|
||||
HasSync = calloc((int)(ModeSpec[CurrentPic.Mode].LineTime * ModeSpec[CurrentPic.Mode].NumLines / (13.0/44100) +1), sizeof(gboolean));
|
||||
if (HasSync == NULL) {
|
||||
perror("Listen: Unable to allocate memory for sync signal");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Get video
|
||||
strftime(rctime, sizeof(rctime)-1, "%H:%Mz", timeptr);
|
||||
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[CurrentPic.Mode].Name);
|
||||
gtk_label_set_markup (GTK_LABEL(gui.label_utc), rctime);
|
||||
gdk_threads_leave ();
|
||||
printf(" getvideo @ %.1f Hz, Skip %d, HedrShift %+d Hz\n", 44100.0, 0, CurrentPic.HedrShift);
|
||||
|
||||
Finished = GetVideo(CurrentPic.Mode, 44100, 0, FALSE);
|
||||
|
||||
gdk_threads_enter ();
|
||||
gtk_widget_set_sensitive (gui.button_abort, FALSE);
|
||||
gdk_threads_leave ();
|
||||
|
||||
id[0] = '\0';
|
||||
|
||||
if (Finished && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gui.tog_fsk))) {
|
||||
gdk_threads_enter ();
|
||||
gtk_statusbar_push (GTK_STATUSBAR(gui.statusbar), 0, "Receiving FSK ID..." );
|
||||
gdk_threads_leave ();
|
||||
GetFSK(id);
|
||||
printf(" FSKID \"%s\"\n",id);
|
||||
gdk_threads_enter ();
|
||||
gtk_label_set_text (GTK_LABEL(gui.label_fskid), id);
|
||||
gdk_threads_leave ();
|
||||
}
|
||||
|
||||
snd_pcm_drop(pcm.handle);
|
||||
|
||||
if (Finished && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gui.tog_slant))) {
|
||||
|
||||
// Fix slant
|
||||
//setVU(0,6);
|
||||
gdk_threads_enter ();
|
||||
gtk_statusbar_push (GTK_STATUSBAR(gui.statusbar), 0, "Calculating slant..." );
|
||||
gtk_widget_set_sensitive (gui.grid_vu, FALSE);
|
||||
gdk_threads_leave ();
|
||||
printf(" FindSync @ %.1f Hz\n",CurrentPic.Rate);
|
||||
CurrentPic.Rate = FindSync(CurrentPic.Mode, CurrentPic.Rate, &CurrentPic.Skip);
|
||||
|
||||
// Final image
|
||||
printf(" getvideo @ %.1f Hz, Skip %d, HedrShift %+d Hz\n", CurrentPic.Rate, CurrentPic.Skip, CurrentPic.HedrShift);
|
||||
GetVideo(CurrentPic.Mode, CurrentPic.Rate, CurrentPic.Skip, TRUE);
|
||||
}
|
||||
|
||||
free (HasSync);
|
||||
HasSync = NULL;
|
||||
|
||||
// Add thumbnail to iconview
|
||||
CurrentPic.thumbbuf = gdk_pixbuf_scale_simple (pixbuf_rx, 100,
|
||||
100.0/ModeSpec[CurrentPic.Mode].ImgWidth * ModeSpec[CurrentPic.Mode].NumLines * ModeSpec[CurrentPic.Mode].LineHeight, GDK_INTERP_HYPER);
|
||||
gdk_threads_enter ();
|
||||
gtk_list_store_prepend (savedstore, &iter);
|
||||
gtk_list_store_set (savedstore, &iter, 0, CurrentPic.thumbbuf, 1, id, -1);
|
||||
gdk_threads_leave ();
|
||||
|
||||
// Save PNG
|
||||
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(gui.tog_save))) {
|
||||
|
||||
//setVU(0,6);
|
||||
|
||||
/*ensure_dir_exists("rx-lum");
|
||||
LumFile = fopen(lumfilename,"w");
|
||||
if (LumFile == NULL)
|
||||
perror("Unable to open luma file for writing");
|
||||
fwrite(StoredLum,1,(ModeSpec[Mode].LineTime * ModeSpec[Mode].NumLines) * 44100,LumFile);
|
||||
fclose(LumFile);*/
|
||||
|
||||
saveCurrentPic();
|
||||
}
|
||||
|
||||
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 ();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* main
|
||||
*/
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return startGui(argc, argv);
|
||||
}
|
||||
|
||||
int startGui(int argc, char *argv[]) {
|
||||
Glib::RefPtr<Gtk::Application> app =
|
||||
Gtk::Application::create(argc, argv,
|
||||
"com.windytan.slowrx");
|
||||
|
||||
Glib::RefPtr<Gtk::Builder> builder = Gtk::Builder::create_from_file("ui/slowrx.ui");
|
||||
Gtk::Window *pWindow;
|
||||
builder->get_widget("window_main", pWindow);
|
||||
|
||||
return app->run(*pWindow);
|
||||
|
||||
FILE *ConfFile;
|
||||
const gchar *confdir;
|
||||
GString *confpath;
|
||||
gchar *confdata;
|
||||
gsize *keylen=NULL;
|
||||
|
||||
gtk_init (&argc, &argv);
|
||||
|
||||
gdk_threads_init ();
|
||||
|
||||
// Load config
|
||||
confdir = g_get_user_config_dir();
|
||||
confpath = g_string_new(confdir);
|
||||
g_string_append(confpath, "/slowrx.ini");
|
||||
|
||||
config = g_key_file_new();
|
||||
if (g_key_file_load_from_file(config, confpath->str, G_KEY_FILE_KEEP_COMMENTS, NULL)) {
|
||||
|
||||
} else {
|
||||
printf("No valid config file found\n");
|
||||
g_key_file_load_from_data(config, "[slowrx]\ndevice=default", -1, G_KEY_FILE_NONE, NULL);
|
||||
}
|
||||
|
||||
// Prepare FFT
|
||||
fft.in = fftw_alloc_real(2048);
|
||||
if (fft.in == NULL) {
|
||||
perror("GetVideo: Unable to allocate memory for FFT");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
fft.out = fftw_alloc_complex(2048);
|
||||
if (fft.out == NULL) {
|
||||
perror("GetVideo: Unable to allocate memory for FFT");
|
||||
fftw_free(fft.in);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
memset(fft.in, 0, sizeof(double) * 2048);
|
||||
|
||||
fft.Plan1024 = fftw_plan_dft_r2c_1d(1024, fft.in, fft.out, FFTW_ESTIMATE);
|
||||
fft.Plan2048 = fftw_plan_dft_r2c_1d(2048, fft.in, fft.out, FFTW_ESTIMATE);
|
||||
|
||||
createGUI();
|
||||
populateDeviceList();
|
||||
|
||||
gtk_main();
|
||||
|
||||
// Save config on exit
|
||||
ConfFile = fopen(confpath->str,"w");
|
||||
if (ConfFile == NULL) {
|
||||
perror("Unable to open config file for writing");
|
||||
} else {
|
||||
confdata = g_key_file_to_data(config,keylen,NULL);
|
||||
fprintf(ConfFile,"%s",confdata);
|
||||
fwrite(confdata,1,(size_t)keylen,ConfFile);
|
||||
fclose(ConfFile);
|
||||
}
|
||||
|
||||
g_object_unref(pixbuf_rx);
|
||||
free(StoredLum);
|
||||
fftw_free(fft.in);
|
||||
fftw_free(fft.out);
|
||||
|
||||
return (EXIT_SUCCESS);
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue