#include <Python.h>
#include <stdlib.h>
#include <math.h>
#include <sys/time.h>
#include <complex.h>
#include <fftw3.h>
#include "quisk.h"
#include <sys/types.h>
#include "microphone.h"
#include "filter.h"
#include "freedv.h"

#ifdef MS_WINDOWS
#include <Winsock2.h>
static int mic_cleanup = 0;		// must clean up winsock
#else
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#endif

#define DEBUG   0
#define DEBUG_LEVEL	0

#if DEBUG_LEVEL || DEBUG_IO || DEBUG
static int debug_timer = 1;		// count up number of samples
#endif

// The microphone samples must be 48000 sps or 8000 sps.  The output sample
//  rate is always MIC_OUT_RATE samples per second

// FM needs pre-emphasis and de-emphasis.  See vk1od.net/FM/FM.htm for details.
// For IIR design, see http://www.abvolt.com/research/publications2.htm.

// Microhone preemphasis: boost high frequencies 0.00 to 1.00
double quisk_mic_preemphasis;
// Microphone clipping; try 3.0 or 4.0
double quisk_mic_clip;

// If true, decimate 48000 sps mic samples to 8000 sps for processing
#define DECIM_8000	1

struct alc {
	complex double * buffer;
	int buf_size;
	int index;
	int block_index;
	int counter;
	int fault;
	double max_magn;
	double gain_now[20];
	double gain_max;
	double gain_min;
	double gain_change;
	double next_change;
	double final_gain;
} ;

// These are external:
int mic_max_display;				// display value of maximum microphone signal level 0 to 2**15 - 1
int quiskSpotLevel = -1;			// level is -1 for Spot button Off; else the Spot level 0 to 1000.
int quiskImdLevel = 500;			// level for rxMode IMD, 0 to 1000

static SOCKET mic_socket = INVALID_SOCKET;	// send microphone samples to a socket
static double mic_agc_level = 0.10;		// Mic levels below this are noise and are ignored

static int mic_level;			// maximum microphone signal level for display
static int mic_timer;			// time to display maximum mic level
static int align4;			// add two bytes to start of audio samples to align to 4 bytes
static double modulation_index = 1.6;	// For FM transmit, the modulation index

static int is_vox = 0;					// Is the VOX level exceeded?
static int vox_level = CLIP16;			// VOX trigger level as a number 0 to CLIP16
static int timeVOX = 2000;				// VOX hang time in milliseconds
static int tx_sample_rate = 48000;	// Used for SoapySDR
static int reverse_tx_sideband;

static int doTxCorrect = 0;				// Corrections for UDP sample transmit
static double TxCorrectLevel;
static complex TxCorrectDc;

// Used for the Hermes protocol
#define HERMES_TX_BUF_SAMPLES	4800	// buffer size in I/Q samples (two shorts)
#define HERMES_TX_BUF_SHORTS	(HERMES_TX_BUF_SAMPLES * 2)
static int hermes_read_index;			// index to read from buffer
static int hermes_write_index;			// index to write to buffer
static int hermes_num_samples;			// number of samples in the buffer
static short hermes_buf[HERMES_TX_BUF_SHORTS];		// buffer to store Tx I/Q samples waiting to be sent at 48 ksps
static int hermes_filter_rx;		// hermes filter to use for Rx
static int hermes_filter_tx;		// hermes filter to use for Tx
static int alex_hpf_rx;                 // Alex HPF to use for Rx
static int alex_hpf_tx;                 // Alex HPF to use for Tx
static int alex_lpf_rx;                 // Alex LPF to use for Rx
static int alex_lpf_tx;                 // Alex LPF to use for Tx

#define TX_BLOCK_SHORTS		600		// transmit UDP packet with this many shorts (two bytes) (perhaps + 1)
#define MIC_MAX_HOLD_TIME	400		// Time to hold the maximum mic level on the Status screen in milliseconds

// If USE_GET_SIN is not zero, replace mic samples with a sin wave at a
// frequency determined by the sidetone slider and an amplitude determined
// by the Spot button level. LEVEL FAILS
// If USE_GET_SIN is 1, pass these samples through the transmit filters.
// If USE_GET_SIN is 2, transmit these samples directly.
#define USE_GET_SIN		0

// If USE_2TONE is not zero, replace samples with a 2-tone test signal.
#define USE_2TONE		0

#if USE_GET_SIN
static void get_sin(complex double * cSamples, int count)
{	// replace mic samples with a sin wave
	int i;
	double freq;
	complex double phase1;		// Phase increment
	static complex double vector1 = CLIP32 / 2;

	// Use the sidetone slider 0 to 1000 to set frequency
	//freq = (quisk_sidetoneCtrl - 500) / 1000.0 * MIC_OUT_RATE;
	freq = quisk_sidetoneCtrl * 5;
	freq = ((int)freq / 50) * 50;
#if USE_GET_SIN == 2
	phase1 = cexp(I * 2.0 * M_PI * freq / MIC_OUT_RATE);
	count *= MIC_OUT_RATE / quisk_sound_state.mic_sample_rate;
#else
	phase1 = cexp(I * 2.0 * M_PI * freq / quisk_sound_state.mic_sample_rate);
#endif
	for (i = 0; i < count; i++) {
		vector1 *= phase1;
		cSamples[i] = vector1;
	}
#if DEBUG_IO || DEBUG
	if (debug_timer == 0)
		printf ("get_sin freq %.0lf\n", freq);
#endif
}
#endif

#if USE_2TONE
static void get_2tone(complex double * cSamples, int count)
{	// replace mic samples
	int i;
	static complex double phase1=0, phase2;		// Phase increment
	static complex double vector1;
	static complex double vector2;

	if (phase1 == 0) {		// initialize
		phase1 = cexp((I * 2.0 * M_PI * IMD_TONE_1) / quisk_sound_state.mic_sample_rate);
		phase2 = cexp((I * 2.0 * M_PI * IMD_TONE_2) / quisk_sound_state.mic_sample_rate);
		vector1 = CLIP32 / 2.0;
		vector2 = CLIP32 / 2.0;
	}
	for (i = 0; i < count; i++) {
		vector1 *= phase1;
		vector2 *= phase2;
		cSamples[i] = (vector1 + vector2);
	}
}
#endif

static double CcmPeak(double * dsamples, complex double * csamples, int count)
{
	int i, j;
	complex double csample;
	double dtmp, dsample, newlevel, oldlevel;
	static double out_short, out_long;
	static struct Ccmpr {
		int buf_size;
		int index_read;
		double themax;
		double level;
		double * d_samp;
		complex double * c_samp;
		double * levl;
	} dat = {0};

	if ( ! dat.buf_size) {		// initialize; the sample rate is 8000
		dat.buf_size = 8000 * 30 / 1000;	// total delay in samples
		dat.index_read = 0;					// index to output; and then write a new sample here
		dat.themax = 1.0;					// maximum level in the buffer
		dat.level = 1.0;					// current output level
		dat.d_samp = (double *) malloc(dat.buf_size * sizeof(double));		// buffer for double samples
		dat.c_samp = (complex double *) malloc(dat.buf_size * sizeof(complex double));	// buffer for complex samples
		dat.levl = (double *) malloc(dat.buf_size * sizeof(double));		// magnitude of the samples
		for (i = 0; i < dat.buf_size; i++) {
			dat.d_samp[i] = 0;
			dat.c_samp[i] = 0;
			dat.levl[i] = 1.0;
		}
		dtmp = 1.0 / 8000;		// sample time
		out_short  = 1.0 - exp(- dtmp / 0.010);		// short time constant
		out_long   = 1.0 - exp(- dtmp / 3.000);		// long time constant
		return 1.0;
	}
	for (i = 0; i < count; i++) {
		if (dsamples) {
			dsample = dsamples[i];
			dsamples[i] = dat.d_samp[dat.index_read] / dat.level;	// FIFO output
			dat.d_samp[dat.index_read] = dsample;		// write new sample at read index
			newlevel = fabs(dsample);
		}
		else {
			csample = csamples[i];
			csamples[i] = dat.c_samp[dat.index_read] / dat.level;	// FIFO output
			dat.c_samp[dat.index_read] = csample;		// write new sample at read index
			newlevel = cabs(csample);
		}
		oldlevel = dat.levl[dat.index_read];
		dat.levl[dat.index_read] = newlevel;
		if (newlevel < dat.themax && oldlevel < dat.themax) {		// some other sample is the maximum
			// no change to dat.themax
		}
		else if (newlevel > dat.themax && newlevel > oldlevel) {	// newlevel is the maximum
			dat.themax = newlevel;
		}
		else {		// search for the maximum level
			dat.themax = 0;		// Find the maximim level in the buffer
			for (j = 0; j < dat.buf_size; j++) {
				if (dat.levl[j] > dat.themax)
					dat.themax = dat.levl[j];
			}
		}
// Increase dat.level if the maximum level is greater than 1.0;
// decrease it slowly back to 1.0 if it is lower.  Output is modulated by dat.level.
		if (dat.themax > 1.0)	// increase rapidly to the peak level
			dat.level = dat.level * (1.0 - out_short) + dat.themax * out_short;
		else				// decrease slowly back to 1.0
			dat.level = dat.level * (1.0 - out_long) + 1.0 * out_long;
		if (++dat.index_read >= dat.buf_size)
			dat.index_read = 0;
	}
	return dat.level;
}

static void init_alc(struct alc * pt, int size)
{  // Call first to set the buffer size. Then call to initialize the structure on each key down.
	int i;

	if (pt->buffer == NULL) {
		pt->buf_size = size;	// do not change the size
		pt->buffer = (complex double *)malloc(size * sizeof(complex double));
		for (i = 0; i < 20; i++)	// initial gain by rx_mode
			switch(i) {
			case DGT_U:
			case DGT_L:
			case DGT_IQ:
				pt->gain_now[i] = 1.4;
				break;
			case FDV_U:
			case FDV_L:
				pt->gain_now[i] = 2.0;
				break;
			default:
				pt->gain_now[i] = 1.0;
				break;
			}
	}
	pt->index = 0;
	pt->block_index = 0;
	pt->counter = 0;
	pt->fault = 0;
	pt->max_magn = 0;
	pt->gain_max = 3.0;
	pt->gain_min = 0.1;
	pt->gain_change = 0;
	pt->next_change = 0;
	pt->final_gain = 0;
	for (i = 0; i < pt->buf_size; i++)
		pt->buffer[i] = 0;
}

static void process_alc(complex double * cSamples, int count, struct alc * pt, rx_mode_type rx_mode)
{  // Automatic Level Control (ALC)
	int i;
	double d, magn;
	complex double csamp;

	for (i = 0; i < count; i++) {
		csamp = cSamples[i];			// new sample to add to buffer
		cSamples[i] = pt->buffer[pt->index] * pt->gain_now[rx_mode];		// remove sample from buffer and apply gain
#if DEBUG_LEVEL || DEBUG_IO || DEBUG
		magn = cabs(cSamples[i]);
		if (magn >= CLIP16)
			printf("ALC clip gain %9.6f level %9.6f\n", pt->gain_now[rx_mode], magn / CLIP16);
#endif
		pt->buffer[pt->index] = csamp;		// add new sample to buffer
		magn = cabs(csamp);			// measure new sample
		if (magn * (pt->gain_now[rx_mode] + pt->gain_change * pt->buf_size) > (CLIP16 - 10)) {
			pt->gain_change = ((CLIP16 - 10) / magn - pt->gain_now[rx_mode]) / pt->buf_size;
			pt->final_gain = pt->gain_now[rx_mode] + pt->gain_change * pt->buf_size;
			if (pt->final_gain > pt->gain_max) {
				pt->final_gain = pt->gain_max;
				pt->gain_change = (pt->final_gain - pt->gain_now[rx_mode]) / pt->buf_size;
			}
			else if (pt->final_gain < pt->gain_min) {
				pt->final_gain = pt->gain_min;
				pt->gain_change = (pt->final_gain - pt->gain_now[rx_mode]) / pt->buf_size;
			}
			pt->block_index = pt->index;
			pt->counter = 0;
			pt->fault = 0;
			pt->next_change = 1E10;
			//printf("ALC DEC: gain %9.6f change %9.6f final gain %9.6f\n", pt->gain_now[rx_mode], pt->gain_change, pt->final_gain);
		}
		else if (pt->index == pt->block_index) {
			//d = cabs(cSamples[i]) / (CLIP16 - 10);
			//printf("ALC Fin: gain %9.6f out level %9.6f\n", pt->gain_now[rx_mode], d);
#if 0
			alc_start_gain = alc_gain;
			k = alc_block_index;
			for (j = 1; j < pt->buf_size; j++) {
				if (++k >= pt->buf_size)
					k = 0;
				magn = cabs(alc_buffer[k]);
				if (magn < 100) {
					alc_fault++;
					continue;
				}
				else {
					d = ((CLIP16 - 10) / magn - alc_start_gain) / j;
					if ( alc_next_change > d)
						alc_next_change = d;
				}
			}
#endif
			d = 5.0;	// number of seconds to double gain
			d = 1.0  / (48000.0 * d);
			if (pt->next_change > d)
				pt->next_change = d;
			if (pt->next_change != 1E10 && pt->fault < pt->buf_size - 10) {
				pt->gain_change = pt->next_change;
			}
			pt->final_gain = pt->gain_now[rx_mode] + pt->gain_change * pt->buf_size;
			if (pt->final_gain > pt->gain_max) {
				pt->final_gain = pt->gain_max;
				pt->gain_change = (pt->final_gain - pt->gain_now[rx_mode]) / pt->buf_size;
			}
			else if (pt->final_gain < pt->gain_min) {
				pt->final_gain = pt->gain_min;
				pt->gain_change = (pt->final_gain - pt->gain_now[rx_mode]) / pt->buf_size;
			}
			//printf("ALC New: gain %9.6f change %9.6f final gain %9.6f\n", pt->gain_now[rx_mode], pt->gain_change, pt->final_gain);
			pt->fault = 0;
			pt->counter = 0;
			pt->next_change = 1E10;
		}
		else {
			if (magn < 100) {
				pt->fault++;
			}
			else {
				d = ((CLIP16 - 10) / magn - pt->final_gain) / ++pt->counter;
				if ( pt->next_change > d)
					pt->next_change = d;
			}
		}
		pt->gain_now[rx_mode] += pt->gain_change;
		if (++pt->index >= pt->buf_size)
			pt->index = 0;
	}
#if DEBUG_LEVEL || DEBUG_IO || DEBUG
	for (i = 0; i < count; i++) {
		magn = cabs(cSamples[i]);
		if (pt->max_magn < magn)
			pt->max_magn = magn;
	}
	if (debug_timer == 0) {
		printf("ALC Out: gain %9.6f max lvl%9.6f final gain %9.6f\n", pt->gain_now[rx_mode], pt->max_magn / CLIP16, pt->final_gain);
		pt->max_magn = 0;
	}
#endif
}

static int tx_filter(complex double * filtered, int count)
{	// Input samples are creal(filtered), output is filtered.  The input rate must be 8000 or 48000 sps.
	int i, is_ssb;
	int sample_rate = 8000;
	double dsample, dtmp, magn;
	complex double csample;
	static double inMax=0.3;
	static double x_1=0;
	static double aaa, bbb, ccc, Xmin, Xmax, Ymax;
	static int samples_size = 0;
	static double * dsamples = NULL;
	static complex double * csamples = NULL;
	static double time_long, time_short;
	static struct quisk_dFilter filtDecim, dfiltInterp;
	static struct quisk_dFilter filtAudio1, filtAudio2, dfiltAudio3;
	static struct quisk_cFilter cfiltAudio3, cfiltInterp;
	static struct quisk_dFilter filter1={NULL}, filter2;
#if DEBUG_IO || DEBUG
	char * clip;
	static double dbOut = 0, Level0 = 0, Level1 = 0, Level2 = 0, Level3 = 0, Level4 = 0;
#endif
	is_ssb = (rxMode == LSB || rxMode == USB);
	if (!filtered) {		// initialization
		if (! filter1.dCoefs) {
			quisk_filt_dInit(&filter1, quiskMicFilt8Coefs, sizeof(quiskMicFilt8Coefs)/sizeof(double));
			quisk_filt_dInit(&filter2, quiskMicFilt8Coefs, sizeof(quiskMicFilt8Coefs)/sizeof(double));
			quisk_filt_dInit(&filtDecim,  quiskLpFilt48Coefs, sizeof(quiskLpFilt48Coefs)/sizeof(double));
			quisk_filt_dInit(&dfiltInterp, quiskLpFilt48Coefs, sizeof(quiskLpFilt48Coefs)/sizeof(double));
			quisk_filt_cInit(&cfiltInterp, quiskLpFilt48Coefs, sizeof(quiskLpFilt48Coefs)/sizeof(double));
			quisk_filt_dInit(&filtAudio1, quiskFiltTx8kAudioB, sizeof(quiskFiltTx8kAudioB)/sizeof(double));
			quisk_filt_dInit(&filtAudio2, quiskFiltTx8kAudioB, sizeof(quiskFiltTx8kAudioB)/sizeof(double));
			quisk_filt_dInit(&dfiltAudio3, quiskFiltTx8kAudioB, sizeof(quiskFiltTx8kAudioB)/sizeof(double));
			quisk_filt_cInit(&cfiltAudio3, quiskFiltTx8kAudioB, sizeof(quiskFiltTx8kAudioB)/sizeof(double));
			dtmp = 1.0 / sample_rate;		// sample time
			time_long   = 1.0 - exp(- dtmp / 3.000);
			time_short  = 1.0 - exp(- dtmp / 0.005);
			Ymax = pow(10.0,  - 1 / 20.0);				// maximum y
			Xmax = pow(10.0,  3 / 20.0);				// x where slope is zero; for x > Xmax, y == Ymax
			Xmin = Ymax - fabs(Ymax - Xmax);		// x where slope is 1 and y = x; start of compression
			aaa = 1.0 / (2.0 * (Xmin - Xmax));		// quadratic
			bbb = -2.0 * aaa * Xmax;
			ccc = Ymax - aaa * Xmax * Xmax - bbb * Xmax;
#if DEBUG_IO || DEBUG
			printf("Compress to %.2lf dB from %.2lf to %.2lf dB\n",
				20 * log10(Ymax), 20 * log10(Xmin), 20 * log10(Xmax));
#endif
		}
		if (is_ssb) {
		  quisk_filt_tune(&filter1, 1650.0 / sample_rate, rxMode != LSB);
		  quisk_filt_tune(&filter2, 1650.0 / sample_rate, rxMode != LSB);
		}
		return 0;
	}
	// check size of dsamples[] and csamples[] buffer
	if (count > samples_size) {
		samples_size = count * 2;
		if (dsamples)
			free(dsamples);
		if (csamples)
			free(csamples);
		dsamples = (double *)malloc(samples_size * sizeof(double));
		csamples = (complex double *)malloc(samples_size * sizeof(complex double));
	}
	// copy to dsamples[], normalize to +/- 1.0
	for (i = 0; i < count; i++)
		dsamples[i] = creal(filtered[i]) / CLIP16;
	// Decimate to 8000 Hz
	if (quisk_sound_state.mic_sample_rate != sample_rate)
		count = quisk_dDecimate(dsamples, count, &filtDecim, quisk_sound_state.mic_sample_rate / sample_rate);
	// restrict bandwidth 300 to 2700 Hz
	count = quisk_dFilter(dsamples, count, &filtAudio1);
#if DEBUG_IO || DEBUG
	// Measure peak input audio level
	for (i = 0; i < count; i++) {
		magn = fabs(dsamples[i]);
		if (magn > Level0)
			Level0 = magn;
	}
#endif
	// high pass filter for preemphasis: See Radcom, January 2010, page 76.
	// quisk_mic_preemphasis == 1 was measured as 6 dB / octave.
	// gain at 800 Hz was measured as 0.104672.
	for (i = 0; i < count; i++) {
		dtmp = dsamples[i];
		dsamples[i] = dtmp - quisk_mic_preemphasis * x_1;
		x_1 = dtmp;	// delayed sample
		dsamples[i] *= 2;		// compensate for loss
#if DEBUG_IO || DEBUG
		magn = fabs(dsamples[i]);
		if (magn > Level1)
			Level1 = magn;
#endif
	}
	if (is_ssb) {	// SSB
		// FIR bandpass filter; separate into I and Q
		for (i = 0; i < count; i++) {
			csample = quisk_dC_out(dsamples[i], &filter1) * 2.0;	// filter loss 0.5
			// Measure average peak input audio level and normalize
			magn = cabs(csample);
			if (magn > inMax)
				inMax = inMax * (1 - time_short) + time_short * magn;
			else if(magn > mic_agc_level)
				inMax = inMax * (1 - time_long) + time_long * magn;
			else
				inMax = inMax * (1 - time_long) + time_long * mic_agc_level;
			csample /= inMax;
			magn /= inMax;
#if DEBUG_IO || DEBUG
			if (magn > Level2)
				Level2 = magn;
#endif
			// Audio compression.
			csample *= quisk_mic_clip;
			magn *= quisk_mic_clip;
			if (magn > 1.0)
				csample = csample / magn;
			dsamples[i] = creal(csample);
		}
	}
	else {		// AM and FM
		// Measure average peak input audio level and normalize
		for (i = 0; i < count; i++) {
			dsample = dsamples[i];
			magn = fabs(dsample);
			if (magn > inMax)
				inMax = inMax * (1 - time_short) + time_short * magn;
			else if(magn > mic_agc_level)
				inMax = inMax * (1 - time_long) + time_long * magn;
			else
				inMax = inMax * (1 - time_long) + time_long * mic_agc_level;
			dsample /= inMax;
			magn /= inMax;
#if DEBUG_IO || DEBUG
			if (magn > Level2)
				Level2 = magn;
#endif
		// Audio compression.
			dsample *= quisk_mic_clip;
			magn *= quisk_mic_clip;
			if (magn < Xmin)
				dsamples[i] = dsample;
			else if (magn > Xmax)
				dsamples[i] = copysign(Ymax, dsample);
			else
				dsamples[i] = copysign(aaa * magn * magn + bbb * magn + ccc, dsample);
		}
	}
	// remove clipping distortion; restrict bandwidth 300 to 2700 Hz
	count = quisk_dFilter(dsamples, count, &filtAudio2);
	if (is_ssb) {	// SSB
		// FIR bandpass filter; separate into I and Q
		for (i = 0; i < count; i++) {
			csamples[i] = quisk_dC_out(dsamples[i], &filter2) * 2.0;	// filter loss 0.5
#if DEBUG_IO || DEBUG
			magn = cabs(csamples[i]);
			if (magn > Level3)
				Level3 = magn;
#endif
		}
		// round off peaks
		CcmPeak(NULL, csamples, count);
#if DEBUG_IO || DEBUG
		for (i = 0; i < count; i++) {
			magn = cabs(csamples[i]);
			if (magn > Level4)
				Level4 = magn;
		}
#endif
		// remove clipping distortion
		count = quisk_cDecimate(csamples, count, &cfiltAudio3, 1);
		// Interpolate up to 48000
		if (MIC_OUT_RATE != sample_rate)
			count = quisk_cInterpolate(csamples, count, &cfiltInterp, MIC_OUT_RATE / sample_rate);
		// convert back to 16 bits
		for (i = 0; i < count; i++) {
			filtered[i] = csamples[i] * CLIP16;
#if DEBUG_IO || DEBUG
			magn = cabs(csamples[i]);
			if (magn > dbOut)
				dbOut = magn;
#endif
		}
	}
	else {		// AM and FM
#if DEBUG_IO || DEBUG
		for (i = 0; i < count; i++) {
			magn = fabs(dsamples[i]);
			if (magn > Level3)
				Level3 = magn;
		}
#endif
		// round off peaks
		CcmPeak(dsamples, NULL, count);
#if DEBUG_IO || DEBUG
		for (i = 0; i < count; i++) {
			magn = fabs(dsamples[i]);
			if (magn > Level4)
				Level4 = magn;
		}
#endif
		// remove clipping distortion
		count = quisk_dFilter(dsamples, count, &dfiltAudio3);
		// Interpolate up to 48000
		if (MIC_OUT_RATE != sample_rate)
			count = quisk_dInterpolate(dsamples, count, &dfiltInterp, MIC_OUT_RATE / sample_rate);
		// convert back to 16 bits
		for (i = 0; i < count; i++) {
			filtered[i] = dsamples[i] * CLIP16;
#if DEBUG_IO || DEBUG
			magn = fabs(dsamples[i]);
			if (magn > dbOut)
				dbOut = magn;
#endif
		}
	}
#if DEBUG_IO || DEBUG
	if (debug_timer == 0) {
		if (dbOut > 1.0)
			clip = "Clip";
		else
			clip = "";
		dbOut = 20 * log10(dbOut);
		printf ("pre %3.1lf dB clip %2.0lf InMax %6.2lf   Level0 %6.2lf  Level1 %6.2lf  Level2 %6.2lf  Level3 %6.2lf  Level4 %6.2lf  dbOut %6.2lf  %s\n",
			quisk_mic_preemphasis, 20 * log10(quisk_mic_clip), 20 * log10(inMax), 20 * log10(Level0),
			20 * log10(Level1), 20 * log10(Level2), 20 * log10(Level3),  20 * log10(Level4), dbOut, clip);
		Level0 = Level1 = Level2 = Level3 = Level4 = dbOut = 0;
	}
	//QuiskPrintTime("    tx_filter", 2);
#endif
	return count;
}

static int tx_filter_digital(complex double * filtered, int count)
{	// Input samples are creal(filtered), output is filtered.
	// This filter has minimal processing and is used for digital modes.
	int i;
	static int do_init = 1;

	static struct quisk_dFilter filter1;
	if (do_init) {		// initialization
		do_init = 0;
		quisk_filt_dInit(&filter1, quiskDgtFilt48Coefs, sizeof(quiskDgtFilt48Coefs)/sizeof(double));    // pass 1350, stop 1650
	}
	if ( ! filtered) {	// Change to rxMode
		quisk_filt_tune(&filter1, 1650.0 / 48000, rxMode != DGT_L && rxMode != LSB);
		return 0;
	}
	for (i = 0; i < count; i++)	// FIR bandpass filter; separate into I and Q
		filtered[i] = quisk_dC_out(creal(filtered[i]), &filter1) * 2.00;	// tuned filter loss 0.5
	//quisk_calc_audio_graph(CLIP16, filtered, NULL, count, 0);
	return count;
}

static int tx_filter_freedv(complex double * filtered, int count, int encode)
{	// Input samples are creal(filtered), output is filtered.
	// This filter is used for digital voice.
	int i;
	int sample_rate = 8000;
	double dtmp, magn, dsample;
	static int samples_size = 0;
	static int last_mode;
	static int do_init = 1;
	static double aaa, bbb, ccc, Xmin, Xmax, Ymax;
	static double time_long, time_short;
	static double inMax=0.3;
	static double * dsamples = NULL;
	static struct quisk_cFilter filter2;
	static struct quisk_dFilter filtDecim;
	static struct quisk_cFilter cfiltInterp;

	if (do_init) {		// initialization
		//QuiskWavWriteOpen(&hWav, "jim.wav", 3, 1, 4, 8000, 1.0 / CLIP16);
		do_init = 0;
		quisk_filt_cInit(&filter2, quiskFilt53D2Coefs, sizeof(quiskFilt53D2Coefs)/sizeof(double));  // pass 1500, stop 1800
		quisk_filt_tune((struct quisk_dFilter *)&filter2, 1600.0 / 8000, 1);	// upper sideband
		last_mode = 11;
		quisk_filt_dInit(&filtDecim,  quiskLpFilt48Coefs, sizeof(quiskLpFilt48Coefs)/sizeof(double));   // pass 3000, stop 4000
		quisk_filt_cInit(&cfiltInterp, quiskLpFilt48Coefs, sizeof(quiskLpFilt48Coefs)/sizeof(double));
		dtmp = 1.0 / sample_rate;		// sample time
		time_long   = 1.0 - exp(- dtmp / 3.000);
		time_short  = 1.0 - exp(- dtmp / 0.005);
		Ymax = pow(10.0,  - 1 / 20.0);				// maximum y
		Xmax = pow(10.0,  3 / 20.0);				// x where slope is zero; for x > Xmax, y == Ymax
		Xmin = Ymax - fabs(Ymax - Xmax);			// x where slope is 1 and y = x; start of compression
		//printf ("Xmin %f\n", Xmin);
		aaa = 1.0 / (2.0 * (Xmin - Xmax));			// quadratic
		bbb = -2.0 * aaa * Xmax;
		ccc = Ymax - aaa * Xmax * Xmax - bbb * Xmax;
	}
	if (last_mode != rxMode) {	// change to sideband
		if (rxMode == FDV_U) {	 // upper sideband
			last_mode = rxMode;
			quisk_filt_tune((struct quisk_dFilter *)&filter2, 1600.0 / 8000, 1);
		}
		else if (rxMode == FDV_L) {   // lower sideband
			last_mode = rxMode;
			quisk_filt_tune((struct quisk_dFilter *)&filter2, 1600.0 / 8000, 0);
		}
	}
	if ( ! filtered)
		return 0;
	// check size of dsamples[] buffer
	if (count > samples_size) {
		samples_size = count * 2;
		if (dsamples)
			free(dsamples);
		dsamples = (double *)malloc(samples_size * sizeof(double));
	}
	// copy to dsamples[]
	for (i = 0; i < count; i++)
		dsamples[i] = creal(filtered[i]) / CLIP16;	// normalize to 1.0000
	// Decimate to 8000 Hz
	if (quisk_sound_state.mic_sample_rate != sample_rate)
		count = quisk_dDecimate(dsamples, count, &filtDecim, quisk_sound_state.mic_sample_rate / sample_rate);
	// Measure average peak input audio level and limit
	for (i = 0; i < count; i++) {
		dsample = dsamples[i];
		magn = fabs(dsample);
		if (magn > inMax)
			inMax = inMax * (1 - time_short) + time_short * magn;
		else if(magn > mic_agc_level)
			inMax = inMax * (1 - time_long) + time_long * magn;
		else
			inMax = inMax * (1 - time_long) + time_long * mic_agc_level;
		dsample = dsample / inMax * Xmin * 0.7;
		magn = fabs(dsample);
		if (magn < Xmin)
			dsamples[i] = dsample;
		else if (magn > Xmax)
			dsamples[i] = copysign(Ymax, dsample);
		else
			dsamples[i] = copysign(aaa * magn * magn + bbb * magn + ccc, dsample);
		dsamples[i] = dsamples[i] * CLIP16;
	}
	//QuiskWavWriteD(&hWav, dsamples, count);
	if (encode && pt_quisk_freedv_tx)   // Encode audio into digital modulation
		count = (* pt_quisk_freedv_tx)(filtered, dsamples, count);
	//quisk_calc_audio_graph(CLIP16, filtered, NULL, count, 0);
	if (freedv_current_mode != FREEDV_MODE_700D)   // 700D has its own filter
		count = quisk_cCDecimate(filtered, count, &filter2, 1);
	// Interpolate up to 48000
	if (MIC_OUT_RATE != sample_rate)
		count = quisk_cInterpolate(filtered, count, &cfiltInterp, MIC_OUT_RATE / sample_rate);
	return count;
}

PyObject * quisk_get_tx_filter(PyObject * self, PyObject * args)
{  // return the TX filter response to display on the graph
// This is for debugging.  Change quisk.py to call QS.get_tx_filter() instead
// of QS.get_filter().
	int i, j, k;
	int freq, time;
	PyObject * tuple2;
	complex double cx;
	double scale;
	double * average, * fft_window, * bufI, * bufQ;
	fftw_complex * samples, * pt;		// complex data for fft
	fftw_plan plan;						// fft plan
	double phase, delta;
	int nTaps = 325;

	if (!PyArg_ParseTuple (args, ""))
		return NULL;

	// Create space for the fft of size data_width
	pt = samples = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * data_width);
	plan = fftw_plan_dft_1d(data_width, pt, pt, FFTW_FORWARD, FFTW_MEASURE);
	average = (double *) malloc(sizeof(double) * (data_width + nTaps));
	fft_window = (double *) malloc(sizeof(double) * data_width);
	bufI = (double *) malloc(sizeof(double) * nTaps);
	bufQ = (double *) malloc(sizeof(double) * nTaps);

	for (i = 0, j = -data_width / 2; i < data_width; i++, j++)	// Hanning
		fft_window[i] = 0.5 + 0.5 * cos(2. * M_PI * j / data_width);

	for (i = 0; i < data_width + nTaps; i++)
		average[i] = 0.5;	// Value for freq == 0
	for (freq = 1; freq < data_width / 2.0 - 10.0; freq++) {
	//freq = data_width * 0.2 / 48.0;
		delta = 2 * M_PI / data_width * freq;
		phase = 0;
		// generate some initial samples to fill the filter pipeline
		for (time = 0; time < data_width + nTaps; time++) {
			average[time] += cos(phase);	// current sample
			phase += delta;
			if (phase > 2 * M_PI)
				phase -= 2 * M_PI;
		}
	}
	// now filter the signal using the transmit filter
	tx_filter(NULL, 0);				// initialize
	scale = 1.0;
	for (i = 0; i < data_width; i++)
		if (fabs(average[i + nTaps]) > scale)
			scale = fabs(average[i + nTaps]);
	scale = CLIP16 / scale;		// limit to CLIP16
	for (i = 0; i < nTaps; i++)
		samples[i] = average[i] * scale;
	tx_filter(samples, nTaps);			// process initial samples
	for (i = 0; i < data_width; i++)
		samples[i] = average[i + nTaps] * scale;
	tx_filter(samples, data_width);	// process the samples

	for (i = 0; i < data_width; i++)	// multiply by window
		samples[i] *= fft_window[i];
	fftw_execute(plan);		// Calculate FFT
	// Normalize and convert to log10
	scale = 0.3 / data_width / scale;
	for (k = 0; k < data_width; k++) {
		cx = samples[k];
		average[k] = cabs(cx) * scale;
		if (average[k] <= 1e-7)		// limit to -140 dB
			average[k] = -7;
		else
			average[k] = log10(average[k]);
	}
	// Return the graph data
	tuple2 = PyTuple_New(data_width);
	i = 0;
	// Negative frequencies:
	for (k = data_width / 2; k < data_width; k++, i++)
		PyTuple_SetItem(tuple2, i, PyFloat_FromDouble(20.0 * average[k]));

	// Positive frequencies:
	for (k = 0; k < data_width / 2; k++, i++)
		PyTuple_SetItem(tuple2, i, PyFloat_FromDouble(20.0 * average[k]));

	free(bufQ);
	free(bufI);
	free(average);
	free(fft_window);
	fftw_destroy_plan(plan);
	fftw_free(samples);

	return tuple2;
}

// Send samples using the Metis-Hermes protocol.  A frame is 8 bytes: L/R audio and I/Q mic samples.
// All samples are 2 bytes.  The 1032 byte UDP packet contains 63*2 radio sound samples, and 63*2 mic I/Q samples.
// Samples are sent synchronously with the input samples.

static void quisk_hermes_tx_reset(void)
{   // Reset the buffer to half full of zero samples
	int i;

	hermes_num_samples = HERMES_TX_BUF_SAMPLES / 2;
	hermes_read_index = 0;
	hermes_write_index = hermes_num_samples * 2;
	for (i = 0; i < HERMES_TX_BUF_SHORTS; i++)	// Put zero mic samples into the buffer
		hermes_buf[i] = 0;
	//printf("quisk_hermes_tx_reset: hermes_num_samples %d\n", hermes_num_samples);
}

static void quisk_hermes_tx_add(complex double * cSamples, int tx_count, int key_down)
{	// Add samples to the Tx buffer.
	int i;
	static int hermes_buf_has_samples=1;

	if (key_down) {		// add non-zero samples to buffer
		hermes_buf_has_samples = 1;
	}
	else if (hermes_buf_has_samples) {	// key is not down; reset buffer to zero
		quisk_hermes_tx_reset();
		hermes_buf_has_samples = 0;
		return;
	}
	else {		// key is not down but buffer is zeroed; just reset pointers
		hermes_num_samples = HERMES_TX_BUF_SAMPLES / 2;
		hermes_read_index = 0;
		hermes_write_index = hermes_num_samples * 2;
		return;
	}
	//printf("hermes_tx_add start: hermes_num_samples %d, tx_count %d\n", hermes_num_samples, tx_count);
	if (hermes_num_samples + tx_count >= HERMES_TX_BUF_SAMPLES) {	// no more space; throw away half the samples
		quisk_udp_mic_error("Tx hermes buffer overflow");
		//printf("Tx hermes buffer overflow: hermes_num_samples %d tx_count %d\n", hermes_num_samples, tx_count);
		i = hermes_num_samples - HERMES_TX_BUF_SAMPLES / 2;	// number of samples to remove
		hermes_num_samples -= i;
		hermes_read_index += i * 2;
		if (hermes_read_index >= HERMES_TX_BUF_SHORTS)
			hermes_read_index -= HERMES_TX_BUF_SHORTS;
	}
	hermes_num_samples += tx_count;
	for (i = 0; i < tx_count; i++) {			// Put transmit mic samples into the buffer
		hermes_buf[hermes_write_index++] = (short)cimag(cSamples[i]);
		hermes_buf[hermes_write_index++] = (short)creal(cSamples[i]);
		if (hermes_write_index >= HERMES_TX_BUF_SHORTS)
			hermes_write_index = 0;
	}
	//printf ("Buffer usage %.1f %%, hermes_num_samples %d, tx_count %d\n", 100.0 * hermes_num_samples / HERMES_TX_BUF_SAMPLES, hermes_num_samples, tx_count);
	//printf("hermes_tx_add end: hermes_num_samples %d\n", hermes_num_samples);
}

void quisk_hermes_tx_send(int tx_socket, int * tx_records)
{	// Send one UDP block of mic samples using the Metis-Hermes protocol.  Timing is from blocks received, rate is 48k.
	// If the key is up we send samples anyway, but the samples are zero.
	int i, offset, sent, ratio;
	short s;
	unsigned char sendbuf[1032];
	unsigned char * pt_buf;
	static unsigned int seq = 0;
	static unsigned char C0_index = 0;
	static int mox_bit=0;	// On key up, send some zero samples before releasing the T/R relay to Rx.
	static int mox_counter;	// Timer for key-up delay.
	unsigned int hlwp = 0;

	//printf("hermes_tx_send start 1: hermes_num_samples %d\n", hermes_num_samples);
	if (tx_records == NULL) {
		seq = 0;
		C0_index = 0;
		quisk_hermes_tx_reset();
		return;
	}
	if (quisk_is_key_down()) {
		mox_bit = 1;
		mox_counter = (int)((quiskKeyupDelay + 30) / 2.625 + 0.5);	// 126 samples per block / 48000 == 2.625 msec
	}
	else {	// Delay un-setting the MOX bit and continue sending zero-valued samples; when Tx signal is zero, unset MOX.
		if (mox_bit) {		// This allows the Tx signal to go to zero before switching T/R relay.
			if (mox_counter > 0)
				mox_counter--;
			else
				mox_bit = 0;
		}
	}
	//printf("hermes_tx_send start 2: hermes_num_samples %d\n", hermes_num_samples);
	ratio = quisk_sound_state.sample_rate / 48000;		// send rate is 48 ksps
	//printf ("quisk_hermes_tx_send ratio %d count %d\n", ratio, *tx_records);
	if (*tx_records / ratio < 63 * 2)		// tx_records is the number of samples received for each receiver
		return;
	// Send 63*2 Tx samples with control bytes
	//printf ("Buffer usage %.1f %%\n", 100.0 * hermes_num_samples / HERMES_TX_BUF_SAMPLES);
	//printf ("Tx  quisk_hermes_tx_send ratio %d, count %d, samples %d\n", ratio, *tx_records, hermes_num_samples);
	*tx_records -= 63 * 2 * ratio;
	if (hermes_num_samples < 63 * 2) {	// Not enough samples to send
		//printf("Tx hermes buffer underflow: hermes_num_samples %d\n", hermes_num_samples);
		quisk_udp_mic_error("Tx hermes buffer underflow");
		quisk_hermes_tx_reset();
	}
	hermes_num_samples -= 63 * 2;
	sendbuf[0] = 0xEF;
	sendbuf[1] = 0xFE;
	sendbuf[2] = 0x01;
	sendbuf[3] = 0x02;
	sendbuf[4] = seq >> 24 & 0xFF;
	sendbuf[5] = seq >> 16 & 0xFF;
	sendbuf[6] = seq >> 8 & 0xFF;
	sendbuf[7] = seq & 0xFF;
	seq++;
	sendbuf[8] = 0x7F;
	sendbuf[9] = 0x7F;
	sendbuf[10] = 0x7F;
	offset = C0_index * 4;		// offset into quisk_pc_to_hermes is C0[7:1] * 4
	sendbuf[11] = C0_index << 1 | mox_bit;			// C0
	sendbuf[12] = quisk_pc_to_hermes[offset++];		// C1
	sendbuf[13] = quisk_pc_to_hermes[offset++];		// C2
	sendbuf[14] = quisk_pc_to_hermes[offset++];		// C3
	sendbuf[15] = quisk_pc_to_hermes[offset++];		// C4
	if (C0_index == 0) {	// Do not change receiver count without stopping Hermes and restarting
		sendbuf[15] = quisk_multirx_count << 3 | 0x04;	// Send the old count, not the changed count
		if (mox_bit)		// send filter selection on J16
			sendbuf[13] = hermes_filter_tx << 1;
		else
			sendbuf[13] = hermes_filter_rx << 1;
	}
        else if ( ! quisk_is_vna && C0_index == 9) {
		if (mox_bit) {		// send Alex filter selection
			sendbuf[14] = alex_hpf_tx;
			sendbuf[15] = alex_lpf_tx;
                }
		else {
			sendbuf[14] = alex_hpf_rx;
			sendbuf[15] = alex_lpf_rx;
                }
        }
	if (++C0_index > 16)
		C0_index = 0;
	pt_buf = sendbuf + 16;
	for (i = 0; i < 63; i++) {		// add 63 samples
		*pt_buf++ = 0x00;			// Left/Right audio sample
		*pt_buf++ = 0x00;
		*pt_buf++ = 0x00;
		*pt_buf++ = 0x00;
		s = hermes_buf[hermes_read_index++];
		*pt_buf++ = (s >> 8) & 0xFF;		// Two bytes of I
		*pt_buf++ = s & 0xFF;
		s = hermes_buf[hermes_read_index++];
		*pt_buf++ = (s >> 8) & 0xFF;		// Two bytes of Q
		*pt_buf++ = s & 0xFF;
		if (hermes_read_index >= HERMES_TX_BUF_SHORTS)
			hermes_read_index = 0;
	}
	sendbuf[520] = 0x7F;
	sendbuf[521] = 0x7F;
	sendbuf[522] = 0x7F;

	// Changes for HermesLite v2 thanks to Steve, KF7O
	if ((quisk_hermeslite_writepointer > 0) && (quisk_hermeslite_writeattempts++ % 8 == 0)) {

		// Only send periodic hermeslite writes in second part of frame
		hlwp = 5*(quisk_hermeslite_writepointer-1);
		sendbuf[523] = quisk_hermeslite_writequeue[hlwp++] << 1 | mox_bit;
		sendbuf[524] = quisk_hermeslite_writequeue[hlwp++];
		sendbuf[525] = quisk_hermeslite_writequeue[hlwp++];
		sendbuf[526] = quisk_hermeslite_writequeue[hlwp++];
		sendbuf[527] = quisk_hermeslite_writequeue[hlwp++];

		if ((sendbuf[523] & 0x80) == 0) {
			// No acknowledge requested so fire and forget
			quisk_hermeslite_writepointer--;
			quisk_hermeslite_writeattempts = 0;	
		}
	} else {
		offset = C0_index * 4;		// offset into quisk_pc_to_hermes is C0[7:1] * 4
		sendbuf[523] = C0_index << 1 | mox_bit;		// C0
		sendbuf[524] = quisk_pc_to_hermes[offset++];		// C1
		sendbuf[525] = quisk_pc_to_hermes[offset++];		// C2
		sendbuf[526] = quisk_pc_to_hermes[offset++];		// C3
		sendbuf[527] = quisk_pc_to_hermes[offset++];		// C4
		if (C0_index == 0) {
			sendbuf[527] = quisk_multirx_count << 3 | 0x04;		// Send the old count, not the changed count
			if (mox_bit)		// send filter selection on J16
				sendbuf[525] = hermes_filter_tx << 1;
			else
				sendbuf[525] = hermes_filter_rx << 1;
		}
                else if ( ! quisk_is_vna && C0_index == 9) {
		        if (mox_bit) {		// send Alex filter selection
			        sendbuf[526] = alex_hpf_tx;
			        sendbuf[527] = alex_lpf_tx;
                        }
		        else {
			        sendbuf[526] = alex_hpf_rx;
			        sendbuf[527] = alex_lpf_rx;
                        }
                }
		if (++C0_index > 16)
			C0_index = 0;
	
		if (quisk_hermeslite_writepointer > 0) quisk_hermeslite_writeattempts++;
	}

	// Abort after 53/8 ~= 5 retries
	if ((quisk_hermeslite_writepointer > 0) && (quisk_hermeslite_writeattempts > 53)) {
		printf("ERROR: Maximum Hermes-Lite write attempts\n");
		// Cancel entire write sequence
		quisk_hermeslite_writepointer = 0;
		quisk_hermeslite_writeattempts = 0;
	}

	pt_buf = sendbuf + 528;
	for (i = 0; i < 63; i++) {		// add 63 samples
		*pt_buf++ = 0x00;			// Left/Right audio sample
		*pt_buf++ = 0x00;
		*pt_buf++ = 0x00;
		*pt_buf++ = 0x00;
		s = hermes_buf[hermes_read_index++];
		*pt_buf++ = (s >> 8) & 0xFF;		// Two bytes of I
		*pt_buf++ = s & 0xFF;
		s = hermes_buf[hermes_read_index++];
		*pt_buf++ = (s >> 8) & 0xFF;		// Two bytes of Q
		*pt_buf++ = s & 0xFF;
		if (hermes_read_index >= HERMES_TX_BUF_SHORTS)
			hermes_read_index = 0;
	}
	sent = send(tx_socket, (char *)sendbuf, 1032, 0);
	if (sent != 1032)
		quisk_udp_mic_error("Tx UDP socket error in Hermes");
	//printf("hermes_tx_send end: hermes_num_samples %d\n", hermes_num_samples);
}

// udp_iq has an initial zero followed by the I/Q samples.
// The initial zero is sent iff align4 == 1.

static void transmit_udp(complex double * cSamples, int count)
{	// Send count samples using the HiQSDR protocol.  Each sample is sent as two shorts (4 bytes) of I/Q data.
	// Transmission is delayed until a whole block of data is available.
	int i, sent;
	static short udp_iq[TX_BLOCK_SHORTS + 1] = {0};
	static int udp_size = 1;

	if (mic_socket == INVALID_SOCKET)
		return;
	if ( ! cSamples) {		// initialization
		udp_size = 1;
		udp_iq[0] = 0;	// should not be necessary
		return;
	}
	if (doTxCorrect) {
		for (i = 0; i < count; i++)
			cSamples[i] = cSamples[i] * TxCorrectLevel + TxCorrectDc;
	}
	for (i = 0; i < count; i++) {	// transmit samples
		udp_iq[udp_size++] = (short)creal(cSamples[i]);
		udp_iq[udp_size++] = (short)cimag(cSamples[i]);
		if (udp_size >= TX_BLOCK_SHORTS) {	// check count
			if (align4)
				sent = send(mic_socket, (char *)udp_iq, udp_size * 2, 0);
			else
				sent = send(mic_socket, (char *)udp_iq + 1, --udp_size * 2, 0);
			if (sent != udp_size * 2)
				printf("Send socket returned %d\n", sent);
			udp_size = 1;
		}
	}
}

static void transmit_mic_carrier(complex double * cSamples, int count, double level)
{	// send a CW carrier instead of mic samples
#if 1
	// transmit a carrier equal to the number of samples
	int i;
	for (i = 0; i < count; i++)
		cSamples[i] = level * CLIP16;
#else
	// replace mic samples with a sin wave
	int i;
	double freq;
	complex double phase1;		// Phase increment
	static complex double vector1 = CLIP16 / 2;

	// Use the sidetone slider 0 to 1000 to set frequency
	freq = quisk_sidetoneCtrl * 5;
	freq = ((int)freq / 50) * 50;
	phase1 = cexp(I * 2.0 * M_PI * freq / 48000.0);
	//phase1 = conj(phase1);
	for (i = 0; i < count; i++) {
		vector1 *= phase1;
		cSamples[i] = vector1 * level;
	}
#endif
}

static void transmit_mic_imd(complex double * cSamples, int count, double level)
{	// send a 2-tone test signal instead of mic samples
	int i;
	complex double v;
	static complex double phase1=0, phase2;		// Phase increment
	static complex double vector1;
	static complex double vector2;

	if (phase1 == 0) {		// initialize
		phase1 = cexp((I * 2.0 * M_PI * IMD_TONE_1) / MIC_OUT_RATE);
		phase2 = cexp((I * 2.0 * M_PI * IMD_TONE_2) / MIC_OUT_RATE);
		vector1 = CLIP16 / 2.0;
		vector2 = CLIP16 / 2.0;
	}
	for (i = 0; i < count; i++) {	// transmit a carrier equal to the number of samples
		vector1 *= phase1;
		vector2 *= phase2;
		v = level * (vector1 + vector2);
		cSamples[i] = v;
	}
}

int quisk_process_microphone(int mic_sample_rate, complex double * cSamples, int count)
{
	int i, sample, maximum, interp, mic_interp, key_down;
	double d, ctcss_delta, audio_scale, ctcss_scale;
	static int key_was_down=0, key_down_counter=0;
	static struct quisk_cFilter filtInterp={NULL};
	static struct quisk_cFilter filtInterp2={NULL};
	static struct quisk_cFilter filt240D4 = {NULL};
	static struct quisk_cFilter filt300D6 = {NULL};
	static struct quisk_cHB45Filter HalfBand = {NULL, 0, 0};
	static double ctcss_angle=0;
	static struct alc tx_alc = {NULL};

#if 0
	// Measure soundcard actual sample rate
	static time_t seconds = 0;
	static int total = 0;
	struct timeval tb;
	static double dtime;

	gettimeofday(&tb);
	total += count;
	if (seconds == 0) {
		seconds = tb.tv_sec;
		dtime = tb.tv_sec + 0.000001 * tb.tv_usec;
	}		
	else if (tb.tv_sec - seconds > 4) {
		printf("Mic soundcard rate %.3f\n", total / (tb.tv_sec + .000001 * tb.tv_usec - dtime));
		seconds = tb.tv_sec;
		printf("backlog %d, count %d\n", backlog, count);
	}
#endif

#if DEBUG_IO || DEBUG
	//QuiskPrintTime("", -1);
#endif

#if DEBUG_IO || DEBUG
	double magn;
	static double out_max=0;
#endif
#if DEBUG_LEVEL || DEBUG_IO || DEBUG
	debug_timer += count;
	if (debug_timer >= mic_sample_rate)		// one second
		debug_timer = 0;
#endif

// Microphone sample are input at mic_sample_rate.  But after processing,
// the output rate is MIC_OUT_RATE.
	interp = MIC_OUT_RATE / mic_sample_rate;
	
#if USE_GET_SIN
	get_sin(cSamples, count);	// Replace mic samples with a sin wave
#endif
#if USE_2TONE
	get_2tone(cSamples, count);	// Replace mic samples with a 2-tone test signal
#endif
	// measure maximum microphone level
	maximum = 1;
	for (i = 0; i < count; i++) {
		cSamples[i] *= (double)CLIP16 / CLIP32;	// convert 32-bit samples to 16 bits
		d = creal(cSamples[i]);
		sample = (int)fabs(d);
		if (sample > maximum)
			maximum = sample;
	}
	// VOX processing
	if (maximum > vox_level) {
		is_vox = mic_sample_rate / 1000 * timeVOX;		// reset timer to maximum
	}
	else if(is_vox) {
		is_vox -= count;		// decrement timer
		if (is_vox < 0)
			is_vox = 0;
	}
	// mic display level
	if (maximum > mic_level)
		mic_level = maximum;
	mic_timer -= count;		// time out the max microphone level to display
	if (mic_timer <= 0) {
		mic_timer = mic_sample_rate / 1000 * MIC_MAX_HOLD_TIME;
		mic_max_display = mic_level;
		mic_level = 1;
	}

	if ( ! tx_alc.buffer)
		init_alc(&tx_alc, 960);	// at 48000 sps, 960 is 20 msec

	// quiskTxHoldState is a state machine to implement a pause for a repeater frequency shift for FM
	key_down = quisk_is_key_down();
	if (rxMode == FM || rxMode == DGT_FM) {
		switch (quiskTxHoldState) {
		case 0:			// Never implement any hold
			break;
		case 1:			// Start hold when key goes down
			if (key_down)
				quiskTxHoldState = 2;
			break;
		case 2:			// Key down hold is in progress; wait until state changes to 3
			break;
		case 3:			// Hold is released; when key goes up, hold starts again
			if ( ! key_down)
				quiskTxHoldState = 4;
			break;
		case 4:			// Key up hold is in progress; wait until state changes to 1
			break;
		}
	}
	if (quiskTxHoldState == 2 || quiskTxHoldState == 4) {		// don't transmit until the hold is cleared
		key_down = 0;
		for (i = 0; i < count; i++)
			cSamples[i] = 0;
	}
	if (key_down != key_was_down) {	
		key_down_counter = 4800;	// Key was pressed. Zero the first few samples to clear the buffers.
		init_alc(&tx_alc, 0);		// init ALC for Tx and RECORD_MIC
		key_was_down = key_down;
	}
	if (key_down || DEBUG_MIC) {		// create transmit I/Q samples
#if USE_GET_SIN == 2
		transmit_udp(cSamples, count * interp);
#else
		if (quiskSpotLevel >= 0) {		// Spot is in use
			count *= interp;
			transmit_mic_carrier(cSamples, count, quiskSpotLevel / 1000.0);
		}
		else switch (rxMode) {
		case LSB:		// LSB
		case USB:		// USB
			if (quisk_record_state == PLAYBACK)
				count = tx_filter_digital(cSamples, count);	// filter samples, minimal processing
			else
				count = tx_filter(cSamples, count);		// filter samples
			process_alc(cSamples, count, &tx_alc, rxMode);
			break;
		case AM:		// AM
			if (quisk_record_state != PLAYBACK)		// no audio processing for recorded sound
				count = tx_filter(cSamples, count);
			for (i = 0; i < count; i++)	// transmit (0.5 + ampl/2, 0)
				cSamples[i] = (creal(cSamples[i]) + CLIP16) * 0.5;
			process_alc(cSamples, count, &tx_alc, rxMode);
			break;
		case FM:		// FM
			if (quisk_record_state != PLAYBACK)		// no audio processing for recorded sound
				count = tx_filter(cSamples, count);
			if (quisk_ctcss_freq > 9) {
				ctcss_delta = 2.0 * M_PI / MIC_OUT_RATE * quisk_ctcss_freq;
				ctcss_scale = 450.0 * modulation_index / quisk_ctcss_freq;	// for 15% of total deviation
				audio_scale = 0.85 * modulation_index / CLIP16;
				for (i = 0; i < count; i++) {
					ctcss_angle += ctcss_delta;
					if (ctcss_angle >= 2.0 * M_PI)
						ctcss_angle -= 2.0 * M_PI;
					cSamples[i] = CLIP16 * cexp(I * (audio_scale * creal(cSamples[i]) + ctcss_scale * sin (ctcss_angle)));
				}
			}
			else {
				audio_scale = modulation_index / CLIP16;
				for (i = 0; i < count; i++)	// this is phase modulation == FM and 6 dB /octave preemphasis
					cSamples[i] = CLIP16 * cexp(I * audio_scale * creal(cSamples[i]));
			}
			process_alc(cSamples, count, &tx_alc, rxMode);
			break;
		case DGT_U:		// external digital modes
		case DGT_L:
		case DGT_IQ:
		case DGT_FM:
			count = tx_filter_digital(cSamples, count);	// filter samples, minimal processing
			process_alc(cSamples, count, &tx_alc, rxMode);
			break;
		case IMD:	// transmit IMD 2-tone test
			count *= interp;
			transmit_mic_imd(cSamples, count, quiskImdLevel / 1000.0);
			break;
		case FDV_U:	// FDV
		case FDV_L:
			count = tx_filter_freedv(cSamples, count, 1);
			process_alc(cSamples, count, &tx_alc, rxMode);
			break;
		default:
			break;
		}
#if DEBUG_IO || DEBUG
		for (i = 0; i < count; i++) {
			magn = cabs(cSamples[i]);
			if (out_max < magn)
				out_max = magn;
		}
		if (debug_timer == 0) {
			printf("Max cSamples[] Output Level %9.6f\n", out_max / CLIP16);
			out_max = 0;
		}
#endif
		if (key_down_counter > 0) {		// zero the first few samples to clear the buffers.
			for (i = 0; i < count && key_down_counter > 0; i++, key_down_counter--) {
				if (key_down_counter < 480)
					cSamples[i] *= (1.0 - key_down_counter / 480.0);	// slow increase at end
				else
					cSamples[i] = 0;	// initial samples are zero
			}
		}
#endif
	}
	if (reverse_tx_sideband)
		for (i = 0; i < count; i++)
			cSamples[i] = conj(cSamples[i]);
        if(quisk_pt_sample_write) {	// Used for SoapySDR
		// Interpolate the mic samples to the Tx sample rate
//printf("Tx sample rate %i\n", tx_sample_rate);
		switch (tx_sample_rate) {
		case 100000:
			count = quisk_cInterp2HB45(cSamples, count, &HalfBand);
			// Fall through
		case  50000:
			if (! filt240D4.dCoefs)
				quisk_filt_cInit(&filt240D4, quiskFilt240D4Coefs, sizeof(quiskFilt240D4Coefs)/sizeof(double));
			if (! filt300D6.dCoefs)
				quisk_filt_cInit(&filt300D6, quiskFilt300D6Coefs, sizeof(quiskFilt300D6Coefs)/sizeof(double));
			count = quisk_cInterpDecim(cSamples, count, &filt240D4, 5, 4);	// 60 kSps
			count = quisk_cInterpDecim(cSamples, count, &filt300D6, 5, 6);	// 50 kSps
			break;
		case 96000:
			if (! filtInterp2.dCoefs)
				quisk_filt_cInit(&filtInterp2, quiskFilt48dec24Coefs, sizeof(quiskFilt48dec24Coefs)/sizeof(double));
			count = quisk_cInterpolate(cSamples, count, &filtInterp2, 2);
			break;
		case 192000:
			if (! filtInterp2.dCoefs)
				quisk_filt_cInit(&filtInterp2, quiskFilt48dec24Coefs, sizeof(quiskFilt48dec24Coefs)/sizeof(double));
			count = quisk_cInterp2HB45(cSamples, count, &HalfBand);
			count = quisk_cInterpolate(cSamples, count, &filtInterp2, 2);
			break;
		default:	// 48000
			break;
		}
		(*quisk_pt_sample_write)(cSamples, count);
	}
	else if (quisk_use_rx_udp == 10) {	// Send Hermes mic samples when key is up or down
		if ( ! quisk_rx_udp_started)
			;
		else {
			if ((rxMode == CWL || rxMode == CWU) && quiskSpotLevel < 0)	// CW and no Spot
				for (i = 0; i < count; i++)
					cSamples[i] = 0;
			quisk_hermes_tx_add(cSamples, count, key_down);
		}
	}
	else if (quisk_use_rx_udp && key_down) {	// Send mic samples to UDP when key is down
		transmit_udp(cSamples, count);
	}
	if (quisk_record_state == RECORD_MIC) {
		switch (rxMode) {
		case LSB:		// LSB
		case USB:		// USB
			count = tx_filter(cSamples, count);	// filter samples
			process_alc(cSamples, count, &tx_alc, rxMode);
			break;
		case AM:		// AM
			count = tx_filter(cSamples, count);
			process_alc(cSamples, count, &tx_alc, rxMode);
			break;
		case FM:		// FM
			count = tx_filter(cSamples, count);
			process_alc(cSamples, count, &tx_alc, rxMode);
			break;
		case FDV_U:	// FDV
		case FDV_L:
			count = tx_filter_freedv(cSamples, count, 0);
			process_alc(cSamples, count, &tx_alc, rxMode);
			break;
		default:
			for (i = 0; i < count; i++)
				cSamples[i] = 0;
			break;
		}
		// Perhaps interpolate the mic samples back to the sound play rate
		mic_interp = quisk_sound_state.playback_rate / MIC_OUT_RATE;
		if (mic_interp > 1) {
			if (! filtInterp.dCoefs)
				quisk_filt_cInit(&filtInterp, quiskFilt12_19Coefs, sizeof(quiskFilt12_19Coefs)/sizeof(double));
			count = quisk_cInterpolate(cSamples, count, &filtInterp, mic_interp);
		}
		quisk_tmp_record(cSamples, count, (double)CLIP32 / CLIP16);	// convert 16 to 32 bits
	}

#if DEBUG_IO || DEBUG
	//QuiskPrintTime("    process_mic", 1);
#endif
	return count;
}

PyObject * quisk_set_tx_audio(PyObject * self, PyObject * args, PyObject * keywds)
{  /* Call with keyword arguments ONLY; change Tx audio parameters */
	static char * kwlist[] = {"vox_level", "vox_time", "mic_clip", "mic_preemphasis", "tx_sample_rate",
		"reverse_tx_sideband", NULL} ;
	int vlevel = -9999, clevel = -9999;

	if (!PyArg_ParseTupleAndKeywords (args, keywds, "|iiidii", kwlist,
			&vlevel, &timeVOX, &clevel, &quisk_mic_preemphasis, &tx_sample_rate, &reverse_tx_sideband))
		return NULL;
	if (vlevel != -9999)
		vox_level = (int)(pow(10.0, vlevel / 20.0) * CLIP16);	// Convert dB to 16-bit sample
	if (clevel != -9999)
		quisk_mic_clip = pow(10.0, clevel / 20.0);	// Convert dB to factor
	Py_INCREF (Py_None);
	return Py_None;
}

PyObject * quisk_set_udp_tx_correct(PyObject * self, PyObject * args)	// Called from GUI thread
{
	double DcI, DcQ, level;

	if (!PyArg_ParseTuple (args, "ddd", &DcI, &DcQ, &level))
		return NULL;
	if (DcI == 0 && DcQ == 0 && level == 1.0){
		doTxCorrect = 0;
	}
	else {
		doTxCorrect = 1;
		TxCorrectDc = (DcI + I * DcQ) * CLIP16;
		DcI = fabs(DcI);
		DcQ = fabs(DcQ);
		if (DcI > DcQ)
			TxCorrectLevel = 1.0 - DcI;
		else
			TxCorrectLevel = 1.0 - DcQ;
		TxCorrectLevel *= level;
	}
	Py_INCREF (Py_None);
	return Py_None;
}

PyObject * quisk_is_vox(PyObject * self, PyObject * args)
{	/* return the VOX state */
	if (!PyArg_ParseTuple (args, ""))
		return NULL;
	return PyInt_FromLong(is_vox);
}

PyObject * quisk_set_hermes_filter(PyObject * self, PyObject * args)
{
	if (!PyArg_ParseTuple (args, "ii", &hermes_filter_rx, &hermes_filter_tx))
		return NULL;
	Py_INCREF (Py_None);
	return Py_None;
}

PyObject * quisk_set_alex_hpf(PyObject * self, PyObject * args)
{
	if (!PyArg_ParseTuple (args, "ii", &alex_hpf_rx, &alex_hpf_tx))
		return NULL;
	Py_INCREF (Py_None);
	return Py_None;
}

PyObject * quisk_set_alex_lpf(PyObject * self, PyObject * args)
{
	if (!PyArg_ParseTuple (args, "ii", &alex_lpf_rx, &alex_lpf_tx))
		return NULL;
	Py_INCREF (Py_None);
	return Py_None;
}

void quisk_close_mic(void)
{
	if (mic_socket != INVALID_SOCKET) {
		close(mic_socket);
		mic_socket = INVALID_SOCKET;
	}
#ifdef MS_WINDOWS
	if (mic_cleanup)
		WSACleanup();
#endif
}

void quisk_open_mic(void)
{
	struct sockaddr_in Addr;
	int sndsize = 48000;
#if DEBUG_IO || DEBUG
	int intbuf;
#ifdef MS_WINDOWS
	int bufsize = sizeof(int);
#else
	socklen_t bufsize = sizeof(int);
#endif
#endif

#ifdef MS_WINDOWS
	WORD wVersionRequested;
	WSADATA wsaData;
#endif

	modulation_index = QuiskGetConfigDouble("modulation_index", 1.6);
	mic_agc_level = QuiskGetConfigDouble("mic_agc_level", 0.1);
	if (quisk_sound_state.tx_audio_port == 0x553B)
		align4 = 0;		// Using old port: data starts at byte 42.
	else
		align4 = 1;		// Start data at byte 44; align to dword
	if (quisk_sound_state.mic_ip[0]) {
#ifdef MS_WINDOWS
		wVersionRequested = MAKEWORD(2, 2);
		if (WSAStartup(wVersionRequested, &wsaData) != 0)
			return;		// failure to start winsock
		mic_cleanup = 1;
#endif
		mic_socket = socket(PF_INET, SOCK_DGRAM, 0);
		if (mic_socket != INVALID_SOCKET) {
			setsockopt(mic_socket, SOL_SOCKET, SO_SNDBUF, (char *)&sndsize, sizeof(sndsize));
			Addr.sin_family = AF_INET;
// This is the UDP port for TX microphone samples, and must agree with the microcontroller.
			Addr.sin_port = htons(quisk_sound_state.tx_audio_port);
#ifdef MS_WINDOWS
			Addr.sin_addr.S_un.S_addr = inet_addr(quisk_sound_state.mic_ip);
#else
			inet_aton(quisk_sound_state.mic_ip, &Addr.sin_addr);
#endif
			if (connect(mic_socket, (const struct sockaddr *)&Addr, sizeof(Addr)) != 0) {
				close(mic_socket);
				mic_socket = INVALID_SOCKET;
			}
			else {
#if DEBUG_IO || DEBUG
				if (getsockopt(mic_socket, SOL_SOCKET, SO_SNDBUF, (char *)&intbuf, &bufsize) == 0)
					printf("UDP mic socket send buffer size %d\n", intbuf);
				else
					printf ("Failure SO_SNDBUF\n");
#endif
			}
		}
	}
}

void quisk_set_tx_mode(void)	// called when the mode rxMode is changed
{
	tx_filter(NULL, 0);
	tx_filter_digital(NULL, 0);
	transmit_udp(NULL, 0);
	tx_filter_freedv(NULL, 0, 0);
}
