changeset 921:4968bbaf1ed8 tonioni

Merge from default branch
author Chris Cannam
date Mon, 23 Mar 2015 10:04:51 +0000
parents b62c2785ed83 (current diff) 78e041e45ff0 (diff)
children 26da827e8fb5
files view/Pane.cpp
diffstat 7 files changed, 510 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/layer/TimeValueLayer.cpp	Tue Nov 11 17:05:44 2014 +0000
+++ b/layer/TimeValueLayer.cpp	Mon Mar 23 10:04:51 2015 +0000
@@ -1151,6 +1151,7 @@
 			// path.quadTo(x0, y0, (x0 + x1) / 2, (y0 + y1) / 2);
 
 		    } else {
+                        path.lineTo(x0, y0);
 			path.lineTo((x0 + x1) / 2, (y0 + y1) / 2);
 		    }
 		}
--- a/svgui.pro	Tue Nov 11 17:05:44 2014 +0000
+++ b/svgui.pro	Mon Mar 23 10:04:51 2015 +0000
@@ -136,6 +136,7 @@
            widgets/Thumbwheel.h \
            widgets/TipDialog.h \
            widgets/TransformFinder.h \
+           widgets/UnitConverter.h \
            widgets/WindowShapePreview.h \
            widgets/WindowTypeSelector.h
 SOURCES += widgets/ActivityLog.cpp \
@@ -173,5 +174,6 @@
            widgets/Thumbwheel.cpp \
            widgets/TipDialog.cpp \
            widgets/TransformFinder.cpp \
+           widgets/UnitConverter.cpp \
            widgets/WindowShapePreview.cpp \
            widgets/WindowTypeSelector.cpp
--- a/view/Pane.cpp	Tue Nov 11 17:05:44 2014 +0000
+++ b/view/Pane.cpp	Mon Mar 23 10:04:51 2015 +0000
@@ -2024,6 +2024,11 @@
 
     int smallThreshold = 10, bigThreshold = 80;
 
+    if (m_manager) {
+        smallThreshold = m_manager->scalePixelSize(smallThreshold);
+        bigThreshold = m_manager->scalePixelSize(bigThreshold);
+    }
+
 //    SVDEBUG << "Pane::updateDragMode: xdiff = " << xdiff << ", ydiff = "
 //              << ydiff << ", canMoveVertical = " << canMoveVertical << ", drag mode = " << m_dragMode << endl;
 
@@ -2288,7 +2293,7 @@
 
         // Sometimes on Linux we're seeing absurdly extreme angles on
         // the first wheel event -- discard those entirely
-        if (abs(m_pendingWheelAngle) >= 600) {
+        if (abs(m_pendingWheelAngle) > 1000) {
             m_pendingWheelAngle = 0;
             return;
         }
--- a/view/ViewManager.cpp	Tue Nov 11 17:05:44 2014 +0000
+++ b/view/ViewManager.cpp	Mon Mar 23 10:04:51 2015 +0000
@@ -720,3 +720,23 @@
     return dark;
 }
 
+int
+ViewManager::scalePixelSize(int pixels)
+{
+    static float ratio = 0.f;
+    if (ratio == 0.f) {
+        float baseEm;
+#ifdef Q_OS_MAC
+        baseEm = 17.f;
+#else
+        baseEm = 15.f;
+#endif
+        float em = QFontMetrics(QFont()).height();
+        ratio = em / baseEm;
+    }
+
+    int scaled = int(pixels * ratio + 0.5);
+    cerr << "scaledSize: " << pixels << " -> " << scaled << " at ratio " << ratio << endl;
+    if (pixels != 0 && scaled == 0) scaled = 1;
+    return scaled;
+}
--- a/view/ViewManager.h	Tue Nov 11 17:05:44 2014 +0000
+++ b/view/ViewManager.h	Mon Mar 23 10:04:51 2015 +0000
@@ -184,6 +184,13 @@
 
     void setMainModelSampleRate(int sr) { m_mainModelSampleRate = sr; }
 
+    /**
+     * Take a "design pixel" size and scale it for the actual
+     * display. This is relevant to hi-dpi systems that do not do
+     * pixel doubling (i.e. Windows and Linux rather than OS/X).
+     */
+    int scalePixelSize(int pixels);
+    
     enum OverlayMode {
         NoOverlays,
         GlobalOverlays,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/widgets/UnitConverter.cpp	Mon Mar 23 10:04:51 2015 +0000
@@ -0,0 +1,401 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Sonic Visualiser
+    An audio file viewer and annotation editor.
+    Centre for Digital Music, Queen Mary, University of London.
+    
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#include "UnitConverter.h"
+
+#include <QSpinBox>
+#include <QComboBox>
+#include <QDoubleSpinBox>
+#include <QLabel>
+#include <QDialogButtonBox>
+#include <QGridLayout>
+#include <QTabWidget>
+
+#include "base/Debug.h"
+#include "base/Pitch.h"
+#include "base/Preferences.h"
+
+using namespace std;
+
+static QString pianoNotes[] = {
+    "C", "C# / Db", "D", "D# / Eb", "E",
+    "F", "F# / Gb", "G", "G# / Ab", "A", "A# / Bb", "B"
+};
+
+UnitConverter::UnitConverter(QWidget *parent) :
+    QDialog(parent)
+{
+    QGridLayout *maingrid = new QGridLayout;
+    setLayout(maingrid);
+    
+    QTabWidget *tabs = new QTabWidget;
+    maingrid->addWidget(tabs, 0, 0);
+    
+    QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Close);
+    maingrid->addWidget(bb, 1, 0);
+    connect(bb, SIGNAL(rejected()), this, SLOT(close()));
+    
+    QFrame *frame = new QFrame;
+    tabs->addTab(frame, tr("Pitch"));
+    
+    QGridLayout *grid = new QGridLayout;
+    frame->setLayout(grid);
+
+    m_freq = new QDoubleSpinBox;
+    m_freq->setSuffix(QString(" Hz"));
+    m_freq->setDecimals(6);
+    m_freq->setMinimum(1e-3);
+    m_freq->setMaximum(1e6);
+    m_freq->setValue(440);
+    connect(m_freq, SIGNAL(valueChanged(double)),
+	    this, SLOT(freqChanged()));
+
+    // The min and max range values for all the remaining controls are
+    // determined by the min and max Hz above
+    
+    m_midi = new QSpinBox;
+    m_midi->setMinimum(-156);
+    m_midi->setMaximum(203);
+    connect(m_midi, SIGNAL(valueChanged(int)),
+	    this, SLOT(midiChanged()));
+
+    m_note = new QComboBox;
+    for (int i = 0; i < 12; ++i) {
+	m_note->addItem(pianoNotes[i]);
+    }
+    connect(m_note, SIGNAL(currentIndexChanged(int)),
+	    this, SLOT(noteChanged()));
+
+    m_octave = new QSpinBox;
+    m_octave->setMinimum(-14);
+    m_octave->setMaximum(15);
+    connect(m_octave, SIGNAL(valueChanged(int)),
+	    this, SLOT(octaveChanged()));
+
+    m_cents = new QDoubleSpinBox;
+    m_cents->setSuffix(tr(" cents"));
+    m_cents->setDecimals(4);
+    m_cents->setMinimum(-50);
+    m_cents->setMaximum(50);
+    connect(m_cents, SIGNAL(valueChanged(double)),
+	    this, SLOT(centsChanged()));
+    
+    int row = 0;
+
+    grid->addWidget(new QLabel(tr("In 12-tone Equal Temperament:")), row, 0, 1, 9);
+
+    ++row;
+    
+    grid->setRowMinimumHeight(row, 8);
+
+    ++row;
+    
+    grid->addWidget(m_freq, row, 0, 2, 1, Qt::AlignRight | Qt::AlignVCenter);
+    grid->addWidget(new QLabel(tr("=")), row, 1, 2, 1, Qt::AlignHCenter | Qt::AlignVCenter);
+
+    grid->addWidget(new QLabel(tr("+")), row, 7, 2, 1, Qt::AlignHCenter | Qt::AlignVCenter);
+    grid->addWidget(m_cents, row, 8, 2, 1, Qt::AlignLeft | Qt::AlignVCenter);
+
+    grid->addWidget(new QLabel(tr("Piano note")), row, 2, 1, 2);
+    grid->addWidget(m_note, row, 4);
+    grid->addWidget(new QLabel(tr("in octave")), row, 5);
+    grid->addWidget(m_octave, row, 6);
+
+    ++row;
+    
+    grid->addWidget(new QLabel(tr("MIDI pitch")), row, 2, 1, 2);
+    grid->addWidget(m_midi, row, 4);
+    
+    ++row;
+
+    grid->setRowStretch(row, 20);
+    grid->setRowMinimumHeight(row, 8);
+
+    ++row;
+
+    m_pitchPrefsLabel = new QLabel;
+    grid->addWidget(m_pitchPrefsLabel, row, 0, 1, 9);
+
+    ++row;
+    
+    grid->addWidget
+	(new QLabel(tr("Note that only pitches in the range 0 to 127 are valid "
+		       "in the MIDI protocol.")),
+	 row, 0, 1, 9);
+
+    ++row;
+    
+    frame = new QFrame;
+    tabs->addTab(frame, tr("Tempo"));
+    
+    grid = new QGridLayout;
+    frame->setLayout(grid);
+
+    m_samples = new QDoubleSpinBox;
+    m_samples->setSuffix(QString(" samples"));
+    m_samples->setDecimals(2);
+    m_samples->setMinimum(1);
+    m_samples->setMaximum(1e8);
+    m_samples->setValue(22050);
+    connect(m_samples, SIGNAL(valueChanged(double)),
+	    this, SLOT(samplesChanged()));
+    
+    m_period = new QDoubleSpinBox;
+    m_period->setSuffix(QString(" ms"));
+    m_period->setDecimals(4);
+    m_period->setMinimum(1e-3);
+    m_period->setMaximum(100000);
+    m_period->setValue(500);
+    connect(m_period, SIGNAL(valueChanged(double)),
+	    this, SLOT(periodChanged()));
+
+    m_bpm = new QDoubleSpinBox;
+    m_bpm->setSuffix(QString(" bpm"));
+    m_bpm->setDecimals(4);
+    m_bpm->setMinimum(0.1);
+    m_bpm->setMaximum(1e6);
+    m_bpm->setValue(120);
+    connect(m_bpm, SIGNAL(valueChanged(double)),
+	    this, SLOT(bpmChanged()));
+
+    m_tempofreq = new QDoubleSpinBox;
+    m_tempofreq->setSuffix(QString(" beats/sec"));
+    m_tempofreq->setDecimals(4);
+    m_tempofreq->setMinimum(1e-3);
+    m_tempofreq->setMaximum(1e5);
+    m_tempofreq->setValue(0.5);
+
+    connect(m_tempofreq, SIGNAL(valueChanged(double)),
+	    this, SLOT(tempofreqChanged()));
+	
+    m_samplerate = new QComboBox;
+    QList<int> rates;
+    rates << 8000;
+    for (int i = 1; i <= 16; i *= 2) {
+	rates << 11025 * i << 12000 * i;
+    }
+    foreach (int r, rates) {
+	m_samplerate->addItem(QString("%1 Hz").arg(r));
+    }
+    connect(m_samplerate, SIGNAL(currentIndexChanged(int)),
+	    this, SLOT(samplerateChanged()));
+    m_samplerate->setCurrentText("44100 Hz");
+    
+    connect(Preferences::getInstance(),
+	    SIGNAL(propertyChanged(PropertyContainer::PropertyName)),
+	    this, SLOT(preferenceChanged(PropertyContainer::PropertyName)));
+
+    row = 0;
+
+    grid->setRowStretch(row, 20);
+    grid->setRowMinimumHeight(row, 8);
+
+    ++row;
+
+    grid->addWidget(new QLabel(tr("Beat period")), row, 0, 2, 1, Qt::AlignVCenter);
+    grid->addWidget(m_period, row, 1);
+    grid->addWidget(new QLabel(tr("=")), row, 2, 2, 1, Qt::AlignVCenter);
+
+    grid->addWidget(m_tempofreq, row, 3);
+
+    grid->addWidget(new QLabel(tr("at")), row, 4, 2, 1, Qt::AlignVCenter);
+    grid->addWidget(m_samplerate, row, 5, 2, 1, Qt::AlignVCenter);
+
+    ++row;
+    
+    grid->addWidget(m_samples, row, 1);
+    grid->addWidget(m_bpm, row, 3);
+
+    ++row;
+    
+    grid->setRowStretch(row, 20);
+    grid->setRowMinimumHeight(row, 8);
+    
+    updatePitchesFromFreq();
+    updatePitchPrefsLabel();
+    updateTempiFromSamples();
+}
+
+UnitConverter::~UnitConverter()
+{
+}
+
+void
+UnitConverter::setTo(QSpinBox *box, int value)
+{
+    box->blockSignals(true);
+    if (value < box->minimum() || value > box->maximum()) {
+	QPalette p;
+	p.setColor(QPalette::Text, Qt::red);
+	box->setPalette(p);
+    } else {
+	box->setPalette(QPalette());
+    }
+    box->setValue(value);
+    box->blockSignals(false);
+}
+
+void
+UnitConverter::setTo(QDoubleSpinBox *box, double value)
+{
+    box->blockSignals(true);
+    if (value < box->minimum() || value > box->maximum()) {
+	QPalette p;
+	p.setColor(QPalette::Text, Qt::red);
+	box->setPalette(p);
+    } else {
+	box->setPalette(QPalette());
+    }
+    box->setValue(value);
+    box->blockSignals(false);
+}
+
+void
+UnitConverter::preferenceChanged(PropertyContainer::PropertyName)
+{
+    updatePitchesFromFreq();
+    updatePitchPrefsLabel();
+}
+
+void
+UnitConverter::updatePitchPrefsLabel()
+{
+    m_pitchPrefsLabel->setText
+	(tr("With concert-A tuning frequency at %1 Hz, and "
+	    "middle C residing in octave %2.\n"
+	    "(These can be changed in the application preferences.)")
+	 .arg(Preferences::getInstance()->getTuningFrequency())
+	 .arg(Preferences::getInstance()->getOctaveOfMiddleC()));
+}
+
+void
+UnitConverter::freqChanged()
+{
+    updatePitchesFromFreq();
+}
+
+void
+UnitConverter::midiChanged()
+{
+    double freq = Pitch::getFrequencyForPitch(m_midi->value(), m_cents->value());
+    m_freq->setValue(freq);
+}
+
+void
+UnitConverter::noteChanged()
+{
+    int pitch = Pitch::getPitchForNoteAndOctave(m_note->currentIndex(),
+						m_octave->value());
+    double freq = Pitch::getFrequencyForPitch(pitch, m_cents->value());
+    m_freq->setValue(freq);
+}
+
+void
+UnitConverter::octaveChanged()
+{
+    int pitch = Pitch::getPitchForNoteAndOctave(m_note->currentIndex(),
+						m_octave->value());
+    double freq = Pitch::getFrequencyForPitch(pitch, m_cents->value());
+    m_freq->setValue(freq);
+}
+
+void
+UnitConverter::centsChanged()
+{
+    double freq = Pitch::getFrequencyForPitch(m_midi->value(), m_cents->value());
+    m_freq->setValue(freq);
+}
+
+void
+UnitConverter::updatePitchesFromFreq()
+{
+    double cents = 0;
+    int pitch = Pitch::getPitchForFrequency(m_freq->value(), &cents);
+    int note, octave;
+    Pitch::getNoteAndOctaveForPitch(pitch, note, octave);
+
+    cerr << "pitch " << pitch << " note " << note << " octave " << octave << " cents " << cents << endl;
+
+    setTo(m_midi, pitch);
+    setTo(m_cents, cents);
+    setTo(m_octave, octave);
+
+    m_note->blockSignals(true);
+    m_note->setCurrentIndex(note);
+    m_note->blockSignals(false);
+}
+
+void
+UnitConverter::samplesChanged()
+{
+    updateTempiFromSamples();
+}
+
+void
+UnitConverter::periodChanged()
+{
+    double rate = getSampleRate();
+    double sec = m_period->value() / 1000.0;
+    double samples = rate * sec;
+    m_samples->setValue(samples);
+}
+
+void
+UnitConverter::bpmChanged()
+{
+    double rate = getSampleRate();
+    double sec = 60.0 / m_bpm->value();
+    double samples = rate * sec;
+    m_samples->setValue(samples);
+}
+
+void
+UnitConverter::tempofreqChanged()
+{
+    double rate = getSampleRate();
+    double samples = rate / m_tempofreq->value();
+    m_samples->setValue(samples);
+}
+
+void
+UnitConverter::samplerateChanged()
+{
+    // Preserve the beat period in seconds, here, not in samples
+    periodChanged();
+}
+
+double
+UnitConverter::getSampleRate()
+{
+    return double(atoi(m_samplerate->currentText().toLocal8Bit().data()));
+}
+
+void
+UnitConverter::updateTempiFromSamples()
+{
+    double samples = m_samples->value();
+    double rate = getSampleRate();
+
+    cerr << samples << " samples at rate " << rate << endl;
+
+    double sec = samples / rate;
+    double hz = rate / samples;
+    double bpm = 60.0 / sec;
+
+    setTo(m_bpm, bpm);
+    setTo(m_period, sec * 1000.0);
+    setTo(m_tempofreq, hz);
+}
+
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/widgets/UnitConverter.h	Mon Mar 23 10:04:51 2015 +0000
@@ -0,0 +1,73 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Sonic Visualiser
+    An audio file viewer and annotation editor.
+    Centre for Digital Music, Queen Mary, University of London.
+    
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#ifndef UNIT_CONVERTER_H
+#define UNIT_CONVERTER_H
+
+#include <QDialog>
+
+#include "base/PropertyContainer.h"
+
+class QSpinBox;
+class QDoubleSpinBox;
+class QComboBox;
+class QLabel;
+
+class UnitConverter : public QDialog
+{
+    Q_OBJECT
+
+public:
+    UnitConverter(QWidget *parent = 0);
+    virtual ~UnitConverter();
+
+private slots:
+    void freqChanged();
+    void midiChanged();
+    void noteChanged();
+    void octaveChanged();
+    void centsChanged();
+
+    void samplesChanged();
+    void periodChanged();
+    void bpmChanged();
+    void tempofreqChanged();
+    void samplerateChanged();
+    
+    void preferenceChanged(PropertyContainer::PropertyName);
+    
+private:
+    QDoubleSpinBox *m_freq;
+    QSpinBox *m_midi;
+    QComboBox *m_note;
+    QSpinBox *m_octave;
+    QDoubleSpinBox *m_cents;
+    QLabel *m_pitchPrefsLabel;
+    void updatePitchesFromFreq();
+    void updatePitchPrefsLabel();
+
+    QDoubleSpinBox *m_samples;
+    QDoubleSpinBox *m_period;
+    QDoubleSpinBox *m_bpm;
+    QDoubleSpinBox *m_tempofreq;
+    QComboBox *m_samplerate;
+    void updateTempiFromSamples();
+
+    double getSampleRate();
+
+    void setTo(QSpinBox *, int);
+    void setTo(QDoubleSpinBox *, double);
+};
+
+#endif