|
From: Tapio V. <aa...@us...> - 2011-01-20 10:31:24
|
Module: editor
Branch: master
Commit: e67b29735bd1838266e5da5512b1d7e4b2accc71
Author: Tapio Vierros <tap...@gm...>
Date: Thu Jan 20 12:29:41 2011 +0200
Initial threaded analyzing implementation.
* Visualization comes in chunks, calculated in the background.
* Crashes on exit.
---
notegraphwidget.cc | 10 +++++++-
notegraphwidget.hh | 2 +
pitchvis.cc | 65 +++++++++++++++++++++++++--------------------------
pitchvis.hh | 18 ++++++++++++-
4 files changed, 59 insertions(+), 36 deletions(-)
diff --git a/notegraphwidget.cc b/notegraphwidget.cc
index 97a07e3..e46fce4 100644
--- a/notegraphwidget.cc
+++ b/notegraphwidget.cc
@@ -109,7 +109,15 @@ void NoteGraphWidget::finalizeNewLyrics()
void NoteGraphWidget::analyzeMusic(QString filepath)
{
- m_pitch.reset(new PitchVis(filepath.toStdString(), this));
+ m_pitch.reset(new PitchVis(filepath, this));
+ m_analyzeTimer = startTimer(2000);
+}
+
+void NoteGraphWidget::timerEvent(QTimerEvent *event)
+{
+ if (!m_pitch.isNull() && m_pitch->newDataAvailable()) {
+ setPixmap(QPixmap::fromImage(m_pitch->getImage()));
+ }
}
int NoteGraphWidget::getNoteLabelId(NoteLabel* note) const
diff --git a/notegraphwidget.hh b/notegraphwidget.hh
index e100453..89cfeb0 100644
--- a/notegraphwidget.hh
+++ b/notegraphwidget.hh
@@ -65,6 +65,7 @@ protected:
void mouseDoubleClickEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent * event);
void keyPressEvent(QKeyEvent *event);
+ void timerEvent(QTimerEvent *event);
private:
void finalizeNewLyrics();
@@ -78,6 +79,7 @@ private:
NoteLabels m_notes;
QScopedPointer<PitchVis> m_pitch;
SeekHandle m_seekHandle;
+ int m_analyzeTimer;
};
diff --git a/pitchvis.cc b/pitchvis.cc
index 2e68940..ffaaf94 100644
--- a/pitchvis.cc
+++ b/pitchvis.cc
@@ -22,26 +22,35 @@ template <typename T> void readVec(std::string const& filename, std::vector<T>&
if (!f) throw std::runtime_error("Error reading " + filename);
}
-PitchVis::PitchVis(std::string const& filename, QWidget *parent): QWidget(parent), step(512), height(768) {
- QProgressDialog progress(tr("Initializing audio decoding..."), tr("&Abort"), 0, 1, this);
- progress.setWindowModality(Qt::WindowModal);
- progress.setValue(0);
+PitchVis::PitchVis(QString const& filename, QWidget *parent)
+ : QWidget(parent), QThread(), mutex(), step(512), height(768), fileName(filename), moreAvailable()
+{
+ start(); // Launch the thread
+}
+void PitchVis::run()
+{
// Initialize FFmpeg decoding
- FFmpeg mpeg(false, true, filename, 44100);
+ FFmpeg mpeg(false, true, fileName.toStdString(), 44100);
while(std::isnan(mpeg.duration())); // Wait for ffmpeg to be ready
- usleep(1000000); // Wait some more
+ msleep(1000); // Wait some more
unsigned width = mpeg.duration() * 44100 / step;
img.resize(width * height);
Analyzer analyzer(44100, "");
- progress.setMaximum(width);
- progress.setLabelText(tr("Analyzing pitch data..."));
- for (unsigned x = 0; x < width; ++x) {
- progress.setValue(x);
- if (progress.wasCanceled()) break;
+ QLabel *ngw = qobject_cast<QLabel*>(QWidget::parent());
+ if (ngw) {
+ ngw->setFixedSize(width, height);
+ } else return;
+ // Create image
+ {
+ QMutexLocker locker(&mutex);
+ image = QImage(width, height, QImage::Format_ARGB32_Premultiplied);
+ }
+
+ for (unsigned x = 0; x < width; ++x) {
// Get decoded samples from ffmpeg
std::vector<float> data(step*2);
mpeg.audioQueue(&*data.begin(), &*data.end(), x * step * 2);
@@ -53,6 +62,8 @@ PitchVis::PitchVis(std::string const& filename, QWidget *parent): QWidget(parent
// Analyze
analyzer.input(beginIt, endIt);
analyzer.process();
+
+ // Peaks
Analyzer::Peaks peaks = analyzer.getPeaks();
for (unsigned i = 0; i < peaks.size(); ++i) {
unsigned y = freq2px(peaks[i].freq);
@@ -67,6 +78,8 @@ PitchVis::PitchVis(std::string const& filename, QWidget *parent): QWidget(parent
pixel(x, y + 1) += p;
pixel(x, y - 1) += p;
}
+
+ // Tones
Analyzer::Tones tones = analyzer.getTones();
unsigned int i = 0;
for (Analyzer::Tones::const_iterator it = tones.begin(), itend = tones.end(); it != itend && i < 3; ++it) {
@@ -78,31 +91,17 @@ PitchVis::PitchVis(std::string const& filename, QWidget *parent): QWidget(parent
Pixel p(0.0f, value, 0.0f);
for (int j = int(y) - 2; j <= int(y) + 2; ++j) pixel(x, j) += p;
}
- }
- progress.setValue(width);
-
- QProgressDialog progress2(tr("Rendering pitch data..."), tr("&Abort"), 0, 1, this);
- progress2.setWindowModality(Qt::WindowModal);
- QImage image(width, height, QImage::Format_ARGB32_Premultiplied);
- unsigned* rgba = reinterpret_cast<unsigned*>(image.bits());
- for (unsigned x = 0; x < width; ++x) {
- progress2.setValue(x);
- if (progress2.wasCanceled()) break;
-
- for (unsigned y = 0; y < height; ++y) {
- rgba[y * width + x] = pixel(x, y).rgba();
+ // Draw
+ {
+ QMutexLocker locker(&mutex);
+ unsigned* rgba = reinterpret_cast<unsigned*>(image.bits());
+ for (unsigned y = 0; y < height; ++y) {
+ rgba[y * width + x] = pixel(x, y).rgba();
+ }
+ moreAvailable = true;
}
}
-
- progress2.setLabelText(tr("Applying image..."));
- QLabel *ngw = qobject_cast<QLabel*>(parent);
- if (ngw) {
- ngw->setPixmap(QPixmap::fromImage(image));
- ngw->setFixedSize(width, height);
- }
-
- progress2.setValue(width);
}
unsigned PitchVis::freq2px(double freq) const { return note2px(scale.getNote(freq)); }
diff --git a/pitchvis.hh b/pitchvis.hh
index 62f7f03..8cb3500 100644
--- a/pitchvis.hh
+++ b/pitchvis.hh
@@ -3,6 +3,8 @@
#include "notes.hh"
#include "util.hh"
#include <QWidget>
+#include <QThread>
+#include <QMutex>
#include <cmath>
#include <string>
#include <vector>
@@ -31,15 +33,27 @@ struct Pixel {
}
};
-class PitchVis: public QWidget {
+class PitchVis: public QWidget, public QThread {
unsigned step;
std::vector<Pixel> img;
MusicalScale scale;
+ QString fileName;
+ QImage image;
+ bool moreAvailable;
+ QMutex mutex;
public:
const std::size_t height;
+
+ PitchVis(QString const& filename, QWidget *parent = NULL);
+
+ void run(); // Thread runs here
+
+ QImage getImage() { QMutexLocker locker(&mutex); moreAvailable = false; return image; }
+ bool newDataAvailable() const { return moreAvailable; }
+
Pixel& pixel(std::size_t x, std::size_t y) { return img[x * height + y]; }
std::size_t width() const { return img.size() / height; }
- PitchVis(std::string const& filename, QWidget *parent = NULL);
+
unsigned freq2px(double freq) const;
unsigned note2px(double note) const;
double px2note(unsigned px) const;
|