From: John Melton G0ORX <john.d.melton@googlemail.com>
Date: Tue, 26 Nov 2019 16:24:33 +0000 (+0000)
Subject: Fixed frequency when in SAT mode and CW modes.  Updated audio to always use float... 
X-Git-Url: https://git.rkrishnan.org/pf/content/%22file:/...?a=commitdiff_plain;h=e451ff3a876e848da2cb2c8f00b1ad7548c65c1a;p=pihpsdr.git

Fixed frequency when in SAT mode and CW modes.  Updated audio to always use float for the samples.
---

diff --git a/audio.c b/audio.c
index 4482ab0..45586f1 100644
--- a/audio.c
+++ b/audio.c
@@ -50,12 +50,12 @@
 int audio = 0;
 int mic_buffer_size = 720; // samples (both left and right)
 
-//static snd_pcm_t *playback_handle=NULL;
 static snd_pcm_t *record_handle=NULL;
+static snd_pcm_format_t record_audio_format;
 
-static float *mic_buffer=NULL;
+static void *mic_buffer=NULL;
 
-static GThread *mic_read_thread_id;
+static GThread *mic_read_thread_id=NULL;
 
 static int running=FALSE;
 
@@ -132,18 +132,18 @@ g_print("audio_open_output: using format %s (%s)\n",snd_pcm_format_name(formats[
 
   rx->local_audio_buffer_offset=0;
   switch(rx->local_audio_format) {
-  case SND_PCM_FORMAT_S16_LE:
+    case SND_PCM_FORMAT_S16_LE:
 g_print("audio_open_output: local_audio_buffer: size=%d sample=%ld\n",rx->local_audio_buffer_size,sizeof(gint16));
-    rx->local_audio_buffer=g_new0(gint16,2*rx->local_audio_buffer_size);
-    break;
-  case SND_PCM_FORMAT_S32_LE:
+      rx->local_audio_buffer=g_new(gint16,2*rx->local_audio_buffer_size);
+        break;
+    case SND_PCM_FORMAT_S32_LE:
 g_print("audio_open_output: local_audio_buffer: size=%d sample=%ld\n",rx->local_audio_buffer_size,sizeof(gint32));
-    rx->local_audio_buffer=g_new0(gint32,2*rx->local_audio_buffer_size);
-    break;
-  case SND_PCM_FORMAT_FLOAT_LE:
-g_print("audio_open_output: local_audio_buffer: size=%d sample=%ld\n",rx->local_audio_buffer_size,sizeof(float));
-    rx->local_audio_buffer=g_new0(float,2*rx->local_audio_buffer_size);
-    break;
+      rx->local_audio_buffer=g_new(gint32,2*rx->local_audio_buffer_size);
+      break;
+    case SND_PCM_FORMAT_FLOAT_LE:
+g_print("audio_open_output: local_audio_buffer: size=%d sample=%ld\n",rx->local_audio_buffer_size,sizeof(gfloat));
+      rx->local_audio_buffer=g_new(gfloat,2*rx->local_audio_buffer_size);
+      break;
   }
   
   g_print("audio_open_output: rx=%d audio_device=%d handle=%p buffer=%p size=%d\n",rx->id,rx->audio_device,rx->playback_handle,rx->local_audio_buffer,rx->local_audio_buffer_size);
@@ -159,17 +159,15 @@ int audio_open_input() {
   unsigned int channels=1;
   int soft_resample=1;
   unsigned int latency=125000;
-
-  int dir=0;
+  char hw[64];
+  int i;
 
   if(transmitter->microphone_name==NULL) {
     transmitter->local_microphone=0;
     return -1;
   }
-g_print("audio_open_input: %s\n",transmitter->microphone_name);
 
-  int i;
-  char hw[64];
+g_print("audio_open_input: %s\n",transmitter->microphone_name);
   
   switch(protocol) {
     case ORIGINAL_PROTOCOL:
@@ -198,24 +196,49 @@ g_print("audio_open_input: %s\n",transmitter->microphone_name);
 
   g_print("audio_open_input: hw=%s\n",hw);
 
-  if ((err = snd_pcm_open (&record_handle, hw, SND_PCM_STREAM_CAPTURE, SND_PCM_ASYNC)) < 0) {
-    g_print("audio_open_input: cannot open audio device %s (%s)\n",
-            hw,
-            snd_strerror (err));
-    return err;
+  for(i=0;i<FORMATS;i++) {
+    if ((err = snd_pcm_open (&record_handle, hw, SND_PCM_STREAM_CAPTURE, SND_PCM_ASYNC)) < 0) {
+      g_print("audio_open_input: cannot open audio device %s (%s)\n",
+              hw,
+              snd_strerror (err));
+      return err;
+    }
+g_print("audio_open_input: handle=%p\n",record_handle);
+
+g_print("audio_open_input: trying format %s (%s)\n",snd_pcm_format_name(formats[i]),snd_pcm_format_description(formats[i]));
+    if ((err = snd_pcm_set_params (record_handle,formats[i],SND_PCM_ACCESS_RW_INTERLEAVED,channels,rate,soft_resample,latency)) < 0) {
+      g_print("audio_open_input: snd_pcm_set_params failed: %s\n",snd_strerror(err));
+      audio_close_input();
+      continue;
+    } else {
+g_print("audio_open_input: using format %s (%s)\n",snd_pcm_format_name(formats[i]),snd_pcm_format_description(formats[i]));
+      record_audio_format=formats[i];
+      break;
+    }
   }
 
-  if ((err = snd_pcm_set_params (record_handle,SND_PCM_FORMAT_FLOAT_LE,SND_PCM_ACCESS_RW_INTERLEAVED,channels,rate,soft_resample,latency)) < 0) {
-    g_print("audio_open_input: snd_pcm_set_params failed: %s\n",snd_strerror(err));
-    audio_close_input();
+  if(i>=FORMATS) {
+    g_print("audio_open_input: cannot find usable format\n");
     return err;
   }
 
-  mic_buffer=g_new0(float,mic_buffer_size);
-
+  switch(record_audio_format) {
+    case SND_PCM_FORMAT_S16_LE:
+g_print("audio_open_input: mic_buffer: size=%d channels=%d sample=%ld bytes\n",mic_buffer_size,channels,sizeof(gint16));
+      mic_buffer=g_new(gint16,mic_buffer_size);
+      break;
+    case SND_PCM_FORMAT_S32_LE:
+g_print("audio_open_input: mic_buffer: size=%d channels=%d sample=%ld bytes\n",mic_buffer_size,channels,sizeof(gint32));
+      mic_buffer=g_new(gint32,mic_buffer_size);
+      break;
+    case SND_PCM_FORMAT_FLOAT_LE:
+g_print("audio_open_input: mic_buffer: size=%d channels=%d sample=%ld bytes\n",mic_buffer_size,channels,sizeof(gfloat));
+      mic_buffer=g_new(gfloat,mic_buffer_size);
+      break;
+  }
 
-  running=TRUE;
-  mic_read_thread_id = g_thread_new( "local mic", mic_read_thread, NULL);
+g_print("audio_open_input: starting mic_read_thread\n");
+  mic_read_thread_id = g_thread_new("local mic",mic_read_thread,NULL);
   if(!mic_read_thread_id )
   {
     g_print("g_thread_new failed on mic_read_thread\n");
@@ -240,13 +263,18 @@ g_print("audio_close_output: rx=%d handle=%p buffer=%p\n",rx->id,rx->playback_ha
 }
 
 void audio_close_input() {
+  g_print("audio_close_input\n");
   running=FALSE;
+  if(mic_read_thread_id!=NULL) {
+    g_thread_join(mic_read_thread_id);
+    mic_read_thread_id=NULL;
+  }
   if(record_handle!=NULL) {
     snd_pcm_close (record_handle);
     record_handle=NULL;
   }
   if(mic_buffer!=NULL) {
-    free(mic_buffer);
+    g_free(mic_buffer);
     mic_buffer=NULL;
   }
 }
@@ -411,12 +439,21 @@ g_print("audio delay=%ld trim=%ld audio_buffer_size=%d\n",delay,trim,rx->local_a
 
 static void *mic_read_thread(gpointer arg) {
   int rc;
+  gfloat *float_buffer;
+  gint32 *long_buffer;
+  gint16 *short_buffer;
+  gfloat sample;
+  int i;
+
+g_print("mic_read_thread: snd_pcm_prepare\n");
   if ((rc = snd_pcm_prepare (record_handle)) < 0) {
     g_print("mic_read_thread: cannot prepare audio interface for use (%s)\n",
             snd_strerror (rc));
     return NULL;
   }
+
 g_print("mic_read_thread: mic_buffer_size=%d\n",mic_buffer_size);
+  running=TRUE;
   while(running) {
     if ((rc = snd_pcm_readi (record_handle, mic_buffer, mic_buffer_size)) != mic_buffer_size) {
       if(running) {
@@ -430,20 +467,36 @@ g_print("mic_read_thread: mic_buffer_size=%d\n",mic_buffer_size);
       }
     } else {
       // process the mic input
-      switch(protocol) {
-        case ORIGINAL_PROTOCOL:
-          old_protocol_process_local_mic(mic_buffer);
-          break;
-        case NEW_PROTOCOL:
-          new_protocol_process_local_mic(mic_buffer);
-          break;
+      for(i=0;i<mic_buffer_size;i++) {
+        switch(record_audio_format) {
+          case SND_PCM_FORMAT_S16_LE:
+            short_buffer=(gint16 *)mic_buffer;
+            sample=(gfloat)short_buffer[i]/32767.0f;
+            break;
+          case SND_PCM_FORMAT_S32_LE:
+            long_buffer=(gint32 *)mic_buffer;
+            sample=(gfloat)long_buffer[i]/4294967295.0f;
+            break;
+          case SND_PCM_FORMAT_FLOAT_LE:
+            float_buffer=(gfloat *)mic_buffer;
+            sample=float_buffer[i];
+            break;
+        }
+        switch(protocol) {
+          case ORIGINAL_PROTOCOL:
+            old_protocol_process_local_mic(sample);
+            break;
+          case NEW_PROTOCOL:
+            new_protocol_process_local_mic(sample);
+            break;
 #ifdef SOAPYSDR
-        case SOAPYSDR_PROTOCOL:
-          soapy_protocol_process_local_mic(mic_buffer);
-          break;
+          case SOAPYSDR_PROTOCOL:
+            soapy_protocol_process_local_mic(sample);
+            break;
 #endif
-        default:
-          break;
+          default:
+            break;
+        }
       }
     }
   }
@@ -522,7 +575,7 @@ g_print("output_device: %s\n",device_id);
     snd_ctl_close(handle);
   }
 
-  // look for dmix
+  // look for dmix and dsnoop
   void **hints, **n;
   char *name, *descr, *io;
 
@@ -536,11 +589,10 @@ g_print("output_device: %s\n",device_id);
 
     if(strncmp("dmix:", name, 5)==0) {
       if(n_output_devices<MAX_AUDIO_DEVICES) {
-        if(strncmp("dmix:CARD=ALSA",name,14)!=0) {
+        //if(strncmp("dmix:CARD=ALSA",name,14)!=0) {
           output_devices[n_output_devices].name=g_new0(char,strlen(name)+1);
           strcpy(output_devices[n_output_devices].name,name);
           output_devices[n_output_devices].description=g_new0(char,strlen(descr)+1);
-          //strcpy(output_devices[n_output_devices].description,descr);
           i=0;
           while(i<strlen(descr) && descr[i]!='\n') {
             output_devices[n_output_devices].description[i]=descr[i];
@@ -550,7 +602,24 @@ g_print("output_device: %s\n",device_id);
           input_devices[n_output_devices].index=i;
           n_output_devices++;
 g_print("output_device: name=%s descr=%s\n",name,descr);
-        }
+        //}
+      }
+    } else if(strncmp("dsnoop:", name, 6)==0) {
+      if(n_input_devices<MAX_AUDIO_DEVICES) {
+        //if(strncmp("dmix:CARD=ALSA",name,14)!=0) {
+          input_devices[n_input_devices].name=g_new0(char,strlen(name)+1);
+          strcpy(input_devices[n_input_devices].name,name);
+          input_devices[n_input_devices].description=g_new0(char,strlen(descr)+1);
+          i=0;
+          while(i<strlen(descr) && descr[i]!='\n') {
+            input_devices[n_input_devices].description[i]=descr[i];
+            i++;
+          }
+          input_devices[n_input_devices].description[i]='\0';
+          input_devices[n_input_devices].index=i;
+          n_input_devices++;
+g_print("input_device: name=%s descr=%s\n",name,descr);
+        //}
       }
     }
 
diff --git a/new_protocol.c b/new_protocol.c
index bd020c5..607e6f0 100644
--- a/new_protocol.c
+++ b/new_protocol.c
@@ -1844,23 +1844,16 @@ static void process_mic_data(int bytes) {
   }
 }
 
-void new_protocol_process_local_mic(float *buffer) {
-  int i;
-  short sample;
-
-  for(i=0;i<MIC_SAMPLES;i++) {
-    sample = (short)(buffer[i]*32767.0);
+void new_protocol_process_local_mic(float sample) {
 #ifdef FREEDV
-    if(active_receiver->freedv) {
-      add_freedv_mic_sample(transmitter,sample);
-    } else {
+  if(active_receiver->freedv) {
+    add_freedv_mic_sample(transmitter,sample);
+  } else {
 #endif
-      add_mic_sample(transmitter,sample);
+    add_mic_sample(transmitter,sample);
 #ifdef FREEDV
-    }
-#endif
   }
-
+#endif
 }
 
 void new_protocol_cw_audio_samples(short left_audio_sample,short right_audio_sample) {
diff --git a/new_protocol.h b/new_protocol.h
index 82875c5..0b08117 100644
--- a/new_protocol.h
+++ b/new_protocol.h
@@ -88,7 +88,7 @@ extern int getMox();
 extern void setTune(int state);
 extern int getTune();
 
-extern void new_protocol_process_local_mic(float *buffer);
+extern void new_protocol_process_local_mic(float sample);
 extern void new_protocol_audio_samples(RECEIVER *rx,short left_audio_sample,short right_audio_sample);
 extern void new_protocol_iq_samples(int isample,int qsample);
 extern void new_protocol_flush_iq_samples();
diff --git a/old_protocol.c b/old_protocol.c
index 4f12a0a..4b407fd 100644
--- a/old_protocol.c
+++ b/old_protocol.c
@@ -1069,23 +1069,16 @@ void old_protocol_iq_samples(int isample,int qsample) {
 }
 
 
-void old_protocol_process_local_mic(float *buffer) {
-  int i;
-  short sample;
-
-// always 48000 samples per second
-  for(i=0;i<720;i++) {
-    sample = (short) (buffer[i]*32767.0);
+void old_protocol_process_local_mic(float sample) {
 #ifdef FREEDV
-    if(active_receiver->freedv) {
-      add_freedv_mic_sample(transmitter,sample);
-    } else {
+  if(active_receiver->freedv) {
+    add_freedv_mic_sample(transmitter,sample);
+  } else {
 #endif
-      add_mic_sample(transmitter,sample);
+    add_mic_sample(transmitter,sample);
 #ifdef FREEDV
-    }
-#endif
   }
+#endif
 }
 
 /*
diff --git a/old_protocol.h b/old_protocol.h
index bda0ab2..8d74530 100644
--- a/old_protocol.h
+++ b/old_protocol.h
@@ -26,7 +26,7 @@ extern void old_protocol_run();
 extern void old_protocol_init(int rx,int pixels,int rate);
 extern void old_protocol_set_mic_sample_rate(int rate);
 
-extern void old_protocol_process_local_mic(float *buffer);
+extern void old_protocol_process_local_mic(float sample);
 extern void old_protocol_audio_samples(RECEIVER *rx,short left_audio_sample,short right_audio_sample);
 extern void old_protocol_iq_samples(int isample,int qsample);
 extern void old_protocol_iq_samples_with_sidetone(int isample,int qsample,int side);
diff --git a/radio_menu.c b/radio_menu.c
index f181ba2..9ee2fe3 100644
--- a/radio_menu.c
+++ b/radio_menu.c
@@ -45,6 +45,7 @@ static GtkWidget *parent_window=NULL;
 static GtkWidget *menu_b=NULL;
 static GtkWidget *dialog=NULL;
 static GtkWidget *rx_gains[3];
+static GtkWidget *tx_gain;
 static GtkWidget *tx_gains[2];
 static GtkWidget *sat_b;
 static GtkWidget *rsat_b;
@@ -101,10 +102,9 @@ static void rx_gain_value_changed_cb(GtkWidget *widget, gpointer data) {
 
 static void drive_gain_value_changed_cb(GtkWidget *widget, gpointer data) {
   DAC *dac=(DAC *)data;
-  int gain;
   if(radio->device==SOAPYSDR_USB_DEVICE) {
-    gain=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
-    soapy_protocol_set_tx_gain(transmitter,(double)gain);
+    transmitter->drive=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
+    soapy_protocol_set_tx_gain(transmitter,(double)transmitter->drive);
     for(int i=0;i<radio->info.soapy.tx_gains;i++) {
       int value=soapy_protocol_get_tx_gain_element(transmitter,radio->info.soapy.tx_gain[i]);
       gtk_spin_button_set_value(GTK_SPIN_BUTTON(tx_gains[i]),(double)value);
@@ -790,10 +790,10 @@ void radio_menu(GtkWidget *parent) {
       GtkWidget *tx_gain_label=gtk_label_new("TX Gain");
       gtk_grid_attach(GTK_GRID(grid),tx_gain_label,col,row,1,1);
       col++;
-      tx_gains[i]=gtk_spin_button_new_with_range(0.0,100.0,1.0);
-      gtk_spin_button_set_value(GTK_SPIN_BUTTON(tx_gains[i]),transmitter->drive);
-      gtk_grid_attach(GTK_GRID(grid),tx_gains[i],col,row,1,1);
-      g_signal_connect(tx_gains[i],"value_changed",G_CALLBACK(drive_gain_value_changed_cb),&adc[0]);
+      tx_gain=gtk_spin_button_new_with_range(0.0,64.0,1.0);
+      gtk_spin_button_set_value(GTK_SPIN_BUTTON(tx_gain),transmitter->drive);
+      gtk_grid_attach(GTK_GRID(grid),tx_gain,col,row,1,1);
+      g_signal_connect(tx_gain,"value_changed",G_CALLBACK(drive_gain_value_changed_cb),&adc[0]);
     }
   }
 #endif
diff --git a/sliders.c b/sliders.c
index 71e6311..7c76438 100644
--- a/sliders.c
+++ b/sliders.c
@@ -550,7 +550,17 @@ void set_drive(double value) {
       scale_status=DRIVE;
       scale_dialog=gtk_dialog_new_with_buttons("Drive",GTK_WINDOW(top_window),GTK_DIALOG_DESTROY_WITH_PARENT,NULL,NULL);
       GtkWidget *content=gtk_dialog_get_content_area(GTK_DIALOG(scale_dialog));
-      drive_scale=gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,0.0, 100.0, 1.00);
+      switch(protocol) {
+#ifdef SOAPYSDR
+        case SOAPYSDR_PROTOCOL:
+          drive_scale=gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,0.0, 64.0, 1.00);
+          break;
+#endif
+        default:
+          drive_scale=gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,0.0, 100.0, 1.00);
+          break;
+      }
+  
       gtk_widget_override_font(drive_scale, pango_font_description_from_string("Sans 10"));
       gtk_widget_set_size_request (drive_scale, 400, 30);
       gtk_range_set_value (GTK_RANGE(drive_scale),value);
diff --git a/soapy_protocol.c b/soapy_protocol.c
index 7530d62..9036c4a 100644
--- a/soapy_protocol.c
+++ b/soapy_protocol.c
@@ -357,23 +357,16 @@ fprintf(stderr,"soapy_protocol: receive_thread: SoapySDRDevice_unmake\n");
   //_exit(0);
 }
 
-void soapy_protocol_process_local_mic(float *buffer) {
-  int i;
-  short sample;
-
-// always 48000 samples per second
-  for(i=0;i<720;i++) {
-    sample=(short)(buffer[i]*32767.0);
+void soapy_protocol_process_local_mic(float sample) {
 #ifdef FREEDV
-    if(active_receiver->freedv) {
-      add_freedv_mic_sample(transmitter,sample);
-    } else {
+  if(active_receiver->freedv) {
+    add_freedv_mic_sample(transmitter,sample);
+  } else {
 #endif
-      add_mic_sample(transmitter,sample);
+    add_mic_sample(transmitter,sample);
 #ifdef FREEDV
-    }
-#endif
   }
+#endif
 }
 
 void soapy_protocol_iq_samples(float isample,float qsample) {
diff --git a/soapy_protocol.h b/soapy_protocol.h
index 22b80a6..5060891 100644
--- a/soapy_protocol.h
+++ b/soapy_protocol.h
@@ -46,7 +46,7 @@ void soapy_protocol_set_tx_antenna(TRANSMITTER *tx,int ant);
 void soapy_protocol_set_tx_gain(TRANSMITTER *tx,int gain);
 void soapy_protocol_set_tx_gain_element(TRANSMITTER *tx,char *name,int gain);
 int soapy_protocol_get_tx_gain_element(TRANSMITTER *tx,char *name);
-void soapy_protocol_process_local_mic(float *buffer);
+void soapy_protocol_process_local_mic(float sample);
 void soapy_protocol_iq_samples(float isample,float qsample);
 void soapy_protocol_set_mic_sample_rate(int rate);
 #endif
diff --git a/transmitter.c b/transmitter.c
index bf41168..d409f14 100644
--- a/transmitter.c
+++ b/transmitter.c
@@ -1067,7 +1067,7 @@ static void full_tx_buffer(TRANSMITTER *tx) {
   }
 }
 
-void add_mic_sample(TRANSMITTER *tx,short mic_sample) {
+void add_mic_sample(TRANSMITTER *tx,float mic_sample) {
   int mode=tx->mode;
   float cwsample;
   double mic_sample_double, ramp;
@@ -1082,7 +1082,7 @@ void add_mic_sample(TRANSMITTER *tx,short mic_sample) {
   if (tune || mode==modeCWL || mode==modeCWU) {
     mic_sample_double=0.0;
   } else {
-    mic_sample_double=(double)mic_sample/32768.0;
+    mic_sample_double=(double)mic_sample;
   }
 
 //
@@ -1234,7 +1234,7 @@ void add_ps_iq_samples(TRANSMITTER *tx, double i_sample_tx,double q_sample_tx, d
 }
 
 #ifdef FREEDV
-void add_freedv_mic_sample(TRANSMITTER *tx, short mic_sample) {
+void add_freedv_mic_sample(TRANSMITTER *tx, float mic_sample) {
   int i,s;
 
   //if(active_receiver->freedv && isTransmitting() && !tune) {
diff --git a/transmitter.h b/transmitter.h
index f792ddb..20c62f3 100644
--- a/transmitter.h
+++ b/transmitter.h
@@ -132,8 +132,8 @@ extern void transmitter_set_am_carrier_level(TRANSMITTER *tx);
 extern void tx_set_pre_emphasize(TRANSMITTER *tx,int state);
 extern void transmitter_set_ctcss(TRANSMITTER *tx,int run,double frequency);
 
-extern void add_mic_sample(TRANSMITTER *tx,short mic_sample);
-extern void add_freedv_mic_sample(TRANSMITTER *tx,short mic_sample);
+extern void add_mic_sample(TRANSMITTER *tx,float mic_sample);
+extern void add_freedv_mic_sample(TRANSMITTER *tx,float mic_sample);
 
 extern void transmitter_save_state(TRANSMITTER *tx);
 extern void transmitter_set_out_of_band(TRANSMITTER *tx);
diff --git a/tx_menu.c b/tx_menu.c
index 33b2660..217e124 100644
--- a/tx_menu.c
+++ b/tx_menu.c
@@ -193,6 +193,8 @@ static void linein_changed(GtkWidget *widget, gpointer data) {
 
 static void local_input_changed_cb(GtkWidget *widget, gpointer data) {
   int i=GPOINTER_TO_INT(data);
+g_print("local_input_changed_cp: %d\n",i);
+g_print("local_input_changed_cp: %s\n",input_devices[i].name);
   if(transmitter->local_microphone) {
     audio_close_input();
   }
@@ -352,9 +354,9 @@ void tx_menu(GtkWidget *parent) {
 
     input=NULL;
     for(i=0;i<n_input_devices;i++) {
-      input=gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(input),input_devices[i].description);
+      input=gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(input),input_devices[i].name);
       if(transmitter->microphone_name!=NULL) {
-        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(input),strcmp(transmitter->microphone_name,input_devices[i].description)==0);
+        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(input),strcmp(transmitter->microphone_name,input_devices[i].name)==0);
       }
       gtk_widget_show(input);
       gtk_grid_attach(GTK_GRID(grid),input,col,row++,2,1);
diff --git a/vfo.c b/vfo.c
index 5360ca1..6aacdc5 100644
--- a/vfo.c
+++ b/vfo.c
@@ -550,13 +550,19 @@ void vfo_a_swap_b() {
 
 void vfo_step(int steps) {
   int id=active_receiver->id;
+  long long saved_freq;
+
   if(!locked) {
     if(vfo[id].ctun) {
+      saved_freq=vfo[id].ctun_frequency;
       vfo[id].ctun_frequency=(vfo[id].ctun_frequency/step + steps)*step;
     } else {
-      vfo[id].frequency=(vfo[id].frequency/step +steps)*step;
+      saved_freq=vfo[id].frequency;
+      vfo[id].frequency=(vfo[id].frequency/step + steps)*step;
     }
 
+//g_print("vfo_step: id=%d steps=%d step=%lld ctun=%d freq=%lld to %lld\n",id,steps,step,vfo[id].ctun,saved_freq,vfo[id].ctun?vfo[id].ctun_frequency:vfo[id].frequency);
+
     int sid=id==0?1:0;
     switch(sat_mode) {
       case SAT_NONE:
@@ -564,26 +570,21 @@ void vfo_step(int steps) {
       case SAT_MODE:
         // A and B increment and decrement together
         if(vfo[sid].ctun) {
-          vfo[sid].ctun_frequency=vfo[sid].ctun_frequency+(steps*step);
+          vfo[sid].ctun_frequency=(vfo[sid].ctun_frequency/step + steps)*step;
         } else {
-          vfo[sid].frequency=vfo[sid].frequency+(steps*step);
+          vfo[sid].frequency=(vfo[sid].frequency/step + steps)*step;
         }
         break;
       case RSAT_MODE:
         // A increments and B decrements or A decrments and B increments
         if(vfo[sid].ctun) {
-          vfo[sid].ctun_frequency=vfo[sid].ctun_frequency-(steps*step);
+          vfo[sid].ctun_frequency=(vfo[sid].ctun_frequency/step + steps)*step;
         } else {
-          vfo[sid].frequency=vfo[sid].frequency-(steps*step);
+          vfo[sid].frequency=(vfo[sid].frequency/step -steps)*step;
         }
         break;
     }
-
     receiver_frequency_changed(active_receiver);
-#ifdef INCLUDED
-    BANDSTACK_ENTRY* entry=bandstack_entry_get_current();
-    setFrequency(active_receiver->frequency+(steps*step));
-#endif
     g_idle_add(ext_vfo_update,NULL);
   }
 }
@@ -593,12 +594,16 @@ void vfo_step(int steps) {
 //         changing the VFO of the active receiver
 //
 void vfo_id_step(int id, int steps) {
+  long long saved_freq;
   if(!locked) {
     if(vfo[id].ctun) {
+      saved_freq=vfo[id].ctun_frequency;
       vfo[id].ctun_frequency=(vfo[id].ctun_frequency/step+steps)*step;
     } else {
+      saved_freq=vfo[id].frequency;
       vfo[id].frequency=(vfo[id].frequency/step+steps)*step;
     }
+//g_print("vfo_id_step: id=%d steps=%d step=%lld ctun=%d freq=%lld to %lld\n",id,steps,step,vfo[id].ctun,saved_freq,vfo[id].ctun?vfo[id].ctun_frequency:vfo[id].frequency);
 
     int sid=id==0?1:0;
     switch(sat_mode) {
@@ -633,22 +638,21 @@ void vfo_id_step(int id, int steps) {
 
 void vfo_move(long long hz,int round) {
   int id=active_receiver->id;
-//g_print("vfo_move: id=%d hz=%lld round=%d sat_mode=%d\n",id,hz,round,sat_mode);
+  long long saved_freq;
   if(!locked) {
     if(vfo[id].ctun) {
+      saved_freq=vfo[id].ctun_frequency;
       vfo[id].ctun_frequency=vfo[id].ctun_frequency+hz;
       if(round && (vfo[id].mode!=modeCWL && vfo[id].mode!=modeCWU)) {
-         //vfo[id].ctun_frequency=((vfo[id].ctun_frequency+(step/2))/step)*step;
          vfo[id].ctun_frequency=(vfo[id].ctun_frequency/step)*step;
       }
-//g_print("vfo_move: id=%d ctun_frequency=%lld\n",id,vfo[id].ctun_frequency);
     } else {
+      saved_freq=vfo[id].frequency;
       vfo[id].frequency=vfo[id].frequency-hz;
       if(round && (vfo[id].mode!=modeCWL && vfo[id].mode!=modeCWU)) {
-         //vfo[id].frequency=((vfo[id].frequency-(step/2))/step)*step;
          vfo[id].frequency=(vfo[id].frequency/step)*step;
       }
-//g_print("vfo_move: id=%d frequency=%lld\n",id,vfo[id].frequency);
+//g_print("vfo_move: id=%d ctun=%d hz=%lld round=%d sat_mode=%d freq=%lld to %lld\n",id,vfo[id].ctun,hz,round,sat_mode,saved_freq,vfo[id].ctun?vfo[id].ctun_frequency:vfo[id].frequency);
     }
 
     int sid=id==0?1:0;
@@ -663,17 +667,13 @@ void vfo_move(long long hz,int round) {
         if(vfo[sid].ctun) {
           vfo[sid].ctun_frequency=vfo[sid].ctun_frequency+hz;
           if(round && (vfo[sid].mode!=modeCWL && vfo[sid].mode!=modeCWU)) {
-             //vfo[sid].ctun_frequency=((vfo[sid].ctun_frequency+(step/2))/step)*step;
              vfo[sid].ctun_frequency=(vfo[sid].ctun_frequency/step)*step;
           }
-//g_print("vfo_move: SAT id=%d ctun_frequency=%lld\n",sid,vfo[sid].ctun_frequency);
         } else {
           vfo[sid].frequency=vfo[sid].frequency+hz;
           if(round && (vfo[sid].mode!=modeCWL && vfo[sid].mode!=modeCWU)) {
-             //vfo[sid].frequency=((vfo[sid].frequency-(step/2))/step)*step;
              vfo[sid].frequency=(vfo[sid].frequency/step)*step;
           }
-//g_print("vfo_move: SAT id=%d frequency=%lld\n",sid,vfo[sid].frequency);
         }
         break;
       case RSAT_MODE:
@@ -684,17 +684,13 @@ void vfo_move(long long hz,int round) {
         if(vfo[sid].ctun) {
           vfo[sid].ctun_frequency=vfo[sid].ctun_frequency-hz;
           if(round && (vfo[sid].mode!=modeCWL && vfo[sid].mode!=modeCWU)) {
-             //vfo[sid].ctun_frequency=((vfo[sid].ctun_frequency-(step/2))/step)*step;
              vfo[sid].ctun_frequency=(vfo[sid].ctun_frequency/step)*step;
           }
-//g_print("vfo_move: RSAT id=%d ctun_frequency=%lld\n",sid,vfo[sid].ctun_frequency);
         } else {
           vfo[sid].frequency=vfo[sid].frequency-hz;
           if(round && (vfo[sid].mode!=modeCWL && vfo[sid].mode!=modeCWU)) {
-             //vfo[sid].frequency=((vfo[sid].frequency+(step/2))/step)*step;
              vfo[sid].frequency=(vfo[sid].frequency/step)*step;
           }
-//g_print("vfo_move: RSAT id=%d frequency=%lld\n",sid,vfo[sid].frequency);
         }
         break;
     }
@@ -710,34 +706,40 @@ void vfo_move_to(long long hz) {
   long long half=(long long)(active_receiver->sample_rate/2);
   long long diff; 
   long long f;
+  long long saved_freq;
 
   if(vfo[id].mode!=modeCWL && vfo[id].mode!=modeCWU) {
     offset=(hz/step)*step;
   }
   f=(vfo[id].frequency-half)+offset;
-//g_print("vfo_move_to: id=%d hz=%lld f=%lld\n",id,hz,f);
 
   if(!locked) {
     if(vfo[id].ctun) {
+      saved_freq=vfo[id].ctun_frequency;
       diff=f-vfo[id].ctun_frequency;
       vfo[id].ctun_frequency=f;
       if(vfo[id].mode==modeCWL) {
         vfo[id].ctun_frequency+=cw_keyer_sidetone_frequency;
+        diff+=cw_keyer_sidetone_frequency;
       } else if(vfo[id].mode==modeCWU) {
         vfo[id].ctun_frequency-=cw_keyer_sidetone_frequency;
+        diff-=cw_keyer_sidetone_frequency;
       }
-//g_print("vfo_move_to: vfo=%d ctun_frequency=%lld diff=%lld\n",id,vfo[id].ctun_frequency,diff);
     } else {
+      saved_freq=vfo[id].frequency;
       diff=f-vfo[id].frequency;
       vfo[id].frequency=f;
       if(vfo[id].mode==modeCWL) {
         vfo[id].frequency+=cw_keyer_sidetone_frequency;
+        diff+=cw_keyer_sidetone_frequency;
       } else if(vfo[id].mode==modeCWU) {
         vfo[id].frequency-=cw_keyer_sidetone_frequency;
+        diff-=cw_keyer_sidetone_frequency;
       }
-//g_print("vfo_move_to: vfo=%d frequency=%lld diff==%lld\n",id,vfo[id].frequency,diff);
     }
 
+//g_print("vfo_move_to: id=%d ctun=%d hz=%lld sat_mode=%d freq=%lld to %lld\n",id,vfo[id].ctun,hz,sat_mode,saved_freq,vfo[id].ctun?vfo[id].ctun_frequency:vfo[id].frequency);
+
     int sid=id==0?1:0;
     switch(sat_mode) {
       case SAT_NONE:
@@ -747,10 +749,11 @@ void vfo_move_to(long long hz) {
         // A and B increment and decrement together
         if(vfo[sid].ctun) {
           vfo[sid].ctun_frequency+=diff;
-//g_print("vfo_move_to: SAT vfo=%d ctun_frequency=%lld\n",sid,vfo[sid].ctun_frequency);
         } else {
           vfo[sid].frequency+=diff;
-//g_print("vfo_move_to: SAT vfo=%d frequency=%lld\n",sid,vfo[sid].frequency);
+        }
+        if(vfo[id].mode!=modeCWL && vfo[id].mode!=modeCWU) {
+          vfo[sid].frequency=vfo[sid].frequency/step*step;
         }
         break;
       case RSAT_MODE:
@@ -758,40 +761,17 @@ void vfo_move_to(long long hz) {
         // A increments and B decrements or A decrements and B increments
         if(vfo[sid].ctun) {
           vfo[sid].ctun_frequency-=diff;
-//g_print("vfo_move_to: RSAT vfo=%d ctun_frequency=%lld\n",sid,vfo[sid].ctun_frequency);
         } else {
           vfo[sid].frequency-=diff;
-//g_print("vfo_move_to: RSAT vfo=%d frequency=%lld\n",sid,vfo[sid].frequency);
+        }
+        if(vfo[id].mode!=modeCWL && vfo[id].mode!=modeCWU) {
+          vfo[sid].frequency=vfo[sid].frequency/step*step;
         }
         break;
     }
 
     receiver_vfo_changed(active_receiver);
 
-#ifdef INCLUDED
-
-    BANDSTACK_ENTRY* entry=bandstack_entry_get_current();
-
-#ifdef SOAPYSDR
-    if(protocol==SOAPYSDR_PROTOCOL) {
-      setFrequency((entry->frequency+active_receiver->dds_offset-hz)/step*step);
-    } else {
-#endif
-      if(vfo[id].ctun) {
-        setFrequency((active_receiver->frequency+hz)/step*step);
-      } else {
-        long long f=(active_receiver->frequency+active_receiver->dds_offset+hz)/step*step;
-        if(vfo[active_receiver->id].mode==modeCWL) {
-          f+=cw_keyer_sidetone_frequency;
-        } else if(vfo[active_receiver->id].mode==modeCWU) {
-          f-=cw_keyer_sidetone_frequency;
-        }
-        setFrequency(f);
-      }
-#ifdef SOAPYSDR
-    }
-#endif
-#endif
     g_idle_add(ext_vfo_update,NULL);
   }
 }