quisk-kc4upr/quisk.h

421 lines
18 KiB
C
Executable File

#define DEBUG_IO 0
#define DEBUG_MIC 0
// Sound parameters
//
#define QUISK_SC_SIZE 128
#define QUISK_PATH_SIZE 256 // max file path length
#define IP_SIZE 32
#define MAX_FILTER_SIZE 10001
#define BIG_VOLUME 2.2e9
#define CLOSED_TEXT "The sound device is closed."
#define CLIP32 2147483647
#define CLIP16 32767
#define SAMP_BUFFER_SIZE 66000 // size of arrays used to capture samples
#define IMD_TONE_1 1200 // frequency of IMD test tones
#define IMD_TONE_2 1600
#define INTERP_FILTER_TAPS 85 // interpolation filter
#define MIC_OUT_RATE 48000 // mic post-processing sample rate
#define PA_LIST_SIZE 16 // max number of pulseaudio devices
#define QUISK_MAX_RECEIVERS 9 // max number of receiver channels
// Test the audio: 0 == No test; normal operation;
// 1 == Copy real data to the output; 2 == copy imaginary data to the output;
// 3 == Copy transmit audio to the output.
#define TEST_AUDIO 0
#ifdef MS_WINDOWS
#define QUISK_SHUT_RD SD_RECEIVE
#define QUISK_SHUT_BOTH SD_BOTH
#else
#define SOCKET int
#define INVALID_SOCKET -1
#define QUISK_SHUT_RD SHUT_RD
#define QUISK_SHUT_BOTH SHUT_RDWR
#endif
#if PY_MAJOR_VERSION >= 3
#define PyInt_FromLong PyLong_FromLong
#define PyInt_Check PyLong_Check
#define PyInt_AsLong PyLong_AsLong
#define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask
#endif
#define PyString_FromString PyUnicode_FromString
typedef enum _rx_mode {
CWL = 0,
CWU = 1,
LSB = 2,
USB = 3,
AM = 4,
FM = 5,
EXT = 6,
DGT_U = 7,
DGT_L = 8,
DGT_IQ = 9,
IMD = 10,
FDV_U = 11,
FDV_L = 12,
DGT_FM = 13
} rx_mode_type;
// Pulseaudio support added by Philip G. Lee. Many thanks!
/*!
* \brief Specifies which driver a \c sound_dev is opened with
*/
typedef enum dev_driver{
DEV_DRIVER_NONE = 0,
DEV_DRIVER_PORTAUDIO,
DEV_DRIVER_ALSA,
DEV_DRIVER_PULSEAUDIO
} dev_driver_t;
struct sound_dev { // data for sound capture or playback device
char name[QUISK_SC_SIZE]; // string name of device
char stream_description[QUISK_SC_SIZE]; // Short description of device/stream
void * handle; // Handle of open device, or NULL
dev_driver_t driver; // Which audio driver the device is using
void * buffer; // Handle of buffer for device
int portaudio_index; // index of portaudio device, or -1
int doAmplPhase; // Amplitude and Phase corrections
double AmPhAAAA;
double AmPhCCCC;
double AmPhDDDD;
double portaudio_latency; // Suggested latency for portaudio device
int sample_rate; // Sample rate such as 48000, 96000, 192000
int sample_bytes; // Size of one channel sample in bytes, either 2 or 3 or 4
int num_channels; // number of channels per frame: 1, 2, 3, ...
int channel_I; // Index of I and Q channels: 0, 1, ...
int channel_Q;
int channel_Delay; // Delay this channel by one sample; -1 for no delay, else channel_I or _Q
int overrange; // Count for ADC overrange (clip) for device
// Number of frames for a read request.
// If 0, the read should be non-blocking and read all available
// frames.
int read_frames;
int latency_frames; // desired latency in audio play samples
int play_buf_size; // size of playback buffer in samples
int use_float; // DirectX: Use IEEE floating point
int dataPos; // DirectX: data position
int oldPlayPos; // DirectX: previous value of playPos
int play_delay; // DirectX: bytes of sound available to play
int started; // DirectX: started flag or state
int dev_error; // read or write error
int dev_underrun; // lack of samples to play
int dev_latency; // latency frames
unsigned int rate_min; // min and max available sample rates
unsigned int rate_max;
unsigned int chan_min; // min and max available number of channels
unsigned int chan_max;
complex double dc_remove; // filter to remove DC from samples
double save_sample; // Used to delay the I or Q sample
char msg1[QUISK_SC_SIZE]; // string for information message
int stream_dir_record; // 1 for recording, 0 for playback
char server[IP_SIZE]; // server string for remote pulseaudio
int stream_format; // format of pulseaudio device
int pulse_stream_state; // state of the pulseaudio stream
volatile int cork_status; // 1 for corked, 0 for uncorked
double average_square; // average of squared sample magnitude
} ;
struct sound_conf {
char dev_capt_name[QUISK_SC_SIZE];
char dev_play_name[QUISK_SC_SIZE];
int sample_rate; // Input sample rate from the ADC
int playback_rate; // Output play rate to sound card
int data_poll_usec;
int latency_millisecs;
unsigned int rate_min;
unsigned int rate_max;
unsigned int chan_min;
unsigned int chan_max;
int read_error;
int write_error;
int underrun_error;
int overrange; // count of ADC overrange (clip) for non-soundcard device
int latencyCapt;
int latencyPlay;
int interupts;
char msg1[QUISK_SC_SIZE];
char err_msg[QUISK_SC_SIZE];
// These parameters are for the microphone:
char mic_dev_name[QUISK_SC_SIZE]; // capture device
char name_of_mic_play[QUISK_SC_SIZE]; // playback device
char mic_ip[IP_SIZE];
int mic_sample_rate; // capture sample rate
int mic_playback_rate; // playback sample rate
int tx_audio_port;
int mic_read_error;
int mic_channel_I; // channel number for microphone: 0, 1, ...
int mic_channel_Q;
double mic_out_volume;
char IQ_server[IP_SIZE]; //IP address of optional streaming IQ server (pulseaudio)
int verbose_pulse; //verbose output for pulse audio
} ;
enum quisk_rec_state {
IDLE,
RECORD_RADIO,
RECORD_MIC,
PLAYBACK,
PLAY_FILE,
PLAY_SAMPLES } ;
extern enum quisk_rec_state quisk_record_state;
struct QuiskWav { // data to create a WAV or RAW audio file
double scale;
int sample_rate;
short format; // RAW is 0; PCM integer is 1; IEEE float is 3.
short nChan;
short bytes_per_sample;
FILE * fp;
unsigned int samples;
int fpStart;
int fpEnd;
int fpPos;
} ;
void QuiskWavClose(struct QuiskWav *);
int QuiskWavWriteOpen(struct QuiskWav *, char *, short, short, short, int, double);
void QuiskWavWriteC(struct QuiskWav *, complex double *, int);
void QuiskWavWriteD(struct QuiskWav *, double *, int);
int QuiskWavReadOpen(struct QuiskWav *, char *, short, short, short, int, double);
void QuiskWavReadC(struct QuiskWav *, complex double *, int);
void QuiskWavReadD(struct QuiskWav *, double *, int);
void QuiskMeasureRate(const char *, int);
extern struct sound_conf quisk_sound_state, * pt_quisk_sound_state;
extern int mic_max_display; // display value of maximum microphone signal level
extern int quiskSpotLevel; // 0 for no spotting; else the level 10 to 1000
extern int data_width;
extern int quisk_using_udp; // is a UDP port used for capture (0 or 1)?
extern int quisk_rx_udp_started; // have we received any data?
extern rx_mode_type rxMode; // mode CWL, USB, etc.
extern int quisk_tx_tune_freq; // Transmit tuning frequency as +/- sample_rate / 2
extern PyObject * quisk_pyConfig; // Configuration module instance
extern double quisk_mic_preemphasis; // Mic preemphasis 0.0 to 1.0; or -1.0
extern double quisk_mic_clip; // Mic clipping; try 3.0 or 4.0
extern int quisk_noise_blanker; // Noise blanker level, 0 for off
extern int quisk_sidetoneCtrl; // sidetone control value 0 to 1000
extern int quiskKeyupDelay; // key-up delay from the config file
extern double quisk_audioVolume; // volume control for radio sound playback, 0.0 to 1.0
extern int quiskImdLevel; // level for rxMode IMD
extern int quiskTxHoldState; // state machine for Tx wait for repeater frequency shift
extern double quisk_ctcss_freq; // frequency in Hertz
extern unsigned char quisk_pc_to_hermes[17 * 4]; // Data to send from the PC to the Hermes hardware
extern unsigned char quisk_hermeslite_writequeue[4 * 5]; // One-time writes to Hermes-Lite
extern unsigned int quisk_hermeslite_writepointer; // write pointer into write queue, nonzero value triggers writes,
extern unsigned int quisk_hermeslite_writeattempts; // counter for write retries
extern unsigned int quisk_hermes_code_version; // Hermes code version from Hermes to PC
extern unsigned int quisk_hermes_board_id; // Hermes board ID from Hermes to PC
extern int quisk_use_rx_udp; // Method of access to UDP hardware
extern complex double cRxFilterOut(complex double, int, int);
extern int quisk_multirx_count; // number of additional receivers zero or 1, 2, 3, ..
extern struct sound_dev quisk_DigitalRx1Output; // Output sound device for sub-receiver 1
extern int quisk_is_vna; // is this the VNA program?
extern PyObject * quisk_set_spot_level(PyObject * , PyObject *);
extern PyObject * quisk_get_tx_filter(PyObject * , PyObject *);
extern PyObject * quisk_set_ampl_phase(PyObject * , PyObject *);
extern PyObject * quisk_capt_channels(PyObject * , PyObject *);
extern PyObject * quisk_play_channels(PyObject * , PyObject *);
extern PyObject * quisk_micplay_channels(PyObject * , PyObject *);
extern PyObject * quisk_sound_devices(PyObject * , PyObject *);
extern PyObject * quisk_pa_sound_devices(PyObject * , PyObject *);
extern PyObject * quisk_sound_errors(PyObject *, PyObject *);
extern PyObject * quisk_set_file_record(PyObject *, PyObject *);
extern PyObject * quisk_set_file_name(PyObject *, PyObject *, PyObject *);
extern PyObject * quisk_set_tx_audio(PyObject *, PyObject *, PyObject *);
extern PyObject * quisk_is_vox(PyObject *, PyObject *);
extern PyObject * quisk_set_udp_tx_correct(PyObject *, PyObject *);
extern PyObject * quisk_set_hermes_filter(PyObject *, PyObject *);
extern PyObject * quisk_set_alex_hpf(PyObject *, PyObject *);
extern PyObject * quisk_set_alex_lpf(PyObject *, PyObject *);
extern PyObject * quisk_freedv_open(PyObject *, PyObject *);
extern PyObject * quisk_freedv_close(PyObject *, PyObject *);
extern PyObject * quisk_freedv_get_snr(PyObject *, PyObject *);
extern PyObject * quisk_freedv_get_version(PyObject *, PyObject *);
extern PyObject * quisk_freedv_get_rx_char(PyObject *, PyObject *);
extern PyObject * quisk_freedv_set_options(PyObject *, PyObject *, PyObject *);
extern PyObject * quisk_set_sparams(PyObject *, PyObject *, PyObject *);
// These function pointers are the Start/Stop/Read interface for
// the SDR-IQ and any other C-language extension modules that return
// radio data samples.
typedef void (* ty_sample_start)(void);
typedef void (* ty_sample_stop)(void);
typedef int (* ty_sample_read)(complex double *);
typedef int (* ty_sample_write)(complex double *, int);
extern ty_sample_write quisk_pt_sample_write;
void quisk_open_sound(void);
void quisk_close_sound(void);
int quisk_process_samples(complex double *, int);
void quisk_play_samples(complex double *, int);
void quisk_play_zeros(int);
void quisk_start_sound(void);
int quisk_get_overrange(void);
void quisk_mixer_set(char *, int, PyObject *, char *, int);
int quisk_read_sound(void);
int quisk_process_microphone(int, complex double *, int);
void quisk_open_mic(void);
void quisk_close_mic(void);
int quisk_open_key(const char *);
void quisk_close_key(void);
void quisk_set_key_down(int);
void quisk_set_tx_mode(void);
void ptimer(int);
int quisk_extern_demod(complex double *, int, double);
void quisk_tmp_microphone(complex double *, int);
void quisk_tmp_record(complex double * , int, double);
void quisk_file_microphone(complex double *, int);
void quisk_file_playback(complex double *, int, double);
void quisk_tmp_playback(complex double *, int, double);
void quisk_hermes_tx_send(int, int *);
void quisk_udp_mic_error(char *);
void quisk_check_freedv_mode(void);
void quisk_calc_audio_graph(double, complex double *, double *, int, int);
int QuiskDeltaMsec(int);
#if defined(ENABLE_GPIO_KEYER)
/* KC4UPR: Define some additional functions for the GPIO Keyer. These
* allow setting various parameters for the keyer.
* mode - straight/bug, Iambic A, Iambic B
* speed - speed in words-per-minute (WPM), 1-60
* weight - dot vs dash weight, in range 33-66
* reverse - reverse left/right paddles (dot/dash by default)
* strict - enforce strict character spacing
* enabled - enable/disable the keyer
* hangtime - msecs to transmit after last CW symbol
*/
void quisk_set_gpio_keyer_mode(int);
void quisk_set_gpio_keyer_speed(int);
void quisk_set_gpio_keyer_weight(int);
void quisk_set_gpio_keyer_reversed(int);
void quisk_set_gpio_keyer_strict(int);
void quisk_set_gpio_keyer_enabled(int);
void quisk_set_gpio_keyer_hangtime(int);
#endif
// Functions supporting digital voice codecs
typedef int (* ty_dvoice_codec_rx)(complex double *, double *, int, int);
typedef int (* ty_dvoice_codec_tx)(complex double *, double *, int);
extern ty_dvoice_codec_rx pt_quisk_freedv_rx;
extern ty_dvoice_codec_tx pt_quisk_freedv_tx;
// Driver function definitions=================================================
int quisk_read_alsa(struct sound_dev *, complex double *);
void quisk_play_alsa(struct sound_dev *, int, complex double *, int, double);
void quisk_start_sound_alsa(struct sound_dev **, struct sound_dev **);
void quisk_close_sound_alsa(struct sound_dev **, struct sound_dev **);
int quisk_read_portaudio(struct sound_dev *, complex double *);
void quisk_play_portaudio(struct sound_dev *, int, complex double *, int, double);
void quisk_start_sound_portaudio(struct sound_dev **, struct sound_dev **);
void quisk_close_sound_portaudio(void);
void play_sound_interface(struct sound_dev * , int, complex double * , int, double);
int quisk_read_pulseaudio(struct sound_dev *, complex double *);
void quisk_play_pulseaudio(struct sound_dev *, int, complex double *, int, double);
void quisk_start_sound_pulseaudio(struct sound_dev **, struct sound_dev **);
void quisk_close_sound_pulseaudio(void);
void quisk_cork_pulseaudio(struct sound_dev *, int);
void quisk_flush_pulseaudio(struct sound_dev *);
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
/*
Functions defined below this point are available for export to other extension modules using the
standard Python CObject or Capsule interface. See the documentation in import_quisk_api.c. Note
that index zero is used for a structure pointer, not a function pointer.
To add a function, declare it twice, use the next array index, and add it to QUISK_API_INIT.
Be very careful; here be dragons!
*/
#ifdef IMPORT_QUISK_API
// For use by modules that import the _quisk symbols
extern void ** Quisk_API; // array of pointers to functions and variables from module _quisk
int import_quisk_api(void); // used to initialize Quisk_API
#define QuiskGetConfigInt (*( int (*) (const char *, int) )Quisk_API[1])
#define QuiskGetConfigDouble (*( double (*) (const char *, double) )Quisk_API[2])
#define QuiskGetConfigString (*( char * (*) (const char *, char *) )Quisk_API[3])
#define QuiskTimeSec (*( double (*) (void) )Quisk_API[4])
#define QuiskSleepMicrosec (*( void (*) (int) )Quisk_API[5])
#define QuiskPrintTime (*( void (*) (const char *, int) )Quisk_API[6])
#define quisk_sample_source (*( void (*) (ty_sample_start, ty_sample_stop, ty_sample_read) )Quisk_API[7])
#define quisk_dvoice_freedv (*( void (*) (ty_dvoice_codec_rx, ty_dvoice_codec_tx) )Quisk_API[8])
#define quisk_is_key_down (*( int (*) (void) )Quisk_API[9])
#define quisk_sample_source4 (*( void (*) (ty_sample_start, ty_sample_stop, ty_sample_read, ty_sample_write) )Quisk_API[10])
//#if defined(ENABLE_GPIO_KEYER)
/* KC4UPR: Provide API definitions for the GPIO Keyer functions.
* However... since this doesn't seem to be required for various other
* functions that are accessible from Python, I've commented it all out,
* since in truth I really don't know what it's for/how to use it.
*/
//#define quisk_set_gpio_keyer_mode (*( void (*) (int) )Quisk_API[11])
//#define quisk_set_gpio_keyer_speed (*( void (*) (int) )Quisk_API[12])
//#define quisk_set_gpio_keyer_weight (*( void (*) (int) )Quisk_API[13])
//#define quisk_set_gpio_keyer_reversed (*( void (*) (int) )Quisk_API[14])
//#define quisk_set_gpio_keyer_strict (*( void (*) (int) )Quisk_API[15])
//#define quisk_set_gpio_keyer_enabled (*( void (*) (int) )Quisk_API[16])
//#define quisk_set_gpio_keyer_hangtime (*( void (*) (int) )Quisk_API[17])
//#endif
#else
// Used to export symbols from _quisk in quisk.c
int QuiskGetConfigInt(const char *, int);
double QuiskGetConfigDouble(const char *, double);
char * QuiskGetConfigString(const char *, char *);
double QuiskTimeSec(void);
void QuiskSleepMicrosec(int);
void QuiskPrintTime(const char *, int);
void quisk_sample_source(ty_sample_start, ty_sample_stop, ty_sample_read);
void quisk_dvoice_freedv(ty_dvoice_codec_rx, ty_dvoice_codec_tx);
int quisk_is_key_down(void);
void quisk_sample_source4(ty_sample_start, ty_sample_stop, ty_sample_read, ty_sample_write);
//#if defined(ENABLE_GPIO_KEYER)
/* KC4UPR: Provide API definitions for the GPIO Keyer functions.
* However... since this doesn't seem to be required for various other
* functions that are accessible from Python, I've commented it all out,
* since in truth I really don't know what it's for/how to use it.
*/
//void quisk_set_gpio_keyer_mode(int);
//void quisk_set_gpio_keyer_speed(int);
//void quisk_set_gpio_keyer_weight(int);
//void quisk_set_gpio_keyer_reversed(int);
//void quisk_set_gpio_keyer_strict(int);
//void quisk_set_gpio_keyer_enabled(int);
//void quisk_set_gpio_keyer_hangtime(int);
//#endif
//#if defined(ENABLE_GPIO_KEYER)
/* KC4UPR: Provide API definitions for the GPIO Keyer functions.
* However... since this doesn't seem to be required for various other
* functions that are accessible from Python, I've commented it all out,
* since in truth I really don't know what it's for/how to use it.
*/
//#define QUISK_API_INIT { \
// &quisk_sound_state, &QuiskGetConfigInt, &QuiskGetConfigDouble, &QuiskGetConfigString, &QuiskTimeSec, \
// &QuiskSleepMicrosec, &QuiskPrintTime, &quisk_sample_source, &quisk_dvoice_freedv, &quisk_is_key_down, \
// &quisk_sample_source4, &quisk_set_gpio_keyer_mode, &quisk_set_gpio_keyer_speed, \
// &quisk_set_gpio_keyer_weight, &quisk_set_gpio_keyer_reversed, &quisk_set_gpio_keyer_strict, \
// &quisk_set_gpio_keyer_enabled, &quisk_set_gpio_keyer_hangtime \
// }
//#else
#define QUISK_API_INIT { \
&quisk_sound_state, &QuiskGetConfigInt, &QuiskGetConfigDouble, &QuiskGetConfigString, &QuiskTimeSec, \
&QuiskSleepMicrosec, &QuiskPrintTime, &quisk_sample_source, &quisk_dvoice_freedv, &quisk_is_key_down, \
&quisk_sample_source4 \
}
//#endif
#endif