#include <iostream>
-// Enables debugging, like writing a GNU Octave .m file to /tmp
-//#define DEBUG_AUDIOSPEC
-
+// (defined in the header file)
#ifdef DEBUG_AUDIOSPEC
#include <QDebug>
#endif
+// Draw lines instead of single pixels.
+// This is about 25 % faster, especially when enlarging the scope to e.g. 1680x1050 px.
+#define AUDIOSPEC_LINES
+
#define MIN_DB_VALUE -120
#define MAX_FREQ_VALUE 96000
#define MIN_FREQ_VALUE 1000
m_fftTools(),
m_lastFFT(),
m_lastFFTLock(1)
+ #ifdef DEBUG_AUDIOSPEC
+ ,m_timeTotal(0)
+ ,m_showTotal(0)
+ #endif
{
ui = new Ui::AudioSpectrum_UI;
ui->setupUi(this);
m_aResetHz = new QAction(i18n("Reset maximum frequency to sampling rate"), this);
+ m_aTrackMouse = new QAction(i18n("Track mouse"), this);
+ m_aTrackMouse->setCheckable(true);
m_menu->addSeparator();
m_menu->addAction(m_aResetHz);
+ m_menu->addAction(m_aTrackMouse);
m_menu->removeAction(m_aRealtime);
writeConfig();
delete m_aResetHz;
+ delete m_aTrackMouse;
}
void AudioSpectrum::readConfig()
ui->windowSize->setCurrentIndex(scopeConfig.readEntry("windowSize", 0));
ui->windowFunction->setCurrentIndex(scopeConfig.readEntry("windowFunction", 0));
+ m_aTrackMouse->setChecked(scopeConfig.readEntry("trackMouse", true));
m_dBmax = scopeConfig.readEntry("dBmax", 0);
m_dBmin = scopeConfig.readEntry("dBmin", -70);
m_freqMax = scopeConfig.readEntry("freqMax", 0);
scopeConfig.writeEntry("windowSize", ui->windowSize->currentIndex());
scopeConfig.writeEntry("windowFunction", ui->windowFunction->currentIndex());
+ scopeConfig.writeEntry("trackMouse", m_aTrackMouse->isChecked());
scopeConfig.writeEntry("dBmax", m_dBmax);
scopeConfig.writeEntry("dBmin", m_dBmin);
if (m_customFreq) {
m_lastFFT = QVector<float>(fftWindow/2);
memcpy(m_lastFFT.data(), &(freqSpectrum[0]), fftWindow/2 * sizeof(float));
- uint right = ((float) m_freqMax)/(m_freq) * (m_lastFFT.size() - 1);
- dbMap = interpolatePeakPreserving(m_lastFFT, m_innerScopeRect.width(), 0, right, -120);
+ uint right = ((float) m_freqMax)/(m_freq/2) * (m_lastFFT.size() - 1);
+ dbMap = interpolatePeakPreserving(m_lastFFT, m_innerScopeRect.width(), 0, right, -180);
m_lastFFTLock.release();
+ QTime drawTime = QTime::currentTime();
+
// Draw the spectrum
QImage spectrum(m_scopeRect.size(), QImage::Format_ARGB32);
spectrum.fill(qRgba(0,0,0,0));
const uint topDist = m_innerScopeRect.top() - m_scopeRect.top();
int yMax;
+#ifdef AUDIOSPEC_LINES
+ QPainter davinci(&spectrum);
+ davinci.setPen(AbstractScopeWidget::penThin);
+#endif
+
for (uint i = 0; i < w; i++) {
yMax = (dbMap[i] - m_dBmin) / (m_dBmax-m_dBmin) * (h-1);
if (yMax < 0) {
} else if (yMax >= (int)h) {
yMax = h-1;
}
+#ifdef AUDIOSPEC_LINES
+ davinci.drawLine(leftDist + i, topDist + h-1, leftDist + i, topDist + h-1 - yMax);
+#else
for (int y = 0; y < yMax && y < (int)h; y++) {
spectrum.setPixel(leftDist + i, topDist + h-y-1, qRgba(225, 182, 255, 255));
}
+#endif
}
+#ifdef DEBUG_AUDIOSPEC
+ m_showTotal++;
+ m_timeTotal += drawTime.elapsed();
+ qDebug() << widgetName() << " took " << drawTime.elapsed() << " ms for drawing. Average: " << ((float)m_timeTotal/m_showTotal) ;
+#endif
+
emit signalScopeRenderingFinished(start.elapsed(), 1);
int x = 0;
const int rightBorder = leftDist + m_innerScopeRect.width()-1;
y = topDist + m_innerScopeRect.height() + textDistY;
- for (uint hz = 0; x <= rightBorder; hz += hzDiff) {
- davinci.setPen(AbstractScopeWidget::penLight);
+ for (int hz = 0; x <= rightBorder; hz += hzDiff) {
+ davinci.setPen(AbstractScopeWidget::penLighter);
x = leftDist + m_innerScopeRect.width() * ((float)hz)/m_freqMax;
if (x <= rightBorder) {
}
}
- if (m_mouseWithinWidget && mouseX < m_innerScopeRect.width()-1) {
+ if (m_aTrackMouse->isChecked() && m_mouseWithinWidget && mouseX < m_innerScopeRect.width()-1) {
davinci.setPen(AbstractScopeWidget::penThin);
x = leftDist + mouseX;
bool drawDb = false;
m_lastFFTLock.acquire();
- if (m_lastFFT.size() > 0) {
- uint right = ((float) m_freqMax)/(m_freq) * (m_lastFFT.size() - 1);
+ // We need to test whether the mouse is inside the widget
+ // because the position could already have changed in the meantime (-> crash)
+ if (m_lastFFT.size() > 0 && mouseX >= 0 && mouseX < m_innerScopeRect.width()) {
+ uint right = ((float) m_freqMax)/(m_freq/2) * (m_lastFFT.size() - 1);
QVector<float> dbMap = AudioSpectrum::interpolatePeakPreserving(m_lastFFT, m_innerScopeRect.width(), 0, right, -120);
db = dbMap[mouseX];
const QVector<float> AudioSpectrum::interpolatePeakPreserving(const QVector<float> in, const uint targetSize, uint left, uint right, float fill)
{
+#ifdef DEBUG_AUDIOSPEC
+ QTime start = QTime::currentTime();
+#endif
+
if (right == 0) {
right = in.size()-1;
}
// Use linear interpolation in order to get smoother display
- if (i == 0 || i == targetSize-1) {
- // ... except if we are at the left or right border of the display or the spectrum
+ if (xi == 0 || xi == in.size()-1) {
+ // ... except if we are at the left or right border of the input sigal.
+ // Special case here since we consider previous and future values as well for
+ // the actual interpolation (not possible here).
out[i] = in[xi];
} else {
if (in[xi] > in[xi+1]
out[i] = fill;
}
+#ifdef DEBUG_AUDIOSPEC
+ qDebug() << "Interpolated " << targetSize << " nodes from " << in.size() << " input points in " << start.elapsed() << " ms";
+#endif
+
return out;
}