File indexing completed on 2024-09-22 05:10:22
0001 /* 0002 * Copyright (c) 2016 Daniel Holanda Noronha. All rights reserved. 0003 * 0004 * This work is licensed under the terms of the MIT license. 0005 * For a copy, see <https://opensource.org/licenses/MIT>. 0006 * 0007 */ 0008 0009 #include "fftcalc.h" 0010 0011 #undef CLAMP 0012 #define CLAMP(a,min,max) ((a) < (min) ? (min) : (a) > (max) ? (max) : (a)) 0013 0014 FFTCalc::FFTCalc(QObject *parent) 0015 :QObject(parent){ 0016 0017 processor.moveToThread(&processorThread); 0018 0019 qRegisterMetaType< QVector<double> >("QVector<double>"); 0020 connect(&processor, SIGNAL(calculatedSpectrum(QVector<double>)), SLOT(setSpectrum(QVector<double>))); 0021 connect(&processor, SIGNAL(allDone()),SLOT(freeCalc())); 0022 processorThread.start(QThread::LowestPriority); 0023 isBusy = false; 0024 } 0025 0026 FFTCalc::~FFTCalc(){ 0027 processorThread.quit(); 0028 processorThread.wait(10000); 0029 } 0030 0031 void FFTCalc::calc(QVector<double> &_array, int duration){ 0032 QMetaObject::invokeMethod(&processor, "processBuffer", 0033 Qt::QueuedConnection, Q_ARG(QVector<double>, _array), Q_ARG(int, duration)); 0034 } 0035 0036 void FFTCalc::setSpectrum(QVector<double> spectrum){ 0037 emit calculatedSpectrum(spectrum); 0038 } 0039 0040 void FFTCalc::freeCalc() 0041 { 0042 isBusy = false; 0043 } 0044 0045 BufferProcessor::BufferProcessor(QObject *parent){ 0046 Q_UNUSED(parent); 0047 timer = new QTimer(this); 0048 connect(timer,SIGNAL(timeout()),this,SLOT(run())); 0049 window.resize(SPECSIZE); 0050 complexFrame.resize(SPECSIZE); 0051 spectrum.resize(SPECSIZE/2); 0052 logscale.resize(SPECSIZE/2+1); 0053 compressed = true; 0054 for(int i=0; i<SPECSIZE;i++){ 0055 window[i] = 0.5 * (1 - cos((2*PI*i)/(SPECSIZE))); 0056 } 0057 for(int i=0; i<=SPECSIZE/2; i++){ 0058 logscale[i] = powf (SPECSIZE/2, (float) 2*i / SPECSIZE) - 0.5f; 0059 } 0060 running = false; 0061 timer->start(100); 0062 } 0063 0064 BufferProcessor::~BufferProcessor(){ 0065 timer->stop(); 0066 0067 } 0068 0069 void BufferProcessor::processBuffer(QVector<double> _array, int duration){ 0070 if(array.size() != _array.size()){ 0071 numberOfChunks = _array.size()/SPECSIZE; 0072 array.resize(_array.size()); 0073 } 0074 interval = duration/numberOfChunks; 0075 if(interval < 1) 0076 interval = 1; 0077 array = _array; 0078 pass = 0; 0079 timer->start(interval); 0080 } 0081 0082 void BufferProcessor::run(){ 0083 unsigned long bufferSize; 0084 qreal amplitude; 0085 if(pass == numberOfChunks){ 0086 emit allDone(); 0087 return; 0088 } 0089 bufferSize = array.size(); 0090 if(bufferSize < SPECSIZE){ 0091 return; 0092 } 0093 for(uint i=0; i<SPECSIZE; i++){ 0094 complexFrame[i] = Complex(window[i]*array[i+pass*SPECSIZE],0); 0095 } 0096 fft(complexFrame); 0097 for(uint i=0; i<SPECSIZE/2;i++){ 0098 qreal SpectrumAnalyserMultiplier = 1e-2; 0099 amplitude = SpectrumAnalyserMultiplier*std::abs(complexFrame[i]); 0100 amplitude = qMax(qreal(0.0), amplitude); 0101 amplitude = qMin(qreal(1.0), amplitude); 0102 complexFrame[i] = amplitude; 0103 } 0104 0105 if(compressed){ 0106 for (int i = 0; i <SPECSIZE/2; i ++){ 0107 int a = ceilf (logscale[i]); 0108 int b = floorf (logscale[i+1]); 0109 float sum = 0; 0110 0111 if (b < a) 0112 sum += complexFrame[b].real()*(logscale[i+1]-logscale[i]); 0113 else{ 0114 if (a > 0) 0115 sum += complexFrame[a-1].real()*(a-logscale[i]); 0116 for (; a < b; a++) 0117 sum += complexFrame[a].real(); 0118 if (b < SPECSIZE/2) 0119 sum += complexFrame[b].real()*(logscale[i+1] - b); 0120 } 0121 0122 sum *= (float) SPECSIZE/24; 0123 float val = 20*log10f (sum); 0124 val = 1 + val / 40; 0125 spectrum[i] = CLAMP (val, 0, 1); 0126 } 0127 } 0128 else{ 0129 for(int i=0; i<SPECSIZE/2; i++){ 0130 spectrum[i] = CLAMP(complexFrame[i].real()*100,0,1); 0131 } 0132 } 0133 emit calculatedSpectrum(spectrum); 0134 pass++; 0135 }