
#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
 */
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);
#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])
//#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);
//#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 \
// }
//#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

