Esempio n. 1
0
/*!
 * \brief Driver interface for playing samples to a device
 * 
 * \param dev Input. Device to play to
 * \param nSamples Input. Number of samples to play
 * \param cSamples Input. Samples to play
 * \param report_latency Input. 1 to report latency, 0 otherwise.
 * \param volume Input. [0,1] volume ratio
 * \returns number of samples read
 */
void play_sound_interface(
   struct sound_dev* dev,
   int nSamples,
   complex double * cSamples,
   int report_latency,
   double volume
)
{
   // Play using correct driver.
   switch( dev->driver )
   {
      case DEV_DRIVER_PORTAUDIO:
         quisk_play_portaudio(dev, nSamples, cSamples, report_latency, volume);
         break;
      case DEV_DRIVER_ALSA:
         quisk_play_alsa(dev, nSamples, cSamples, report_latency, volume);
         break;
      case DEV_DRIVER_PULSEAUDIO:
         quisk_play_pulseaudio(dev, nSamples, cSamples, report_latency, volume);
         break;
      case DEV_DRIVER_NONE:
      default:
         break;
   }
}
Esempio n. 2
0
File: sound.c Progetto: n1ywb/quisk
int quisk_read_sound(void)	// Called from sound thread
{  // called in an infinite loop by the main program
	int i, nSamples, mic_count, mic_interp, retval, is_cw, mic_sample_rate;
	complex tx_mic_phase;
	static double cwEnvelope=0;
	static double cwCount=0;
	static complex tuneVector = (double)CLIP32 / CLIP16;	// Convert 16-bit to 32-bit samples
	static struct quisk_cFilter filtInterp={NULL};

	quisk_sound_state.interupts++;
#if DEBUG_IO > 1
	QuiskPrintTime("Start read_sound", 0);
#endif
	if (pt_sample_read) {			// read samples from SDR-IQ
		nSamples = (*pt_sample_read)(cSamples);
	}
	else if (quisk_using_udp) {	// read samples from UDP port
		nSamples = quisk_read_rx_udp(cSamples);
	}
	else if (Capture.handle) {							// blocking read from soundcard
		if (Capture.portaudio_index < 0)
			nSamples = quisk_read_alsa(&Capture, cSamples);
		else
			nSamples = quisk_read_portaudio(&Capture, cSamples);
		if (Capture.channel_Delay >= 0)	// delay the I or Q channel by one sample
			delay_sample(&Capture, (double *)cSamples, nSamples);
		if (Capture.doAmplPhase)		// amplitude and phase corrections
			correct_sample(&Capture, cSamples, nSamples);
	}
	else {
		nSamples = 0;
	}
	retval = nSamples;		// retval remains the number of samples read
#if DEBUG_IO
	debug_timer += nSamples;
	if (debug_timer >= quisk_sound_state.sample_rate)		// one second
		debug_timer = 0;
#endif
#if DEBUG_IO > 2
	ptimer (nSamples);
#endif
	quisk_sound_state.latencyCapt = nSamples;	// samples available
#if DEBUG_IO > 1
	QuiskPrintTime("  read samples", 0);
#endif
	// Perhaps record the samples to a file
	if (want_record) {
		if (is_recording_samples) {
			record_samples(cSamples, nSamples);   // Record samples
		}
		else if (file_name_samples[0]) {
			if (record_samples(NULL, -1))	 // Open file
				is_recording_samples = 1;
		}
	}
	else if (is_recording_samples) {
		record_samples(NULL, -2);		 // Close file
		is_recording_samples = 0;
	}
#if ! DEBUG_MIC
	nSamples = quisk_process_samples(cSamples, nSamples);
#endif
#if DEBUG_IO > 1
	QuiskPrintTime("  process samples", 0);
#endif
	if (Playback.portaudio_index < 0)
		quisk_play_alsa(&Playback, nSamples, cSamples, 1);
	else
		quisk_play_portaudio(&Playback, nSamples, cSamples, 1);
	if (rxMode == 7) {
		if (DigitalOutput.portaudio_index < 0)
			quisk_play_alsa(&DigitalOutput, nSamples, cSamples, 0);
		else
			quisk_play_portaudio(&DigitalOutput, nSamples, cSamples, 0);
	}
	// Perhaps record the speaker audio to a file
	if (want_record) {
		if (is_recording_audio) {
			record_audio(cSamples, nSamples);   // Record samples
		}
		else if (file_name_audio[0]) {
			if (record_audio(NULL, -1))	 // Open file
				is_recording_audio = 1;
		}
	}
	else if (is_recording_audio) {
		record_audio(NULL, -2);		 // Close file
		is_recording_audio = 0;
	}

#if DEBUG_IO > 1
	QuiskPrintTime("  play samples", 0);
#endif
	// Read and process the microphone
	mic_count = 0;
	mic_sample_rate = quisk_sound_state.mic_sample_rate;
	if (MicCapture.handle) {
		if (MicCapture.portaudio_index < 0)
			mic_count = quisk_read_alsa(&MicCapture, cSamples);
		else
			mic_count = quisk_read_portaudio(&MicCapture, cSamples);
	}
	if (quisk_record_state == PLAYBACK) {	// Discard previous samples and replace with saved sound
		quisk_tmp_microphone(cSamples, mic_count);
	}
	if (rxMode == 7) {		// Discard previous samples and use digital samples
		if (DigitalInput.handle) {
			mic_sample_rate = DigitalInput.sample_rate;
			if (DigitalInput.portaudio_index < 0)
				mic_count = quisk_read_alsa(&DigitalInput, cSamples);
			else
				mic_count = quisk_read_portaudio(&DigitalInput, cSamples);
		}
		else {
			mic_count = 0;
		}
	}
	if (mic_count > 0) {
#if DEBUG_IO > 1
		QuiskPrintTime("  mic-read", 0);
#endif
		// quisk_process_microphone returns samples at the sample rate MIC_OUT_RATE
		mic_count = quisk_process_microphone(mic_sample_rate, cSamples, mic_count);
#if DEBUG_MIC == 1
		if ( ! quisk_is_key_down())
			for (i = 0; i < mic_count; i++)
				cSamples[i] = 0;
		for (i = 0; i < mic_count; i++)
			cSamples[i] *= (double)CLIP32 / CLIP16;	// convert 16-bit samples to 32 bits
		quisk_process_samples(cSamples, mic_count);
#endif
#if DEBUG_IO > 1
		QuiskPrintTime("  mic-proc", 0);
#endif
	}
	// Mic playback without a mic is needed for CW
	if (MicPlayback.handle) {		// Mic playback: send mic I/Q samples to a sound card
		if (rxMode == 0 || rxMode == 1) {	// Transmit CW
			is_cw = 1;
		}
		else {
			is_cw = 0;
			cwCount = 0;
			cwEnvelope = 0.0;
		}
		tx_mic_phase = cexp(( -I * 2.0 * M_PI * quisk_tx_tune_freq) / MicPlayback.sample_rate);
		if (is_cw) {	// Transmit CW; use capture device for timing, not microphone
			cwCount += (double)retval * MicPlayback.sample_rate / quisk_sound_state.sample_rate;
			mic_count = 0;
			if (quisk_is_key_down()) {
				while (cwCount >= 1.0) {
					if (cwEnvelope < 1.0) {
						cwEnvelope += 1. / (MicPlayback.sample_rate * 5e-3);	// 5 milliseconds
						if (cwEnvelope > 1.0)
							cwEnvelope = 1.0;
					}
					cSamples[mic_count++] = (CLIP16 - 1) * cwEnvelope * tuneVector * quisk_sound_state.mic_out_volume;
					tuneVector *= tx_mic_phase;
					cwCount -= 1;
				}
			}
			else {		// key is up
				while (cwCount >= 1.0) {
					if (cwEnvelope > 0.0) {
						cwEnvelope -= 1.0 / (MicPlayback.sample_rate * 5e-3);	// 5 milliseconds
						if (cwEnvelope < 0.0)
							cwEnvelope = 0.0;
					}
					cSamples[mic_count++] = (CLIP16 - 1) * cwEnvelope * tuneVector * quisk_sound_state.mic_out_volume;
					tuneVector *= tx_mic_phase;
					cwCount -= 1;
				}
			}
		}
		else {		// Transmit SSB
			if ( ! quisk_is_key_down()) {
				for (i = 0; i < mic_count; i++)
					cSamples[i] = 0.0;
			}
		}
		// Perhaps interpolate the mic samples back to the mic play rate
		mic_interp = MicPlayback.sample_rate / MIC_OUT_RATE;
		if ( ! is_cw && mic_interp > 1) {
			if (! filtInterp.dCoefs)
				quisk_filt_cInit(&filtInterp, quiskFilt12_19Coefs, sizeof(quiskFilt12_19Coefs)/sizeof(double));
			mic_count = quisk_cInterpolate(cSamples, mic_count, &filtInterp, mic_interp);
		}
		// Tune the samples to frequency
		if ( ! is_cw) {
			for (i = 0; i < mic_count; i++) {
				cSamples[i] = conj(cSamples[i]) * tuneVector * quisk_sound_state.mic_out_volume;
				tuneVector *= tx_mic_phase;
			}
		}
		// delay the I or Q channel by one sample
		if (MicPlayback.channel_Delay >= 0)
			delay_sample(&MicPlayback, (double *)cSamples, mic_count);
		// amplitude and phase corrections
		if (MicPlayback.doAmplPhase)
			correct_sample (&MicPlayback, cSamples, mic_count);
		// play mic samples
		if (MicPlayback.portaudio_index < 0)
			quisk_play_alsa(&MicPlayback, mic_count, cSamples, 0);
		else
			quisk_play_portaudio(&MicPlayback, mic_count, cSamples, 0);
#if DEBUG_MIC == 2
		quisk_process_samples(cSamples, mic_count);
#endif
	}
#if DEBUG_IO > 1
	QuiskPrintTime("  finished", 0);
#endif
	// Return negative number for error
	return retval;
}