#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