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 }