X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Faudioscopes%2Faudiospectrum.cpp;h=f8cf3ebaa114e6d3e86672b4a4f21f1c8816591a;hb=893498c6ea67208b800b6ae0c354ba1f5641edc2;hp=c9986f9dc6ff238acd9177c3c188c5a7173c3b09;hpb=7d12e6ef9d9b43edea5d8cd010786e2c1b1bc795;p=kdenlive diff --git a/src/audioscopes/audiospectrum.cpp b/src/audioscopes/audiospectrum.cpp index c9986f9d..f8cf3eba 100644 --- a/src/audioscopes/audiospectrum.cpp +++ b/src/audioscopes/audiospectrum.cpp @@ -36,8 +36,7 @@ const QString AudioSpectrum::directions[] = {"North", "Northeast", "East", "Sou AudioSpectrum::AudioSpectrum(QWidget *parent) : AbstractAudioScopeWidget(false, parent), - m_fftCfgs(), - m_windowFunctions(), + m_fftTools(), m_freqMax(10000), m_customFreq(false), m_rescaleMinDist(8), @@ -70,6 +69,7 @@ AudioSpectrum::AudioSpectrum(QWidget *parent) : bool b = true; b &= connect(m_aResetHz, SIGNAL(triggered()), this, SLOT(slotResetMaxFreq())); + b &= connect(ui->windowFunction, SIGNAL(currentIndexChanged(int)), this, SLOT(forceUpdate())); Q_ASSERT(b); @@ -83,10 +83,6 @@ AudioSpectrum::~AudioSpectrum() { writeConfig(); - QHash::iterator i; - for (i = m_fftCfgs.begin(); i != m_fftCfgs.end(); i++) { - free(*i); - } delete m_aResetHz; } @@ -159,78 +155,12 @@ QImage AudioSpectrum::renderAudioScope(uint, const QVector audioFrame, // Show the window size used, for information ui->labelFFTSizeNumber->setText(QVariant(fftWindow).toString()); - // Get the kiss_fft configuration from the config cache - // or build a new configuration if the requested one is not available. - kiss_fftr_cfg myCfg; - const QString signature = cfgSignature(fftWindow); - if (m_fftCfgs.contains(signature)) { -#ifdef DEBUG_AUDIOSPEC - qDebug() << "Re-using FFT configuration with size " << fftWindow; -#endif - myCfg = m_fftCfgs.value(signature); - } else { -#ifdef DEBUG_AUDIOSPEC - qDebug() << "Creating FFT configuration with size " << fftWindow; -#endif - myCfg = kiss_fftr_alloc(fftWindow, 0,0,0); - m_fftCfgs.insert(signature, myCfg); - } - float data[fftWindow]; + // Get the spectral power distribution of the input samples, + // using the given window size and function float freqSpectrum[fftWindow/2]; - - // Prepare frequency space vector. The resulting FFT vector is only half as long. - kiss_fft_cpx freqData[fftWindow/2]; - - - - // Copy the first channel's audio into a vector for the FFT display - // (only one channel handled at the moment) - if (num_samples < fftWindow) { - std::fill(&data[num_samples], &data[fftWindow-1], 0); - } - FFTTools::WindowType windowType = (FFTTools::WindowType) ui->windowFunction->itemData(ui->windowFunction->currentIndex()).toInt(); - QVector window; - float windowScaleFactor = 1; - if (windowType != FFTTools::Window_Rect) { - const QString signature = FFTTools::windowSignature(windowType, fftWindow, 0); - if (m_windowFunctions.contains(signature)) { -#ifdef DEBUG_AUDIOSPEC - qDebug() << "Re-using window function with signature " << signature; -#endif - window = m_windowFunctions.value(signature); - } else { -#ifdef DEBUG_AUDIOSPEC - qDebug() << "Building new window function with signature " << signature; -#endif - window = FFTTools::window(windowType, fftWindow, 0); - m_windowFunctions.insert(signature, window); - } - windowScaleFactor = 1.0/window[fftWindow]; - } - - // Normalize signals to [0,1] to get correct dB values later on - for (int i = 0; i < num_samples && i < fftWindow; i++) { - if (windowType != FFTTools::Window_Rect) { - data[i] = (float) audioFrame.data()[i*num_channels] / 32767.0f * window[i]; - } else { - data[i] = (float) audioFrame.data()[i*num_channels] / 32767.0f; - } - } - - // Calculate the Fast Fourier Transform for the input data - kiss_fftr(myCfg, data, freqData); - - - // Logarithmic scale: 20 * log ( 2 * magnitude / N ) with magnitude = sqrt(r² + i²) - // with N = FFT size (after FFT, 1/2 window size) - for (int i = 0; i < fftWindow/2; i++) { - // Logarithmic scale: 20 * log ( 2 * magnitude / N ) with magnitude = sqrt(r² + i²) - // with N = FFT size (after FFT, 1/2 window size) - freqSpectrum[i] = 20*log(pow(pow(fabs(freqData[i].r * windowScaleFactor),2) + pow(fabs(freqData[i].i * windowScaleFactor),2), .5)/((float)fftWindow/2.0f))/log(10);; - } - + m_fftTools.fftNormalized(audioFrame, 0, num_channels, freqSpectrum, windowType, fftWindow, 0); // Draw the spectrum @@ -342,7 +272,7 @@ QImage AudioSpectrum::renderHUD(uint) hud.fill(qRgba(0,0,0,0)); QPainter davinci(&hud); - davinci.setPen(AbstractAudioScopeWidget::penLight); + davinci.setPen(AbstractScopeWidget::penLight); int y; for (int db = -dbDiff; db > m_dBmin; db -= dbDiff) { @@ -360,20 +290,32 @@ QImage AudioSpectrum::renderHUD(uint) davinci.drawText(leftDist + m_innerScopeRect.width() + textDistX, topDist+m_innerScopeRect.height()+6, i18n("%1 dB", m_dBmin)); const uint hzDiff = ceil( ((float)minDistX)/m_innerScopeRect.width() * m_freqMax / 1000 ) * 1000; - int x; + int x = 0; + const int rightBorder = leftDist + m_innerScopeRect.width()-1; y = topDist + m_innerScopeRect.height() + textDistY; - for (uint hz = 0; hz <= m_freqMax; hz += hzDiff) { + for (uint hz = 0; x <= rightBorder; hz += hzDiff) { + davinci.setPen(AbstractScopeWidget::penLight); x = leftDist + m_innerScopeRect.width() * ((float)hz)/m_freqMax; - davinci.drawLine(x, topDist, x, topDist + m_innerScopeRect.height()+6); - if (hz < m_freqMax) { + + if (x <= rightBorder) { + davinci.drawLine(x, topDist, x, topDist + m_innerScopeRect.height()+6); + } + if (hz < m_freqMax && x+textDistY < leftDist + m_innerScopeRect.width()) { davinci.drawText(x-4, y, QVariant(hz/1000).toString()); } else { - davinci.drawText(x-10, y, i18n("%1 kHz",hz/1000)); + x = leftDist + m_innerScopeRect.width(); + davinci.drawLine(x, topDist, x, topDist + m_innerScopeRect.height()+6); + davinci.drawText(x-10, y, i18n("%1 kHz").arg((double)m_freqMax/1000, 0, 'f', 1)); } if (hz > 0) { - for (uint dHz = 1; dHz < 4; dHz++) { + // Draw finer lines between the main lines + davinci.setPen(AbstractScopeWidget::penLightDots); + for (uint dHz = 3; dHz > 0; dHz--) { x = leftDist + m_innerScopeRect.width() * ((float)hz - dHz * hzDiff/4.0f)/m_freqMax; + if (x > rightBorder) { + break; + } davinci.drawLine(x, topDist, x, topDist + m_innerScopeRect.height()-1); } }