annotate widgets/UnitConverter.cpp @ 892:af63372e9002

Start connecting up tempo bits
author Chris Cannam
date Tue, 09 Dec 2014 13:53:44 +0000
parents 09b2940f483a
children 78ae34f388f6
rev   line source
Chris@885 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@885 2
Chris@885 3 /*
Chris@885 4 Sonic Visualiser
Chris@885 5 An audio file viewer and annotation editor.
Chris@885 6 Centre for Digital Music, Queen Mary, University of London.
Chris@885 7
Chris@885 8 This program is free software; you can redistribute it and/or
Chris@885 9 modify it under the terms of the GNU General Public License as
Chris@885 10 published by the Free Software Foundation; either version 2 of the
Chris@885 11 License, or (at your option) any later version. See the file
Chris@885 12 COPYING included with this distribution for more information.
Chris@885 13 */
Chris@885 14
Chris@885 15 #include "UnitConverter.h"
Chris@885 16
Chris@885 17 #include <QSpinBox>
Chris@885 18 #include <QComboBox>
Chris@885 19 #include <QDoubleSpinBox>
Chris@885 20 #include <QLabel>
Chris@885 21 #include <QDialogButtonBox>
Chris@885 22 #include <QGridLayout>
Chris@889 23 #include <QTabWidget>
Chris@885 24
Chris@885 25 #include "base/Debug.h"
Chris@885 26 #include "base/Pitch.h"
Chris@888 27 #include "base/Preferences.h"
Chris@885 28
Chris@885 29 using namespace std;
Chris@885 30
Chris@886 31 static QString pianoNotes[] = {
Chris@886 32 "C", "C# / Db", "D", "D# / Eb", "E",
Chris@886 33 "F", "F# / Gb", "G", "G# / Ab", "A", "A# / Bb", "B"
Chris@886 34 };
Chris@886 35
Chris@885 36 UnitConverter::UnitConverter(QWidget *parent) :
Chris@885 37 QDialog(parent)
Chris@885 38 {
Chris@889 39 QGridLayout *maingrid = new QGridLayout;
Chris@889 40 setLayout(maingrid);
Chris@889 41
Chris@889 42 QTabWidget *tabs = new QTabWidget;
Chris@889 43 maingrid->addWidget(tabs, 0, 0);
Chris@889 44
Chris@889 45 QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Close);
Chris@889 46 maingrid->addWidget(bb, 1, 0);
Chris@889 47 connect(bb, SIGNAL(rejected()), this, SLOT(close()));
Chris@889 48
Chris@889 49 QFrame *frame = new QFrame;
Chris@889 50 tabs->addTab(frame, tr("Pitch"));
Chris@889 51
Chris@885 52 QGridLayout *grid = new QGridLayout;
Chris@889 53 frame->setLayout(grid);
Chris@885 54
Chris@889 55 m_freq = new QDoubleSpinBox;
Chris@889 56 m_freq->setSuffix(QString(" Hz"));
Chris@889 57 m_freq->setDecimals(6);
Chris@889 58 m_freq->setMinimum(1e-3);
Chris@889 59 m_freq->setMaximum(1e6);
Chris@889 60 m_freq->setValue(440);
Chris@889 61 connect(m_freq, SIGNAL(valueChanged(double)),
Chris@889 62 this, SLOT(freqChanged(double)));
Chris@885 63
Chris@888 64 // The min and max range values for all the remaining controls are
Chris@888 65 // determined by the min and max Hz above
Chris@888 66
Chris@885 67 m_midi = new QSpinBox;
Chris@888 68 m_midi->setMinimum(-156);
Chris@888 69 m_midi->setMaximum(203);
Chris@885 70 connect(m_midi, SIGNAL(valueChanged(int)),
Chris@885 71 this, SLOT(midiChanged(int)));
Chris@885 72
Chris@885 73 m_note = new QComboBox;
Chris@886 74 for (int i = 0; i < 12; ++i) {
Chris@886 75 m_note->addItem(pianoNotes[i]);
Chris@886 76 }
Chris@886 77 connect(m_note, SIGNAL(currentIndexChanged(int)),
Chris@886 78 this, SLOT(noteChanged(int)));
Chris@885 79
Chris@885 80 m_octave = new QSpinBox;
Chris@888 81 m_octave->setMinimum(-14);
Chris@888 82 m_octave->setMaximum(15);
Chris@886 83 connect(m_octave, SIGNAL(valueChanged(int)),
Chris@886 84 this, SLOT(octaveChanged(int)));
Chris@885 85
Chris@885 86 m_cents = new QDoubleSpinBox;
Chris@885 87 m_cents->setSuffix(tr(" cents"));
Chris@885 88 m_cents->setDecimals(4);
Chris@885 89 m_cents->setMinimum(-50);
Chris@885 90 m_cents->setMaximum(50);
Chris@885 91 connect(m_cents, SIGNAL(valueChanged(double)),
Chris@885 92 this, SLOT(centsChanged(double)));
Chris@885 93
Chris@886 94 int row = 1;
Chris@886 95
Chris@892 96 grid->addWidget(m_freq, row, 0, 2, 1, Qt::AlignRight | Qt::AlignVCenter);
Chris@892 97 grid->addWidget(new QLabel(tr("=")), row, 1, 2, 1, Qt::AlignHCenter | Qt::AlignVCenter);
Chris@885 98
Chris@892 99 grid->addWidget(new QLabel(tr("+")), row, 7, 2, 1, Qt::AlignHCenter | Qt::AlignVCenter);
Chris@892 100 grid->addWidget(m_cents, row, 8, 2, 1, Qt::AlignLeft | Qt::AlignVCenter);
Chris@885 101
Chris@886 102 grid->addWidget(new QLabel(tr("Piano note")), row, 2, 1, 2);
Chris@886 103 grid->addWidget(m_note, row, 4);
Chris@886 104 grid->addWidget(new QLabel(tr("in octave")), row, 5);
Chris@886 105 grid->addWidget(m_octave, row, 6);
Chris@886 106
Chris@886 107 ++row;
Chris@886 108
Chris@888 109 grid->addWidget(new QLabel(tr("MIDI pitch")), row, 2, 1, 2);
Chris@886 110 grid->addWidget(m_midi, row, 4);
Chris@886 111
Chris@886 112 ++row;
Chris@885 113
Chris@891 114 m_pitchPrefsLabel = new QLabel;
Chris@891 115 grid->addWidget(m_pitchPrefsLabel, row, 0, 1, 9);
Chris@888 116
Chris@888 117 ++row;
Chris@888 118
Chris@888 119 grid->addWidget
Chris@888 120 (new QLabel(tr("Note that only pitches in the range 0 to 127 are valid "
Chris@888 121 "in the MIDI protocol.")),
Chris@888 122 row, 0, 1, 9);
Chris@888 123
Chris@888 124 ++row;
Chris@891 125
Chris@891 126 frame = new QFrame;
Chris@891 127 tabs->addTab(frame, tr("Tempo"));
Chris@891 128
Chris@891 129 grid = new QGridLayout;
Chris@891 130 frame->setLayout(grid);
Chris@885 131
Chris@892 132 m_samples = new QDoubleSpinBox;
Chris@892 133 m_samples->setSuffix(QString(" samples"));
Chris@892 134 m_samples->setDecimals(3);
Chris@892 135 m_samples->setMinimum(2);
Chris@892 136 m_samples->setMaximum(1e10);
Chris@892 137 m_samples->setValue(22050);
Chris@892 138 connect(m_samples, SIGNAL(valueChanged(double)),
Chris@892 139 this, SLOT(samplesChanged(double)));
Chris@892 140
Chris@892 141 m_period = new QDoubleSpinBox;
Chris@892 142 m_period->setSuffix(QString(" ms"));
Chris@892 143 m_period->setDecimals(4);
Chris@892 144 m_period->setMinimum(1e-10);
Chris@892 145 m_period->setMaximum(1000);
Chris@892 146 m_period->setValue(500);
Chris@892 147 connect(m_period, SIGNAL(valueChanged(double)),
Chris@892 148 this, SLOT(periodChanged(double)));
Chris@892 149
Chris@892 150 m_bpm = new QDoubleSpinBox;
Chris@892 151 m_bpm->setSuffix(QString(" bpm"));
Chris@892 152 m_bpm->setDecimals(4);
Chris@892 153 m_bpm->setMinimum(0.1);
Chris@892 154 m_bpm->setMaximum(1e6);
Chris@892 155 m_bpm->setValue(120);
Chris@892 156 connect(m_bpm, SIGNAL(valueChanged(double)),
Chris@892 157 this, SLOT(bpmChanged(double)));
Chris@892 158
Chris@892 159 m_tempofreq = new QDoubleSpinBox;
Chris@892 160 m_tempofreq->setSuffix(QString(" beats/sec"));
Chris@892 161 m_tempofreq->setDecimals(4);
Chris@892 162 m_tempofreq->setMinimum(1e-4);
Chris@892 163 m_tempofreq->setMaximum(1e6);
Chris@892 164 m_tempofreq->setValue(0.5);
Chris@892 165 connect(m_tempofreq, SIGNAL(valueChanged(double)),
Chris@892 166 this, SLOT(tempofreqChanged(double)));
Chris@892 167
Chris@892 168 m_samplerate = new QComboBox;
Chris@892 169 QList<int> rates;
Chris@892 170 rates << 8000;
Chris@892 171 for (int i = 1; i <= 16; i *= 2) {
Chris@892 172 rates << 11025 * i << 12000 * i;
Chris@892 173 }
Chris@892 174 foreach (int r, rates) {
Chris@892 175 m_samplerate->addItem(QString("%1 Hz").arg(r));
Chris@892 176 }
Chris@892 177 connect(m_samplerate, SIGNAL(currentItemChanged(QString)),
Chris@892 178 this, SLOT(samplerateChanged(QString)));
Chris@892 179 m_samplerate->setCurrentText("44100 Hz");
Chris@892 180
Chris@891 181 connect(Preferences::getInstance(),
Chris@891 182 SIGNAL(propertyChanged(PropertyContainer::PropertyName)),
Chris@891 183 this, SLOT(preferenceChanged(PropertyContainer::PropertyName)));
Chris@892 184
Chris@892 185 row = 1;
Chris@892 186
Chris@892 187 grid->addWidget(new QLabel(tr("Beat period")), row, 0);
Chris@892 188 grid->addWidget(m_samples, row, 1);
Chris@892 189 grid->addWidget(new QLabel(tr("=")), row, 2);
Chris@892 190
Chris@892 191 grid->addWidget(new QLabel(tr("at sample rate")), row, 4);
Chris@892 192 grid->addWidget(m_samplerate, row, 5);
Chris@892 193
Chris@892 194 grid->addWidget(m_bpm, row, 3);
Chris@892 195
Chris@892 196 ++row;
Chris@891 197
Chris@892 198 grid->addWidget(m_period, row, 3);
Chris@892 199
Chris@892 200 ++row;
Chris@892 201
Chris@892 202 grid->addWidget(m_tempofreq, row, 3);
Chris@892 203
Chris@889 204 updatePitchesFromFreq();
Chris@891 205 updatePitchPrefsLabel();
Chris@891 206 updateTempiFromSamples();
Chris@885 207 }
Chris@885 208
Chris@885 209 UnitConverter::~UnitConverter()
Chris@885 210 {
Chris@885 211 }
Chris@885 212
Chris@885 213 void
Chris@891 214 UnitConverter::preferenceChanged(PropertyContainer::PropertyName)
Chris@891 215 {
Chris@891 216 updatePitchesFromFreq();
Chris@891 217 updatePitchPrefsLabel();
Chris@891 218 }
Chris@891 219
Chris@891 220 void
Chris@891 221 UnitConverter::updatePitchPrefsLabel()
Chris@891 222 {
Chris@891 223 m_pitchPrefsLabel->setText
Chris@891 224 (tr("With concert-A tuning frequency at %1 Hz, and "
Chris@891 225 "middle C residing in octave %2.\n"
Chris@891 226 "(These can be changed in the application preferences.)")
Chris@891 227 .arg(Preferences::getInstance()->getTuningFrequency())
Chris@891 228 .arg(Preferences::getInstance()->getOctaveOfMiddleC()));
Chris@891 229 }
Chris@891 230
Chris@891 231 void
Chris@889 232 UnitConverter::freqChanged(double freq)
Chris@885 233 {
Chris@889 234 cerr << "freqChanged: " << freq << endl;
Chris@889 235 updatePitchesFromFreq();
Chris@885 236 }
Chris@885 237
Chris@885 238 void
Chris@885 239 UnitConverter::midiChanged(int midi)
Chris@885 240 {
Chris@885 241 cerr << "midiChanged: " << midi << endl;
Chris@889 242 double freq = Pitch::getFrequencyForPitch(m_midi->value(), m_cents->value());
Chris@889 243 cerr << "freq -> " << freq << endl;
Chris@889 244 m_freq->setValue(freq);
Chris@885 245 }
Chris@885 246
Chris@885 247 void
Chris@885 248 UnitConverter::noteChanged(int note)
Chris@885 249 {
Chris@885 250 cerr << "noteChanged: " << note << endl;
Chris@887 251 int pitch = Pitch::getPitchForNoteAndOctave(m_note->currentIndex(),
Chris@887 252 m_octave->value());
Chris@889 253 double freq = Pitch::getFrequencyForPitch(pitch, m_cents->value());
Chris@889 254 cerr << "freq -> " << freq << endl;
Chris@889 255 m_freq->setValue(freq);
Chris@885 256 }
Chris@885 257
Chris@885 258 void
Chris@885 259 UnitConverter::octaveChanged(int oct)
Chris@885 260 {
Chris@885 261 cerr << "octaveChanged: " << oct << endl;
Chris@888 262 int pitch = Pitch::getPitchForNoteAndOctave(m_note->currentIndex(),
Chris@888 263 m_octave->value());
Chris@889 264 double freq = Pitch::getFrequencyForPitch(pitch, m_cents->value());
Chris@889 265 cerr << "freq -> " << freq << endl;
Chris@889 266 m_freq->setValue(freq);
Chris@885 267 }
Chris@885 268
Chris@885 269 void
Chris@885 270 UnitConverter::centsChanged(double cents)
Chris@885 271 {
Chris@885 272 cerr << "centsChanged: " << cents << endl;
Chris@889 273 double freq = Pitch::getFrequencyForPitch(m_midi->value(), m_cents->value());
Chris@889 274 cerr << "freq -> " << freq << endl;
Chris@889 275 m_freq->setValue(freq);
Chris@885 276 }
Chris@885 277
Chris@885 278 void
Chris@889 279 UnitConverter::updatePitchesFromFreq()
Chris@885 280 {
Chris@892 281 double cents = 0;
Chris@889 282 int pitch = Pitch::getPitchForFrequency(m_freq->value(), &cents);
Chris@887 283 int note, octave;
Chris@887 284 Pitch::getNoteAndOctaveForPitch(pitch, note, octave);
Chris@885 285
Chris@888 286 cerr << "pitch " << pitch << " note " << note << " octave " << octave << " cents " << cents << endl;
Chris@888 287
Chris@885 288 m_midi->blockSignals(true);
Chris@885 289 m_cents->blockSignals(true);
Chris@887 290 m_note->blockSignals(true);
Chris@887 291 m_octave->blockSignals(true);
Chris@885 292
Chris@885 293 m_midi->setValue(pitch);
Chris@885 294 m_cents->setValue(cents);
Chris@887 295 m_note->setCurrentIndex(note);
Chris@887 296 m_octave->setValue(octave);
Chris@887 297
Chris@885 298 m_midi->blockSignals(false);
Chris@885 299 m_cents->blockSignals(false);
Chris@887 300 m_note->blockSignals(false);
Chris@887 301 m_octave->blockSignals(false);
Chris@885 302 }
Chris@885 303
Chris@891 304 void
Chris@892 305 UnitConverter::samplesChanged(double)
Chris@892 306 {
Chris@892 307 updateTempiFromSamples();
Chris@892 308 }
Chris@892 309
Chris@892 310 void
Chris@892 311 UnitConverter::periodChanged(double)
Chris@892 312 {
Chris@892 313 double rate = getSampleRate();
Chris@892 314 double sec = m_period->value() / 1000.0;
Chris@892 315 double samples = rate * sec;
Chris@892 316 m_samples->setValue(samples);
Chris@892 317 }
Chris@892 318
Chris@892 319 void
Chris@892 320 UnitConverter::bpmChanged(double)
Chris@892 321 {
Chris@892 322 double rate = getSampleRate();
Chris@892 323 double sec = 60.0 / m_bpm->value();
Chris@892 324 double samples = rate * sec;
Chris@892 325 m_samples->setValue(samples);
Chris@892 326 }
Chris@892 327
Chris@892 328 void
Chris@892 329 UnitConverter::tempofreqChanged(double)
Chris@892 330 {
Chris@892 331 double rate = getSampleRate();
Chris@892 332 double samples = rate / m_tempofreq->value();
Chris@892 333 m_samples->setValue(samples);
Chris@892 334 }
Chris@892 335
Chris@892 336 void
Chris@892 337 UnitConverter::samplerateChanged(QString)
Chris@892 338 {
Chris@892 339 updateTempiFromSamples();
Chris@892 340 }
Chris@892 341
Chris@892 342 double
Chris@892 343 UnitConverter::getSampleRate()
Chris@892 344 {
Chris@892 345 return double(atoi(m_samplerate->currentText().toLocal8Bit().data()));
Chris@892 346 }
Chris@892 347
Chris@892 348 void
Chris@891 349 UnitConverter::updateTempiFromSamples()
Chris@891 350 {
Chris@892 351 double samples = m_samples->value();
Chris@892 352 double rate = getSampleRate();
Chris@892 353
Chris@892 354 cerr << samples << " samples at rate " << rate << endl;
Chris@892 355
Chris@892 356 double sec = samples / rate;
Chris@892 357 double hz = rate / samples;
Chris@892 358 double bpm = 60.0 / sec;
Chris@892 359
Chris@892 360 m_bpm->blockSignals(true);
Chris@892 361 m_period->blockSignals(true);
Chris@892 362 m_tempofreq->blockSignals(true);
Chris@892 363
Chris@892 364 m_bpm->setValue(bpm);
Chris@892 365 m_period->setValue(sec * 1000.0);
Chris@892 366 m_tempofreq->setValue(hz);
Chris@892 367
Chris@892 368 m_bpm->blockSignals(false);
Chris@892 369 m_period->blockSignals(false);
Chris@892 370 m_tempofreq->blockSignals(false);
Chris@891 371 }
Chris@885 372
Chris@885 373