working manual slant adjustment; CurrentPic struct; etc

pull/5/head
Oona 2013-01-17 08:44:38 +02:00
rodzic 2fccddba62
commit 0ad0414c41
11 zmienionych plików z 204 dodań i 153 usunięć

111
common.c
Wyświetl plik

@ -2,6 +2,8 @@
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <gtk/gtk.h>
#include <alsa/asoundlib.h>
@ -10,31 +12,33 @@
#include "common.h"
bool Abort = false;
bool Adaptive = true;
bool BufferDrop = false;
double *in = NULL;
bool *HasSync = NULL;
gshort HedrShift = 0;
bool ManualActivated = false;
bool ManualResync = false;
int MaxPcm = 0;
double *out = NULL;
gint16 *PcmBuffer = NULL;
int PcmPointer = 0;
int MaxPcm = 0;
guchar *StoredLum = NULL;
bool *HasSync = NULL;
double *in = NULL;
double *out = NULL;
gshort HedrShift = 0;
bool Adaptive = true;
bool ManualActivated = false;
bool Abort = false;
bool BufferDrop = false;
pthread_t thread1;
GuiObjs gui;
PicMeta CurrentPic;
GdkPixbuf *pixbuf_rx = NULL;
GdkPixbuf *pixbuf_disp = NULL;
GdkPixbuf *pixbuf_PWR = NULL;
GdkPixbuf *pixbuf_SNR = NULL;
GdkPixbuf *pixbuf_rx = NULL;
GdkPixbuf *pixbuf_disp = NULL;
GdkPixbuf *pixbuf_PWR = NULL;
GdkPixbuf *pixbuf_SNR = NULL;
GtkListStore *savedstore = NULL;
GKeyFile *keyfile = NULL;
GKeyFile *config = NULL;
snd_pcm_t *pcm_handle = NULL;
@ -63,6 +67,36 @@ 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 ***/
@ -117,7 +151,7 @@ void evt_changeDevices() {
break;
}
g_key_file_set_string(keyfile,"slowrx","device",gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(gui.combo_card)));
g_key_file_set_string(config,"slowrx","device",gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(gui.combo_card)));
pthread_create (&thread1, NULL, Listen, NULL);
@ -134,25 +168,50 @@ void evt_clearPix() {
// Manual slant adjust
void evt_clickimg(GtkWidget *widget, GdkEventButton* event, GdkWindowEdge edge) {
static double prevx=0,prevy=0;
static double prevx=0,prevy=0,newrate;
static bool secondpress=false;
double dx,dy,a;
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))) {
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);
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 {
prevx = event->x;
prevy = event->y;
secondpress = true;
prevx = x;
prevy = y;
}
} else {
secondpress=false;
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(gui.tog_setedge), false);
}
}

Wyświetl plik

@ -10,9 +10,9 @@ extern bool Abort;
extern bool Adaptive;
extern bool BufferDrop;
extern bool *HasSync;
extern gshort HedrShift;
extern double *in;
extern bool ManualActivated;
extern bool ManualResync;
extern int MaxPcm;
extern double *out;
extern gint16 *PcmBuffer;
@ -64,13 +64,25 @@ extern GdkPixbuf *pixbuf_disp;
extern GtkListStore *savedstore;
extern GKeyFile *keyfile;
extern GKeyFile *config;
extern snd_pcm_t *pcm_handle;
extern fftw_plan Plan1024;
extern fftw_plan Plan2048;
typedef struct _PicMeta PicMeta;
struct _PicMeta {
gshort HedrShift;
guchar Mode;
double Rate;
int Skip;
GdkPixbuf *thumbbuf;
char timestr[40];
};
extern PicMeta CurrentPic;
// SSTV modes
enum {
UNKNOWN=0,
@ -87,7 +99,7 @@ enum {
GBR, RGB, YUV, BW
};
typedef struct ModeSpecDef {
typedef struct ModeSpec {
char *Name;
char *ShortName;
double SyncLen;
@ -99,9 +111,9 @@ typedef struct ModeSpecDef {
gushort ImgHeight;
guchar YScale;
guchar ColorEnc;
} ModeSpecDef;
} _ModeSpec;
extern ModeSpecDef ModeSpec[];
extern _ModeSpec ModeSpec[];
guchar clip (double a);
void createGUI ();
@ -115,6 +127,7 @@ int initPcmDevice ();
void *Listen ();
void populateDeviceList ();
void readPcm (gint numsamples);
void saveCurrentPic();
void setVU (short int PcmValue, double SNRdB);
void evt_AbortRx ();

6
fsk.c
Wyświetl plik

@ -54,9 +54,9 @@ void GetFSK (char *dest) {
// FFT of last 22 ms
fftw_execute(Plan2048);
LoBin = GetBin(1900+HedrShift, FFTLen)-1;
MidBin = GetBin(2000+HedrShift, FFTLen);
HiBin = GetBin(2100+HedrShift, FFTLen)+1;
LoBin = GetBin(1900+CurrentPic.HedrShift, FFTLen)-1;
MidBin = GetBin(2000+CurrentPic.HedrShift, FFTLen);
HiBin = GetBin(2100+CurrentPic.HedrShift, FFTLen)+1;
LoPow = 0;
HiPow = 0;

10
gui.c
Wyświetl plik

@ -71,11 +71,11 @@ void createGUI() {
gtk_combo_box_set_active(GTK_COMBO_BOX(gui.combo_mode), 0);
if (g_key_file_get_string(keyfile,"slowrx","rxdir",NULL) != NULL) {
gtk_entry_set_text(GTK_ENTRY(gui.entry_picdir),g_key_file_get_string(keyfile,"slowrx","rxdir",NULL));
if (g_key_file_get_string(config,"slowrx","rxdir",NULL) != NULL) {
gtk_entry_set_text(GTK_ENTRY(gui.entry_picdir),g_key_file_get_string(config,"slowrx","rxdir",NULL));
} else {
g_key_file_set_string(keyfile,"slowrx","rxdir",g_get_home_dir());
gtk_entry_set_text(GTK_ENTRY(gui.entry_picdir),g_key_file_get_string(keyfile,"slowrx","rxdir",NULL));
g_key_file_set_string(config,"slowrx","rxdir",g_get_home_dir());
gtk_entry_set_text(GTK_ENTRY(gui.entry_picdir),g_key_file_get_string(config,"slowrx","rxdir",NULL));
}
setVU(0, -100);
@ -146,7 +146,7 @@ void evt_chooseDir() {
NULL);
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
g_key_file_set_string(keyfile,"slowrx","rxdir",gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)));
g_key_file_set_string(config,"slowrx","rxdir",gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)));
gtk_entry_set_text(GTK_ENTRY(gui.entry_picdir),gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)));
}

Wyświetl plik

@ -36,7 +36,7 @@
* <http://www.tima.com/~djones/line.txt>
*/
ModeSpecDef ModeSpec[] = {
_ModeSpec ModeSpec[] = {
[M1] = { // N7CXI, 2000
.Name = "Martin M1",

2
pcm.c
Wyświetl plik

@ -83,7 +83,7 @@ void populateDeviceList() {
snd_card_get_name(card,&cardname);
gdk_threads_enter();
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(gui.combo_card), cardname);
if (strcmp(cardname,g_key_file_get_string(keyfile,"slowrx","device",NULL)) == 0)
if (strcmp(cardname,g_key_file_get_string(config,"slowrx","device",NULL)) == 0)
gtk_combo_box_set_active(GTK_COMBO_BOX(gui.combo_card), row);
gdk_threads_leave();

153
slowrx.c
Wyświetl plik

@ -21,52 +21,18 @@
#include "common.h"
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);
}
}
}
// The thread that listens to VIS headers and calls decoders etc
void *Listen() {
int Skip = 0;
char timestr[40], rctime[8];
GString *pngfilename;
char rctime[8];
guchar Mode=0;
double Rate;
struct tm *timeptr = NULL;
time_t timet;
bool Finished;
GdkPixbuf *thumbbuf;
char id[20];
GtkTreeIter iter;
/** Prepare FFT **/
in = fftw_malloc(sizeof(double) * 2048);
if (in == NULL) {
perror("GetVideo: Unable to allocate memory for FFT");
exit(EXIT_FAILURE);
}
out = fftw_malloc(sizeof(double) * 2048);
if (out == NULL) {
perror("GetVideo: Unable to allocate memory for FFT");
fftw_free(in);
exit(EXIT_FAILURE);
}
memset(in, 0, sizeof(double) * 2048);
memset(out, 0, sizeof(double) * 2048);
Plan1024 = fftw_plan_r2r_1d(1024, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
Plan2048 = fftw_plan_r2r_1d(2048, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
while (true) {
gdk_threads_enter ();
@ -75,12 +41,10 @@ void *Listen() {
gtk_widget_set_sensitive (gui.button_clear, true);
gdk_threads_leave ();
HedrShift = 0;
PcmPointer = 0;
Rate = 44100;
snd_pcm_prepare(pcm_handle);
snd_pcm_start (pcm_handle);
Abort = false;
Abort = false;
do {
@ -90,25 +54,44 @@ void *Listen() {
// 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();
PcmPointer = 0;
snd_pcm_prepare(pcm_handle);
snd_pcm_start (pcm_handle);
}
} while (Mode == 0);
printf(" ==== %s ====\n", ModeSpec[Mode].Name);
// 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(timestr, sizeof(timestr)-1,"%Y%m%d-%H%M%Sz", timeptr);
strftime(CurrentPic.timestr, sizeof(CurrentPic.timestr)-1,"%Y%m%d-%H%M%Sz", timeptr);
// Allocate space for cached Lum
StoredLum = calloc( (int)(ModeSpec[Mode].LineLen * ModeSpec[Mode].ImgHeight + 1) * 44100, sizeof(guchar));
free(StoredLum);
StoredLum = calloc( (int)(ModeSpec[CurrentPic.Mode].LineLen * ModeSpec[CurrentPic.Mode].ImgHeight + 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[Mode].LineLen * ModeSpec[Mode].ImgHeight / SYNCPIXLEN +1), sizeof(bool));
HasSync = calloc((int)(ModeSpec[CurrentPic.Mode].LineLen * ModeSpec[CurrentPic.Mode].ImgHeight / SYNCPIXLEN +1), sizeof(bool));
if (HasSync == NULL) {
perror("Listen: Unable to allocate memory for sync signal");
exit(EXIT_FAILURE);
@ -125,12 +108,12 @@ void *Listen() {
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_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, HedrShift);
printf(" getvideo @ %.1f Hz, Skip %d, HedrShift %+d Hz\n", 44100.0, 0, CurrentPic.HedrShift);
Finished = GetVideo(Mode, 44100, 0, false);
Finished = GetVideo(CurrentPic.Mode, 44100, 0, false);
gdk_threads_enter ();
gtk_widget_set_sensitive (gui.button_abort, false);
@ -159,38 +142,28 @@ void *Listen() {
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",Rate);
Rate = FindSync(Mode, Rate, &Skip);
printf(" FindSync @ %.1f Hz\n",CurrentPic.Rate);
CurrentPic.Rate = FindSync(CurrentPic.Mode, CurrentPic.Rate, &CurrentPic.Skip);
// Final image
gdk_threads_enter ();
gtk_statusbar_push (GTK_STATUSBAR(gui.statusbar), 0, "Redrawing..." );
gdk_threads_leave ();
printf(" getvideo @ %.1f Hz, Skip %d, HedrShift %+d Hz\n", Rate, Skip, HedrShift);
GetVideo(Mode, Rate, Skip, true);
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
thumbbuf = gdk_pixbuf_scale_simple (pixbuf_rx, 100,
100.0/ModeSpec[Mode].ImgWidth * ModeSpec[Mode].ImgHeight * ModeSpec[Mode].YScale, GDK_INTERP_HYPER);
CurrentPic.thumbbuf = gdk_pixbuf_scale_simple (pixbuf_rx, 100,
100.0/ModeSpec[CurrentPic.Mode].ImgWidth * ModeSpec[CurrentPic.Mode].ImgHeight * ModeSpec[CurrentPic.Mode].YScale, GDK_INTERP_HYPER);
gdk_threads_enter ();
gtk_list_store_prepend (savedstore, &iter);
gtk_list_store_set (savedstore, &iter, 0, thumbbuf, 1, id, -1);
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))) {
pngfilename = g_string_new(g_key_file_get_string(keyfile,"slowrx","rxdir",NULL));
g_string_append_printf(pngfilename, "/%s_%s.png", timestr, ModeSpec[Mode].ShortName);
printf(" Saving to %s\n", pngfilename->str);
gdk_threads_enter ();
gtk_statusbar_push (GTK_STATUSBAR(gui.statusbar), 0, "Saving..." );
gdk_threads_leave ();
setVU(0,-100);
/*ensure_dir_exists("rx-lum");
@ -200,20 +173,9 @@ void *Listen() {
fwrite(StoredLum,1,(ModeSpec[Mode].LineLen * ModeSpec[Mode].ImgHeight) * 44100,LumFile);
fclose(LumFile);*/
// Save the received image as PNG
GdkPixbuf *scaledpb;
scaledpb = gdk_pixbuf_scale_simple (pixbuf_rx, ModeSpec[Mode].ImgWidth,
ModeSpec[Mode].ImgHeight * ModeSpec[Mode].YScale, GDK_INTERP_HYPER);
ensure_dir_exists(g_key_file_get_string(keyfile,"slowrx","rxdir",NULL));
gdk_pixbuf_savev(scaledpb, pngfilename->str, "png", NULL, NULL, NULL);
g_object_unref(scaledpb);
g_string_free(pngfilename, true);
saveCurrentPic();
}
free(StoredLum);
StoredLum = NULL;
gdk_threads_enter ();
gtk_widget_set_sensitive (gui.frame_slant, true);
gtk_widget_set_sensitive (gui.frame_manual, true);
@ -245,14 +207,32 @@ int main(int argc, char *argv[]) {
confpath = g_string_new(confdir);
g_string_append(confpath, "/slowrx.ini");
keyfile = g_key_file_new();
if (g_key_file_load_from_file(keyfile, confpath->str, G_KEY_FILE_KEEP_COMMENTS, NULL)) {
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(keyfile, "[slowrx]\ndevice=default", -1, G_KEY_FILE_NONE, NULL);
g_key_file_load_from_data(config, "[slowrx]\ndevice=default", -1, G_KEY_FILE_NONE, NULL);
}
// Prepare FFT
in = fftw_malloc(sizeof(double) * 2048);
if (in == NULL) {
perror("GetVideo: Unable to allocate memory for FFT");
exit(EXIT_FAILURE);
}
out = fftw_malloc(sizeof(double) * 2048);
if (out == NULL) {
perror("GetVideo: Unable to allocate memory for FFT");
fftw_free(in);
exit(EXIT_FAILURE);
}
memset(in, 0, sizeof(double) * 2048);
memset(out, 0, sizeof(double) * 2048);
Plan1024 = fftw_plan_r2r_1d(1024, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
Plan2048 = fftw_plan_r2r_1d(2048, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
createGUI();
populateDeviceList();
@ -262,14 +242,17 @@ int main(int argc, char *argv[]) {
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);
}
confdata = g_key_file_to_data(keyfile,keylen,NULL);
fprintf(ConfFile,"%s",confdata);
fwrite(confdata,1,(size_t)keylen,ConfFile);
fclose(ConfFile);
g_object_unref(pixbuf_rx);
free(StoredLum);
fftw_free(in);
fftw_free(out);
return (EXIT_SUCCESS);
}

Wyświetl plik

@ -546,6 +546,7 @@
<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>
@ -571,7 +572,7 @@
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Manual resync</property>
<property name="label" translatable="yes">Manual slant adj.</property>
<property name="use_markup">True</property>
</object>
</child>

5
sync.c
Wyświetl plik

@ -79,7 +79,7 @@ double FindSync (guchar Mode, double Rate, int *Skip) {
printf(" %.1f° (d=%d) @ %.1f Hz", slantAngle, dMost, Rate);
// Adjust sample rate
Rate = Rate + tan(deg2rad(90 - slantAngle)) / LineWidth * Rate;
Rate += tan(deg2rad(90 - slantAngle)) / LineWidth * Rate;
if (slantAngle > 89 && slantAngle < 91) {
printf(" slant OK :)\n");
@ -113,7 +113,8 @@ double FindSync (guchar Mode, double Rate, int *Skip) {
}
}
// If pulse is on the right side, it just probably slipped out the left edge
// If pulse is near the right edge of the iamge, it just probably slipped
// out the left edge
if (xmax > 350) xmax -= 350;
// Skip until the start of the line.

20
video.c
Wyświetl plik

@ -98,7 +98,7 @@ bool GetVideo(guchar Mode, double Rate, int Skip, bool Redraw) {
gdk_threads_leave();
Length = ModeSpec[Mode].LineLen * ModeSpec[Mode].ImgHeight * 44100;
SyncTargetBin = GetBin(1200+HedrShift, FFTLen);
SyncTargetBin = GetBin(1200+CurrentPic.HedrShift, FFTLen);
LopassBin = GetBin(5000, FFTLen);
Abort = false;
SyncSampleNum = 0;
@ -132,14 +132,14 @@ bool GetVideo(guchar Mode, double Rate, int Skip, bool Redraw) {
fftw_execute(Plan1024);
for (i=0;i<LopassBin;i++) {
if (i >= GetBin(1500+HedrShift, FFTLen) && i <= GetBin(2300+HedrShift, FFTLen))
if (i >= GetBin(1500+CurrentPic.HedrShift, FFTLen) && i <= GetBin(2300+CurrentPic.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 /= (GetBin(2300+HedrShift, FFTLen) - GetBin(1500+HedrShift, FFTLen));
Praw /= (GetBin(2300+CurrentPic.HedrShift, FFTLen) - GetBin(1500+CurrentPic.HedrShift, FFTLen));
Psync /= 2.0;
// If there is more than twice the amount of power per Hz in the
@ -166,16 +166,16 @@ bool GetVideo(guchar Mode, double Rate, int Skip, bool Redraw) {
// Calculate video-plus-noise power (1500-2300 Hz)
Pvideo_plus_noise = 0;
for (n = GetBin(1500+HedrShift, FFTLen); n <= GetBin(2300+HedrShift, FFTLen); n++)
for (n = GetBin(1500+CurrentPic.HedrShift, FFTLen); n <= GetBin(2300+CurrentPic.HedrShift, FFTLen); n++)
Pvideo_plus_noise += pow(out[n], 2) + pow(out[FFTLen - n], 2);
// Calculate noise-only power (400-800 Hz + 2700-3400 Hz)
Pnoise_only = 0;
for (n = GetBin(400+HedrShift, FFTLen); n <= GetBin(800+HedrShift, FFTLen); n++)
for (n = GetBin(400+CurrentPic.HedrShift, FFTLen); n <= GetBin(800+CurrentPic.HedrShift, FFTLen); n++)
Pnoise_only += pow(out[n], 2) + pow(out[FFTLen - n], 2);
for (n = GetBin(2700+HedrShift, FFTLen); n <= GetBin(3400+HedrShift, FFTLen); n++)
for (n = GetBin(2700+CurrentPic.HedrShift, FFTLen); n <= GetBin(3400+CurrentPic.HedrShift, FFTLen); n++)
Pnoise_only += pow(out[n], 2) + pow(out[FFTLen - n], 2);
// Bandwidths
@ -231,7 +231,7 @@ bool GetVideo(guchar Mode, double Rate, int Skip, bool Redraw) {
MaxBin = 0;
// Find the bin with most power
for (n = GetBin(1500 + HedrShift, FFTLen) - 1; n <= GetBin(2300 + HedrShift, FFTLen) + 1; n++) {
for (n = GetBin(1500 + CurrentPic.HedrShift, FFTLen) - 1; n <= GetBin(2300 + CurrentPic.HedrShift, FFTLen) + 1; n++) {
Power[n] = pow(out[n],2) + pow(out[FFTLen - n], 2);
if (MaxBin == 0 || Power[n] > Power[MaxBin]) MaxBin = n;
@ -239,7 +239,7 @@ bool GetVideo(guchar Mode, double Rate, int Skip, bool Redraw) {
}
// Find the peak frequency by Gaussian interpolation
if (MaxBin > GetBin(1500 + HedrShift, FFTLen) - 1 && MaxBin < GetBin(2300 + HedrShift, FFTLen) + 1) {
if (MaxBin > GetBin(1500 + CurrentPic.HedrShift, FFTLen) - 1 && MaxBin < GetBin(2300 + CurrentPic.HedrShift, FFTLen) + 1) {
Freq = MaxBin + (log( Power[MaxBin + 1] / Power[MaxBin - 1] )) /
(2 * log( pow(Power[MaxBin], 2) / (Power[MaxBin + 1] * Power[MaxBin - 1])));
// In Hertz
@ -247,7 +247,7 @@ bool GetVideo(guchar Mode, double Rate, int Skip, bool Redraw) {
InterpFreq = Freq;
} else {
// Clip if out of bounds
Freq = ( (MaxBin > GetBin(1900 + HedrShift, FFTLen)) ? 2300 : 1500 ) + HedrShift;
Freq = ( (MaxBin > GetBin(1900 + CurrentPic.HedrShift, FFTLen)) ? 2300 : 1500 ) + CurrentPic.HedrShift;
}
NextFFTtime += 0.3e-3;
@ -258,7 +258,7 @@ bool GetVideo(guchar Mode, double Rate, int Skip, bool Redraw) {
InterpFreq = PrevFreq + (t - NextFFTtime + 0.6e-3) * ((Freq - PrevFreq) / 0.3e-3);
// Calculate luminency & store for later use
StoredLum[SampleNum] = clip((InterpFreq - (1500 + HedrShift)) / 3.1372549);
StoredLum[SampleNum] = clip((InterpFreq - (1500 + CurrentPic.HedrShift)) / 3.1372549);
}

22
vis.c
Wyświetl plik

@ -37,12 +37,12 @@ guchar GetVIS () {
printf("Waiting for header\n");
gdk_threads_enter();
gtk_statusbar_push( GTK_STATUSBAR(gui.statusbar), 0, "Ready" );
gtk_statusbar_push( GTK_STATUSBAR(gui.statusbar), 0, "Listening" );
gdk_threads_leave();
while ( true ) {
if (Abort) return(0);
if (Abort || ManualResync) return(0);
// Read 10 ms from sound card
readPcm(441);
@ -77,10 +77,10 @@ guchar GetVIS () {
// Is there a pattern that looks like (the end of) a calibration header + VIS?
// Tolerance ±25 Hz
HedrShift = 0;
CurrentPic.HedrShift = 0;
gotvis = false;
for (i = 0; i < 3; i++) {
if (HedrShift != 0) break;
if (CurrentPic.HedrShift != 0) break;
for (j = 0; j < 3; j++) {
if ( (tone[1*3+i] > tone[0+j] - 25 && tone[1*3+i] < tone[0+j] + 25) && // 1900 Hz leader
(tone[2*3+i] > tone[0+j] - 25 && tone[2*3+i] < tone[0+j] + 25) && // 1900 Hz leader
@ -103,13 +103,13 @@ guchar GetVIS () {
}
}
if (gotvis) {
HedrShift = tone[0+j] - 1900;
CurrentPic.HedrShift = tone[0+j] - 1900;
VIS = Bit[0] + (Bit[1] << 1) + (Bit[2] << 2) + (Bit[3] << 3) + (Bit[4] << 4) +
(Bit[5] << 5) + (Bit[6] << 6);
ParityBit = Bit[7];
printf(" VIS %d (%02Xh) @ %+d Hz\n", VIS, VIS, HedrShift);
printf(" VIS %d (%02Xh) @ %+d Hz\n", VIS, VIS, CurrentPic.HedrShift);
Parity = Bit[0] ^ Bit[1] ^ Bit[2] ^ Bit[3] ^ Bit[4] ^ Bit[5] ^ Bit[6];
@ -124,7 +124,7 @@ guchar GetVIS () {
} else {
gdk_threads_enter();
gtk_combo_box_set_active (GTK_COMBO_BOX(gui.combo_mode), VISmap[VIS]-1);
gtk_spin_button_set_value (GTK_SPIN_BUTTON(gui.spin_shift), HedrShift);
gtk_spin_button_set_value (GTK_SPIN_BUTTON(gui.spin_shift), CurrentPic.HedrShift);
gdk_threads_leave();
break;
}
@ -145,7 +145,7 @@ guchar GetVIS () {
gdk_threads_leave();
selmode = gtk_combo_box_get_active (GTK_COMBO_BOX(gui.combo_mode)) + 1;
HedrShift = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(gui.spin_shift));
CurrentPic.HedrShift = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(gui.spin_shift));
VIS = 0;
for (i=0; i<0x80; i++) {
if (VISmap[i] == selmode) {
@ -170,12 +170,6 @@ guchar GetVIS () {
readPcm(20e-3 * 44100);
PcmPointer += 20e-3 * 44100;
// In case of Scottie, skip first sync pulse
/*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");
return 0;