| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | #include "dsp/spectrumvis.h"
 | 
					
						
							|  |  |  | #include "gui/glspectrum.h"
 | 
					
						
							|  |  |  | #include "dsp/dspcommands.h"
 | 
					
						
							|  |  |  | #include "util/messagequeue.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define MAX_FFT_SIZE 4096
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-06 15:10:22 +01:00
										 |  |  | #ifndef LINUX
 | 
					
						
							|  |  |  | inline double log2f(double n) | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	return log(n) / log(2.0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-18 02:47:14 +02:00
										 |  |  | MESSAGE_CLASS_DEFINITION(SpectrumVis::MsgConfigureSpectrumVis, Message) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-28 23:47:15 +02:00
										 |  |  | const Real SpectrumVis::m_mult = (10.0f / log2f(10.0f)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-22 14:07:24 +01:00
										 |  |  | SpectrumVis::SpectrumVis(Real scalef, GLSpectrum* glSpectrum) : | 
					
						
							| 
									
										
										
										
											2016-10-02 22:29:04 +02:00
										 |  |  | 	BasebandSampleSink(), | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 	m_fft(FFTEngine::create()), | 
					
						
							|  |  |  | 	m_fftBuffer(MAX_FFT_SIZE), | 
					
						
							| 
									
										
										
										
											2018-07-06 01:34:05 +02:00
										 |  |  | 	m_powerSpectrum(MAX_FFT_SIZE), | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 	m_fftBufferFill(0), | 
					
						
							| 
									
										
										
										
											2015-07-15 01:19:39 +02:00
										 |  |  | 	m_needMoreSamples(false), | 
					
						
							| 
									
										
										
										
											2018-01-22 14:07:24 +01:00
										 |  |  | 	m_scalef(scalef), | 
					
						
							| 
									
										
										
										
											2015-10-22 02:27:56 +02:00
										 |  |  | 	m_glSpectrum(glSpectrum), | 
					
						
							| 
									
										
										
										
											2018-06-30 22:30:42 +02:00
										 |  |  | 	m_averageNb(0), | 
					
						
							| 
									
										
										
										
											2018-10-12 08:47:14 +02:00
										 |  |  | 	m_avgMode(AvgModeNone), | 
					
						
							| 
									
										
										
										
											2018-07-06 01:34:05 +02:00
										 |  |  | 	m_linear(false), | 
					
						
							| 
									
										
										
										
											2018-06-30 22:30:42 +02:00
										 |  |  | 	m_ofs(0), | 
					
						
							| 
									
										
										
										
											2018-07-06 01:34:05 +02:00
										 |  |  |     m_powFFTDiv(1.0), | 
					
						
							| 
									
										
										
										
											2015-10-22 02:27:56 +02:00
										 |  |  | 	m_mutex(QMutex::Recursive) | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-08-12 09:03:02 +02:00
										 |  |  | 	setObjectName("SpectrumVis"); | 
					
						
							| 
									
										
										
										
											2018-07-06 01:34:05 +02:00
										 |  |  | 	handleConfigure(1024, 0, 0, AvgModeNone, FFTWindow::BlackmanHarris, false); | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | SpectrumVis::~SpectrumVis() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	delete m_fft; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-01 02:16:59 +02:00
										 |  |  | void SpectrumVis::configure(MessageQueue* msgQueue, | 
					
						
							|  |  |  |         int fftSize, | 
					
						
							|  |  |  |         int overlapPercent, | 
					
						
							|  |  |  |         unsigned int averagingNb, | 
					
						
							|  |  |  |         int averagingMode, | 
					
						
							| 
									
										
										
										
											2018-07-04 23:11:28 +02:00
										 |  |  |         FFTWindow::Function window, | 
					
						
							|  |  |  |         bool linear) | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-07-04 23:11:28 +02:00
										 |  |  | 	MsgConfigureSpectrumVis* cmd = new MsgConfigureSpectrumVis(fftSize, overlapPercent, averagingNb, averagingMode, window, linear); | 
					
						
							| 
									
										
										
										
											2015-08-14 05:00:28 +02:00
										 |  |  | 	msgQueue->push(cmd); | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-25 20:13:34 +02:00
										 |  |  | void SpectrumVis::feedTriggered(const SampleVector::const_iterator& triggerPoint, const SampleVector::const_iterator& end, bool positiveOnly) | 
					
						
							| 
									
										
										
										
											2015-07-15 01:19:39 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-07-21 22:52:52 +02:00
										 |  |  | 	feed(triggerPoint, end, positiveOnly); // normal feed from trigger point
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							| 
									
										
										
										
											2015-07-15 01:19:39 +02:00
										 |  |  | 	if (triggerPoint == end) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		// the following piece of code allows to terminate the FFT that ends past the end of scope captured data
 | 
					
						
							|  |  |  | 		// that is the spectrum will include the captured data
 | 
					
						
							|  |  |  | 		// just do nothing if you want the spectrum to be included inside the scope captured data
 | 
					
						
							|  |  |  | 		// that is to drop the FFT that dangles past the end of captured data
 | 
					
						
							|  |  |  | 		if (m_needMoreSamples) { | 
					
						
							|  |  |  | 			feed(begin, end, positiveOnly); | 
					
						
							|  |  |  | 			m_needMoreSamples = false;      // force finish
 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		feed(triggerPoint, end, positiveOnly); // normal feed from trigger point
 | 
					
						
							| 
									
										
										
										
											2015-07-21 22:52:52 +02:00
										 |  |  | 	}*/ | 
					
						
							| 
									
										
										
										
											2015-07-15 01:19:39 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-25 08:24:23 +02:00
										 |  |  | void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleVector::const_iterator& end, bool positiveOnly) | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	// if no visualisation is set, send the samples to /dev/null
 | 
					
						
							| 
									
										
										
										
											2015-08-25 08:24:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-21 08:58:33 +01:00
										 |  |  | 	if (m_glSpectrum == 0) { | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 		return; | 
					
						
							| 
									
										
										
										
											2015-08-25 08:24:23 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-21 08:58:33 +01:00
										 |  |  |     if (!m_mutex.tryLock(0)) { // prevent conflicts with configuration process
 | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-25 08:24:23 +02:00
										 |  |  | 	SampleVector::const_iterator begin(cbegin); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (begin < end) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2015-08-17 08:29:34 +02:00
										 |  |  | 		std::size_t todo = end - begin; | 
					
						
							|  |  |  | 		std::size_t samplesNeeded = m_refillSize - m_fftBufferFill; | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-25 08:24:23 +02:00
										 |  |  | 		if (todo >= samplesNeeded) | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 			// fill up the buffer
 | 
					
						
							|  |  |  | 			std::vector<Complex>::iterator it = m_fftBuffer.begin() + m_fftBufferFill; | 
					
						
							| 
									
										
										
										
											2015-08-25 08:24:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			for (std::size_t i = 0; i < samplesNeeded; ++i, ++begin) | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2018-01-22 14:07:24 +01:00
										 |  |  | 				*it++ = Complex(begin->real() / m_scalef, begin->imag() / m_scalef); | 
					
						
							| 
									
										
										
										
											2015-08-25 08:24:23 +02:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// apply fft window (and copy from m_fftBuffer to m_fftIn)
 | 
					
						
							|  |  |  | 			m_window.apply(&m_fftBuffer[0], m_fft->in()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// calculate FFT
 | 
					
						
							|  |  |  | 			m_fft->transform(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// extract power spectrum and reorder buckets
 | 
					
						
							|  |  |  | 			const Complex* fftOut = m_fft->out(); | 
					
						
							| 
									
										
										
										
											2014-06-17 20:13:49 +01:00
										 |  |  | 			Complex c; | 
					
						
							|  |  |  | 			Real v; | 
					
						
							| 
									
										
										
										
											2015-08-17 08:29:34 +02:00
										 |  |  | 			std::size_t halfSize = m_fftSize / 2; | 
					
						
							| 
									
										
										
										
											2014-06-15 09:32:25 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-12 08:47:14 +02:00
										 |  |  | 			if (m_avgMode == AvgModeNone) | 
					
						
							| 
									
										
										
										
											2018-07-01 22:36:36 +02:00
										 |  |  | 			{ | 
					
						
							|  |  |  |                 if ( positiveOnly ) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     for (std::size_t i = 0; i < halfSize; i++) | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         c = fftOut[i]; | 
					
						
							|  |  |  |                         v = c.real() * c.real() + c.imag() * c.imag(); | 
					
						
							| 
									
										
										
										
											2018-07-06 01:34:05 +02:00
										 |  |  |                         v = m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs; | 
					
						
							|  |  |  |                         m_powerSpectrum[i * 2] = v; | 
					
						
							|  |  |  |                         m_powerSpectrum[i * 2 + 1] = v; | 
					
						
							| 
									
										
										
										
											2018-07-01 22:36:36 +02:00
										 |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     for (std::size_t i = 0; i < halfSize; i++) | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         c = fftOut[i + halfSize]; | 
					
						
							|  |  |  |                         v = c.real() * c.real() + c.imag() * c.imag(); | 
					
						
							| 
									
										
										
										
											2018-07-06 01:34:05 +02:00
										 |  |  |                         v = m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs; | 
					
						
							|  |  |  |                         m_powerSpectrum[i] = v; | 
					
						
							| 
									
										
										
										
											2018-07-01 22:36:36 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |                         c = fftOut[i]; | 
					
						
							|  |  |  |                         v = c.real() * c.real() + c.imag() * c.imag(); | 
					
						
							| 
									
										
										
										
											2018-07-06 01:34:05 +02:00
										 |  |  |                         v = m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs; | 
					
						
							|  |  |  |                         m_powerSpectrum[i + halfSize] = v; | 
					
						
							| 
									
										
										
										
											2018-07-01 22:36:36 +02:00
										 |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 // send new data to visualisation
 | 
					
						
							| 
									
										
										
										
											2018-07-06 01:34:05 +02:00
										 |  |  |                 m_glSpectrum->newSpectrum(m_powerSpectrum, m_fftSize); | 
					
						
							| 
									
										
										
										
											2018-07-01 22:36:36 +02:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-10-12 08:47:14 +02:00
										 |  |  | 			else if (m_avgMode == AvgModeMovingAvg) | 
					
						
							| 
									
										
										
										
											2015-08-25 08:24:23 +02:00
										 |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2018-07-01 02:16:59 +02:00
										 |  |  | 	            if ( positiveOnly ) | 
					
						
							|  |  |  | 	            { | 
					
						
							|  |  |  | 	                for (std::size_t i = 0; i < halfSize; i++) | 
					
						
							|  |  |  | 	                { | 
					
						
							|  |  |  | 	                    c = fftOut[i]; | 
					
						
							|  |  |  | 	                    v = c.real() * c.real() + c.imag() * c.imag(); | 
					
						
							|  |  |  | 	                    v = m_movingAverage.storeAndGetAvg(v, i); | 
					
						
							| 
									
										
										
										
											2018-07-06 01:34:05 +02:00
										 |  |  | 	                    v = m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs; | 
					
						
							|  |  |  | 	                    m_powerSpectrum[i * 2] = v; | 
					
						
							|  |  |  | 	                    m_powerSpectrum[i * 2 + 1] = v; | 
					
						
							| 
									
										
										
										
											2018-07-01 02:16:59 +02:00
										 |  |  | 	                } | 
					
						
							|  |  |  | 	            } | 
					
						
							|  |  |  | 	            else | 
					
						
							|  |  |  | 	            { | 
					
						
							|  |  |  | 	                for (std::size_t i = 0; i < halfSize; i++) | 
					
						
							|  |  |  | 	                { | 
					
						
							|  |  |  | 	                    c = fftOut[i + halfSize]; | 
					
						
							|  |  |  | 	                    v = c.real() * c.real() + c.imag() * c.imag(); | 
					
						
							|  |  |  | 	                    v = m_movingAverage.storeAndGetAvg(v, i+halfSize); | 
					
						
							| 
									
										
										
										
											2018-07-06 01:34:05 +02:00
										 |  |  | 	                    v = m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs; | 
					
						
							|  |  |  | 	                    m_powerSpectrum[i] = v; | 
					
						
							| 
									
										
										
										
											2018-07-01 02:16:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	                    c = fftOut[i]; | 
					
						
							|  |  |  | 	                    v = c.real() * c.real() + c.imag() * c.imag(); | 
					
						
							|  |  |  | 	                    v = m_movingAverage.storeAndGetAvg(v, i); | 
					
						
							| 
									
										
										
										
											2018-07-06 01:34:05 +02:00
										 |  |  | 	                    v = m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs; | 
					
						
							|  |  |  | 	                    m_powerSpectrum[i + halfSize] = v; | 
					
						
							| 
									
										
										
										
											2018-07-01 02:16:59 +02:00
										 |  |  | 	                } | 
					
						
							|  |  |  | 	            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	            // send new data to visualisation
 | 
					
						
							| 
									
										
										
										
											2018-07-06 01:34:05 +02:00
										 |  |  | 	            m_glSpectrum->newSpectrum(m_powerSpectrum, m_fftSize); | 
					
						
							| 
									
										
										
										
											2018-07-01 02:16:59 +02:00
										 |  |  | 	            m_movingAverage.nextAverage(); | 
					
						
							| 
									
										
										
										
											2015-08-25 08:24:23 +02:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-10-12 08:47:14 +02:00
										 |  |  | 			else if (m_avgMode == AvgModeFixedAvg) | 
					
						
							| 
									
										
										
										
											2015-08-25 08:24:23 +02:00
										 |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2018-07-01 02:16:59 +02:00
										 |  |  | 			    double avg; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if ( positiveOnly ) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     for (std::size_t i = 0; i < halfSize; i++) | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         c = fftOut[i]; | 
					
						
							|  |  |  |                         v = c.real() * c.real() + c.imag() * c.imag(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         if (m_fixedAverage.storeAndGetAvg(avg, v, i)) | 
					
						
							|  |  |  |                         { | 
					
						
							| 
									
										
										
										
											2018-10-12 08:47:14 +02:00
										 |  |  |                             avg = m_linear ? avg/m_powFFTDiv : m_mult * log2f(avg) + m_ofs; | 
					
						
							| 
									
										
										
										
											2018-07-06 01:34:05 +02:00
										 |  |  |                             m_powerSpectrum[i * 2] = avg; | 
					
						
							|  |  |  |                             m_powerSpectrum[i * 2 + 1] = avg; | 
					
						
							| 
									
										
										
										
											2018-07-01 02:16:59 +02:00
										 |  |  |                         } | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     for (std::size_t i = 0; i < halfSize; i++) | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         c = fftOut[i + halfSize]; | 
					
						
							|  |  |  |                         v = c.real() * c.real() + c.imag() * c.imag(); | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-01 02:16:59 +02:00
										 |  |  |                         if (m_fixedAverage.storeAndGetAvg(avg, v, i+halfSize)) | 
					
						
							|  |  |  |                         { // result available
 | 
					
						
							| 
									
										
										
										
											2018-10-12 08:47:14 +02:00
										 |  |  |                             avg = m_linear ? avg/m_powFFTDiv : m_mult * log2f(avg) + m_ofs; | 
					
						
							| 
									
										
										
										
											2018-07-06 01:34:05 +02:00
										 |  |  |                             m_powerSpectrum[i] = avg; | 
					
						
							| 
									
										
										
										
											2018-07-01 02:16:59 +02:00
										 |  |  |                         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         c = fftOut[i]; | 
					
						
							|  |  |  |                         v = c.real() * c.real() + c.imag() * c.imag(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         if (m_fixedAverage.storeAndGetAvg(avg, v, i)) | 
					
						
							|  |  |  |                         { // result available
 | 
					
						
							| 
									
										
										
										
											2018-10-12 08:47:14 +02:00
										 |  |  |                             avg = m_linear ? avg/m_powFFTDiv : m_mult * log2f(avg) + m_ofs; | 
					
						
							| 
									
										
										
										
											2018-07-06 01:34:05 +02:00
										 |  |  |                             m_powerSpectrum[i + halfSize] = avg; | 
					
						
							| 
									
										
										
										
											2018-07-01 02:16:59 +02:00
										 |  |  |                         } | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-12 08:47:14 +02:00
										 |  |  |                 if (m_fixedAverage.nextAverage()) { // result available
 | 
					
						
							|  |  |  |                     m_glSpectrum->newSpectrum(m_powerSpectrum, m_fftSize); // send new data to visualisation
 | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else if (m_avgMode == AvgModeMax) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 			    double max; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if ( positiveOnly ) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     for (std::size_t i = 0; i < halfSize; i++) | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         c = fftOut[i]; | 
					
						
							|  |  |  |                         v = c.real() * c.real() + c.imag() * c.imag(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         if (m_max.storeAndGetMax(max, v, i)) | 
					
						
							|  |  |  |                         { | 
					
						
							|  |  |  |                             max = m_linear ? max/m_powFFTDiv : m_mult * log2f(max) + m_ofs; | 
					
						
							|  |  |  |                             m_powerSpectrum[i * 2] = max; | 
					
						
							|  |  |  |                             m_powerSpectrum[i * 2 + 1] = max; | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     for (std::size_t i = 0; i < halfSize; i++) | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         c = fftOut[i + halfSize]; | 
					
						
							|  |  |  |                         v = c.real() * c.real() + c.imag() * c.imag(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         if (m_max.storeAndGetMax(max, v, i+halfSize)) | 
					
						
							|  |  |  |                         { // result available
 | 
					
						
							|  |  |  |                             max = m_linear ? max/m_powFFTDiv : m_mult * log2f(max) + m_ofs; | 
					
						
							|  |  |  |                             m_powerSpectrum[i] = max; | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         c = fftOut[i]; | 
					
						
							|  |  |  |                         v = c.real() * c.real() + c.imag() * c.imag(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         if (m_max.storeAndGetMax(max, v, i)) | 
					
						
							|  |  |  |                         { // result available
 | 
					
						
							|  |  |  |                             max = m_linear ? max/m_powFFTDiv : m_mult * log2f(max) + m_ofs; | 
					
						
							|  |  |  |                             m_powerSpectrum[i + halfSize] = max; | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (m_max.nextMax()) { // result available
 | 
					
						
							|  |  |  |                     m_glSpectrum->newSpectrum(m_powerSpectrum, m_fftSize); // send new data to visualisation
 | 
					
						
							| 
									
										
										
										
											2018-07-01 02:16:59 +02:00
										 |  |  |                 } | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// advance buffer respecting the fft overlap factor
 | 
					
						
							|  |  |  | 			std::copy(m_fftBuffer.begin() + m_refillSize, m_fftBuffer.end(), m_fftBuffer.begin()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// start over
 | 
					
						
							|  |  |  | 			m_fftBufferFill = m_overlapSize; | 
					
						
							| 
									
										
										
										
											2015-07-15 01:19:39 +02:00
										 |  |  | 			m_needMoreSamples = false; | 
					
						
							| 
									
										
										
										
											2015-08-25 08:24:23 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 			// not enough samples for FFT - just fill in new data and return
 | 
					
						
							|  |  |  | 			for(std::vector<Complex>::iterator it = m_fftBuffer.begin() + m_fftBufferFill; begin < end; ++begin) | 
					
						
							| 
									
										
										
										
											2015-08-25 08:24:23 +02:00
										 |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2018-01-22 14:07:24 +01:00
										 |  |  | 				*it++ = Complex(begin->real() / m_scalef, begin->imag() / m_scalef); | 
					
						
							| 
									
										
										
										
											2015-08-25 08:24:23 +02:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 			m_fftBufferFill += todo; | 
					
						
							| 
									
										
										
										
											2015-07-15 01:19:39 +02:00
										 |  |  | 			m_needMoreSamples = true; | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-11-21 08:58:33 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	 m_mutex.unlock(); | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void SpectrumVis::start() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void SpectrumVis::stop() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-14 05:00:28 +02:00
										 |  |  | bool SpectrumVis::handleMessage(const Message& message) | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-08-18 02:47:14 +02:00
										 |  |  | 	if (MsgConfigureSpectrumVis::match(message)) | 
					
						
							| 
									
										
										
										
											2015-08-14 05:00:28 +02:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2015-08-18 02:47:14 +02:00
										 |  |  | 		MsgConfigureSpectrumVis& conf = (MsgConfigureSpectrumVis&) message; | 
					
						
							| 
									
										
										
										
											2018-07-01 02:16:59 +02:00
										 |  |  | 		handleConfigure(conf.getFFTSize(), | 
					
						
							|  |  |  | 		        conf.getOverlapPercent(), | 
					
						
							|  |  |  | 		        conf.getAverageNb(), | 
					
						
							| 
									
										
										
										
											2018-10-12 08:47:14 +02:00
										 |  |  | 		        conf.getAvgMode(), | 
					
						
							| 
									
										
										
										
											2018-07-06 01:34:05 +02:00
										 |  |  | 		        conf.getWindow(), | 
					
						
							|  |  |  | 		        conf.getLinear()); | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-08-14 05:00:28 +02:00
										 |  |  | 	else | 
					
						
							| 
									
										
										
										
											2015-06-23 20:05:28 +02:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2015-08-14 05:00:28 +02:00
										 |  |  | 		return false; | 
					
						
							| 
									
										
										
										
											2015-06-23 20:05:28 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-01 02:16:59 +02:00
										 |  |  | void SpectrumVis::handleConfigure(int fftSize, | 
					
						
							|  |  |  |         int overlapPercent, | 
					
						
							|  |  |  |         unsigned int averageNb, | 
					
						
							| 
									
										
										
										
											2018-10-12 08:47:14 +02:00
										 |  |  |         AvgMode averagingMode, | 
					
						
							| 
									
										
										
										
											2018-07-06 01:34:05 +02:00
										 |  |  |         FFTWindow::Function window, | 
					
						
							|  |  |  |         bool linear) | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-10-12 08:47:14 +02:00
										 |  |  | //    qDebug("SpectrumVis::handleConfigure, fftSize: %d overlapPercent: %d averageNb: %u averagingMode: %d window: %d linear: %s",
 | 
					
						
							|  |  |  | //            fftSize, overlapPercent, averageNb, (int) averagingMode, (int) window, linear ? "true" : "false");
 | 
					
						
							| 
									
										
										
										
											2015-10-22 02:27:56 +02:00
										 |  |  | 	QMutexLocker mutexLocker(&m_mutex); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-14 05:00:28 +02:00
										 |  |  | 	if (fftSize > MAX_FFT_SIZE) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 		fftSize = MAX_FFT_SIZE; | 
					
						
							| 
									
										
										
										
											2015-08-14 05:00:28 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	else if (fftSize < 64) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 		fftSize = 64; | 
					
						
							| 
									
										
										
										
											2015-08-14 05:00:28 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (overlapPercent > 100) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 		m_overlapPercent = 100; | 
					
						
							| 
									
										
										
										
											2015-08-14 05:00:28 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	else if (overlapPercent < 0) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 		m_overlapPercent = 0; | 
					
						
							| 
									
										
										
										
											2015-08-14 05:00:28 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-22 03:04:42 +01:00
										 |  |  | 	else | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  |         m_overlapPercent = overlapPercent; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	m_fftSize = fftSize; | 
					
						
							|  |  |  | 	m_fft->configure(m_fftSize, false); | 
					
						
							|  |  |  | 	m_window.create(window, m_fftSize); | 
					
						
							|  |  |  | 	m_overlapSize = (m_fftSize * m_overlapPercent) / 100; | 
					
						
							|  |  |  | 	m_refillSize = m_fftSize - m_overlapSize; | 
					
						
							|  |  |  | 	m_fftBufferFill = m_overlapSize; | 
					
						
							| 
									
										
										
										
											2018-10-16 23:56:09 +02:00
										 |  |  | 	m_movingAverage.resize(fftSize, averageNb > 1000 ? 1000 : averageNb); // Capping to avoid out of memory condition
 | 
					
						
							| 
									
										
										
										
											2018-07-01 02:16:59 +02:00
										 |  |  | 	m_fixedAverage.resize(fftSize, averageNb); | 
					
						
							| 
									
										
										
										
											2018-10-12 08:47:14 +02:00
										 |  |  | 	m_max.resize(fftSize, averageNb); | 
					
						
							| 
									
										
										
										
											2018-06-30 22:30:42 +02:00
										 |  |  | 	m_averageNb = averageNb; | 
					
						
							| 
									
										
										
										
											2018-10-12 08:47:14 +02:00
										 |  |  | 	m_avgMode = averagingMode; | 
					
						
							| 
									
										
										
										
											2018-07-06 01:34:05 +02:00
										 |  |  | 	m_linear = linear; | 
					
						
							| 
									
										
										
										
											2018-06-28 23:47:15 +02:00
										 |  |  | 	m_ofs = 20.0f * log10f(1.0f / m_fftSize); | 
					
						
							| 
									
										
										
										
											2018-07-06 01:34:05 +02:00
										 |  |  | 	m_powFFTDiv = m_fftSize*m_fftSize; | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | } |