You can subscribe to this list here.
| 2009 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(25) |
Jul
(288) |
Aug
(119) |
Sep
(31) |
Oct
(59) |
Nov
(458) |
Dec
(359) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2010 |
Jan
(268) |
Feb
(26) |
Mar
(36) |
Apr
(48) |
May
(119) |
Jun
(37) |
Jul
(173) |
Aug
(429) |
Sep
(137) |
Oct
(156) |
Nov
(59) |
Dec
(45) |
| 2011 |
Jan
(398) |
Feb
(257) |
Mar
(49) |
Apr
(5) |
May
(34) |
Jun
(11) |
Jul
(38) |
Aug
(12) |
Sep
(1) |
Oct
(49) |
Nov
(5) |
Dec
(10) |
| 2012 |
Jan
(21) |
Feb
(32) |
Mar
(20) |
Apr
(1) |
May
(2) |
Jun
|
Jul
(173) |
Aug
|
Sep
(25) |
Oct
(6) |
Nov
(44) |
Dec
|
|
From: Lasse Kärkkäi. <tr...@us...> - 2011-01-21 14:36:06
|
Module: editor Branch: master Commit: 01a8d0c663f210957b6a9a930281eadc59d2e08a Author: Lasse Karkkainen <tro...@tr...> Date: Fri Jan 21 11:22:23 2011 +0100 Merge branch 'master' of git.performous.org:/gitroot/performous/editor --- |
|
From: Lasse Kärkkäi. <tr...@us...> - 2011-01-21 14:36:03
|
Module: editor Branch: master Commit: ec4531dd9f91237249cf6f4c7cb3e9f3bf4eb07e Author: Lasse Karkkainen <tro...@tr...> Date: Thu Jan 20 17:47:15 2011 +0100 Merge branch 'master' of git.performous.org:/gitroot/performous/editor --- |
|
From: Lasse Kärkkäi. <tr...@us...> - 2011-01-21 14:36:00
|
Module: editor
Branch: master
Commit: c1b57fb0d20f0cf1e66ae6a53c831963f0d53460
Author: Lasse Karkkainen <tro...@tr...>
Date: Thu Jan 20 16:49:24 2011 +0100
Linked tones
---
pitch.cc | 37 +++++++++++++++----------------------
pitch.hh | 4 +++-
2 files changed, 18 insertions(+), 23 deletions(-)
diff --git a/pitch.cc b/pitch.cc
index 4691f02..4a291c0 100644
--- a/pitch.cc
+++ b/pitch.cc
@@ -12,7 +12,7 @@ static const std::size_t FFT_STEP = 512; // Step size in samples, should be <=
static const double FFT_MINFREQ = 45.0;
static const double FFT_MAXFREQ = 3000.0;
-Tone::Tone(): freq(), level() {
+Tone::Tone(): freq(), level(), prev(), next() {
for (std::size_t i = 0; i < MAXHARM; ++i) harmonics[i] = 0.0;
}
@@ -168,28 +168,21 @@ void Analyzer::calcTones() {
}
void Analyzer::temporalMerge(Tones& tones) {
- /*Tones::iterator oldit;
- for (Tones::const_iterator it = tones.begin(), itend = tones.end(); it != itend; ++it) {
- if () oldit = std::find(
- }
- // Iterate over old tones
- for (ToneSeries::reverse_iterator oldit = m_toneSeries.rbegin(); oldit != m_toneSeries.rend(); ++oldit) {
- if (
- // Try to find a matching new tone
- while (it != tones.end() && *it < *oldit) ++it;
- // If match found
- if (it != tones.end() && *it == *oldit) {
- // Merge the old tone into the new tone
- it->age = oldit->age + 1;
- it->levelSlow = 0.5 * oldit->levelSlow + 0.5 * it->level;
- it->freqSlow = 0.5 * oldit->freqSlow + 0.5 * it->freq;
- } else if (oldit->levelSlow > 1e-8) {
- // Insert a decayed version of the old tone into new tones
- Tone& t = *tones.insert(it, *oldit);
- t.level = 0.0;
- t.levelSlow *= 0.01;
+ if (!m_moments.empty()) {
+ Tones& old = m_moments.back().m_tones;
+ Tones::iterator it = tones.begin();
+ // Iterate over old tones
+ for (Tones::iterator oldit = old.begin(); oldit != old.end(); ++oldit) {
+ // Try to find a matching new tone
+ while (it != tones.end() && *it < *oldit) ++it;
+ // If match found
+ if (it != tones.end() && *it == *oldit) {
+ // Link together the old and the new tones
+ oldit->next = &*it;
+ it->prev = &*oldit;
+ }
}
- }*/
+ }
m_moments.push_back(Moment(0.0, tones));
}
diff --git a/pitch.hh b/pitch.hh
index e3fdfe0..e2b25c0 100644
--- a/pitch.hh
+++ b/pitch.hh
@@ -18,7 +18,9 @@ struct Tone {
double harmonics[MAXHARM]; ///< Harmonics' levels
Tone();
bool operator==(double f) const; ///< Compare for rough frequency match
- // Linked list of a contin
+ // Linked list of a continuous tone
+ Tone* prev;
+ Tone* next;
};
struct Moment {
|
|
From: Tapio V. <aa...@us...> - 2011-01-21 12:04:35
|
Module: editor Branch: master Commit: 7597027111eec1d9762ef01d45368b4d9906c626 Author: Tapio Vierros <tap...@gm...> Date: Fri Jan 21 14:03:54 2011 +0200 Don't #include the whole <QtGui> --- editorapp.cc | 8 +++++++- notegraphwidget.cc | 8 +++++++- notelabel.cc | 5 ++++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/editorapp.cc b/editorapp.cc index 85fa44f..916d627 100644 --- a/editorapp.cc +++ b/editorapp.cc @@ -1,4 +1,10 @@ -#include <QtGui> +#include <QProgressBar> +#include <QMessageBox> +#include <QFileDialog> +#include <QClipboard> +#include <QMimeData> +#include <QWhatsThis> +#include <QUrl> #include <phonon/AudioOutput> #include <iostream> #include "config.hh" diff --git a/notegraphwidget.cc b/notegraphwidget.cc index 7a41ff3..1eee744 100644 --- a/notegraphwidget.cc +++ b/notegraphwidget.cc @@ -1,4 +1,10 @@ -#include <QtGui> +#include <QMouseEvent> +#include <QKeyEvent> +#include <QInputDialog> +#include <QLineEdit> +#include <QScrollArea> +#include <QScrollBar> +#include <QPainter> #include <iostream> #include <algorithm> #include <cmath> diff --git a/notelabel.cc b/notelabel.cc index 1fa5fcf..6e1d00f 100644 --- a/notelabel.cc +++ b/notelabel.cc @@ -1,4 +1,7 @@ -#include <QtGui> +#include <QMouseEvent> +#include <QResizeEvent> +#include <QToolTip> +#include <QPainter> #include <iostream> #include "notelabel.hh" #include "notegraphwidget.hh" |
|
From: Tapio V. <aa...@us...> - 2011-01-21 10:12:25
|
Module: editor
Branch: master
Commit: 2aba089093166d1b21436643411240c2ba995dee
Author: Tapio Vierros <tap...@gm...>
Date: Fri Jan 21 12:11:41 2011 +0200
Simplify lyric editing handling and allow editing with Enter-key.
---
notegraphwidget.cc | 16 +++++++++++++---
notegraphwidget.hh | 1 +
2 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/notegraphwidget.cc b/notegraphwidget.cc
index 7c9dfea..7a41ff3 100644
--- a/notegraphwidget.cc
+++ b/notegraphwidget.cc
@@ -310,15 +310,22 @@ void NoteGraphWidget::mouseDoubleClickEvent(QMouseEvent *event)
return;
}
+ editLyric(child);
+}
+
+void NoteGraphWidget::editLyric(NoteLabel *note) {
+ if (!note) return;
+
// Spawn an input dialog
bool ok;
QString text = QInputDialog::getText(this, tr("Edit lyric"),
tr("Lyric:"), QLineEdit::Normal,
- child->lyric(), &ok);
+ note->lyric(), &ok);
if (ok && !text.isEmpty()) {
- child->setLyric(text);
+ note->setLyric(text);
+ // Create undo operation
Operation op("LYRIC");
- op << getNoteLabelId(child) << text;
+ op << getNoteLabelId(note) << text;
doOperation(op, Operation::NO_EXEC);
}
}
@@ -361,6 +368,9 @@ void NoteGraphWidget::mouseMoveEvent(QMouseEvent *event)
void NoteGraphWidget::keyPressEvent(QKeyEvent *event)
{
switch (event->key()) {
+ case Qt::Key_Return: // Edit lyric
+ editLyric(m_selectedNote);
+ break;
case Qt::Key_Left: // Select note on the left
if (m_selectedNote && m_notes.size() > 1 && m_selectedNote != m_notes.front()) {
for (NoteLabels::iterator it = m_notes.begin(); it != m_notes.end(); ++it) {
diff --git a/notegraphwidget.hh b/notegraphwidget.hh
index ab77485..3db1520 100644
--- a/notegraphwidget.hh
+++ b/notegraphwidget.hh
@@ -47,6 +47,7 @@ public:
int getNoteLabelId(NoteLabel* note) const;
NoteLabels& noteLabels() { return m_notes; }
void doOperation(const Operation& op, Operation::OperationFlags flags = Operation::NORMAL);
+ void editLyric(NoteLabel *note);
int s2px(double sec) const;
double px2s(int px) const;
|
|
From: Tapio V. <aa...@us...> - 2011-01-21 09:26:28
|
Module: editor
Branch: master
Commit: 46a4a6784b0058c1c8a23a8bed13135bf1b5ec42
Author: Tapio Vierros <tap...@gm...>
Date: Fri Jan 21 11:25:27 2011 +0200
Simplify playback buttons handling --> less buggy.
---
editor.ui | 3 ---
editorapp.cc | 28 +++++++++++++++++-----------
editorapp.hh | 3 ++-
3 files changed, 19 insertions(+), 15 deletions(-)
diff --git a/editor.ui b/editor.ui
index 43fb2ea..b7872c6 100644
--- a/editor.ui
+++ b/editor.ui
@@ -328,9 +328,6 @@
<property name="text">
<string>Play</string>
</property>
- <property name="checkable">
- <bool>true</bool>
- </property>
</widget>
</item>
<item row="0" column="1">
diff --git a/editorapp.cc b/editorapp.cc
index c15ac3a..85fa44f 100644
--- a/editorapp.cc
+++ b/editorapp.cc
@@ -257,6 +257,7 @@ void EditorApp::on_actionSaveAs_triggered()
bool EditorApp::promptSaving()
{
+ updateSongMeta(); // Make sure the stuff in textboxes is updated
if (hasUnsavedChanges) {
QMessageBox::StandardButton b = QMessageBox::question(this, tr("Unsaved changes"),
tr("There are unsaved changes, which would be lost. Save now?"),
@@ -376,6 +377,7 @@ void EditorApp::on_actionMusicFile_triggered()
ui.valMusicFile->setText(fileName);
// Metadata is updated when it becomes available (signal)
player->setCurrentSource(Phonon::MediaSource(QUrl::fromLocalFile(fileName)));
+ noteGraph->updateMusicPos(0, false);
// Fire up analyzer
noteGraph->analyzeMusic(fileName);
}
@@ -474,22 +476,26 @@ void EditorApp::metaDataChanged()
}
}
-void EditorApp::on_cmdPlay_toggled(bool checked)
+void EditorApp::playButton()
+{
+ if (player && player->state() == Phonon::PlayingState) {
+ ui.cmdPlay->setText(tr("Pause"));
+ ui.cmdPlay->setIcon(QIcon::fromTheme("media-playback-pause"));
+ } else {
+ ui.cmdPlay->setText(tr("Play"));
+ ui.cmdPlay->setIcon(QIcon::fromTheme("media-playback-start"));
+ }
+}
+
+void EditorApp::on_cmdPlay_clicked()
{
if (player) {
if (player->currentSource().type() == Phonon::MediaSource::Empty
|| player->currentSource().type() == Phonon::MediaSource::Invalid) {
on_actionMusicFile_triggered();
} else {
- if (checked) {
- player->play();
- ui.cmdPlay->setText(tr("Playing..."));
- ui.cmdPlay->setIcon(QIcon::fromTheme("media-playback-pause"));
- } else {
- player->pause();
- ui.cmdPlay->setText(tr("Play"));
- ui.cmdPlay->setIcon(QIcon::fromTheme("media-playback-start"));
- }
+ if (player && player->state() == Phonon::PlayingState) player->pause();
+ else player->play();
}
}
}
@@ -498,7 +504,6 @@ void EditorApp::on_cmdStop_clicked()
{
if (player) player->stop();
if (noteGraph) noteGraph->updateMusicPos(0, false);
- ui.cmdPlay->setChecked(false);
}
void EditorApp::audioTick(qint64 time)
@@ -510,6 +515,7 @@ void EditorApp::audioTick(qint64 time)
void EditorApp::playerStateChanged(Phonon::State newstate, Phonon::State oldstate)
{
(void)oldstate;
+ playButton();
if (newstate != Phonon::PlayingState) {
noteGraph->stopMusic();
if (newstate == Phonon::ErrorState) {
diff --git a/editorapp.hh b/editorapp.hh
index df07a97..2b2172a 100644
--- a/editorapp.hh
+++ b/editorapp.hh
@@ -27,6 +27,7 @@ private:
bool promptSaving();
void saveProject(QString fileName);
void doOpStack();
+ void playButton();
public slots:
void operationDone(const Operation &op);
@@ -38,7 +39,7 @@ public slots:
// Automatic slots
- void on_cmdPlay_toggled(bool checked);
+ void on_cmdPlay_clicked();
void on_cmdStop_clicked();
// File menu
|
|
From: Tapio V. <aa...@us...> - 2011-01-20 15:01:38
|
Module: editor
Branch: master
Commit: 80f523dcd9700d76a908f0bd0e0fbd94e826ed57
Author: Tapio Vierros <tap...@gm...>
Date: Thu Jan 20 17:00:26 2011 +0200
Viewport follows SeekHandle during playback.
---
notegraphwidget.cc | 12 ++++++++++++
1 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/notegraphwidget.cc b/notegraphwidget.cc
index ff914ea..7c9dfea 100644
--- a/notegraphwidget.cc
+++ b/notegraphwidget.cc
@@ -493,7 +493,19 @@ void SeekHandle::mouseMoveEvent(QMouseEvent *event)
void SeekHandle::timerEvent(QTimerEvent *event)
{
+ (void)event;
move(x() + 1, 0);
+
+ // Make handle always visible in the ScrollArea
+ if (parentWidget() && parentWidget()->parentWidget()) {
+ QScrollArea *scrollArea = qobject_cast<QScrollArea*>(parentWidget()->parentWidget()->parent());
+ if (scrollArea) {
+ QScrollBar *scrollVer = scrollArea->verticalScrollBar();
+ int y = 0;
+ if (scrollVer) y = scrollVer->value();
+ scrollArea->ensureVisible(x() + scrollArea->width()/3, y, scrollArea->width()/3, 0);
+ }
+ }
}
|
|
From: Tapio V. <aa...@us...> - 2011-01-20 15:01:36
|
Module: editor
Branch: master
Commit: 0215a8351d38f3c1df405f39102953078a67543a
Author: Tapio Vierros <tap...@gm...>
Date: Thu Jan 20 16:26:47 2011 +0200
Simplify seeking.
---
editorapp.cc | 2 +-
notegraphwidget.cc | 18 ++++++++++--------
notegraphwidget.hh | 3 ++-
3 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/editorapp.cc b/editorapp.cc
index 8d496f2..c15ac3a 100644
--- a/editorapp.cc
+++ b/editorapp.cc
@@ -78,7 +78,7 @@ EditorApp::EditorApp(QWidget *parent): QMainWindow(parent), projectFileName(), h
connect(player, SIGNAL(tick(qint64)), this, SLOT(audioTick(qint64)));
connect(player, SIGNAL(stateChanged(Phonon::State,Phonon::State)), this, SLOT(playerStateChanged(Phonon::State,Phonon::State)));
connect(player, SIGNAL(metaDataChanged()), this, SLOT(metaDataChanged()));
- connect(noteGraph, SIGNAL(seek(qint64)), player, SLOT(seek(qint64)));
+ connect(noteGraph, SIGNAL(seeked(qint64)), player, SLOT(seek(qint64)));
}
void EditorApp::operationDone(const Operation &op)
diff --git a/notegraphwidget.cc b/notegraphwidget.cc
index a54ab59..ff914ea 100644
--- a/notegraphwidget.cc
+++ b/notegraphwidget.cc
@@ -201,6 +201,12 @@ void NoteGraphWidget::stopMusic()
m_seekHandle.killTimer(m_seekHandle.moveTimerId);
}
+void NoteGraphWidget::seek(int x)
+{
+ m_seekHandle.move(x - m_seekHandle.width()/2, 0);
+ emit seeked(1000 * px2s(x));
+}
+
void NoteGraphWidget::mousePressEvent(QMouseEvent *event)
{
NoteLabel *child = qobject_cast<NoteLabel*>(childAt(event->pos()));
@@ -216,7 +222,6 @@ void NoteGraphWidget::mousePressEvent(QMouseEvent *event)
} else {
// Seeking
m_seeking = true;
- m_panHotSpot = event->pos();
setCursor(QCursor(Qt::SizeHorCursor));
}
return;
@@ -301,8 +306,7 @@ void NoteGraphWidget::mouseDoubleClickEvent(QMouseEvent *event)
NoteLabel *child = qobject_cast<NoteLabel*>(childAt(event->pos()));
if (!child) {
// Double click empty space = seek there
- m_seekHandle.move(event->x() - m_seekHandle.width() / 2, 0);
- emit seek(1000 * px2s(event->x()));
+ seek(event->x());
return;
}
@@ -331,11 +335,9 @@ void NoteGraphWidget::mouseMoveEvent(QMouseEvent *event)
}
// Seeking
- if (m_seeking) {
- QPoint diff = event->pos() - m_panHotSpot;
- m_seekHandle.move(m_panHotSpot.x() + diff.x() - m_seekHandle.width()/2, 0);
- emit seek(1000 * px2s(event->pos().x()));
- }
+ if (m_seeking)
+ seek(event->x());
+
// Pan
else if (!m_panHotSpot.isNull()) {
setCursor(QCursor(Qt::ClosedHandCursor));
diff --git a/notegraphwidget.hh b/notegraphwidget.hh
index d8f861d..ab77485 100644
--- a/notegraphwidget.hh
+++ b/notegraphwidget.hh
@@ -39,6 +39,7 @@ public:
void updateMusicPos(qint64 time, bool smoothing);
void stopMusic();
+ void seek(int x);
void selectNote(NoteLabel *note);
NoteLabel* selectedNote() const { return m_selectedNote; }
@@ -57,7 +58,7 @@ signals:
void updateNoteInfo(NoteLabel*);
void analyzeProgress(int, int);
void operationDone(const Operation&);
- void seek(qint64 time);
+ void seeked(qint64 time);
protected:
void mousePressEvent(QMouseEvent *event);
|
|
From: Tapio V. <aa...@us...> - 2011-01-20 14:08:56
|
Module: editor
Branch: master
Commit: f552bc137b9df5dc28d019c47fbae02765a04d52
Author: Tapio Vierros <tap...@gm...>
Date: Thu Jan 20 16:06:12 2011 +0200
SeekHandle fixes & improvements.
* Double click empty space to seek there.
* Fixed hover cursor not showing.
* Slightly prettier bar with gray background.
* Better drag mouse positioning.
---
notegraphwidget.cc | 17 +++++++++++------
1 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/notegraphwidget.cc b/notegraphwidget.cc
index 7fece07..a54ab59 100644
--- a/notegraphwidget.cc
+++ b/notegraphwidget.cc
@@ -299,8 +299,12 @@ void NoteGraphWidget::wheelEvent(QWheelEvent *event)
void NoteGraphWidget::mouseDoubleClickEvent(QMouseEvent *event)
{
NoteLabel *child = qobject_cast<NoteLabel*>(childAt(event->pos()));
- if (!child)
+ if (!child) {
+ // Double click empty space = seek there
+ m_seekHandle.move(event->x() - m_seekHandle.width() / 2, 0);
+ emit seek(1000 * px2s(event->x()));
return;
+ }
// Spawn an input dialog
bool ok;
@@ -329,8 +333,8 @@ void NoteGraphWidget::mouseMoveEvent(QMouseEvent *event)
// Seeking
if (m_seeking) {
QPoint diff = event->pos() - m_panHotSpot;
- m_seekHandle.move(m_panHotSpot.x() + diff.x(), 0);
- emit seek(1000 * px2s(m_seekHandle.x()));
+ m_seekHandle.move(m_panHotSpot.x() + diff.x() - m_seekHandle.width()/2, 0);
+ emit seek(1000 * px2s(event->pos().x()));
}
// Pan
else if (!m_panHotSpot.isNull()) {
@@ -462,19 +466,20 @@ SeekHandle::SeekHandle(QWidget *parent)
image.fill(qRgba(0, 0, 0, 0));
QLinearGradient gradient(0, 0, image.width()-1, 0);
gradient.setColorAt(0.00, QColor(255,255,0,0));
- gradient.setColorAt(0.25, QColor(255,255,0,50));
+ gradient.setColorAt(0.25, QColor(255,255,0,0));
gradient.setColorAt(0.50, QColor(255,255,0,200));
- gradient.setColorAt(0.75, QColor(255,255,0,50));
+ gradient.setColorAt(0.75, QColor(255,255,0,0));
gradient.setColorAt(1.00, QColor(255,255,0,0));
QPainter painter;
painter.begin(&image);
painter.setRenderHint(QPainter::Antialiasing);
painter.setBrush(gradient);
+ painter.setPen(Qt::NoPen);
painter.drawRect(QRect(0, 0, image.width(), image.height()));
setPixmap(QPixmap::fromImage(image));
-
+ setMouseTracking(true);
setStatusTip(tr("Seek by dragging"));
}
|
|
From: Tapio V. <aa...@us...> - 2011-01-20 14:08:53
|
Module: editor
Branch: master
Commit: f824b2f837ec1b863843d5e40c2cca10a9ec4a3f
Author: Tapio Vierros <tap...@gm...>
Date: Thu Jan 20 15:39:48 2011 +0200
Messagebox for audio errors.
---
editorapp.cc | 5 +++++
notegraphwidget.cc | 2 +-
2 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/editorapp.cc b/editorapp.cc
index dc4f6f8..8d496f2 100644
--- a/editorapp.cc
+++ b/editorapp.cc
@@ -512,6 +512,11 @@ void EditorApp::playerStateChanged(Phonon::State newstate, Phonon::State oldstat
(void)oldstate;
if (newstate != Phonon::PlayingState) {
noteGraph->stopMusic();
+ if (newstate == Phonon::ErrorState) {
+ QString errst(tr("Error playing audio!"));
+ if (player) errst += " " + player->errorString();
+ QMessageBox::critical(this, tr("Playback error"), errst);
+ }
}
}
diff --git a/notegraphwidget.cc b/notegraphwidget.cc
index 3314729..7fece07 100644
--- a/notegraphwidget.cc
+++ b/notegraphwidget.cc
@@ -115,7 +115,7 @@ void NoteGraphWidget::finalizeNewLyrics()
void NoteGraphWidget::analyzeMusic(QString filepath)
{
m_pitch.reset(new PitchVis(filepath, this));
- m_analyzeTimer = startTimer(1000);
+ m_analyzeTimer = startTimer(2000);
}
void NoteGraphWidget::timerEvent(QTimerEvent *event)
|
|
From: Tapio V. <aa...@us...> - 2011-01-20 13:20:18
|
Module: editor
Branch: master
Commit: 5f9bc04f78f9676d5f87fad8d005a7e3433c60c2
Author: Tapio Vierros <tap...@gm...>
Date: Thu Jan 20 15:19:02 2011 +0200
Super neat statusbar progressbar for analyzation progress indication.
---
editorapp.cc | 17 +++++++++++++++++
editorapp.hh | 3 +++
notegraphwidget.cc | 12 +++++++++---
notegraphwidget.hh | 1 +
pitchvis.cc | 3 ++-
pitchvis.hh | 2 ++
6 files changed, 34 insertions(+), 4 deletions(-)
diff --git a/editorapp.cc b/editorapp.cc
index ad98c79..dc4f6f8 100644
--- a/editorapp.cc
+++ b/editorapp.cc
@@ -62,6 +62,10 @@ EditorApp::EditorApp(QWidget *parent): QMainWindow(parent), projectFileName(), h
ui.cmdPlay->setIcon(QIcon::fromTheme("media-playback-start"));
ui.cmdStop->setIcon(QIcon::fromTheme("media-playback-stop"));
+ statusbarProgress = new QProgressBar(NULL);
+ ui.statusbar->addPermanentWidget(statusbarProgress);
+ connect(noteGraph, SIGNAL(analyzeProgress(int, int)), this, SLOT(analyzeProgress(int, int)));
+
hasUnsavedChanges = false;
updateMenuStates();
@@ -146,6 +150,19 @@ void EditorApp::updateNoteInfo(NoteLabel *note)
}
}
+void EditorApp::analyzeProgress(int value, int maximum)
+{
+ if (statusbarProgress) {
+ if (value == maximum) {
+ statusbarProgress->hide();
+ } else {
+ statusbarProgress->setMaximum(maximum);
+ statusbarProgress->setValue(value);
+ statusbarProgress->show();
+ }
+ }
+}
+
void EditorApp::on_actionNew_triggered()
{
if (promptSaving()) {
diff --git a/editorapp.hh b/editorapp.hh
index 16540f8..df07a97 100644
--- a/editorapp.hh
+++ b/editorapp.hh
@@ -5,6 +5,7 @@
#include "operation.hh"
#include "song.hh"
+class QProgressBar;
class NoteLabel;
class NoteGraphWidget;
namespace Phonon {
@@ -30,6 +31,7 @@ private:
public slots:
void operationDone(const Operation &op);
void updateNoteInfo(NoteLabel *note);
+ void analyzeProgress(int value, int maximum);
void metaDataChanged();
void audioTick(qint64 time);
void playerStateChanged(Phonon::State newstate, Phonon::State olstate);
@@ -78,6 +80,7 @@ private:
QScopedPointer<Song> song;
Phonon::MediaObject *player;
Phonon::AudioOutput *audioOutput;
+ QProgressBar *statusbarProgress;
QString projectFileName;
bool hasUnsavedChanges;
};
diff --git a/notegraphwidget.cc b/notegraphwidget.cc
index 3bf8c54..3314729 100644
--- a/notegraphwidget.cc
+++ b/notegraphwidget.cc
@@ -115,13 +115,19 @@ void NoteGraphWidget::finalizeNewLyrics()
void NoteGraphWidget::analyzeMusic(QString filepath)
{
m_pitch.reset(new PitchVis(filepath, this));
- m_analyzeTimer = startTimer(2000);
+ m_analyzeTimer = startTimer(1000);
}
void NoteGraphWidget::timerEvent(QTimerEvent *event)
{
- if (!m_pitch.isNull() && m_pitch->newDataAvailable()) {
- setPixmap(QPixmap::fromImage(m_pitch->getImage()));
+ (void)event;
+ if (!m_pitch.isNull()) {
+ if (m_pitch->newDataAvailable())
+ setPixmap(QPixmap::fromImage(m_pitch->getImage()));
+ if (m_pitch->isFinished()) {
+ killTimer(m_analyzeTimer);
+ emit analyzeProgress(width(), width());
+ } else emit analyzeProgress(m_pitch->getXValue(), width());
}
}
diff --git a/notegraphwidget.hh b/notegraphwidget.hh
index 7143b02..d8f861d 100644
--- a/notegraphwidget.hh
+++ b/notegraphwidget.hh
@@ -55,6 +55,7 @@ public:
signals:
void updateNoteInfo(NoteLabel*);
+ void analyzeProgress(int, int);
void operationDone(const Operation&);
void seek(qint64 time);
diff --git a/pitchvis.cc b/pitchvis.cc
index 61cfc97..55f3cb0 100644
--- a/pitchvis.cc
+++ b/pitchvis.cc
@@ -23,7 +23,7 @@ template <typename T> void readVec(std::string const& filename, std::vector<T>&
}
PitchVis::PitchVis(QString const& filename, QWidget *parent)
- : QWidget(parent), QThread(), mutex(), step(512), height(768), fileName(filename), moreAvailable()
+ : QWidget(parent), QThread(), mutex(), step(512), height(768), fileName(filename), moreAvailable(), curX()
{
start(); // Launch the thread
}
@@ -52,6 +52,7 @@ void PitchVis::run()
for (unsigned x = 0; x < width; ++x) {
if (cancelled) return;
+ curX = x;
// Get decoded samples from ffmpeg
std::vector<float> data(step*2);
diff --git a/pitchvis.hh b/pitchvis.hh
index 21ae0ca..0af29c6 100644
--- a/pitchvis.hh
+++ b/pitchvis.hh
@@ -41,6 +41,7 @@ class PitchVis: public QWidget, public QThread {
QImage image;
bool moreAvailable;
bool cancelled;
+ int curX;
QMutex mutex;
public:
const std::size_t height;
@@ -53,6 +54,7 @@ public:
QImage getImage() { QMutexLocker locker(&mutex); moreAvailable = false; return image; }
bool newDataAvailable() const { return moreAvailable; }
+ int getXValue() const { return curX; }
Pixel& pixel(std::size_t x, std::size_t y) { return img[x * height + y]; }
std::size_t width() const { return img.size() / height; }
|
|
From: Lasse Kärkkäi. <tr...@us...> - 2011-01-20 13:12:45
|
Module: editor
Branch: master
Commit: a983fa83a59fec8ff29bba3ec2af61d8ad30d88d
Author: Lasse Karkkainen <tro...@tr...>
Date: Thu Jan 20 14:12:29 2011 +0100
Remove optimization that b0rks harmonic detection
---
pitch.cc | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/pitch.cc b/pitch.cc
index 0cd9e19..4691f02 100644
--- a/pitch.cc
+++ b/pitch.cc
@@ -118,7 +118,7 @@ void Analyzer::calcTones() {
// Strongest first
std::sort(combos.rbegin(), combos.rend());
// Keep only a reasonable amount of strongest frequencies.
- if (combos.size() > 10) combos.resize(10);
+ //if (combos.size() > 10) combos.resize(10);
// Try to combine combos into tones (collections of harmonics)
Tones tones;
for (Combos::const_iterator it = combos.begin(), end = combos.end(); it != end; ++it) {
|
|
From: Tapio V. <aa...@us...> - 2011-01-20 11:20:20
|
Module: editor
Branch: master
Commit: 6b32cd3d4502d07b38dc2f52a84efceb50193abb
Author: Tapio Vierros <tap...@gm...>
Date: Thu Jan 20 13:19:33 2011 +0200
NoteLabel y-movement is constrained to note levels.
---
notegraphwidget.cc | 7 +++++--
notelabel.cc | 5 ++++-
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/notegraphwidget.cc b/notegraphwidget.cc
index 816f06e..3bf8c54 100644
--- a/notegraphwidget.cc
+++ b/notegraphwidget.cc
@@ -18,6 +18,11 @@ namespace {
NoteGraphWidget::NoteGraphWidget(QWidget *parent)
: QLabel(parent), m_noteHalfHeight(), m_panHotSpot(), m_selectedNote(), m_selectedAction(NONE), m_seeking(), m_actionHappened(), m_pitch(), m_seekHandle(this)
{
+ // Determine NoteLabel height
+ NoteLabel templabel(Note(" "), NULL);
+ m_noteHalfHeight = templabel.height()/2;
+ templabel.close();
+
// FIXME: Temporary hack to make testing quicker
analyzeMusic("music.ogg");
@@ -174,8 +179,6 @@ void NoteGraphWidget::updateNotes()
gap = FloatingGap(child->x() + child->width());
}
}
- if (!m_notes.isEmpty())
- m_noteHalfHeight = m_notes.front()->height()/2;
}
void NoteGraphWidget::updateMusicPos(qint64 time, bool smoothing)
diff --git a/notelabel.cc b/notelabel.cc
index 48e652b..1fa5fcf 100644
--- a/notelabel.cc
+++ b/notelabel.cc
@@ -103,7 +103,10 @@ void NoteLabel::mouseMoveEvent(QMouseEvent *event)
// Moving
QPoint newpos = pos() + event->pos() - m_hotspot;
move(newpos);
- if (ngw) ngw->updateNotes();
+ if (ngw) {
+ move(x(), ngw->n2px(ngw->px2n(y())));
+ ngw->updateNotes();
+ }
// Check if we need a new hotspot, because the note was constrained
if (pos().x() != newpos.x()) m_hotspot.rx() = event->x();
|
|
From: Tapio V. <aa...@us...> - 2011-01-20 11:06:47
|
Module: editor
Branch: master
Commit: 68e78ccd5fef2fccce5180a1ff89495297b336ea
Author: Tapio Vierros <tap...@gm...>
Date: Thu Jan 20 13:05:46 2011 +0200
NoteLabels are y-centered with respect to pitch level.
---
notegraphwidget.cc | 10 ++++++----
notegraphwidget.hh | 3 ++-
2 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/notegraphwidget.cc b/notegraphwidget.cc
index e46fce4..816f06e 100644
--- a/notegraphwidget.cc
+++ b/notegraphwidget.cc
@@ -16,7 +16,7 @@ namespace {
}
NoteGraphWidget::NoteGraphWidget(QWidget *parent)
- : QLabel(parent), m_panHotSpot(), m_selectedNote(), m_selectedAction(NONE), m_seeking(), m_actionHappened(), m_pitch(), m_seekHandle(this)
+ : QLabel(parent), m_noteHalfHeight(), m_panHotSpot(), m_selectedNote(), m_selectedAction(NONE), m_seeking(), m_actionHappened(), m_pitch(), m_seekHandle(this)
{
// FIXME: Temporary hack to make testing quicker
analyzeMusic("music.ogg");
@@ -64,7 +64,7 @@ void NoteGraphWidget::setLyrics(QString lyrics)
QString word;
ts >> word;
if (!word.isEmpty()) {
- m_notes.push_back(new NoteLabel(Note(word.toStdString()), this, QPoint(0, m_pitch->note2px(24)), QSize(), !first));
+ m_notes.push_back(new NoteLabel(Note(word.toStdString()), this, QPoint(0, n2px(24)), QSize(), !first));
doOperation(opFromNote(*m_notes.back(), m_notes.size()-1), Operation::NO_EXEC);
first = false;
}
@@ -174,6 +174,8 @@ void NoteGraphWidget::updateNotes()
gap = FloatingGap(child->x() + child->width());
}
}
+ if (!m_notes.isEmpty())
+ m_noteHalfHeight = m_notes.front()->height()/2;
}
void NoteGraphWidget::updateMusicPos(qint64 time, bool smoothing)
@@ -438,8 +440,8 @@ void NoteGraphWidget::doOperation(const Operation& op, Operation::OperationFlags
int NoteGraphWidget::s2px(double sec) const { return m_pitch->time2px(sec); }
double NoteGraphWidget::px2s(int px) const { return m_pitch->px2time(px); }
-int NoteGraphWidget::n2px(int note) const { return m_pitch->note2px(note); }
-int NoteGraphWidget::px2n(int px) const { return m_pitch->px2note(px); }
+int NoteGraphWidget::n2px(int note) const { return m_pitch->note2px(note) - m_noteHalfHeight; }
+int NoteGraphWidget::px2n(int px) const { return m_pitch->px2note(px + m_noteHalfHeight); }
diff --git a/notegraphwidget.hh b/notegraphwidget.hh
index 89cfeb0..7143b02 100644
--- a/notegraphwidget.hh
+++ b/notegraphwidget.hh
@@ -70,7 +70,8 @@ protected:
private:
void finalizeNewLyrics();
- int m_requiredWidth;
+ int m_requiredWidth;
+ int m_noteHalfHeight;
QPoint m_panHotSpot;
NoteLabel* m_selectedNote;
enum NoteAction { NONE, RESIZE, MOVE } m_selectedAction;
|
|
From: Tapio V. <aa...@us...> - 2011-01-20 10:56:39
|
Module: editor
Branch: master
Commit: 774ace2988d7aae0cd4a6f732c75e1ffdd0148e9
Author: Tapio Vierros <tap...@gm...>
Date: Thu Jan 20 12:55:59 2011 +0200
Set applicationName and applicationVersion.
---
editorapp.cc | 3 ++-
main.cc | 3 +++
2 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/editorapp.cc b/editorapp.cc
index 7fca538..ad98c79 100644
--- a/editorapp.cc
+++ b/editorapp.cc
@@ -1,6 +1,7 @@
#include <QtGui>
#include <phonon/AudioOutput>
#include <iostream>
+#include "config.hh"
#include "editorapp.hh"
#include "notelabel.hh"
#include "notegraphwidget.hh"
@@ -119,7 +120,7 @@ void EditorApp::updateMenuStates()
QFileInfo finfo(projectFileName);
QString proName = finfo.fileName().isEmpty() ? tr("Untitled") : finfo.fileName();
if (hasUnsavedChanges) proName += "*";
- setWindowTitle("Editor - " + proName);
+ setWindowTitle(QString(PACKAGE) + " - " + proName);
}
void EditorApp::updateNoteInfo(NoteLabel *note)
diff --git a/main.cc b/main.cc
index 2b916cf..c155354 100644
--- a/main.cc
+++ b/main.cc
@@ -1,4 +1,5 @@
#include <QApplication>
+#include "config.hh"
#include "editorapp.hh"
int main(int argc, char *argv[])
@@ -6,6 +7,8 @@ int main(int argc, char *argv[])
Q_INIT_RESOURCE(editor);
QApplication app(argc, argv);
+ app.setApplicationName(PACKAGE);
+ app.setApplicationVersion(VERSION);
EditorApp window;
window.show();
|
|
From: Tapio V. <aa...@us...> - 2011-01-20 10:45:51
|
Module: editor
Branch: master
Commit: 45b23754e3f423813a5928a861b03fa3be291736
Author: Tapio Vierros <tap...@gm...>
Date: Thu Jan 20 12:44:40 2011 +0200
Fix analyzer thread causing crashing by implementing cancel mechanism.
---
pitchvis.cc | 4 ++++
pitchvis.hh | 3 +++
2 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/pitchvis.cc b/pitchvis.cc
index e1c44ef..61cfc97 100644
--- a/pitchvis.cc
+++ b/pitchvis.cc
@@ -51,6 +51,8 @@ void PitchVis::run()
}
for (unsigned x = 0; x < width; ++x) {
+ if (cancelled) return;
+
// Get decoded samples from ffmpeg
std::vector<float> data(step*2);
mpeg.audioQueue(&*data.begin(), &*data.end(), x * step * 2);
@@ -60,6 +62,7 @@ void PitchVis::run()
da::step_iterator<float> endIt(&*data.end(), 2);
// Analyze
+ if (cancelled) return;
analyzer.input(beginIt, endIt);
analyzer.process();
@@ -93,6 +96,7 @@ void PitchVis::run()
// Draw
{
+ if (cancelled) return;
QMutexLocker locker(&mutex);
unsigned* rgba = reinterpret_cast<unsigned*>(image.bits());
for (unsigned y = 0; y < height; ++y) {
diff --git a/pitchvis.hh b/pitchvis.hh
index 8cb3500..21ae0ca 100644
--- a/pitchvis.hh
+++ b/pitchvis.hh
@@ -40,13 +40,16 @@ class PitchVis: public QWidget, public QThread {
QString fileName;
QImage image;
bool moreAvailable;
+ bool cancelled;
QMutex mutex;
public:
const std::size_t height;
PitchVis(QString const& filename, QWidget *parent = NULL);
+ ~PitchVis() { stop(); wait(); }
void run(); // Thread runs here
+ void stop() { cancelled = true; }
QImage getImage() { QMutexLocker locker(&mutex); moreAvailable = false; return image; }
bool newDataAvailable() const { return moreAvailable; }
|
|
From: Lasse Kärkkäi. <tr...@us...> - 2011-01-20 10:35:08
|
Module: editor Branch: master Commit: 0e470c3776f50e7ac152c3406c48f8844546780c Author: Lasse Karkkainen <tro...@tr...> Date: Thu Jan 20 11:34:00 2011 +0100 Merge branch 'tonetracking' --- |
|
From: Lasse Kärkkäi. <tr...@us...> - 2011-01-20 10:35:05
|
Module: editor
Branch: master
Commit: 85ab78d206f7f645b726515b5f8c6fdfe7e60b67
Author: Lasse Karkkainen <tro...@tr...>
Date: Thu Jan 20 11:33:46 2011 +0100
Fix the segfault
---
pitch.hh | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/pitch.hh b/pitch.hh
index eb1327e..e3fdfe0 100644
--- a/pitch.hh
+++ b/pitch.hh
@@ -84,7 +84,7 @@ public:
/** Get the peak level in dB (negative value, 0.0 means clipping, sometimes clipping may occur at lower levels too). **/
double getLevel() const { return 10.0 * log10(m_level); }
/** Get a list of all tones detected. **/
- Tones const& getTones() const { return m_moments.back().m_tones; /* FIXME */ }
+ Tones getTones() const { return m_moments.empty() ? Tones() : m_moments.back().m_tones; /* FIXME */ }
/** Find a tone within the singing range; prefers strong tones around 200-400 Hz. **/
//Tone const* findTone(double minfreq = 70.0, double maxfreq = 700.0) const;
std::string const& getId() const { return m_id; }
|
|
From: Lasse Kärkkäi. <tr...@us...> - 2011-01-20 10:35:00
|
Module: editor Branch: master Commit: 6ea69db5de861c1e6eceff24015e073e1b901241 Author: Lasse Karkkainen <tro...@tr...> Date: Thu Jan 20 11:30:54 2011 +0100 Merge branch 'master' into tonetracking --- |
|
From: Lasse Kärkkäi. <tr...@us...> - 2011-01-20 10:34:57
|
Module: editor
Branch: master
Commit: 9ec8b1a1c4cda67e5e9829491836a09132a4940c
Author: Lasse Karkkainen <tro...@tr...>
Date: Thu Jan 20 11:27:37 2011 +0100
It compiles, ship i-- No, wait, it still segfaults :(
---
pitch.cc | 42 +++++++++++++++++-------------------------
pitch.hh | 11 ++++++-----
pitchvis.cc | 5 ++---
3 files changed, 25 insertions(+), 33 deletions(-)
diff --git a/pitch.cc b/pitch.cc
index a5a6c3b..0cd9e19 100644
--- a/pitch.cc
+++ b/pitch.cc
@@ -2,8 +2,6 @@
#include "libda/fft.hpp"
#include <cmath>
-#include <iostream>
-#include <iomanip>
#include <numeric>
static const unsigned FFT_P = 11; // FFT size setting, will use 2^FFT_P sample FFT
@@ -14,23 +12,10 @@ static const std::size_t FFT_STEP = 512; // Step size in samples, should be <=
static const double FFT_MINFREQ = 45.0;
static const double FFT_MAXFREQ = 3000.0;
-Tone::Tone():
- freq(),
- freqSlow(),
- level(),
- levelSlow(),
- age()
-{
+Tone::Tone(): freq(), level() {
for (std::size_t i = 0; i < MAXHARM; ++i) harmonics[i] = 0.0;
}
-void Tone::print() const {
- if (age < Tone::MINAGE) return;
- std::cout << std::fixed << std::setprecision(1) << freq << " Hz, age " << age << ", " << level2dB(level) << " dB:";
- for (std::size_t i = 0; i < 8; ++i) std::cout << " " << harmonics[i];
- std::cout << std::endl;
-}
-
bool Tone::operator==(double f) const {
return std::abs(freq / f - 1.0) < 0.03; // Half semitone
}
@@ -161,7 +146,7 @@ void Analyzer::calcTones() {
}
if (miss) ++misses;
}
- t.freqSlow = t.freq /= t.level; // Average instead of sum
+ t.freq /= t.level; // Average instead of sum
if (score > bestScore) {
bestScore = score;
bestTone = t;
@@ -179,15 +164,17 @@ void Analyzer::calcTones() {
else ++it2;
}
}
-// std::cerr << std::endl;
- mergeWithOld(tones);
- m_tones.swap(tones);
+ temporalMerge(tones);
}
-void Analyzer::mergeWithOld(Tones& tones) const {
- Tones::iterator it = tones.begin();
+void Analyzer::temporalMerge(Tones& tones) {
+ /*Tones::iterator oldit;
+ for (Tones::const_iterator it = tones.begin(), itend = tones.end(); it != itend; ++it) {
+ if () oldit = std::find(
+ }
// Iterate over old tones
- for (Tones::const_iterator oldit = m_tones.begin(); oldit != m_tones.end(); ++oldit) {
+ for (ToneSeries::reverse_iterator oldit = m_toneSeries.rbegin(); oldit != m_toneSeries.rend(); ++oldit) {
+ if (
// Try to find a matching new tone
while (it != tones.end() && *it < *oldit) ++it;
// If match found
@@ -202,7 +189,8 @@ void Analyzer::mergeWithOld(Tones& tones) const {
t.level = 0.0;
t.levelSlow *= 0.01;
}
- }
+ }*/
+ m_moments.push_back(Moment(0.0, tones));
}
void Analyzer::process() {
@@ -210,7 +198,7 @@ void Analyzer::process() {
while (calcFFT()) calcTones();
}
-Tone const* Analyzer::findTone(double minfreq, double maxfreq) const {
+/*Tone const* Analyzer::findTone(double minfreq, double maxfreq) const {
Tone const* best = NULL;
double bestscore = -getInf();
for (Tones::const_iterator it = m_tones.begin(); it != m_tones.end(); ++it) {
@@ -226,5 +214,9 @@ Tone const* Analyzer::findTone(double minfreq, double maxfreq) const {
}
m_oldfreq = (best ? best->freq : 0.0);
return best;
+}*/
+
+Moment::Moment(double t, Tones& tones): m_time(t) {
+ m_tones.swap(tones);
}
diff --git a/pitch.hh b/pitch.hh
index 402f73d..eb1327e 100644
--- a/pitch.hh
+++ b/pitch.hh
@@ -23,8 +23,9 @@ struct Tone {
struct Moment {
typedef std::list<Tone> Tones;
- Tones tones;
- double time;
+ Tones m_tones;
+ double m_time;
+ Moment(double t, Tones& tones);
};
/// A peak contains information about a single frequency
@@ -83,9 +84,9 @@ public:
/** Get the peak level in dB (negative value, 0.0 means clipping, sometimes clipping may occur at lower levels too). **/
double getLevel() const { return 10.0 * log10(m_level); }
/** Get a list of all tones detected. **/
- Tones const& getTones() const;
+ Tones const& getTones() const { return m_moments.back().m_tones; /* FIXME */ }
/** Find a tone within the singing range; prefers strong tones around 200-400 Hz. **/
- Tone const* findTone(double minfreq = 70.0, double maxfreq = 700.0) const;
+ //Tone const* findTone(double minfreq = 70.0, double maxfreq = 700.0) const;
std::string const& getId() const { return m_id; }
private:
@@ -102,6 +103,6 @@ private:
mutable double m_oldfreq;
bool calcFFT();
void calcTones();
- void mergeWithSeries(Tones const& tones);
+ void temporalMerge(Tones& tones);
};
diff --git a/pitchvis.cc b/pitchvis.cc
index 5bcca18..1fd4da7 100644
--- a/pitchvis.cc
+++ b/pitchvis.cc
@@ -69,10 +69,9 @@ PitchVis::PitchVis(std::string const& filename, QWidget *parent): QWidget(parent
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) {
- if (it->age < Tone::MINAGE) continue;
- unsigned y = freq2px(it->freqSlow);
+ unsigned y = freq2px(it->freq);
if (y == 0 || y >= height - 1) continue;
- float value = 0.003 * (level2dB(it->levelSlow) + 80.0);
+ float value = 0.003 * (level2dB(it->level) + 80.0);
if (value <= 0.0) continue;
Pixel p(0.0f, value, 0.0f);
for (int j = int(y) - 2; j <= int(y) + 2; ++j) pixel(x, j) += p;
|
|
From: Lasse Kärkkäi. <tr...@us...> - 2011-01-20 10:34:55
|
Module: editor
Branch: master
Commit: dbe2361ae71fd77be88edcaff6eb59e4e9cc2751
Author: Lasse Karkkainen <tro...@tr...>
Date: Wed Jan 19 19:14:45 2011 +0100
Pitch timeseries tracking header (implementation still WIP)
---
pitch.hh | 21 +++++++++++----------
1 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/pitch.hh b/pitch.hh
index bfe6240..402f73d 100644
--- a/pitch.hh
+++ b/pitch.hh
@@ -13,18 +13,18 @@ static inline double dB2level(double db) { return std::pow(10.0, db / 20.0); }
/// A tone is a collection of a base frequency (freq) and all its harmonics
struct Tone {
static const std::size_t MAXHARM = 16; ///< The maximum number of harmonics tracked
- static const std::size_t MINAGE = 2; ///< The minimum age required for a tone to be output
double freq; ///< Frequency (Hz)
- double freqSlow; ///< Stable frequency
double level; ///< Level (linear)
- double levelSlow; ///< Stable level, useful for graphics rendering
double harmonics[MAXHARM]; ///< Harmonics' levels
- std::size_t age; ///< How many times the tone has been detected in row
Tone();
- void print() const; ///< Prints Tone to std::cout
bool operator==(double f) const; ///< Compare for rough frequency match
- /// Less-than compare by levels (instead of frequencies like operator< does)
- static bool levelCompare(Tone const& l, Tone const& r) { return l.levelSlow < r.levelSlow; }
+ // Linked list of a contin
+};
+
+struct Moment {
+ typedef std::list<Tone> Tones;
+ Tones tones;
+ double time;
};
/// A peak contains information about a single frequency
@@ -52,6 +52,7 @@ public:
typedef std::vector<std::complex<float> > Fourier; ///< FFT vector (the first level of detection)
typedef std::vector<Peak> Peaks; ///< Peaks (the second level of detection)
typedef std::list<Tone> Tones; ///< Tones (the final level of detection)
+ typedef std::list<Moment> Moments; ///< Time-serie history of time and tones
/// constructor
Analyzer(double rate, std::string id);
/** Add input data to buffer. This is thread-safe (against other functions). **/
@@ -82,7 +83,7 @@ public:
/** Get the peak level in dB (negative value, 0.0 means clipping, sometimes clipping may occur at lower levels too). **/
double getLevel() const { return 10.0 * log10(m_level); }
/** Get a list of all tones detected. **/
- Tones const& getTones() const { return m_tones; }
+ Tones const& getTones() const;
/** Find a tone within the singing range; prefers strong tones around 200-400 Hz. **/
Tone const* findTone(double minfreq = 70.0, double maxfreq = 700.0) const;
std::string const& getId() const { return m_id; }
@@ -97,10 +98,10 @@ private:
std::vector<float> m_fftLastPhase;
double m_level;
Peaks m_peaks;
- Tones m_tones;
+ Moments m_moments;
mutable double m_oldfreq;
bool calcFFT();
void calcTones();
- void mergeWithOld(Tones& tones) const;
+ void mergeWithSeries(Tones const& tones);
};
|
|
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;
|
|
From: Tapio V. <aa...@us...> - 2011-01-20 09:29:53
|
Module: editor
Branch: master
Commit: 64406d22d541dde789cba496a7049a270e3da753
Author: Tapio Vierros <tap...@gm...>
Date: Thu Jan 20 11:28:52 2011 +0200
Move pitch pixmap applying to pitchvis.
This is preparation for threading.
---
notegraphwidget.cc | 18 ------------------
pitchvis.cc | 26 +++++++++++++++++++++++++-
2 files changed, 25 insertions(+), 19 deletions(-)
diff --git a/notegraphwidget.cc b/notegraphwidget.cc
index c2e91b7..97a07e3 100644
--- a/notegraphwidget.cc
+++ b/notegraphwidget.cc
@@ -110,24 +110,6 @@ void NoteGraphWidget::finalizeNewLyrics()
void NoteGraphWidget::analyzeMusic(QString filepath)
{
m_pitch.reset(new PitchVis(filepath.toStdString(), this));
- unsigned width = m_pitch->width(), height = m_pitch->height;
- QProgressDialog progress(tr("Rendering pitch data..."), tr("&Abort"), 0, width, this);
- progress.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) {
- progress.setValue(x);
- if (progress.wasCanceled()) break;
-
- for (unsigned y = 0; y < height; ++y) {
- rgba[y * width + x] = m_pitch->pixel(x, y).rgba();
- }
- }
- setPixmap(QPixmap::fromImage(image));
- progress.setValue(width);
-
- setFixedSize(width, height);
}
int NoteGraphWidget::getNoteLabelId(NoteLabel* note) const
diff --git a/pitchvis.cc b/pitchvis.cc
index 5bcca18..2e68940 100644
--- a/pitchvis.cc
+++ b/pitchvis.cc
@@ -6,6 +6,7 @@
#include <iostream>
#include <stdexcept>
#include <QProgressDialog>
+#include <QLabel>
/** Read the entire file into a vector of some type.
The file needs to be in the machine-native endianess. **/
@@ -39,7 +40,7 @@ PitchVis::PitchVis(std::string const& filename, QWidget *parent): QWidget(parent
progress.setLabelText(tr("Analyzing pitch data..."));
for (unsigned x = 0; x < width; ++x) {
progress.setValue(x);
- if (progress.wasCanceled()) return;
+ if (progress.wasCanceled()) break;
// Get decoded samples from ffmpeg
std::vector<float> data(step*2);
@@ -79,6 +80,29 @@ PitchVis::PitchVis(std::string const& filename, QWidget *parent): QWidget(parent
}
}
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();
+ }
+ }
+
+ 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)); }
|
|
From: Tapio V. <aa...@us...> - 2011-01-20 09:29:50
|
Module: editor
Branch: master
Commit: dc3463b3dd3effc6b3402f0c6c8c5f0fdbdd79d0
Author: Tapio Vierros <tap...@gm...>
Date: Thu Jan 20 11:07:38 2011 +0200
Make SeekHandle invisibly wider for easier grabbing.
---
notegraphwidget.cc | 10 ++++++----
1 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/notegraphwidget.cc b/notegraphwidget.cc
index 22d2f00..c2e91b7 100644
--- a/notegraphwidget.cc
+++ b/notegraphwidget.cc
@@ -457,12 +457,14 @@ SeekHandle::SeekHandle(QWidget *parent)
: QLabel(parent)
{
// FIXME: height from notegraph
- QImage image(8, 768, QImage::Format_ARGB32_Premultiplied);
+ QImage image(16, 768, QImage::Format_ARGB32_Premultiplied);
image.fill(qRgba(0, 0, 0, 0));
QLinearGradient gradient(0, 0, image.width()-1, 0);
- gradient.setColorAt(0.0, QColor(255,255,0,50));
- gradient.setColorAt(0.5, QColor(255,255,0,200));
- gradient.setColorAt(1.0, QColor(255,255,0,50));
+ gradient.setColorAt(0.00, QColor(255,255,0,0));
+ gradient.setColorAt(0.25, QColor(255,255,0,50));
+ gradient.setColorAt(0.50, QColor(255,255,0,200));
+ gradient.setColorAt(0.75, QColor(255,255,0,50));
+ gradient.setColorAt(1.00, QColor(255,255,0,0));
QPainter painter;
painter.begin(&image);
|
|
From: Tapio V. <aa...@us...> - 2011-01-20 09:04:02
|
Module: editor
Branch: master
Commit: 70da8ed859cec6b85bdfdfed4bb5b44a2eeacaa2
Author: Tapio Vierros <tap...@gm...>
Date: Thu Jan 20 11:03:19 2011 +0200
Primitive SeekHandle movement smoothener.
---
editorapp.cc | 25 +++++++++++++++++--------
editorapp.hh | 2 ++
notegraphwidget.cc | 16 ++++++++++++++--
notegraphwidget.hh | 8 ++++++--
4 files changed, 39 insertions(+), 12 deletions(-)
diff --git a/editorapp.cc b/editorapp.cc
index f2c7ecb..7fca538 100644
--- a/editorapp.cc
+++ b/editorapp.cc
@@ -1,5 +1,4 @@
#include <QtGui>
-#include <phonon/MediaObject>
#include <phonon/AudioOutput>
#include <iostream>
#include "editorapp.hh"
@@ -72,6 +71,7 @@ EditorApp::EditorApp(QWidget *parent): QMainWindow(parent), projectFileName(), h
Phonon::createPath(player, audioOutput);
// Audio signals
connect(player, SIGNAL(tick(qint64)), this, SLOT(audioTick(qint64)));
+ connect(player, SIGNAL(stateChanged(Phonon::State,Phonon::State)), this, SLOT(playerStateChanged(Phonon::State,Phonon::State)));
connect(player, SIGNAL(metaDataChanged()), this, SLOT(metaDataChanged()));
connect(noteGraph, SIGNAL(seek(qint64)), player, SLOT(seek(qint64)));
}
@@ -406,7 +406,7 @@ void EditorApp::on_actionLyricsFromClipboard_triggered()
void EditorApp::on_actionWhatsThis_triggered()
{
- QWhatsThis::enterWhatsThisMode ();
+ QWhatsThis::enterWhatsThisMode();
}
void EditorApp::on_actionAbout_triggered()
@@ -456,11 +456,6 @@ void EditorApp::metaDataChanged()
}
}
-void EditorApp::audioTick(qint64 time)
-{
- if (noteGraph) noteGraph->updateMusicPos(time);
-}
-
void EditorApp::on_cmdPlay_toggled(bool checked)
{
if (player) {
@@ -484,10 +479,24 @@ void EditorApp::on_cmdPlay_toggled(bool checked)
void EditorApp::on_cmdStop_clicked()
{
if (player) player->stop();
- if (noteGraph) noteGraph->updateMusicPos(0);
+ if (noteGraph) noteGraph->updateMusicPos(0, false);
ui.cmdPlay->setChecked(false);
}
+void EditorApp::audioTick(qint64 time)
+{
+ if (noteGraph && player)
+ noteGraph->updateMusicPos(time, (player->state() == Phonon::PlayingState ? true : false));
+}
+
+void EditorApp::playerStateChanged(Phonon::State newstate, Phonon::State oldstate)
+{
+ (void)oldstate;
+ if (newstate != Phonon::PlayingState) {
+ noteGraph->stopMusic();
+ }
+}
+
void EditorApp::on_txtTitle_editingFinished() { updateSongMeta(); }
void EditorApp::on_txtArtist_editingFinished() { updateSongMeta(); }
void EditorApp::on_txtGenre_editingFinished() { updateSongMeta(); }
diff --git a/editorapp.hh b/editorapp.hh
index 276030f..16540f8 100644
--- a/editorapp.hh
+++ b/editorapp.hh
@@ -1,5 +1,6 @@
#pragma once
+#include <phonon/MediaObject>
#include "ui_editor.h"
#include "operation.hh"
#include "song.hh"
@@ -31,6 +32,7 @@ public slots:
void updateNoteInfo(NoteLabel *note);
void metaDataChanged();
void audioTick(qint64 time);
+ void playerStateChanged(Phonon::State newstate, Phonon::State olstate);
// Automatic slots
diff --git a/notegraphwidget.cc b/notegraphwidget.cc
index 4c189ec..22d2f00 100644
--- a/notegraphwidget.cc
+++ b/notegraphwidget.cc
@@ -186,10 +186,18 @@ void NoteGraphWidget::updateNotes()
}
}
-void NoteGraphWidget::updateMusicPos(qint64 time)
+void NoteGraphWidget::updateMusicPos(qint64 time, bool smoothing)
{
int x = s2px(time / 1000.0) - m_seekHandle.width() / 2;
+ m_seekHandle.killTimer(m_seekHandle.moveTimerId);
m_seekHandle.move(x, 0);
+ if (smoothing)
+ m_seekHandle.moveTimerId = m_seekHandle.startTimer(px2s(1) * 1000);
+}
+
+void NoteGraphWidget::stopMusic()
+{
+ m_seekHandle.killTimer(m_seekHandle.moveTimerId);
}
void NoteGraphWidget::mousePressEvent(QMouseEvent *event)
@@ -320,7 +328,6 @@ void NoteGraphWidget::mouseMoveEvent(QMouseEvent *event)
// Seeking
if (m_seeking) {
QPoint diff = event->pos() - m_panHotSpot;
- std::cout << diff.x() << " " << event->pos().x() << " " << m_panHotSpot.x() << std::endl;
m_seekHandle.move(m_panHotSpot.x() + diff.x(), 0);
emit seek(1000 * px2s(m_seekHandle.x()));
}
@@ -474,6 +481,11 @@ void SeekHandle::mouseMoveEvent(QMouseEvent *event)
event->ignore();
}
+void SeekHandle::timerEvent(QTimerEvent *event)
+{
+ move(x() + 1, 0);
+}
+
void FloatingGap::addNote(NoteLabel* n)
diff --git a/notegraphwidget.hh b/notegraphwidget.hh
index e4ab11a..e100453 100644
--- a/notegraphwidget.hh
+++ b/notegraphwidget.hh
@@ -16,7 +16,10 @@ class SeekHandle: public QLabel
Q_OBJECT
public:
SeekHandle(QWidget *parent = 0);
+ int moveTimerId;
+protected:
void mouseMoveEvent(QMouseEvent *event);
+ void timerEvent(QTimerEvent *event);
};
@@ -33,7 +36,9 @@ public:
void setLyrics(const VocalTrack &track);
void analyzeMusic(QString filepath);
void updateNotes();
- void updateMusicPos(qint64 time);
+
+ void updateMusicPos(qint64 time, bool smoothing);
+ void stopMusic();
void selectNote(NoteLabel *note);
NoteLabel* selectedNote() const { return m_selectedNote; }
@@ -48,7 +53,6 @@ public:
int px2n(int px) const;
int h() const { return m_pitch->height; }
-
signals:
void updateNoteInfo(NoteLabel*);
void operationDone(const Operation&);
|