mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-31 13:00:26 -04:00 
			
		
		
		
	UDP source plugin: implemented squelch gate
This commit is contained in:
		
							parent
							
								
									2c3f7fe690
								
							
						
					
					
						commit
						587d38665d
					
				| @ -30,17 +30,9 @@ MESSAGE_CLASS_DEFINITION(UDPSrc::MsgUDPSrcConfigureImmediate, Message) | ||||
| MESSAGE_CLASS_DEFINITION(UDPSrc::MsgUDPSrcSpectrum, Message) | ||||
| 
 | ||||
| UDPSrc::UDPSrc(MessageQueue* uiMessageQueue, UDPSrcGUI* udpSrcGUI, BasebandSampleSink* spectrum) : | ||||
| 	m_udpPort(9999), | ||||
| 	m_gain(1.0), | ||||
| 	m_audioActive(false), | ||||
| 	m_audioStereo(false), | ||||
| 	m_volume(20), | ||||
|     m_fmDeviation(2500), | ||||
|     m_outMovingAverage(480, 1e-10), | ||||
|     m_inMovingAverage(480, 1e-10), | ||||
|     m_audioFifo(4, 24000), | ||||
|     m_squelch(1e-6), | ||||
|     m_squelchEnabled(true), | ||||
|     m_squelchOpen(false), | ||||
|     m_squelchOpenCount(0), | ||||
|     m_squelchCloseCount(0), | ||||
| @ -49,22 +41,17 @@ UDPSrc::UDPSrc(MessageQueue* uiMessageQueue, UDPSrcGUI* udpSrcGUI, BasebandSampl | ||||
| { | ||||
| 	setObjectName("UDPSrc"); | ||||
| 
 | ||||
| 	m_udpBuffer = new UDPSink<Sample>(this, udpBlockSize, m_udpPort); | ||||
| 	m_udpBufferMono = new UDPSink<FixReal>(this, udpBlockSize, m_udpPort); | ||||
| 	m_udpBuffer = new UDPSink<Sample>(this, udpBlockSize, m_config.m_udpPort); | ||||
| 	m_udpBufferMono = new UDPSink<FixReal>(this, udpBlockSize, m_config.m_udpPort); | ||||
| 	m_audioSocket = new QUdpSocket(this); | ||||
| 	m_udpAudioBuf = new char[m_udpAudioPayloadSize]; | ||||
| 
 | ||||
| 	m_audioBuffer.resize(1<<9); | ||||
| 	m_audioBufferFill = 0; | ||||
| 
 | ||||
| 	m_inputSampleRate = 96000; | ||||
| 	m_sampleFormat = FormatS16LE; | ||||
| 	m_outputSampleRate = 48000; | ||||
| 	m_rfBandwidth = 32000; | ||||
| 	m_audioPort = m_udpPort - 1; | ||||
| 	m_nco.setFreq(0, m_inputSampleRate); | ||||
| 	m_interpolator.create(16, m_inputSampleRate, m_rfBandwidth / 2.0); | ||||
| 	m_sampleDistanceRemain = m_inputSampleRate / m_outputSampleRate; | ||||
| 	m_nco.setFreq(0, m_config.m_inputSampleRate); | ||||
| 	m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_rfBandwidth / 2.0); | ||||
| 	m_sampleDistanceRemain = m_config.m_inputSampleRate / m_config.m_outputSampleRate; | ||||
| 	m_uiMessageQueue = uiMessageQueue; | ||||
| 	m_udpSrcGUI = udpSrcGUI; | ||||
| 	m_spectrum = spectrum; | ||||
| @ -77,13 +64,13 @@ UDPSrc::UDPSrc(MessageQueue* uiMessageQueue, UDPSrcGUI* udpSrcGUI, BasebandSampl | ||||
| 	m_scale = 0; | ||||
| 	m_magsq = 0; | ||||
| 	m_inMagsq = 0; | ||||
| 	UDPFilter = new fftfilt(0.0, (m_rfBandwidth / 2.0) / m_outputSampleRate, udpBlockSize); | ||||
| 	UDPFilter = new fftfilt(0.0, (m_config.m_rfBandwidth / 2.0) / m_config.m_outputSampleRate, udpBlockSize); | ||||
| 
 | ||||
| 	m_phaseDiscri.setFMScaling((float) m_outputSampleRate / (2.0f * m_fmDeviation)); | ||||
| 	m_phaseDiscri.setFMScaling((float) m_config. m_outputSampleRate / (2.0f * m_config.m_fmDeviation)); | ||||
| 
 | ||||
| 	if (m_audioSocket->bind(QHostAddress::LocalHost, m_audioPort)) | ||||
| 	if (m_audioSocket->bind(QHostAddress::LocalHost, m_config.m_audioPort)) | ||||
| 	{ | ||||
| 		qDebug("UDPSrc::UDPSrc: bind audio socket to port %d", m_audioPort); | ||||
| 		qDebug("UDPSrc::UDPSrc: bind audio socket to port %d", m_config.m_audioPort); | ||||
| 		connect(m_audioSocket, SIGNAL(readyRead()), this, SLOT(audioReadyRead()), Qt::QueuedConnection); | ||||
| 	} | ||||
| 	else | ||||
| @ -101,9 +88,10 @@ UDPSrc::~UDPSrc() | ||||
| 	delete m_udpBufferMono; | ||||
| 	delete[] m_udpAudioBuf; | ||||
| 	if (UDPFilter) delete UDPFilter; | ||||
| 	if (m_audioActive) DSPEngine::instance()->removeAudioSink(&m_audioFifo); | ||||
| 	if (m_running.m_audioActive) DSPEngine::instance()->removeAudioSink(&m_audioFifo); | ||||
| } | ||||
| 
 | ||||
| /** what needs the "apply" button validation */ | ||||
| void UDPSrc::configure(MessageQueue* messageQueue, | ||||
| 		SampleFormat sampleFormat, | ||||
| 		Real outputSampleRate, | ||||
| @ -111,7 +99,8 @@ void UDPSrc::configure(MessageQueue* messageQueue, | ||||
| 		int fmDeviation, | ||||
| 		QString& udpAddress, | ||||
| 		int udpPort, | ||||
| 		int audioPort) | ||||
| 		int audioPort, | ||||
| 		bool force) | ||||
| { | ||||
| 	Message* cmd = MsgUDPSrcConfigure::create(sampleFormat, | ||||
| 			outputSampleRate, | ||||
| @ -119,17 +108,21 @@ void UDPSrc::configure(MessageQueue* messageQueue, | ||||
| 			fmDeviation, | ||||
| 			udpAddress, | ||||
| 			udpPort, | ||||
| 			audioPort); | ||||
| 			audioPort, | ||||
| 			force); | ||||
| 	messageQueue->push(cmd); | ||||
| } | ||||
| 
 | ||||
| /** changes applied immediately */ | ||||
| void UDPSrc::configureImmediate(MessageQueue* messageQueue, | ||||
| 		bool audioActive, | ||||
| 		bool audioStereo, | ||||
| 		Real boost, | ||||
| 		int  volume, | ||||
| 		Real squelchDB, | ||||
| 		bool squelchEnabled) | ||||
| 		Real squelchGate, | ||||
| 		bool squelchEnabled, | ||||
| 		bool force) | ||||
| { | ||||
| 	Message* cmd = MsgUDPSrcConfigureImmediate::create( | ||||
| 			audioActive, | ||||
| @ -137,7 +130,9 @@ void UDPSrc::configureImmediate(MessageQueue* messageQueue, | ||||
| 			boost, | ||||
| 			volume, | ||||
| 			squelchDB, | ||||
| 			squelchEnabled); | ||||
| 			squelchGate, | ||||
| 			squelchEnabled, | ||||
| 			force); | ||||
| 	messageQueue->push(cmd); | ||||
| } | ||||
| 
 | ||||
| @ -171,11 +166,11 @@ void UDPSrc::feed(const SampleVector::const_iterator& begin, const SampleVector: | ||||
| 			Sample ss(ci.real(), ci.imag()); | ||||
| 			m_sampleBuffer.push_back(ss); | ||||
| 
 | ||||
| 			m_sampleDistanceRemain += m_inputSampleRate / m_outputSampleRate; | ||||
| 			m_sampleDistanceRemain += m_running.m_inputSampleRate / m_running.m_outputSampleRate; | ||||
| 
 | ||||
| 			calculateSquelch(m_inMagsq); | ||||
| 
 | ||||
| 			if (m_sampleFormat == FormatLSB) // binaural LSB
 | ||||
| 			if (m_running.m_sampleFormat == FormatLSB) // binaural LSB
 | ||||
| 			{ | ||||
| 				int n_out = UDPFilter->runSSB(ci, &sideband, false); | ||||
| 
 | ||||
| @ -183,14 +178,14 @@ void UDPSrc::feed(const SampleVector::const_iterator& begin, const SampleVector: | ||||
| 				{ | ||||
| 					for (int i = 0; i < n_out; i++) | ||||
| 					{ | ||||
| 						l = m_squelchOpen ? sideband[i].real() * m_gain : 0; | ||||
| 						r = m_squelchOpen ? sideband[i].imag() * m_gain : 0; | ||||
| 						l = m_squelchOpen ? sideband[i].real() * m_running.m_gain : 0; | ||||
| 						r = m_squelchOpen ? sideband[i].imag() * m_running.m_gain : 0; | ||||
| 					    m_udpBuffer->write(Sample(l, r)); | ||||
| 					    m_outMovingAverage.feed((l*l + r*r) / (1<<30)); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			if (m_sampleFormat == FormatUSB) // binaural USB
 | ||||
| 			if (m_running.m_sampleFormat == FormatUSB) // binaural USB
 | ||||
| 			{ | ||||
| 				int n_out = UDPFilter->runSSB(ci, &sideband, true); | ||||
| 
 | ||||
| @ -198,26 +193,26 @@ void UDPSrc::feed(const SampleVector::const_iterator& begin, const SampleVector: | ||||
| 				{ | ||||
| 					for (int i = 0; i < n_out; i++) | ||||
| 					{ | ||||
| 						l = m_squelchOpen ? sideband[i].real() * m_gain : 0; | ||||
| 						r = m_squelchOpen ? sideband[i].imag() * m_gain : 0; | ||||
| 						l = m_squelchOpen ? sideband[i].real() * m_running.m_gain : 0; | ||||
| 						r = m_squelchOpen ? sideband[i].imag() * m_running.m_gain : 0; | ||||
| 						m_udpBuffer->write(Sample(l, r)); | ||||
| 						m_outMovingAverage.feed((l*l + r*r) / (1<<30)); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			else if (m_sampleFormat == FormatNFM) | ||||
| 			else if (m_running.m_sampleFormat == FormatNFM) | ||||
| 			{ | ||||
| 				double demod = m_squelchOpen ? 32768.0 * m_phaseDiscri.phaseDiscriminator(ci) * m_gain : 0; | ||||
| 				double demod = m_squelchOpen ? 32768.0 * m_phaseDiscri.phaseDiscriminator(ci) * m_running.m_gain : 0; | ||||
| 				m_udpBuffer->write(Sample(demod, demod)); | ||||
| 				m_outMovingAverage.feed((demod * demod) / (1<<30)); | ||||
| 			} | ||||
| 			else if (m_sampleFormat == FormatNFMMono) | ||||
| 			else if (m_running.m_sampleFormat == FormatNFMMono) | ||||
| 			{ | ||||
| 				FixReal demod = m_squelchOpen ? (FixReal) (32768.0f * m_phaseDiscri.phaseDiscriminator(ci) * m_gain) : 0; | ||||
| 				FixReal demod = m_squelchOpen ? (FixReal) (32768.0f * m_phaseDiscri.phaseDiscriminator(ci) * m_running.m_gain) : 0; | ||||
| 				m_udpBufferMono->write(demod); | ||||
| 				m_outMovingAverage.feed((demod * demod) / 1073741824.0); | ||||
| 			} | ||||
| 			else if (m_sampleFormat == FormatLSBMono) // Monaural LSB
 | ||||
| 			else if (m_running.m_sampleFormat == FormatLSBMono) // Monaural LSB
 | ||||
| 			{ | ||||
| 				int n_out = UDPFilter->runSSB(ci, &sideband, false); | ||||
| 
 | ||||
| @ -225,13 +220,13 @@ void UDPSrc::feed(const SampleVector::const_iterator& begin, const SampleVector: | ||||
| 				{ | ||||
| 					for (int i = 0; i < n_out; i++) | ||||
| 					{ | ||||
| 						l = m_squelchOpen ? (sideband[i].real() + sideband[i].imag()) * 0.7 * m_gain : 0; | ||||
| 						l = m_squelchOpen ? (sideband[i].real() + sideband[i].imag()) * 0.7 * m_running.m_gain : 0; | ||||
| 						m_udpBufferMono->write(l); | ||||
| 						m_outMovingAverage.feed((l * l) / (1<<30)); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			else if (m_sampleFormat == FormatUSBMono) // Monaural USB
 | ||||
| 			else if (m_running.m_sampleFormat == FormatUSBMono) // Monaural USB
 | ||||
| 			{ | ||||
| 				int n_out = UDPFilter->runSSB(ci, &sideband, true); | ||||
| 
 | ||||
| @ -239,15 +234,15 @@ void UDPSrc::feed(const SampleVector::const_iterator& begin, const SampleVector: | ||||
| 				{ | ||||
| 					for (int i = 0; i < n_out; i++) | ||||
| 					{ | ||||
| 						l = m_squelchOpen ? (sideband[i].real() + sideband[i].imag()) * 0.7 * m_gain : 0; | ||||
| 						l = m_squelchOpen ? (sideband[i].real() + sideband[i].imag()) * 0.7 * m_running.m_gain : 0; | ||||
| 						m_udpBufferMono->write(l); | ||||
| 						m_outMovingAverage.feed((l * l) / (1<<30)); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			else if (m_sampleFormat == FormatAMMono) | ||||
| 			else if (m_running.m_sampleFormat == FormatAMMono) | ||||
| 			{ | ||||
| 				FixReal demod = m_squelchOpen ? (FixReal) (sqrt(inMagSq) * m_gain) : 0; | ||||
| 				FixReal demod = m_squelchOpen ? (FixReal) (sqrt(inMagSq) * m_running.m_gain) : 0; | ||||
| 				m_udpBufferMono->write(demod); | ||||
| 				m_outMovingAverage.feed((demod * demod) / (1<<30)); | ||||
| 			} | ||||
| @ -255,9 +250,9 @@ void UDPSrc::feed(const SampleVector::const_iterator& begin, const SampleVector: | ||||
| 			{ | ||||
| 			    if (m_squelchOpen) | ||||
| 			    { | ||||
| 	                Sample s(ci.real() * m_gain, ci.imag() * m_gain); | ||||
| 	                Sample s(ci.real() * m_running.m_gain, ci.imag() * m_running.m_gain); | ||||
| 	                m_udpBuffer->write(s); | ||||
| 	                m_outMovingAverage.feed((inMagSq*m_gain*m_gain) / (1<<30)); | ||||
| 	                m_outMovingAverage.feed((inMagSq*m_running.m_gain*m_running.m_gain) / (1<<30)); | ||||
| 			    } | ||||
| 			    else | ||||
| 			    { | ||||
| @ -298,68 +293,38 @@ bool UDPSrc::handleMessage(const Message& cmd) | ||||
| 	{ | ||||
| 		DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd; | ||||
| 
 | ||||
| 		m_settingsMutex.lock(); | ||||
| 		m_config.m_inputSampleRate = notif.getSampleRate(); | ||||
| 		m_config.m_inputFrequencyOffset = notif.getFrequencyOffset(); | ||||
| 
 | ||||
| 		m_inputSampleRate = notif.getSampleRate(); | ||||
| 		m_nco.setFreq(-notif.getFrequencyOffset(), m_inputSampleRate); | ||||
| 		m_interpolator.create(16, m_inputSampleRate, m_rfBandwidth / 2.0); | ||||
| 		m_sampleDistanceRemain = m_inputSampleRate / m_outputSampleRate; | ||||
| 		apply(false); | ||||
| 
 | ||||
| 		m_settingsMutex.unlock(); | ||||
| 		qDebug() << "UDPSrc::handleMessage: MsgChannelizerNotification: m_inputSampleRate: " << m_config.m_inputSampleRate | ||||
|                  << " frequencyOffset: " << notif.getFrequencyOffset(); | ||||
| 
 | ||||
| 		qDebug() << "UDPSrc::handleMessage: MsgChannelizerNotification: m_inputSampleRate: " << m_inputSampleRate | ||||
| 				<< " frequencyOffset: " << notif.getFrequencyOffset(); | ||||
| 
 | ||||
| 		return true; | ||||
|         return true; | ||||
| 	} | ||||
| 	else if (MsgUDPSrcConfigureImmediate::match(cmd)) | ||||
| 	{ | ||||
| 		MsgUDPSrcConfigureImmediate& cfg = (MsgUDPSrcConfigureImmediate&) cmd; | ||||
| 
 | ||||
| 		m_settingsMutex.lock(); | ||||
| 		m_config.m_audioActive = cfg.getAudioActive(); | ||||
| 		m_config.m_audioStereo = cfg.getAudioStereo(); | ||||
| 		m_config.m_gain = cfg.getGain(); | ||||
| 		m_config.m_volume = cfg.getVolume(); | ||||
| 		m_config.m_squelch = CalcDb::powerFromdB(cfg.getSquelchDB()); | ||||
| 		m_config.m_squelchGate = cfg.getSquelchGate(); | ||||
| 		m_config.m_squelchEnabled = cfg.getSquelchEnabled(); | ||||
| 
 | ||||
| 		if (cfg.getAudioActive() != m_audioActive) | ||||
| 		{ | ||||
| 			m_audioActive = cfg.getAudioActive(); | ||||
| 
 | ||||
| 			if (m_audioActive) | ||||
| 			{ | ||||
| 				m_audioBufferFill = 0; | ||||
| 				DSPEngine::instance()->addAudioSink(&m_audioFifo); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				DSPEngine::instance()->removeAudioSink(&m_audioFifo); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if (cfg.getAudioStereo() != m_audioStereo) | ||||
| 		{ | ||||
| 			m_audioStereo = cfg.getAudioStereo(); | ||||
| 		} | ||||
| 
 | ||||
| 		if (cfg.getGain() != m_gain) | ||||
| 		{ | ||||
| 		    m_gain = cfg.getGain(); | ||||
| 		} | ||||
| 
 | ||||
| 		if (cfg.getVolume() != m_volume) | ||||
| 		{ | ||||
| 			m_volume = cfg.getVolume(); | ||||
| 		} | ||||
| 
 | ||||
| 		m_squelch = CalcDb::powerFromdB(cfg.getSquelchDB()); | ||||
| 		m_squelchEnabled = cfg.getSquelchEnabled(); | ||||
| 
 | ||||
| 		m_settingsMutex.unlock(); | ||||
| 		apply(cfg.getForce()); | ||||
| 
 | ||||
| 		qDebug() << "UDPSrc::handleMessage: MsgUDPSrcConfigureImmediate: " | ||||
| 				<< " m_audioActive: " << m_audioActive | ||||
| 				<< " m_audioStereo: " << m_audioStereo | ||||
| 				<< " m_gain: " << m_gain | ||||
| 				<< " m_squelchEnabled: " << m_squelchEnabled | ||||
|                 << " m_squelch: " << m_squelch | ||||
|                 << " getSquelchDB: " << cfg.getSquelchDB(); | ||||
| 				<< " m_audioActive: " << m_config.m_audioActive | ||||
| 				<< " m_audioStereo: " << m_config.m_audioStereo | ||||
| 				<< " m_gain: " << m_config.m_gain | ||||
| 				<< " m_squelchEnabled: " << m_config.m_squelchEnabled | ||||
|                 << " m_squelch: " << m_config.m_squelch | ||||
|                 << " getSquelchDB: " << cfg.getSquelchDB() | ||||
|                 << " m_squelchGate" << m_config.m_squelchGate; | ||||
| 
 | ||||
| 		return true; | ||||
| 
 | ||||
| @ -368,67 +333,22 @@ bool UDPSrc::handleMessage(const Message& cmd) | ||||
| 	{ | ||||
| 		MsgUDPSrcConfigure& cfg = (MsgUDPSrcConfigure&) cmd; | ||||
| 
 | ||||
| 		m_settingsMutex.lock(); | ||||
| 		m_config.m_sampleFormat = cfg.getSampleFormat(); | ||||
| 		m_config.m_outputSampleRate = cfg.getOutputSampleRate(); | ||||
| 		m_config.m_rfBandwidth = cfg.getRFBandwidth(); | ||||
| 		m_config.m_udpAddressStr = cfg.getUDPAddress(); | ||||
| 		m_config.m_udpPort = cfg.getUDPPort(); | ||||
| 		m_config.m_audioPort = cfg.getAudioPort(); | ||||
| 		m_config.m_fmDeviation = cfg.getFMDeviation(); | ||||
| 
 | ||||
| 		m_sampleFormat = cfg.getSampleFormat(); | ||||
| 		m_outputSampleRate = cfg.getOutputSampleRate(); | ||||
| 		m_rfBandwidth = cfg.getRFBandwidth(); | ||||
| 		apply(cfg.getForce()); | ||||
| 
 | ||||
| 		if (cfg.getUDPAddress() != m_udpAddressStr) | ||||
| 		{ | ||||
| 			m_udpAddressStr = cfg.getUDPAddress(); | ||||
| 			m_udpBuffer->setAddress(m_udpAddressStr); | ||||
| 			m_udpBufferMono->setAddress(m_udpAddressStr); | ||||
| 		} | ||||
| 
 | ||||
| 		if (cfg.getUDPPort() != m_udpPort) | ||||
| 		{ | ||||
| 			m_udpPort = cfg.getUDPPort(); | ||||
| 			m_udpBuffer->setPort(m_udpPort); | ||||
| 			m_udpBufferMono->setPort(m_udpPort); | ||||
| 		} | ||||
| 
 | ||||
| 		if (cfg.getAudioPort() != m_audioPort) | ||||
| 		{ | ||||
| 			m_audioPort = cfg.getAudioPort(); | ||||
| 
 | ||||
| 			disconnect(m_audioSocket, SIGNAL(readyRead()), this, SLOT(audioReadyRead())); | ||||
| 			delete m_audioSocket; | ||||
| 			m_audioSocket = new QUdpSocket(this); | ||||
| 
 | ||||
| 			if (m_audioSocket->bind(QHostAddress::LocalHost, m_audioPort)) | ||||
| 			{ | ||||
| 				connect(m_audioSocket, SIGNAL(readyRead()), this, SLOT(audioReadyRead()), Qt::QueuedConnection); | ||||
| 				qDebug("UDPSrc::handleMessage: audio socket bound to port %d", m_audioPort); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				qWarning("UDPSrc::handleMessage: cannot bind audio socket"); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if (cfg.getFMDeviation() != m_fmDeviation) | ||||
| 		{ | ||||
| 			m_fmDeviation = cfg.getFMDeviation(); | ||||
| 			m_phaseDiscri.setFMScaling((float) m_outputSampleRate / (2.0f * m_fmDeviation)); | ||||
| 		} | ||||
| 
 | ||||
| 		m_interpolator.create(16, m_inputSampleRate, m_rfBandwidth / 2.0); | ||||
| 		m_sampleDistanceRemain = m_inputSampleRate / m_outputSampleRate; | ||||
| 		UDPFilter->create_filter(0.0, (m_rfBandwidth / 2.0) / m_outputSampleRate); | ||||
| 
 | ||||
|         m_inMovingAverage.resize(m_outputSampleRate * 0.01, 1e-10);   // 10 ms
 | ||||
|         m_outMovingAverage.resize(m_outputSampleRate * 0.01, 1e-10); // 10 ms
 | ||||
|         m_squelchThreshold = m_outputSampleRate * 0.05; // 50 ms
 | ||||
| 
 | ||||
| 		m_settingsMutex.unlock(); | ||||
| 
 | ||||
| 		qDebug() << "UDPSrc::handleMessage: MsgUDPSrcConfigure: m_sampleFormat: " << m_sampleFormat | ||||
| 				<< " m_outputSampleRate: " << m_outputSampleRate | ||||
| 				<< " m_rfBandwidth: " << m_rfBandwidth | ||||
| 				<< " m_udpAddressStr: " << m_udpAddressStr | ||||
| 				<< " m_udpPort: " << m_udpPort | ||||
| 				<< " m_audioPort: " << m_audioPort; | ||||
| 		qDebug() << "UDPSrc::handleMessage: MsgUDPSrcConfigure: m_sampleFormat: " << m_config.m_sampleFormat | ||||
| 				<< " m_outputSampleRate: " << m_config.m_outputSampleRate | ||||
| 				<< " m_rfBandwidth: " << m_config.m_rfBandwidth | ||||
| 				<< " m_udpAddressStr: " << m_config.m_udpAddressStr | ||||
| 				<< " m_udpPort: " << m_config.m_udpPort | ||||
| 				<< " m_audioPort: " << m_config.m_audioPort; | ||||
| 
 | ||||
| 		return true; | ||||
| 	} | ||||
| @ -455,6 +375,83 @@ bool UDPSrc::handleMessage(const Message& cmd) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void UDPSrc::apply(bool force) | ||||
| { | ||||
|     m_settingsMutex.lock(); | ||||
| 
 | ||||
|     if ((m_config.m_inputSampleRate != m_running.m_inputSampleRate) || | ||||
|         (m_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset) || | ||||
|         (m_config.m_rfBandwidth != m_running.m_rfBandwidth) || | ||||
|         (m_config.m_outputSampleRate != m_running.m_outputSampleRate) || force) | ||||
|     { | ||||
|         m_nco.setFreq(-m_config.m_inputFrequencyOffset, m_config.m_inputSampleRate); | ||||
|         m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_rfBandwidth / 2.0); | ||||
|         m_sampleDistanceRemain = m_config.m_inputSampleRate / m_config.m_outputSampleRate; | ||||
| 
 | ||||
|         m_squelchThreshold = m_config.m_outputSampleRate * m_config.m_squelchGate; | ||||
|         initSquelch(m_squelchOpen); | ||||
| 
 | ||||
|         m_inMovingAverage.resize(m_config.m_outputSampleRate * 0.01, 1e-10);  // 10 ms
 | ||||
|         m_outMovingAverage.resize(m_config.m_outputSampleRate * 0.01, 1e-10); // 10 ms
 | ||||
|     } | ||||
| 
 | ||||
|     if ((m_config.m_audioActive != m_config.m_audioActive) || force) | ||||
|     { | ||||
|         if (m_config.m_audioActive) | ||||
|         { | ||||
|             m_audioBufferFill = 0; | ||||
|             DSPEngine::instance()->addAudioSink(&m_audioFifo); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             DSPEngine::instance()->removeAudioSink(&m_audioFifo); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if ((m_config.m_squelchGate != m_running.m_squelchGate) || force) | ||||
|     { | ||||
|         m_squelchThreshold = m_config.m_outputSampleRate * m_config.m_squelchGate; | ||||
|     } | ||||
| 
 | ||||
|     if ((m_config.m_udpAddressStr != m_running.m_udpAddressStr) || force) | ||||
|     { | ||||
|         m_udpBuffer->setAddress(m_config.m_udpAddressStr); | ||||
|         m_udpBufferMono->setAddress(m_config.m_udpAddressStr); | ||||
|     } | ||||
| 
 | ||||
|     if ((m_config.m_udpPort != m_running.m_udpPort) || force) | ||||
|     { | ||||
|         m_udpBuffer->setPort(m_config.m_udpPort); | ||||
|         m_udpBufferMono->setPort(m_config.m_udpPort); | ||||
|     } | ||||
| 
 | ||||
|     if ((m_config.m_audioPort != m_running.m_audioPort) || force) | ||||
|     { | ||||
|         disconnect(m_audioSocket, SIGNAL(readyRead()), this, SLOT(audioReadyRead())); | ||||
|         delete m_audioSocket; | ||||
|         m_audioSocket = new QUdpSocket(this); | ||||
| 
 | ||||
|         if (m_audioSocket->bind(QHostAddress::LocalHost, m_config.m_audioPort)) | ||||
|         { | ||||
|             connect(m_audioSocket, SIGNAL(readyRead()), this, SLOT(audioReadyRead()), Qt::QueuedConnection); | ||||
|             qDebug("UDPSrc::handleMessage: audio socket bound to port %d", m_config.m_audioPort); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             qWarning("UDPSrc::handleMessage: cannot bind audio socket"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if ((m_config.m_fmDeviation != m_running.m_fmDeviation) || force) | ||||
|     { | ||||
|         m_phaseDiscri.setFMScaling((float) m_config.m_outputSampleRate / (2.0f * m_config.m_fmDeviation)); | ||||
|     } | ||||
| 
 | ||||
|     m_settingsMutex.unlock(); | ||||
| 
 | ||||
|     m_running = m_config; | ||||
| } | ||||
| 
 | ||||
| void UDPSrc::audioReadyRead() | ||||
| { | ||||
| 	while (m_audioSocket->hasPendingDatagrams()) | ||||
| @ -463,16 +460,16 @@ void UDPSrc::audioReadyRead() | ||||
| 	    qint64 udpReadBytes = m_audioSocket->readDatagram(m_udpAudioBuf, pendingDataSize, 0, 0); | ||||
| 		//qDebug("UDPSrc::audioReadyRead: %lld", udpReadBytes);
 | ||||
| 
 | ||||
| 		if (m_audioActive) | ||||
| 		if (m_running.m_audioActive) | ||||
| 		{ | ||||
| 			if (m_audioStereo) | ||||
| 			if (m_running.m_audioStereo) | ||||
| 			{ | ||||
| 				for (int i = 0; i < udpReadBytes - 3; i += 4) | ||||
| 				{ | ||||
| 					qint16 l_sample = (qint16) *(&m_udpAudioBuf[i]); | ||||
| 					qint16 r_sample = (qint16) *(&m_udpAudioBuf[i+2]); | ||||
| 					m_audioBuffer[m_audioBufferFill].l  = l_sample * m_volume; | ||||
| 					m_audioBuffer[m_audioBufferFill].r  = r_sample * m_volume; | ||||
| 					m_audioBuffer[m_audioBufferFill].l  = l_sample * m_running.m_volume; | ||||
| 					m_audioBuffer[m_audioBufferFill].r  = r_sample * m_running.m_volume; | ||||
| 					++m_audioBufferFill; | ||||
| 
 | ||||
| 					if (m_audioBufferFill >= m_audioBuffer.size()) | ||||
| @ -493,8 +490,8 @@ void UDPSrc::audioReadyRead() | ||||
| 				for (int i = 0; i < udpReadBytes - 1; i += 2) | ||||
| 				{ | ||||
| 					qint16 sample = (qint16) *(&m_udpAudioBuf[i]); | ||||
| 					m_audioBuffer[m_audioBufferFill].l  = sample * m_volume; | ||||
| 					m_audioBuffer[m_audioBufferFill].r  = sample * m_volume; | ||||
| 					m_audioBuffer[m_audioBufferFill].l  = sample * m_running.m_volume; | ||||
| 					m_audioBuffer[m_audioBufferFill].r  = sample * m_running.m_volume; | ||||
| 					++m_audioBufferFill; | ||||
| 
 | ||||
| 					if (m_audioBufferFill >= m_audioBuffer.size()) | ||||
|  | ||||
| @ -67,14 +67,17 @@ public: | ||||
| 			int fmDeviation, | ||||
| 			QString& udpAddress, | ||||
| 			int udpPort, | ||||
| 			int audioPort); | ||||
| 			int audioPort, | ||||
| 			bool force); | ||||
| 	void configureImmediate(MessageQueue* messageQueue, | ||||
| 			bool audioActive, | ||||
| 			bool audioStereo, | ||||
| 			Real gain, | ||||
| 			int volume, | ||||
| 			Real squelchDB, | ||||
| 			bool squelchEnabled); | ||||
| 			Real squelchGate, | ||||
| 			bool squelchEnabled, | ||||
| 			bool force); | ||||
| 	void setSpectrum(MessageQueue* messageQueue, bool enabled); | ||||
| 	double getMagSq() const { return m_magsq; } | ||||
| 	double getInMagSq() const { return m_inMagsq; } | ||||
| @ -102,6 +105,7 @@ protected: | ||||
| 		const QString& getUDPAddress() const { return m_udpAddress; } | ||||
| 		int getUDPPort() const { return m_udpPort; } | ||||
| 		int getAudioPort() const { return m_audioPort; } | ||||
| 		bool getForce() const { return m_force; } | ||||
| 
 | ||||
| 		static MsgUDPSrcConfigure* create(SampleFormat | ||||
| 				sampleFormat, | ||||
| @ -110,7 +114,8 @@ protected: | ||||
| 				int fmDeviation, | ||||
| 				QString& udpAddress, | ||||
| 				int udpPort, | ||||
| 				int audioPort) | ||||
| 				int audioPort, | ||||
| 				bool force) | ||||
| 		{ | ||||
| 			return new MsgUDPSrcConfigure(sampleFormat, | ||||
| 					sampleRate, | ||||
| @ -118,7 +123,8 @@ protected: | ||||
| 					fmDeviation, | ||||
| 					udpAddress, | ||||
| 					udpPort, | ||||
| 					audioPort); | ||||
| 					audioPort, | ||||
| 					force); | ||||
| 		} | ||||
| 
 | ||||
| 	private: | ||||
| @ -129,6 +135,7 @@ protected: | ||||
| 		QString m_udpAddress; | ||||
| 		int m_udpPort; | ||||
| 		int m_audioPort; | ||||
| 		bool m_force; | ||||
| 
 | ||||
| 		MsgUDPSrcConfigure(SampleFormat sampleFormat, | ||||
| 				Real outputSampleRate, | ||||
| @ -136,7 +143,8 @@ protected: | ||||
| 				int fmDeviation, | ||||
| 				QString& udpAddress, | ||||
| 				int udpPort, | ||||
| 				int audioPort) : | ||||
| 				int audioPort, | ||||
| 				bool force) : | ||||
| 			Message(), | ||||
| 			m_sampleFormat(sampleFormat), | ||||
| 			m_outputSampleRate(outputSampleRate), | ||||
| @ -144,7 +152,8 @@ protected: | ||||
| 			m_fmDeviation(fmDeviation), | ||||
| 			m_udpAddress(udpAddress), | ||||
| 			m_udpPort(udpPort), | ||||
| 			m_audioPort(audioPort) | ||||
| 			m_audioPort(audioPort), | ||||
| 			m_force(force) | ||||
| 		{ } | ||||
| 	}; | ||||
| 
 | ||||
| @ -157,7 +166,9 @@ protected: | ||||
| 		bool getAudioActive() const { return m_audioActive; } | ||||
| 		bool getAudioStereo() const { return m_audioStereo; } | ||||
| 		Real getSquelchDB() const { return m_squelchDB; } | ||||
| 		Real getSquelchGate() const { return m_squelchGate; } | ||||
| 		bool getSquelchEnabled() const { return m_squelchEnabled; } | ||||
| 		bool getForce() const { return m_force; } | ||||
| 
 | ||||
| 		static MsgUDPSrcConfigureImmediate* create( | ||||
| 				bool audioActive, | ||||
| @ -165,7 +176,9 @@ protected: | ||||
| 				int gain, | ||||
| 				int volume, | ||||
| 				Real squelchDB, | ||||
| 				bool squelchEnabled) | ||||
| 				Real squelchGate, | ||||
| 				bool squelchEnabled, | ||||
| 				bool force) | ||||
| 		{ | ||||
| 			return new MsgUDPSrcConfigureImmediate( | ||||
| 					audioActive, | ||||
| @ -173,7 +186,9 @@ protected: | ||||
| 					gain, | ||||
| 					volume, | ||||
| 					squelchDB, | ||||
| 					squelchEnabled); | ||||
| 					squelchGate, | ||||
| 					squelchEnabled, | ||||
| 					force); | ||||
| 		} | ||||
| 
 | ||||
| 	private: | ||||
| @ -182,7 +197,9 @@ protected: | ||||
| 		bool m_audioActive; | ||||
| 		bool m_audioStereo; | ||||
| 		Real m_squelchDB; | ||||
|         Real m_squelchGate; // seconds
 | ||||
| 		bool m_squelchEnabled; | ||||
| 		bool m_force; | ||||
| 
 | ||||
| 		MsgUDPSrcConfigureImmediate( | ||||
| 				bool audioActive, | ||||
| @ -190,14 +207,18 @@ protected: | ||||
| 				Real gain, | ||||
| 				int volume, | ||||
|                 Real squelchDB, | ||||
|                 bool squelchEnabled) : | ||||
|                 Real squelchGate, | ||||
|                 bool squelchEnabled, | ||||
|                 bool force) : | ||||
| 			Message(), | ||||
| 			m_gain(gain), | ||||
|             m_volume(volume), | ||||
| 			m_audioActive(audioActive), | ||||
| 			m_audioStereo(audioStereo), | ||||
| 			m_squelchDB(squelchDB), | ||||
| 			m_squelchEnabled(squelchEnabled) | ||||
|             m_squelchGate(squelchGate), | ||||
| 			m_squelchEnabled(squelchEnabled), | ||||
| 			m_force(force) | ||||
| 		{ } | ||||
| 	}; | ||||
| 
 | ||||
| @ -221,23 +242,54 @@ protected: | ||||
| 		{ } | ||||
| 	}; | ||||
| 
 | ||||
|     struct Config { | ||||
|         Real m_outputSampleRate; | ||||
|         SampleFormat m_sampleFormat; | ||||
|         Real m_inputSampleRate; | ||||
|         qint64 m_inputFrequencyOffset; | ||||
|         Real m_rfBandwidth; | ||||
|         int m_fmDeviation; | ||||
|         bool m_channelMute; | ||||
|         Real m_gain; | ||||
|         Real m_squelch; //!< squared magnitude
 | ||||
|         Real m_squelchGate; //!< seconds
 | ||||
|         bool m_squelchEnabled; | ||||
|         bool m_audioActive; | ||||
|         bool m_audioStereo; | ||||
|         int m_volume; | ||||
| 
 | ||||
|         QString m_udpAddressStr; | ||||
|         quint16 m_udpPort; | ||||
|         quint16 m_audioPort; | ||||
| 
 | ||||
|         Config() : | ||||
|             m_outputSampleRate(48000), | ||||
|             m_sampleFormat(FormatS16LE), | ||||
|             m_inputSampleRate(48000), | ||||
|             m_inputFrequencyOffset(0), | ||||
|             m_rfBandwidth(12500), | ||||
|             m_fmDeviation(2500), | ||||
|             m_channelMute(false), | ||||
|             m_gain(1.0), | ||||
|             m_squelch(1e-6), | ||||
|             m_squelchGate(0.0), | ||||
|             m_squelchEnabled(true), | ||||
|             m_audioActive(false), | ||||
|             m_audioStereo(false), | ||||
|             m_volume(20), | ||||
|             m_udpAddressStr("127.0.0.1"), | ||||
|             m_udpPort(9999), | ||||
|             m_audioPort(9998) | ||||
|         {} | ||||
|     }; | ||||
| 
 | ||||
|     Config m_config; | ||||
|     Config m_running; | ||||
| 
 | ||||
| 	MessageQueue* m_uiMessageQueue; | ||||
| 	UDPSrcGUI* m_udpSrcGUI; | ||||
| 	QUdpSocket *m_audioSocket; | ||||
| 
 | ||||
| 	int m_inputSampleRate; | ||||
| 
 | ||||
| 	int m_sampleFormat; | ||||
| 	Real m_outputSampleRate; | ||||
| 	Real m_rfBandwidth; | ||||
| 	QString m_udpAddressStr; | ||||
| 	quint16 m_udpPort; | ||||
| 	quint16 m_audioPort; | ||||
| 	Real m_gain; | ||||
| 	bool m_audioActive; | ||||
| 	bool m_audioStereo; | ||||
| 	int m_volume; | ||||
| 	int m_fmDeviation; | ||||
| 	double m_magsq; | ||||
|     double m_inMagsq; | ||||
|     MovingAverage<double> m_outMovingAverage; | ||||
| @ -270,34 +322,54 @@ protected: | ||||
| 
 | ||||
|     PhaseDiscriminators m_phaseDiscri; | ||||
| 
 | ||||
|     Real m_squelch; //!< squared magnitude
 | ||||
|     bool m_squelchEnabled; | ||||
|     bool m_squelchOpen; | ||||
|     int  m_squelchOpenCount; | ||||
|     int  m_squelchCloseCount; | ||||
|     int m_squelchThreshold; | ||||
|     int m_squelchThreshold; //!< number of samples computed from given gate
 | ||||
| 
 | ||||
| 	QMutex m_settingsMutex; | ||||
| 
 | ||||
| 	void apply(bool force); | ||||
| 
 | ||||
|     inline void calculateSquelch(double value) | ||||
|     { | ||||
|         if ((!m_squelchEnabled) || (value > m_squelch)) | ||||
|         if ((!m_running.m_squelchEnabled) || (value > m_running.m_squelch)) | ||||
|         { | ||||
|             if (m_squelchOpenCount < m_squelchThreshold) { | ||||
|                 m_squelchOpenCount++; | ||||
|             } else { | ||||
|                 m_squelchCloseCount = m_squelchThreshold; | ||||
|             if (m_squelchThreshold == 0) | ||||
|             { | ||||
|                 m_squelchOpen = true; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if (m_squelchOpenCount < m_squelchThreshold) | ||||
|                 { | ||||
|                     m_squelchOpenCount++; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     m_squelchCloseCount = m_squelchThreshold; | ||||
|                     m_squelchOpen = true; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             if (m_squelchCloseCount > 0) { | ||||
|                 m_squelchCloseCount--; | ||||
|             } else { | ||||
|                 m_squelchOpenCount = 0; | ||||
|             if (m_squelchThreshold == 0) | ||||
|             { | ||||
|                 m_squelchOpen = false; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if (m_squelchCloseCount > 0) | ||||
|                 { | ||||
|                     m_squelchCloseCount--; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     m_squelchOpenCount = 0; | ||||
|                     m_squelchOpen = false; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -197,8 +197,8 @@ bool UDPSrcGUI::deserialize(const QByteArray& data) | ||||
| 		blockApplySettings(false); | ||||
| 		m_channelMarker.blockSignals(false); | ||||
| 
 | ||||
| 		applySettingsImmediate(); | ||||
| 		applySettings(); | ||||
| 		applySettingsImmediate(true); | ||||
| 		applySettings(true); | ||||
| 		return true; | ||||
| 	} | ||||
| 	else | ||||
| @ -297,8 +297,8 @@ UDPSrcGUI::UDPSrcGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget* | ||||
| 	ui->spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum); | ||||
| 
 | ||||
| 	displaySettings(); | ||||
| 	applySettingsImmediate(); | ||||
| 	applySettings(); | ||||
| 	applySettingsImmediate(true); | ||||
| 	applySettings(true); | ||||
| } | ||||
| 
 | ||||
| UDPSrcGUI::~UDPSrcGUI() | ||||
| @ -323,9 +323,10 @@ void UDPSrcGUI::displaySettings() | ||||
|     ui->gainText->setText(tr("%1").arg(ui->gain->value()/10.0, 0, 'f', 1)); | ||||
|     ui->volumeText->setText(QString("%1").arg(ui->volume->value())); | ||||
|     ui->squelchText->setText(tr("%1").arg(ui->squelch->value()*1.0, 0, 'f', 0)); | ||||
|     ui->squelchGateText->setText(tr("%1").arg(ui->squelchGate->value()*10.0, 0, 'f', 0)); | ||||
| } | ||||
| 
 | ||||
| void UDPSrcGUI::applySettingsImmediate() | ||||
| void UDPSrcGUI::applySettingsImmediate(bool force) | ||||
| { | ||||
| 	if (m_doApplySettings) | ||||
| 	{ | ||||
| @ -340,12 +341,14 @@ void UDPSrcGUI::applySettingsImmediate() | ||||
| 		    m_gain, | ||||
| 			m_volume, | ||||
| 			ui->squelch->value() * 1.0f, | ||||
| 			ui->squelch->value() != -100); | ||||
| 			ui->squelchGate->value() * 0.01f, | ||||
| 			ui->squelch->value() != -100, | ||||
| 			force); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void UDPSrcGUI::applySettings() | ||||
| void UDPSrcGUI::applySettings(bool force) | ||||
| { | ||||
| 	if (m_doApplySettings) | ||||
| 	{ | ||||
| @ -461,7 +464,8 @@ void UDPSrcGUI::applySettings() | ||||
| 			fmDeviation, | ||||
| 			m_udpAddress, | ||||
| 			udpPort, | ||||
| 			audioPort); | ||||
| 			audioPort, | ||||
| 			force); | ||||
| 
 | ||||
| 		ui->applyBtn->setEnabled(false); | ||||
| 	} | ||||
| @ -554,6 +558,12 @@ void UDPSrcGUI::on_squelch_valueChanged(int value) | ||||
|     applySettingsImmediate(); | ||||
| } | ||||
| 
 | ||||
| void UDPSrcGUI::on_squelchGate_valueChanged(int value) | ||||
| { | ||||
|     ui->squelchGateText->setText(tr("%1").arg(value*10.0, 0, 'f', 0)); | ||||
|     applySettingsImmediate(); | ||||
| } | ||||
| 
 | ||||
| void UDPSrcGUI::onWidgetRolled(QWidget* widget, bool rollDown) | ||||
| { | ||||
| 	if ((widget == ui->spectrumBox) && (m_udpSrc != 0)) | ||||
|  | ||||
| @ -75,6 +75,7 @@ private slots: | ||||
| 	void on_gain_valueChanged(int value); | ||||
| 	void on_volume_valueChanged(int value); | ||||
| 	void on_squelch_valueChanged(int value); | ||||
| 	void on_squelchGate_valueChanged(int value); | ||||
| 	void tick(); | ||||
| 
 | ||||
| private: | ||||
| @ -111,8 +112,8 @@ private: | ||||
| 	virtual ~UDPSrcGUI(); | ||||
| 
 | ||||
|     void blockApplySettings(bool block); | ||||
| 	void applySettings(); | ||||
| 	void applySettingsImmediate(); | ||||
| 	void applySettings(bool force = false); | ||||
| 	void applySettingsImmediate(bool force = false); | ||||
| 	void displaySettings(); | ||||
| 
 | ||||
| 	void leaveEvent(QEvent*); | ||||
|  | ||||
| @ -236,6 +236,38 @@ | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item> | ||||
|        <spacer name="horizontalSpacer_2"> | ||||
|         <property name="orientation"> | ||||
|          <enum>Qt::Horizontal</enum> | ||||
|         </property> | ||||
|         <property name="sizeHint" stdset="0"> | ||||
|          <size> | ||||
|           <width>40</width> | ||||
|           <height>20</height> | ||||
|          </size> | ||||
|         </property> | ||||
|        </spacer> | ||||
|       </item> | ||||
|       <item> | ||||
|        <widget class="QLabel" name="inputPower"> | ||||
|         <property name="minimumSize"> | ||||
|          <size> | ||||
|           <width>40</width> | ||||
|           <height>0</height> | ||||
|          </size> | ||||
|         </property> | ||||
|         <property name="toolTip"> | ||||
|          <string>Input power (dB) to which squelch applies</string> | ||||
|         </property> | ||||
|         <property name="text"> | ||||
|          <string>-100.0</string> | ||||
|         </property> | ||||
|         <property name="alignment"> | ||||
|          <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|      </layout> | ||||
|     </item> | ||||
|     <item row="6" column="0"> | ||||
| @ -637,18 +669,40 @@ | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item> | ||||
|        <widget class="QLabel" name="inputPower"> | ||||
|        <widget class="QDial" name="squelchGate"> | ||||
|         <property name="maximumSize"> | ||||
|          <size> | ||||
|           <width>22</width> | ||||
|           <height>22</height> | ||||
|          </size> | ||||
|         </property> | ||||
|         <property name="toolTip"> | ||||
|          <string>Squelch gate (ms)</string> | ||||
|         </property> | ||||
|         <property name="maximum"> | ||||
|          <number>50</number> | ||||
|         </property> | ||||
|         <property name="pageStep"> | ||||
|          <number>1</number> | ||||
|         </property> | ||||
|         <property name="value"> | ||||
|          <number>5</number> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item> | ||||
|        <widget class="QLabel" name="squelchGateText"> | ||||
|         <property name="minimumSize"> | ||||
|          <size> | ||||
|           <width>40</width> | ||||
|           <width>24</width> | ||||
|           <height>0</height> | ||||
|          </size> | ||||
|         </property> | ||||
|         <property name="toolTip"> | ||||
|          <string>Input power (dB) to which squelch applies</string> | ||||
|          <string>Squelch gate (ms)</string> | ||||
|         </property> | ||||
|         <property name="text"> | ||||
|          <string>-100.0</string> | ||||
|          <string>000</string> | ||||
|         </property> | ||||
|         <property name="alignment"> | ||||
|          <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user