# USBOZY_INCLUDE=USBOZY
# uncomment the line to below include support local CW keyer
-LOCALCW_INCLUDE=LOCALCW
+#LOCALCW_INCLUDE=LOCALCW
# uncomment the line below for SoapySDR
-SOAPYSDR_INCLUDE=SOAPYSDR
+#SOAPYSDR_INCLUDE=SOAPYSDR
# uncomment the line to below include support for sx1509 i2c expander
#SX1509_INCLUDE=sx1509
#STEMLAB_DISCOVERY=STEMLAB_DISCOVERY
# uncomment the line below to include support for STEMlab discovery (WITHOUT AVAHI)
-STEMLAB_DISCOVERY=STEMLAB_DISCOVERY_NOAVAHI
+#STEMLAB_DISCOVERY=STEMLAB_DISCOVERY_NOAVAHI
+# uncomment to get ALSA audio module on Linux (default is now to use pulseaudio)
+#AUDIO_MODULE=ALSA
# uncomment the line below for various debug facilities
#DEBUG_OPTION=-D DEBUG
# very early code not included yet
#SERVER_INCLUDE=SERVER
-# uncomment to get ALSA audio module on Linux
-#AUDIO_MODULE=ALSA
-
CFLAGS?= -O -Wno-deprecated-declarations
PKG_CONFIG = pkg-config
SYSLIBS=-lrt
endif
ifeq ($(UNAME_S), Darwin)
-SYSLIBS=-framework IOkit
+SYSLIBS=-framework IOKit
endif
OPTIONS=$(SMALL_SCREEN_OPTIONS) $(MIDI_OPTIONS) $(PURESIGNAL_OPTIONS) $(REMOTE_OPTIONS) $(USBOZY_OPTIONS) \
$(GPIO_OPTIONS) $(GPIOD_OPTIONS) $(SOAPYSDR_OPTIONS) $(LOCALCW_OPTIONS) \
- $(STEMLAB_OPTIONS) $(PTT_OPTIONES) $(SERVER_OPTIONS) $(AUDIO_OPTIONS) \
+ $(STEMLAB_OPTIONS) $(PTT_OPTIONES) $(SERVER_OPTIONS) $(AUDIO_OPTIONS) $(GPIO_OPTIONS) \
-D GIT_DATE='"$(GIT_DATE)"' -D GIT_VERSION='"$(GIT_VERSION)"' $(DEBUG_OPTION)
LIBS= -lm -lwdsp -lpthread $(SYSLIBS) $(AUDIO_LIBS) $(USBOZY_LIBS) $(GTKLIBS) \
int audio = 0;
int mic_buffer_size = 720; // samples (both left and right)
+static GMutex audio_mutex;
static snd_pcm_t *record_handle=NULL;
static snd_pcm_format_t record_audio_format;
g_print("audio_open_input: hw=%s\n",hw);
for(i=0;i<FORMATS;i++) {
+ g_mutex_lock(&audio_mutex);
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));
+ record_handle=NULL;
+ g_mutex_unlock(&audio_mutex);
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));
+ g_mutex_unlock(&audio_mutex);
audio_close_input();
continue;
} else {
if(i>=FORMATS) {
g_print("audio_open_input: cannot find usable format\n");
+ g_mutex_unlock(&audio_mutex);
audio_close_input();
return err;
}
mic_ring_buffer=(float *) g_new(float,MICRINGLEN);
mic_ring_read_pt = mic_ring_write_pt=0;
if (mic_ring_buffer == NULL) {
+ g_mutex_unlock(&audio_mutex);
audio_close_input();
return -1;
}
mic_read_thread_id = g_thread_try_new("microphone",mic_read_thread,NULL,&error);
if(!mic_read_thread_id ) {
g_print("g_thread_new failed on mic_read_thread: %s\n",error->message);
+ g_mutex_unlock(&audio_mutex);
audio_close_input();
return -1;
}
+ g_mutex_unlock(&audio_mutex);
return 0;
}
}
void audio_close_input() {
- void *p;
g_print("audio_close_input\n");
running=FALSE;
+ g_mutex_lock(&audio_mutex);
if(mic_read_thread_id!=NULL) {
g_print("audio_close_input: wait for thread to complete\n");
g_thread_join(mic_read_thread_id);
mic_read_thread_id=NULL;
}
+ g_mutex_lock(&audio_mutex);
if(record_handle!=NULL) {
g_print("audio_close_input: snd_pcm_close\n");
snd_pcm_close (record_handle);
g_free(mic_buffer);
mic_buffer=NULL;
}
- //
- // We do not want to do a mutex lock/unlock for every single mic sample
- // accessed. Since only the ring buffer is maintained by the functions
- // audio_get_next_mic_sample() and in the "mic read thread",
- // it is more than enough to wait 2 msec after setting mic_ring_buffer to NULL
- // before actually releasing the storage.
- //
if (mic_ring_buffer != NULL) {
- p=mic_ring_buffer;
- mic_ring_buffer=NULL;
- usleep(2);
- g_free(p);
+ g_free(mic_ring_buffer);
}
+ g_mutex_unlock(&audio_mutex);
}
//
float audio_get_next_mic_sample() {
int newpt;
float sample;
+ g_mutex_lock(&audio_mutex);
if ((mic_ring_buffer == NULL) || (mic_ring_read_pt == mic_ring_write_pt)) {
// no buffer, or nothing in buffer: insert silence
sample=0.0;
} else {
- // the "existence" of the ring buffer is now guaranteed for 1 msec,
- // see audio_close_input(),
newpt = mic_ring_read_pt+1;
if (newpt == MICRINGLEN) newpt=0;
sample=mic_ring_buffer[mic_ring_read_pt];
// atomic update of read pointer
mic_ring_read_pt=newpt;
}
+ g_mutex_unlock(&audio_mutex);
return sample;
}
g_print("audio_get_cards\n");
+ g_mutex_init(&audio_mutex);
n_input_devices=0;
n_output_devices=0;
extern AUDIO_DEVICE input_devices[MAX_AUDIO_DEVICES];
extern int n_output_devices;
extern AUDIO_DEVICE output_devices[MAX_AUDIO_DEVICES];
-extern GMutex audio_mutex;
-extern gint local_microphone_buffer_size;
extern int audio_open_input();
extern void audio_close_input();
extern int audio_open_output(RECEIVER *rx);
extern void audio_close_output(RECEIVER *rx);
extern int audio_write(RECEIVER *rx,float left_sample,float right_sample);
-extern int cw_audio_write(RECEIVER *rx,float sample);
+extern int cw_audio_write(RECEIVER *rx, float sample);
extern void audio_get_cards();
char * audio_get_error_string(int err);
float audio_get_next_mic_sample();
if (max_encoders > 0) {
- grid=gtk_grid_new();
- gtk_grid_set_column_homogeneous(GTK_GRID(grid),FALSE);
- gtk_grid_set_row_homogeneous(GTK_GRID(grid),TRUE);
- gtk_grid_set_column_spacing (GTK_GRID(grid),2);
- gtk_grid_set_row_spacing (GTK_GRID(grid),2);
+ grid=gtk_grid_new();
+ gtk_grid_set_column_homogeneous(GTK_GRID(grid),FALSE);
+ gtk_grid_set_row_homogeneous(GTK_GRID(grid),TRUE);
+ gtk_grid_set_column_spacing (GTK_GRID(grid),2);
+ gtk_grid_set_row_spacing (GTK_GRID(grid),2);
/*
- widget=gtk_label_new(NULL);
- gtk_label_set_markup (GTK_LABEL(widget), "<span foreground=\"#ff0000\"><b>Note: Pin number now use Broadcom GPIO</b></span>");
- gtk_grid_attach(GTK_GRID(grid),widget,col,row,6,1);
+ widget=gtk_label_new(NULL);
+ gtk_label_set_markup (GTK_LABEL(widget), "<span foreground=\"#ff0000\"><b>Note: Pin number now use Broadcom GPIO</b></span>");
+ gtk_grid_attach(GTK_GRID(grid),widget,col,row,6,1);
- row++;
- col=0;
+ row++;
+ col=0;
*/
- widget=gtk_label_new("");
- gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
- col++;
-
- widget=gtk_label_new(NULL);
- gtk_label_set_markup (GTK_LABEL(widget), controller==CONTROLLER2_V2?"<b>Bottom Encoder</b>":"<b>Encoder</b>");
- gtk_grid_attach(GTK_GRID(grid),widget,col,row,2,1);
- col+=2;
+ widget=gtk_label_new("");
+ gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+ col++;
- if(controller==CONTROLLER2_V2) {
widget=gtk_label_new(NULL);
- gtk_label_set_markup (GTK_LABEL(widget), "<b>Top Encoder</b>");
+ gtk_label_set_markup (GTK_LABEL(widget), controller==CONTROLLER2_V2?"<b>Bottom Encoder</b>":"<b>Encoder</b>");
gtk_grid_attach(GTK_GRID(grid),widget,col,row,2,1);
col+=2;
- }
-
- widget=gtk_label_new(NULL);
- gtk_label_set_markup (GTK_LABEL(widget), "<b>Switch</b>");
- gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
- row++;
- col=0;
+ if(controller==CONTROLLER2_V2) {
+ widget=gtk_label_new(NULL);
+ gtk_label_set_markup (GTK_LABEL(widget), "<b>Top Encoder</b>");
+ gtk_grid_attach(GTK_GRID(grid),widget,col,row,2,1);
+ col+=2;
+ }
- widget=gtk_label_new(NULL);
- gtk_label_set_markup (GTK_LABEL(widget), "<b>ID</b>");
- gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
- col++;
+ widget=gtk_label_new(NULL);
+ gtk_label_set_markup (GTK_LABEL(widget), "<b>Switch</b>");
+ gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
- widget=gtk_label_new(NULL);
- gtk_label_set_markup (GTK_LABEL(widget), "<b>Gpio A</b>");
- gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
- col++;
+ row++;
+ col=0;
- widget=gtk_label_new(NULL);
- gtk_label_set_markup (GTK_LABEL(widget), "<b>Gpio B</b>");
- gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
- col++;
+ widget=gtk_label_new(NULL);
+ gtk_label_set_markup (GTK_LABEL(widget), "<b>ID</b>");
+ gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+ col++;
- if(controller==CONTROLLER2_V2) {
widget=gtk_label_new(NULL);
gtk_label_set_markup (GTK_LABEL(widget), "<b>Gpio A</b>");
gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
gtk_label_set_markup (GTK_LABEL(widget), "<b>Gpio B</b>");
gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
col++;
- }
- widget=gtk_label_new(NULL);
- gtk_label_set_markup (GTK_LABEL(widget), "<b>Gpio</b>");
- gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
- col++;
+ if(controller==CONTROLLER2_V2) {
+ widget=gtk_label_new(NULL);
+ gtk_label_set_markup (GTK_LABEL(widget), "<b>Gpio A</b>");
+ gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+ col++;
- row++;
- col=0;
+ widget=gtk_label_new(NULL);
+ gtk_label_set_markup (GTK_LABEL(widget), "<b>Gpio B</b>");
+ gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+ col++;
+ }
- for(i=0;i<max_encoders;i++) {
widget=gtk_label_new(NULL);
- gchar id[16];
- g_sprintf(id,"<b>%d</b>",i);
- gtk_label_set_markup (GTK_LABEL(widget), id);
+ gtk_label_set_markup (GTK_LABEL(widget), "<b>Gpio</b>");
gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
col++;
- widget=gtk_spin_button_new_with_range (0.0,28.0,1.0);
- gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget),encoders[i].bottom_encoder_address_a);
- gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
- col++;
-
- widget=gtk_spin_button_new_with_range (0.0,28.0,1.0);
- gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget),encoders[i].bottom_encoder_address_b);
- gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
- col++;
-
- if(controller==CONTROLLER2_V2 && i<(max_encoders-1)) {
- widget=gtk_spin_button_new_with_range (0.0,28.0,1.0);
- gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget),encoders[i].top_encoder_address_a);
+ row++;
+ col=0;
+
+ for(i=0;i<max_encoders;i++) {
+ widget=gtk_label_new(NULL);
+ gchar id[16];
+ g_sprintf(id,"<b>%d</b>",i);
+ gtk_label_set_markup (GTK_LABEL(widget), id);
gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
col++;
-
+
widget=gtk_spin_button_new_with_range (0.0,28.0,1.0);
- gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget),encoders[i].top_encoder_address_b);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget),encoders[i].bottom_encoder_address_a);
gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
col++;
- }
-
- if(i<(max_encoders-1)) {
+
widget=gtk_spin_button_new_with_range (0.0,28.0,1.0);
- gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget),encoders[i].switch_address);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget),encoders[i].bottom_encoder_address_b);
gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
col++;
- }
+
+ if(controller==CONTROLLER2_V2 && i<(max_encoders-1)) {
+ widget=gtk_spin_button_new_with_range (0.0,28.0,1.0);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget),encoders[i].top_encoder_address_a);
+ gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+ col++;
+
+ widget=gtk_spin_button_new_with_range (0.0,28.0,1.0);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget),encoders[i].top_encoder_address_b);
+ gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+ col++;
+ }
+
+ if(i<(max_encoders-1)) {
+ widget=gtk_spin_button_new_with_range (0.0,28.0,1.0);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget),encoders[i].switch_address);
+ gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+ col++;
+ }
- row++;
- col=0;
- }
- gtk_notebook_append_page(GTK_NOTEBOOK(notebook),grid,gtk_label_new("Encoders"));
+ row++;
+ col=0;
+ }
+ gtk_notebook_append_page(GTK_NOTEBOOK(notebook),grid,gtk_label_new("Encoders"));
}
#ifdef LOCALCW
//
- // C2V2 uses *all* available GPIO lines, therefore we cannot do
- // CW there. The special switch_address -1 means "do not use"
+ // Controller2 V2 uses *all* available GPIO lines, therefore we cannot
+ // present this tab.
+ // Accept "-1" as GPIO line, this means "do not use"
//
if(controller !=CONTROLLER2_V2) {
char text[64];
#include "receiver.h"
#include "new_protocol.h"
#include "old_protocol.h"
-#ifdef LOCALCW
#include "iambic.h"
-#endif
#include "ext.h"
static GtkWidget *parent_window=NULL;
#ifdef SOAPYSDR
#include "soapy_protocol.h"
#endif
-#ifdef GPIO
#include "actions.h"
#include "gpio.h"
-#endif
static GtkWidget *parent_window=NULL;
for (i=0; i<STEPS; i++) {
if (steps[i] == step) break;
}
- if (i >= STEPS) i=0;
+ //
+ // This should not happen (step size not found). If it happens,
+ // take the seond-smallest one such that the step size remains
+ // small after changing it.
+ //
+ if (i >= STEPS) i=1;
if (direction > 0) {
i++;
}
if (i >= STEPS) i=STEPS;
if (i < 0 ) i=0;
+ step=steps[i];
vfo_update();
}
temp=active_receiver->pan;
int vfo=freq_command->id;
long long f=ntohll(freq_command->hz);
- local_set_frequency(vfo,f);
+ set_frequency(vfo,f);
vfo_update();
send_vfo_data(client,VFO_A);
send_vfo_data(client,VFO_B);
// for a combined attenuator/preamplifier with the AD9866 chip.
// The value is between 0 and 60 and formally correspondes to
// to an RX gain of -12 to +48 dB. However, we set here that
- // a value of +16 (that is, 28 on the 0-60 scale) corresponds to
+ // a value of +14 (that is, 26 on the 0-60 scale) corresponds to
// "zero attenuation"
- chk_data(37 -(frame[4] & 0x3F) , rx_att[0], "RX1 HL ATT/GAIN");
+ // This means that the nominal value of "RX gain calibration" is 14.
+ chk_data(26 -(frame[4] & 0x3F) , rx_att[0], "RX1 HL ATT/GAIN");
} else {
chk_data((frame[4] & 0x1F) >> 0, rx_att[0], "RX1 ATT");
chk_data((frame[4] & 0x20) >> 5, rx1_attE, "RX1 ATT enable");
//
EXTERN double c1,c2;
-//
-// Forward declarations for the audio functions
-//
-void audio_get_cards(void);
-void audio_open_output();
-void audio_write(int16_t, int16_t);
-
//
// Forward declarations for new protocol stuff
//
#ifndef _IAMBIC_H
#define _IAMBIC_H
+#ifdef LOCALCW
enum {
CHECK = 0,
STRAIGHT,
int keyer_init();
#endif
+#endif
int chan;
int t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12;
int onoff, delay;
- struct desc *desc,*dp;
+ struct desc *desc;
enum MIDItype type;
enum MIDIevent event;
- int i;
char c;
MidiReleaseCommands();
case MIDI_ACTION_DIV_COARSEPHASE: // knob or wheel supported
case MIDI_ACTION_DIV_FINEPHASE: // knob or wheel supported
case MIDI_ACTION_DIV_PHASE: // knob or wheel supported
+ dnew=0.0;
switch (type) {
case MIDI_TYPE_KNOB:
// coarse: change phase from -180 to 180
}
break;
default:
- // do not change
- // we should not come here anyway
- dnew = 0.0;
+ // do nothing
break;
}
// dnew is the delta
break;
/////////////////////////////////////////////////////////// "RFGAIN"
case MIDI_ACTION_RF_GAIN: // knob or wheel supported
- if (type == MIDI_TYPE_KNOB) {
+ switch (type) {
+ case MIDI_TYPE_KNOB:
dnew=val;
- } else if (type == MIDI_TYPE_WHEEL) {
+ break;
+ case MIDI_TYPE_WHEEL:
dnew=adc[active_receiver->id].gain+val;
+ break;
+ default:
+ // Arriving here means there is an error somewhere else
+ dnew=0.0;
+ break;
}
if (dnew < 0.0) dnew = 0.0;
if (dnew > 100.0) dnew = 100.0;
/////////////////////////////////////////////////////////// "RITCLEAR"
case MIDI_ACTION_RIT_CLEAR: // only key supported
// clear RIT value
- vfo[active_receiver->id].rit = new;
+ vfo[active_receiver->id].rit = 0;
+ vfo[active_receiver->id].rit_enabled = 0;
vfo_update();
break;
/////////////////////////////////////////////////////////// "RITSTEP"
};
static GtkWidget *parent_window=NULL;
-static GtkWidget *menu_b=NULL;
static GtkWidget *dialog=NULL;
-static GtkWidget *midi_enable_b;
-
static GtkListStore *store;
static GtkWidget *view;
static GtkWidget *scrolled_window=NULL;
static GtkTreeIter iter;
struct desc *current_cmd;
-static GtkWidget *filename;
-
static GtkWidget *newEvent;
static GtkWidget *newChannel;
static GtkWidget *newNote;
}
static void type_changed_cb(GtkWidget *widget, gpointer data) {
- int i=0;
- int j=0;
// update actions available for the type
gchar *type=gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(widget));
GtkWidget *save_dialog;
GtkFileChooser *chooser;
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE;
- gchar *filename;
gint res;
- struct desc *cmd;
save_dialog = gtk_file_chooser_dialog_new ("Save File",
GTK_WINDOW(dialog),
GtkWidget *load_dialog;
GtkFileChooser *chooser;
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
- gchar *filename;
gint res;
- struct desc *cmd;
load_dialog = gtk_file_chooser_dialog_new ("Open MIDI File",
GTK_WINDOW(dialog),
GtkWidget *load_dialog;
GtkFileChooser *chooser;
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
- gchar *filename;
gint res;
- struct desc *cmd;
load_dialog = gtk_file_chooser_dialog_new ("Open LEGACY MIDI File",
GTK_WINDOW(dialog),
//g_print("%s: type=%s action=%s\n",__FUNCTION__,str_type,str_action);
thisAction=MIDI_ACTION_NONE;
+ onoff=0;
i=0;
while(ActionTable[i].action!=MIDI_ACTION_LAST) {
if(strcmp(ActionTable[i].str,str_action)==0) {
static int update(void *data) {
int state=GPOINTER_TO_INT(data);
gchar text[32];
- gint i=1;
- gint j;
switch(state) {
case UPDATE_NEW:
#include "toolbar.h"
#include "vox.h"
#include "ext.h"
-#ifdef LOCALCW
#include "iambic.h"
-#endif
#define min(x,y) (x<y?x:y)
static pthread_mutex_t tx_spec_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t hi_prio_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t general_mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_mutex_t p2_audio_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t audio_mutex = PTHREAD_MUTEX_INITIALIZER;
static int local_ptt=0;
//
// Only process samples if transmitting in CW
//
- pthread_mutex_lock(&p2_audio_mutex);
+ pthread_mutex_lock(&audio_mutex);
// insert the samples
audiobuffer[audioindex++]=left_audio_sample>>8;
audiobuffer[audioindex++]=left_audio_sample;
audioindex=4;
audiosequence++;
}
- pthread_mutex_unlock(&p2_audio_mutex);
+ pthread_mutex_unlock(&audio_mutex);
}
}
//
if (isTransmitting() && (txmode==modeCWU || txmode==modeCWL)) return;
- pthread_mutex_lock(&p2_audio_mutex);
+ pthread_mutex_lock(&audio_mutex);
// insert the samples
audiobuffer[audioindex++]=left_audio_sample>>8;
audiobuffer[audioindex++]=left_audio_sample;
audioindex=4;
audiosequence++;
}
- pthread_mutex_unlock(&p2_audio_mutex);
+ pthread_mutex_unlock(&audio_mutex);
}
void new_protocol_flush_iq_samples() {
#include "toolbar.h"
#include "vfo.h"
#include "ext.h"
-#ifdef LOCALCW
#include "iambic.h"
-#endif
#include "error_handler.h"
#define min(x,y) (x<y?x:y)
static PaStream *record_handle=NULL;
+
int n_input_devices;
AUDIO_DEVICE input_devices[MAX_AUDIO_DEVICES];
int n_output_devices;
AUDIO_DEVICE output_devices[MAX_AUDIO_DEVICES];
+static GMutex audio_mutex;
int n_input_devices=0;
int n_output_devices=0;
PaError err;
+ g_mutex_init(&audio_mutex);
err = Pa_Initialize();
if( err != paNoError )
{
- fprintf(stderr, "PORTAUDIO ERROR: Pa_Initialize: %s\n", Pa_GetErrorText(err));
+ g_print("%s: init error %s\n", __FUNCTION__,Pa_GetErrorText(err));
return;
}
numDevices = Pa_GetDeviceCount();
input_devices[n_input_devices].index=i;
n_input_devices++;
}
- fprintf(stderr,"PORTAUDIO INPUT DEVICE, No=%d, Name=%s\n", i, deviceInfo->name);
+ g_print("%s: INPUT DEVICE, No=%d, Name=%s\n", __FUNCTION__, i, deviceInfo->name);
}
outputParameters.device = i;
output_devices[n_output_devices].index=i;
n_output_devices++;
}
- fprintf(stderr,"PORTAUDIO OUTPUT DEVICE, No=%d, Name=%s\n", i, deviceInfo->name);
+ g_print("%s: OUTPUT DEVICE, No=%d, Name=%s\n", __FUNCTION__, i, deviceInfo->name);
}
}
}
break;
}
}
- fprintf(stderr,"audio_open_input: name=%s PADEV=%d\n",transmitter->microphone_name,padev);
+ g_print("%s: name=%s PADEV=%d\n", __FUNCTION__, transmitter->microphone_name, padev);
//
- // Should not occur, but possibly device name not found
+ // Device name possibly came from props file and device is no longer there
//
if (padev < 0) {
return -1;
}
+ g_mutex_lock(&audio_mutex);
+
bzero( &inputParameters, sizeof( inputParameters ) ); //not necessary if you are filling in all the fields
inputParameters.channelCount = 1; // MONO
inputParameters.device = padev;
err = Pa_OpenStream(&record_handle, &inputParameters, NULL, 48000.0, (unsigned long) MY_AUDIO_BUFFER_SIZE,
paNoFlag, pa_mic_cb, NULL);
if (err != paNoError) {
- fprintf(stderr, "PORTAUDIO ERROR: AOI open stream: %s\n",Pa_GetErrorText(err));
+ g_print("%s: open stream error %s\n", __FUNCTION__, Pa_GetErrorText(err));
+ record_handle=NULL;
+ g_mutex_unlock(&audio_mutex);
return -1;
}
mic_ring_buffer=(float *) g_new(float,MY_RING_BUFFER_SIZE);
mic_ring_outpt = mic_ring_inpt=0;
+
if (mic_ring_buffer == NULL) {
+ Pa_CloseStream(record_handle);
+ record_handle=NULL;
+ g_print("%s: alloc buffer failed.\n", __FUNCTION__);
+ g_mutex_unlock(&audio_mutex);
return -1;
}
err = Pa_StartStream(record_handle);
if (err != paNoError) {
- fprintf(stderr, "PORTAUDIO ERROR: AOI start stream:%s\n",Pa_GetErrorText(err));
+ g_print("%s: start stream error %s\n", __FUNCTION__, Pa_GetErrorText(err));
+ Pa_CloseStream(record_handle);
+ record_handle=NULL;
+ g_free(mic_ring_buffer);
+ mic_ring_buffer=NULL;
+ g_mutex_unlock(&audio_mutex);
return -1;
}
+
+ //
+ // Finished!
+ //
+ g_mutex_unlock(&audio_mutex);
return 0;
}
+
//
// PortAudio call-back function for Audio output
//
float *out = (float *)outputBuffer;
RECEIVER *rx = (RECEIVER *)userdata;
int i, newpt;
- float *buffer=rx->local_audio_buffer;
int avail; // only used for debug
if (out == NULL) {
- fprintf(stderr,"PortAudio error: bogus audio buffer in callback\n");
+ g_print("%s: bogus audio buffer in callback\n", __FUNCTION__);
return paContinue;
}
- // DEBUG: report water mark
- //avail = rx->local_audio_buffer_inpt - rx->local_audio_buffer_outpt;
- //if (avail < 0) avail += MY_RING_BUFFER_SIZE;
- //fprintf(stderr,"AVAIL=%d\n", avail);
- newpt=rx->local_audio_buffer_outpt;
- for (i=0; i< framesPerBuffer; i++) {
- if (rx->local_audio_buffer_inpt == newpt) {
- // Ring buffer empty, send zero sample
- *out++ = 0.0;
- } else {
- *out++ = buffer[newpt++];
- if (newpt >= MY_RING_BUFFER_SIZE) newpt=0;
- rx->local_audio_buffer_outpt=newpt;
+ g_mutex_lock(&rx->local_audio_mutex);
+ if (rx->local_audio_buffer != NULL) {
+ //
+ // Mutex protection: if the buffer is non-NULL it cannot vanish
+ // util callback is completed
+ // DEBUG: report water mark
+ //avail = rx->local_audio_buffer_inpt - rx->local_audio_buffer_outpt;
+ //if (avail < 0) avail += MY_RING_BUFFER_SIZE;
+ //g_print("%s: AVAIL=%d\n", __FUNCTION__, avail);
+ newpt=rx->local_audio_buffer_outpt;
+ for (i=0; i< framesPerBuffer; i++) {
+ if (rx->local_audio_buffer_inpt == newpt) {
+ // Ring buffer empty, send zero sample
+ *out++ = 0.0;
+ } else {
+ *out++ = rx->local_audio_buffer[newpt++];
+ if (newpt >= MY_RING_BUFFER_SIZE) newpt=0;
+ rx->local_audio_buffer_outpt=newpt;
+ }
}
}
+ g_mutex_unlock(&rx->local_audio_mutex);
return paContinue;
}
{
float *in = (float *)inputBuffer;
int i, newpt;
- float sample;
if (in == NULL) {
// This should not happen, so we do not send silence etc.
- fprintf(stderr,"PortAudio error: bogus audio buffer in callback\n");
+ g_print("%s: bogus audio buffer in callback\n", __FUNCTION__);
return paContinue;
}
- //
- // send the samples in the buffer
- //
- for (i=0; i<framesPerBuffer; i++) {
- sample=in[i];
- switch(protocol) {
- case ORIGINAL_PROTOCOL:
- case NEW_PROTOCOL:
-#ifdef SOAPYSDR
- case SOAPYSDR_PROTOCOL:
-#endif
- //
- // put sample into ring buffer
- //
- if (mic_ring_buffer != NULL) {
- // the "existence" of the ring buffer is now guaranteed for 1 msec,
- // see audio_close_input(),
- newpt=mic_ring_inpt +1;
- if (newpt == MY_RING_BUFFER_SIZE) newpt=0;
- if (newpt != mic_ring_outpt) {
- // buffer space available, do the write
- mic_ring_buffer[mic_ring_inpt]=sample;
- // atomic update of mic_ring_inpt
- mic_ring_inpt=newpt;
- }
- }
- break;
- default:
- break;
+ g_mutex_lock(&audio_mutex);
+ if (mic_ring_buffer != NULL) {
+ //
+ // mutex protected: ring buffer cannot vanish
+ //
+ for (i=0; i<framesPerBuffer; i++) {
+ //
+ // put sample into ring buffer
+ //
+ newpt=mic_ring_inpt +1;
+ if (newpt == MY_RING_BUFFER_SIZE) newpt=0;
+ if (newpt != mic_ring_outpt) {
+ // buffer space available, do the write
+ mic_ring_buffer[mic_ring_inpt]=in[i];
+ // atomic update of mic_ring_inpt
+ mic_ring_inpt=newpt;
+ }
}
}
+ g_mutex_unlock(&audio_mutex);
return paContinue;
}
float audio_get_next_mic_sample() {
int newpt;
float sample;
+ g_mutex_lock(&audio_mutex);
+ //
+ // mutex protected (for every single sample!):
+ // ring buffer cannot vanish while being processed here
+ //
if ((mic_ring_buffer == NULL) || (mic_ring_outpt == mic_ring_inpt)) {
// no buffer, or nothing in buffer: insert silence
sample=0.0;
} else {
- // the "existence" of the ring buffer is now guaranteed for 1 msec,
- // see audio_close_input(),
newpt = mic_ring_outpt+1;
if (newpt == MY_RING_BUFFER_SIZE) newpt=0;
sample=mic_ring_buffer[mic_ring_outpt];
// atomic update of read pointer
mic_ring_outpt=newpt;
}
+ g_mutex_unlock(&audio_mutex);
return sample;
}
break;
}
}
- fprintf(stderr,"audio_open_output: name=%s PADEV=%d\n",rx->audio_name,padev);
+ g_print("%s: name=%s PADEV=%d\n", __FUNCTION__, rx->audio_name, padev);
//
- // Should not occur, but possibly device name not found
+ // Device name possibly came from props file and device is no longer there
//
if (padev < 0) {
return -1;
}
g_mutex_lock(&rx->local_audio_mutex);
+
bzero( &outputParameters, sizeof( outputParameters ) ); //not necessary if you are filling in all the fields
outputParameters.channelCount = 1; // Always MONO
outputParameters.device = padev;
outputParameters.suggestedLatency = 0.0; //Pa_GetDeviceInfo(padev)->defaultLowOutputLatency ;
outputParameters.hostApiSpecificStreamInfo = NULL; //See you specific host's API docs for info on using this field
+ err = Pa_OpenStream(&(rx->playstream), NULL, &outputParameters, 48000.0, (unsigned long) MY_AUDIO_BUFFER_SIZE,
+ paNoFlag, pa_out_cb, rx);
+ if (err != paNoError) {
+ g_print("%s: open stream error %s\n", __FUNCTION__, Pa_GetErrorText(err));
+ rx->playstream = NULL;
+ g_mutex_unlock(&rx->local_audio_mutex);
+ return -1;
+ }
+
//
// This is now a ring buffer much larger than a single audio buffer
//
rx->local_audio_buffer_outpt=0;
rx->local_audio_cw=0;
- err = Pa_OpenStream(&(rx->playback_handle), NULL, &outputParameters, 48000.0, (unsigned long) MY_AUDIO_BUFFER_SIZE,
- paNoFlag, pa_out_cb, rx);
- if (err != paNoError || rx->local_audio_buffer == NULL) {
- fprintf(stderr,"PORTAUDIO ERROR: out open stream: %s\n",Pa_GetErrorText(err));
- rx->playback_handle = NULL;
- if (rx->local_audio_buffer) g_free(rx->local_audio_buffer);
- rx->local_audio_buffer = NULL;
+ if (rx->local_audio_buffer == NULL) {
+ g_print("%s: allocate buffer failed\n", __FUNCTION__);
+ Pa_CloseStream(rx->playstream);
+ rx->playstream=NULL;
g_mutex_unlock(&rx->local_audio_mutex);
return -1;
}
- err = Pa_StartStream(rx->playback_handle);
+ err = Pa_StartStream(rx->playstream);
if (err != paNoError) {
- fprintf(stderr,"PORTAUDIO ERROR: out start stream:%s\n",Pa_GetErrorText(err));
- rx->playback_handle=NULL;
- if (rx->local_audio_buffer) g_free(rx->local_audio_buffer);
+ g_print("%s: error starting stream:%s\n",__FUNCTION__,Pa_GetErrorText(err));
+ Pa_CloseStream(rx->playstream);
+ rx->playstream=NULL;
+ g_free(rx->local_audio_buffer);
rx->local_audio_buffer = NULL;
g_mutex_unlock(&rx->local_audio_mutex);
return -1;
}
+ //
+ // Finished!
+ //
g_mutex_unlock(&rx->local_audio_mutex);
return 0;
}
void audio_close_input()
{
PaError err;
- void *p;
- fprintf(stderr,"AudioCloseInput: %s\n", transmitter->microphone_name);
+ g_print("%s: micname=%s\n", __FUNCTION__,transmitter->microphone_name);
+ g_mutex_lock(&audio_mutex);
if(record_handle!=NULL) {
err = Pa_StopStream(record_handle);
if (err != paNoError) {
- fprintf(stderr,"PORTAUDIO ERROR: in stop stream: %s\n",Pa_GetErrorText(err));
+ g_print("%s: error stopping stream: %s\n",__FUNCTION__,Pa_GetErrorText(err));
}
err = Pa_CloseStream(record_handle);
if (err != paNoError) {
- fprintf(stderr,"PORTAUDIO ERROR: in close stream: %s\n",Pa_GetErrorText(err));
+ g_print("%s: %s\n",__FUNCTION__,Pa_GetErrorText(err));
}
record_handle=NULL;
}
- //
- // We do not want to do a mutex lock/unlock for every single mic sample
- // accessed. Since only the ring buffer is maintained by the functions
- // audio_get_next_mic_sample() and in the "mic callback" function,
- // it is more than enough to wait 2 msec after setting mic_ring_buffer to NULL
- // before actually releasing the storage.
- //
if (mic_ring_buffer != NULL) {
- p=mic_ring_buffer;
- mic_ring_buffer=NULL;
- usleep(2);
- g_free(p);
+ g_free(mic_ring_buffer);
}
+ g_mutex_unlock(&audio_mutex);
}
//
void audio_close_output(RECEIVER *rx) {
PaError err;
- fprintf(stderr,"AudioCloseOutput: %s\n", rx->audio_name);
+ g_print("%s: device=%sn", __FUNCTION__,rx->audio_name);
g_mutex_lock(&rx->local_audio_mutex);
if(rx->local_audio_buffer!=NULL) {
rx->local_audio_buffer=NULL;
}
- if(rx->playback_handle!=NULL) {
- err = Pa_StopStream(rx->playback_handle);
+ if(rx->playstream!=NULL) {
+ err = Pa_StopStream(rx->playstream);
if (err != paNoError) {
- fprintf(stderr,"PORTAUDIO ERROR: out stop stream: %s\n",Pa_GetErrorText(err));
+ g_print("%s: stop stream error %s\n", __FUNCTION__, Pa_GetErrorText(err));
}
- err = Pa_CloseStream(rx->playback_handle);
+ err = Pa_CloseStream(rx->playstream);
if (err != paNoError) {
- fprintf(stderr,"PORTAUDIO ERROR: out close stream: %s\n",Pa_GetErrorText(err));
+ g_print("%s: close stream error %s\n",__FUNCTION__,Pa_GetErrorText(err));
}
- rx->playback_handle=NULL;
+ rx->playstream=NULL;
}
g_mutex_unlock(&rx->local_audio_mutex);
}
}
g_mutex_lock(&rx->local_audio_mutex);
- if (rx->playback_handle != NULL && buffer != NULL) {
+ if (rx->playstream != NULL && buffer != NULL) {
if (rx->local_audio_cw == 1) {
//
// We come from a TX->RX transition:
// Thus we have an active latency management.
//
int cw_audio_write(RECEIVER *rx, float sample) {
- float *buffer = rx->local_audio_buffer;
int oldpt, newpt;
static int count=0;
int avail;
int adjust;
g_mutex_lock(&rx->local_audio_mutex);
- if (rx->playback_handle != NULL && buffer != NULL) {
+ if (rx->playstream != NULL && rx->local_audio_buffer != NULL) {
if (rx->local_audio_cw == 0 && cw_keyer_sidetone_volume > 0) {
//
// First time producing CW audio after RX/TX transition:
// empty audio buffer and insert 512 samples of silence
//
rx->local_audio_cw=1;
- bzero(buffer, 512*sizeof(float));
+ bzero(rx->local_audio_buffer, 512*sizeof(float));
rx->local_audio_buffer_inpt=512;
rx->local_audio_buffer_outpt=0;
count=0;
//
// buffer space available
//
- buffer[oldpt] = sample;
+ rx->local_audio_buffer[oldpt] = sample;
rx->local_audio_buffer_inpt=newpt;
}
break;
// insert two samples of silence. No check on "buffer full" needed
//
oldpt=rx->local_audio_buffer_inpt;
- buffer[oldpt++]=0.0;
+ rx->local_audio_buffer[oldpt++]=0.0;
if (oldpt == MY_RING_BUFFER_SIZE) oldpt=0;
- buffer[oldpt++]=0.0;
+ rx->local_audio_buffer[oldpt++]=0.0;
if (oldpt == MY_RING_BUFFER_SIZE) oldpt=0;
rx->local_audio_buffer_inpt=oldpt;
break;
case 2:
//
// buffer becomes too full, and we just saw
- // 16 samples of silence: just skip it
+ // 16 samples of silence: just skip the last "silent" sample
//
break;
}
//
// Ring buffer for "local microphone" samples
-// NOTE: lead large buffer for some "loopback" devices which produce
+// NOTE: need large buffer for some "loopback" devices which produce
// samples in large chunks if fed from digimode programs.
//
#define MICRINGLEN 6000
static pa_context *pa_ctx;
static pa_simple* microphone_stream;
static gint local_microphone_buffer_offset;
-static float *local_microphone_buffer;
-static GThread *mic_read_thread_id;
+static float *local_microphone_buffer=NULL;
+static GThread *mic_read_thread_id=0;
static gboolean running;
gint local_microphone_buffer_size=720;
-GMutex audio_mutex;
+static GMutex audio_mutex;
static void source_list_cb(pa_context *context,const pa_source_info *s,int eol,void *data) {
int i;
g_mutex_lock(&audio_mutex);
main_loop=pa_glib_mainloop_new(NULL);
main_loop_api=pa_glib_mainloop_get_api(main_loop);
- pa_ctx=pa_context_new(main_loop_api,"linhpsdr");
+ pa_ctx=pa_context_new(main_loop_api,"piHPSDR");
pa_context_connect(pa_ctx,NULL,0,NULL);
pa_context_set_state_callback(pa_ctx, state_cb, NULL);
}
g_print("%s: running=%d\n",__FUNCTION__,running);
while(running) {
- g_mutex_lock(&audio_mutex);
- if(local_microphone_buffer==NULL) {
- running=0;
- } else {
- rc=pa_simple_read(microphone_stream,
+ //
+ // It is guaranteed that local_microphone_buffer, mic_ring_buffer, and microphone_stream
+ // will not be destroyed until this thread has terminated (and waited for via thread joining)
+ //
+ rc=pa_simple_read(microphone_stream,
local_microphone_buffer,
local_microphone_buffer_size*sizeof(float),
&err);
- if(rc<0) {
- running=0;
- g_print("%s: returned %d error=%d (%s)\n",__FUNCTION__,rc,err,pa_strerror(err));
- } else {
- gint newpt;
- for(gint i=0;i<local_microphone_buffer_size;i++) {
- gfloat sample=local_microphone_buffer[i];
- switch(protocol) {
- case ORIGINAL_PROTOCOL:
- case NEW_PROTOCOL:
-#ifdef SOAPYSDR
- case SOAPYSDR_PROTOCOL:
-#endif
- //
- // put sample into ring buffer
- //
- if (mic_ring_buffer != NULL) {
- // the "existence" of the ring buffer is now guaranteed for 1 msec,
- // see audio_close_input().
- newpt=mic_ring_write_pt +1;
- if (newpt == MICRINGLEN) newpt=0;
- if (newpt != mic_ring_read_pt) {
- // buffer space available, do the write
- mic_ring_buffer[mic_ring_write_pt]=sample;
- // atomic update of mic_ring_write_pt
- mic_ring_write_pt=newpt;
- }
- }
- break;
- default:
- break;
- }
+ if(rc<0) {
+ running=FALSE;
+ g_print("%s: returned %d error=%d (%s)\n",__FUNCTION__,rc,err,pa_strerror(err));
+ } else {
+ int newpt;
+ for(gint i=0;i<local_microphone_buffer_size;i++) {
+ gfloat sample=local_microphone_buffer[i];
+ //
+ // put sample into ring buffer
+ //
+ newpt=mic_ring_write_pt +1;
+ if (newpt == MICRINGLEN) newpt=0;
+ if (newpt != mic_ring_read_pt) {
+ // buffer space available, do the write
+ mic_ring_buffer[mic_ring_write_pt]=sample;
+ // atomic update of mic_ring_write_pt
+ mic_ring_write_pt=newpt;
}
}
}
- g_mutex_unlock(&audio_mutex);
}
g_print("%s: exit\n",__FUNCTION__);
}
mic_ring_buffer=(float *) g_new(float,MICRINGLEN);
mic_ring_read_pt = mic_ring_write_pt=0;
if (mic_ring_buffer == NULL) {
+ g_mutex_unlock(&audio_mutex);
audio_close_input();
return -1;
}
}
void audio_close_input() {
+ running=FALSE;
g_mutex_lock(&audio_mutex);
+
+ if(mic_read_thread_id!=NULL) {
+g_print("audio_close_input: wait for thread to complete\n");
+ //
+ // wait for the mic read thread to terminate,
+ // then destroy the stream and the buffers
+ // This way, the buffers cannot "vanish" in the mic read thread
+ //
+ g_thread_join(mic_read_thread_id);
+ mic_read_thread_id=NULL;
+ }
if(microphone_stream!=NULL) {
pa_simple_free(microphone_stream);
microphone_stream=NULL;
+ }
+ if (local_microphone_buffer != NULL) {
g_free(local_microphone_buffer);
local_microphone_buffer=NULL;
}
+ if (mic_ring_buffer != NULL) {
+ g_free(mic_ring_buffer);
+ }
g_mutex_unlock(&audio_mutex);
}
float audio_get_next_mic_sample() {
int newpt;
float sample;
-
+ g_mutex_lock(&audio_mutex);
if ((mic_ring_buffer == NULL) || (mic_ring_read_pt == mic_ring_write_pt)) {
// no buffer, or nothing in buffer: insert silence
- g_print("%s: no samples\n",__FUNCTION__);
sample=0.0;
} else {
- // the "existence" of the ring buffer is now guaranteed for 1 msec,
- // see audio_close_input(),
newpt = mic_ring_read_pt+1;
if (newpt == MICRINGLEN) newpt=0;
sample=mic_ring_buffer[mic_ring_read_pt];
// atomic update of read pointer
mic_ring_read_pt=newpt;
}
+ g_mutex_unlock(&audio_mutex);
return sample;
}
int err;
g_mutex_lock(&rx->local_audio_mutex);
- if(rx->local_audio_buffer==NULL) {
- rx->local_audio_buffer_offset=0;
- rx->local_audio_buffer=g_new0(float,2*rx->local_audio_buffer_size);
- }
- rx->local_audio_buffer[rx->local_audio_buffer_offset*2]=sample;
- rx->local_audio_buffer[(rx->local_audio_buffer_offset*2)+1]=sample;
- rx->local_audio_buffer_offset++;
- if(rx->local_audio_buffer_offset>=rx->local_audio_buffer_size) {
- rc=pa_simple_write(rx->playstream,
- rx->local_audio_buffer,
- rx->local_audio_buffer_size*sizeof(float)*2,
- &err);
- if(rc!=0) {
- fprintf(stderr,"audio_write failed err=%d\n",err);
+ if (rx->playstream != NULL && rx->local_audio_buffer != NULL) { // Note this test must be done "mutex-protected"
+ rx->local_audio_buffer[rx->local_audio_buffer_offset*2]=sample;
+ rx->local_audio_buffer[(rx->local_audio_buffer_offset*2)+1]=sample;
+ rx->local_audio_buffer_offset++;
+ if(rx->local_audio_buffer_offset>=rx->local_audio_buffer_size) {
+ rc=pa_simple_write(rx->playstream,
+ rx->local_audio_buffer,
+ rx->local_audio_buffer_size*sizeof(float)*2,
+ &err);
+ if(rc!=0) {
+ fprintf(stderr,"cw_audio_write failed err=%d\n",err);
+ }
+ rx->local_audio_buffer_offset=0;
}
- rx->local_audio_buffer_offset=0;
}
g_mutex_unlock(&rx->local_audio_mutex);
int err;
g_mutex_lock(&rx->local_audio_mutex);
- if(rx->local_audio_buffer==NULL) {
- rx->local_audio_buffer_offset=0;
- rx->local_audio_buffer=g_new0(float,2*rx->local_audio_buffer_size);
- }
- rx->local_audio_buffer[rx->local_audio_buffer_offset*2]=left_sample;
- rx->local_audio_buffer[(rx->local_audio_buffer_offset*2)+1]=right_sample;
- rx->local_audio_buffer_offset++;
- if(rx->local_audio_buffer_offset>=rx->local_audio_buffer_size) {
- rc=pa_simple_write(rx->playstream,
- rx->local_audio_buffer,
- rx->local_audio_buffer_size*sizeof(float)*2,
- &err);
- if(rc!=0) {
- fprintf(stderr,"audio_write failed err=%d\n",err);
+ if (rx->playstream != NULL && rx->local_audio_buffer != NULL) { // Note this test must be done "mutex-protected"
+ rx->local_audio_buffer[rx->local_audio_buffer_offset*2]=left_sample;
+ rx->local_audio_buffer[(rx->local_audio_buffer_offset*2)+1]=right_sample;
+ rx->local_audio_buffer_offset++;
+ if(rx->local_audio_buffer_offset>=rx->local_audio_buffer_size) {
+ rc=pa_simple_write(rx->playstream,
+ rx->local_audio_buffer,
+ rx->local_audio_buffer_size*sizeof(float)*2,
+ &err);
+ if(rc!=0) {
+ fprintf(stderr,"audio_write failed err=%d\n",err);
+ }
+ rx->local_audio_buffer_offset=0;
}
- rx->local_audio_buffer_offset=0;
}
g_mutex_unlock(&rx->local_audio_mutex);
if(rx->display_waterfall) {
waterfall_init(rx,rx->width,height);
-g_print("%ss: waterfall height=%d y=%d %p\n",__FUNCTION__,height,y,rx->waterfall);
+g_print("%s: waterfall height=%d y=%d %p\n",__FUNCTION__,height,y,rx->waterfall);
g_object_weak_ref(G_OBJECT(rx->waterfall),receiver_weak_notify,(gpointer)rx);
gtk_fixed_put(GTK_FIXED(rx->panel),rx->waterfall,0,y);
}
rx->panadapter_step=20;
rx->volume=5.0;
- //rx->rf_gain=50.0;
rx->squelch_enable=0;
rx->squelch=0;
rx->agc_slope=35.0;
rx->agc_hang_threshold=0.0;
-#if defined(ALSA) || defined(PORTAUDIO)
- rx->playback_handle=NULL;
-#endif
-#ifdef PULSEAUDIO
- rx->playstream=NULL;
-#endif
rx->local_audio_buffer=NULL;
rx->local_audio_buffer_size=2048;
rx->local_audio=0;
rx->waterfall_automatic=1;
rx->volume=0.1;
- //rx->rf_gain=50.0;
rx->dither=0;
rx->random=0;
rx->agc_slope=35.0;
rx->agc_hang_threshold=0.0;
- //rx->playback_handle=NULL;
rx->local_audio=0;
g_mutex_init(&rx->local_audio_mutex);
rx->local_audio_buffer=NULL;
gint audio_device;
gchar *audio_name;
#ifdef PORTAUDIO
- PaStream *playback_handle;
+ PaStream *playstream;
gint local_audio_buffer_inpt; // pointer in audio ring-buffer
gint local_audio_buffer_outpt; // pointer in audio ring-buffer
float *local_audio_buffer;
#include "rigctl_menu.h"
#include "noise_menu.h"
#include "new_protocol.h"
-#ifdef LOCALCW
#include "iambic.h" // declare keyer_update()
-#endif
#include <math.h>
#define NEW_PARSER
if(command[4]==';') {
// read the step size
int i=0;
- for(i=0;i<=14;i++) {
+ for(i=0;i<STEPS;i++) {
if(steps[i]==step) break;
}
if(i<=14) {
} else if(command[6]==';') {
// set the step size
int i=atoi(&command[4]) ;
- if(i>=0 && i<=14) {
+ if(i>=0 && i<STEPS) {
step=steps[i];
vfo_update();
}
if(command[6]==';') {
int step_index=atoi(&command[4]);
long long hz=0;
- if(step_index>=0 && step_index<=14) {
+ if(step_index>=0 && step_index<STEPS) {
hz=(long long)steps[step_index];
}
if(hz!=0LL) {
if(command[6]==';') {
int step_index=atoi(&command[4]);
long long hz=0;
- if(step_index>=0 && step_index<=14) {
+ if(step_index>=0 && step_index<STEPS) {
hz=(long long)steps[step_index];
}
if(hz!=0LL) {
if(command[6]==';') {
int step_index=atoi(&command[4]);
long long hz=0;
- if(step_index>=0 && step_index<=14) {
+ if(step_index>=0 && step_index<STEPS) {
hz=(long long)steps[step_index];
}
if(hz!=0LL) {
if(command[6]==';') {
int step_index=atoi(&command[4]);
long long hz=0;
- if(step_index>=0 && step_index<=14) {
+ if(step_index>=0 && step_index<STEPS) {
hz=(long long)steps[step_index];
}
if(hz!=0LL) {
#include "rx_panadapter.h"
#include "vfo.h"
#include "mode.h"
-#include "actions.h"
#ifdef GPIO
#include "gpio.h"
#endif
#include "client_server.h"
#endif
-#define LINE_WIDTH 0.5
+#define LINE_THIN 0.5
+#define LINE_THICK 1.0
//static float panadapter_max=-60.0;
//static float panadapter_min=-160.0;
//clear_panadater_surface();
cairo_t *cr;
cr = cairo_create (rx->panadapter_surface);
- cairo_set_line_width(cr, LINE_WIDTH);
+ cairo_set_line_width(cr, LINE_THIN);
cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
cairo_rectangle(cr,0,0,display_width,display_height);
cairo_fill(cr);
cw_frequency=filter_left+((filter_right-filter_left)/2.0);
cairo_move_to(cr,cw_frequency,10.0);
cairo_line_to(cr,cw_frequency,(double)display_height);
+ cairo_set_line_width(cr, LINE_THICK);
cairo_stroke(cr);
}
}
double dbm_per_line=(double)display_height/((double)rx->panadapter_high-(double)rx->panadapter_low);
- cairo_set_line_width(cr, LINE_WIDTH);
+ cairo_set_line_width(cr, LINE_THIN);
cairo_select_font_face(cr, DISPLAY_FONT, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size(cr, DISPLAY_FONT_SIZE2);
char v[32];
cairo_show_text(cr, v);
}
}
+ cairo_set_line_width(cr, LINE_THIN);
cairo_stroke(cr);
// plot frequency markers
}
f = ((min_display/divisor)*divisor)+divisor;
-
cairo_select_font_face(cr, DISPLAY_FONT,
CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_BOLD);
cairo_show_text(cr, v);
f+=divisor;
}
+ cairo_set_line_width(cr, LINE_THIN);
cairo_stroke(cr);
if(vfoband!=band60) {
// band edges
if(band->frequencyMin!=0LL) {
cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);
- cairo_set_line_width(cr, LINE_WIDTH);
+ cairo_set_line_width(cr, LINE_THICK);
if((min_display<band->frequencyMin)&&(max_display>band->frequencyMin)) {
i=(band->frequencyMin-min_display)/(long long)HzPerPixel;
cairo_move_to(cr,(double)i,0.0);
cairo_line_to(cr,(double)i,(double)display_height);
+ cairo_set_line_width(cr, LINE_THICK);
cairo_stroke(cr);
}
if((min_display<band->frequencyMax)&&(max_display>band->frequencyMax)) {
i=(band->frequencyMax-min_display)/(long long)HzPerPixel;
cairo_move_to(cr,(double)i,0.0);
cairo_line_to(cr,(double)i,(double)display_height);
+ cairo_set_line_width(cr, LINE_THICK);
cairo_stroke(cr);
}
}
// agc
if(rx->agc!=AGC_OFF) {
+ cairo_set_line_width(cr, LINE_THICK);
double knee_y=rx->agc_thresh+(double)adc[rx->adc].attenuation;
if (filter_board == ALEX && rx->adc == 0) knee_y += (double)(10*rx->alex_attenuation);
knee_y = floor((rx->panadapter_high - knee_y)
cairo_fill(cr);
cairo_move_to(cr,40.0,hang_y);
cairo_line_to(cr,(double)display_width-40.0,hang_y);
+ cairo_set_line_width(cr, LINE_THICK);
cairo_stroke(cr);
cairo_move_to(cr,48.0,hang_y);
cairo_show_text(cr, "-H");
cairo_fill(cr);
cairo_move_to(cr,40.0,knee_y);
cairo_line_to(cr,(double)display_width-40.0,knee_y);
+ cairo_set_line_width(cr, LINE_THICK);
cairo_stroke(cr);
cairo_move_to(cr,48.0,knee_y);
cairo_show_text(cr, "-G");
} else {
cairo_set_source_rgb (cr, 0.5, 0.0, 0.0);
}
- cairo_set_line_width(cr, LINE_WIDTH);
cairo_move_to(cr,vfofreq+(offset/HzPerPixel),0.0);
cairo_line_to(cr,vfofreq+(offset/HzPerPixel),(double)display_height);
+ cairo_set_line_width(cr, LINE_THIN);
cairo_stroke(cr);
// signal
}
#ifdef SOAPYSDR
if(protocol==SOAPYSDR_PROTOCOL) {
- //s1-=rx->rf_gain;
s1-=adc[rx->adc].gain;
}
#endif
}
#ifdef SOAPYSDR
if(protocol==SOAPYSDR_PROTOCOL) {
- //s2-=rx->rf_gain;
s2-=adc[rx->adc].gain;
}
#endif
cairo_line_to(cr, (double)i, s2);
}
- cairo_pattern_t *gradient=NULL;
+ cairo_pattern_t *gradient;
+ gradient=NULL;
if(display_gradient) {
gradient = cairo_pattern_create_linear(0.0, display_height, 0.0, 0.0);
// calculate where S9 is
if(display_filled) {
cairo_close_path (cr);
cairo_fill_preserve (cr);
- cairo_set_line_width(cr, LINE_WIDTH);
+ cairo_set_line_width(cr, LINE_THIN);
} else {
//
- // if not filling, use a full pixel's width
+ // if not filling, use thicker line
//
- cairo_set_line_width(cr, 1.0);
+ cairo_set_line_width(cr, LINE_THICK);
}
cairo_stroke(cr);
}
#endif
*/
+
if(display_sequence_errors) {
if(sequence_errors!=0) {
cairo_move_to(cr,100.0,50.0);
}
static void step_select_cb (GtkToggleButton *widget, gpointer data) {
- if(gtk_toggle_button_get_active(widget)) {
+ int val=GPOINTER_TO_INT(data);
+ if(gtk_toggle_button_get_active(widget) && val >= 0 && val<STEPS) {
step=steps[GPOINTER_TO_INT(data)];
g_idle_add(ext_vfo_update,NULL);
}
double mult;
long long f;
static int set = 0;
- SET_FREQUENCY *fp;
// Instead of messing with LOCALE settings,
// we print a "0.0" and look what the decimal
g_idle_add(ext_vfo_update,NULL);
}
-static GtkWidget *last_mode;
-
void vfo_menu(GtkWidget *parent,int vfo) {
int i;
gtk_misc_set_alignment (GTK_MISC (label), 1, .5);
gtk_grid_attach(GTK_GRID(grid),label,0,1,3,1);
- GtkWidget *step_rb=NULL;
for (i=0; i<16; i++) {
btn[i]=gtk_button_new_with_label(btn_labels[i]);
set_button_text_color(btn[i],"black");