annotate src/Analyser.cpp @ 198:bb391844e2aa

Switching pitch candidate no longer wraps around: you can't go higher than the highest or lower than the lowest (though you can go either "up" or "down" if none of the alternate candidates has been selected yet, regardless of whether the candidates are higher or lower than the actual pitch track)
author Chris Cannam
date Wed, 05 Mar 2014 11:39:28 +0000
parents 73fafd70996e
children 0ba33d6c0a71
rev   line source
Chris@6 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@6 2
Chris@6 3 /*
Chris@6 4 Tony
Chris@6 5 An intonation analysis and annotation tool
Chris@6 6 Centre for Digital Music, Queen Mary, University of London.
Chris@6 7 This file copyright 2006-2012 Chris Cannam and QMUL.
Chris@6 8
Chris@6 9 This program is free software; you can redistribute it and/or
Chris@6 10 modify it under the terms of the GNU General Public License as
Chris@6 11 published by the Free Software Foundation; either version 2 of the
Chris@6 12 License, or (at your option) any later version. See the file
Chris@6 13 COPYING included with this distribution for more information.
Chris@6 14 */
Chris@6 15
Chris@6 16 #include "Analyser.h"
Chris@6 17
Chris@6 18 #include "transform/TransformFactory.h"
Chris@6 19 #include "transform/ModelTransformer.h"
gyorgyf@14 20 #include "transform/FeatureExtractionModelTransformer.h"
Chris@6 21 #include "framework/Document.h"
Chris@6 22 #include "data/model/WaveFileModel.h"
Chris@6 23 #include "view/Pane.h"
Chris@6 24 #include "view/PaneStack.h"
Chris@6 25 #include "layer/Layer.h"
Chris@6 26 #include "layer/TimeValueLayer.h"
matthiasm@13 27 #include "layer/NoteLayer.h"
matthiasm@11 28 #include "layer/FlexiNoteLayer.h"
Chris@120 29 #include "layer/WaveformLayer.h"
Chris@6 30 #include "layer/ColourDatabase.h"
Chris@145 31 #include "layer/ColourMapper.h"
gyorgyf@16 32 #include "layer/LayerFactory.h"
Chris@145 33 #include "layer/SpectrogramLayer.h"
Chris@161 34 #include "layer/Colour3DPlotLayer.h"
Chris@6 35
Chris@83 36 #include <QSettings>
Chris@83 37
Chris@163 38 using std::vector;
Chris@163 39
Chris@6 40 Analyser::Analyser() :
Chris@6 41 m_document(0),
Chris@6 42 m_fileModel(0),
Chris@133 43 m_paneStack(0),
Chris@188 44 m_pane(0),
Chris@188 45 m_currentCandidate(-1),
Chris@188 46 m_candidatesVisible(false)
Chris@6 47 {
Chris@83 48 QSettings settings;
Chris@83 49 settings.beginGroup("LayerDefaults");
Chris@83 50 settings.setValue
Chris@83 51 ("timevalues",
Chris@83 52 QString("<layer verticalScale=\"%1\" plotStyle=\"%2\" "
Chris@83 53 "scaleMinimum=\"%3\" scaleMaximum=\"%4\"/>")
Chris@145 54 .arg(int(TimeValueLayer::AutoAlignScale))
matthiasm@182 55 .arg(int(TimeValueLayer::PlotPoints))
Chris@83 56 .arg(27.5f).arg(880.f)); // temporary values: better get the real extents of the data from the model
Chris@83 57 settings.setValue
Chris@83 58 ("flexinotes",
Chris@83 59 QString("<layer verticalScale=\"%1\"/>")
Chris@83 60 .arg(int(FlexiNoteLayer::AutoAlignScale)));
Chris@83 61 settings.endGroup();
Chris@6 62 }
Chris@6 63
Chris@6 64 Analyser::~Analyser()
Chris@6 65 {
Chris@6 66 }
Chris@6 67
Chris@140 68 QString
Chris@6 69 Analyser::newFileLoaded(Document *doc, WaveFileModel *model,
Chris@6 70 PaneStack *paneStack, Pane *pane)
Chris@6 71 {
Chris@6 72 m_document = doc;
Chris@6 73 m_fileModel = model;
Chris@133 74 m_paneStack = paneStack;
Chris@6 75 m_pane = pane;
Chris@6 76
Chris@165 77 m_reAnalysingSelection = Selection();
Chris@165 78 m_reAnalysisCandidates.clear();
Chris@167 79 m_currentCandidate = -1;
Chris@184 80 m_candidatesVisible = false;
Chris@165 81
Chris@161 82 // Note that we need at least one main-model layer (time ruler,
Chris@161 83 // waveform or what have you). It could be hidden if we don't want
Chris@161 84 // to see it but it must exist.
Chris@6 85
Chris@161 86 QString warning, error;
Chris@161 87
Chris@161 88 // This isn't fatal -- we can proceed without
Chris@161 89 // visualisations. Other failures are fatal though.
Chris@161 90 warning = addVisualisations();
Chris@161 91
Chris@161 92 error = addWaveform();
Chris@161 93 if (error != "") return error;
Chris@161 94
Chris@161 95 error = addAnalyses();
Chris@161 96 if (error != "") return error;
Chris@161 97
Chris@161 98 loadState(Audio);
Chris@161 99 loadState(PitchTrack);
Chris@161 100 loadState(Notes);
Chris@161 101 loadState(Spectrogram);
Chris@161 102
Chris@161 103 emit layersChanged();
Chris@161 104
Chris@161 105 return warning;
Chris@161 106 }
Chris@161 107
Chris@161 108 QString
Chris@161 109 Analyser::addVisualisations()
Chris@161 110 {
Chris@165 111 /*
Chris@161 112 TransformFactory *tf = TransformFactory::getInstance();
Chris@161 113
Chris@161 114 QString name = "Constant-Q";
Chris@161 115 QString base = "vamp:cqvamp:cqvamp:";
Chris@161 116 QString out = "constantq";
Chris@6 117
Chris@145 118 // A spectrogram, off by default. Must go at the back because it's
Chris@145 119 // opaque
Chris@145 120
Chris@161 121 QString notFound = tr("Transform \"%1\" not found, spectrogram will not be enabled.<br><br>Is the %2 Vamp plugin correctly installed?");
Chris@161 122 if (!tf->haveTransform(base + out)) {
Chris@161 123 return notFound.arg(base + out).arg(name);
Chris@161 124 }
Chris@161 125
Chris@161 126 Transform transform = tf->getDefaultTransformFor
Chris@161 127 (base + out, m_fileModel->getSampleRate());
Chris@162 128 transform.setParameter("bpo", 36);
Chris@161 129
Chris@161 130 Colour3DPlotLayer *spectrogram = qobject_cast<Colour3DPlotLayer *>
Chris@161 131 (m_document->createDerivedLayer(transform, m_fileModel));
Chris@161 132
Chris@161 133 if (!spectrogram) return tr("Transform \"%1\" did not run correctly (no layer or wrong layer type returned)").arg(base + out);
Chris@165 134 */
Chris@165 135
Chris@145 136 SpectrogramLayer *spectrogram = qobject_cast<SpectrogramLayer *>
Chris@145 137 (m_document->createMainModelLayer(LayerFactory::MelodicRangeSpectrogram));
Chris@165 138
Chris@145 139 spectrogram->setColourMap((int)ColourMapper::BlackOnWhite);
Chris@162 140 spectrogram->setNormalizeHybrid(true);
Chris@165 141 // spectrogram->setSmooth(true);
Chris@165 142 // spectrogram->setGain(0.5); //!!! arbitrary at this point
Chris@167 143 spectrogram->setMinFrequency(15);
Chris@165 144 spectrogram->setGain(100);
Chris@145 145 m_document->addLayerToView(m_pane, spectrogram);
Chris@145 146 spectrogram->setLayerDormant(m_pane, true);
Chris@145 147
Chris@145 148 m_layers[Spectrogram] = spectrogram;
Chris@145 149
Chris@161 150 return "";
Chris@161 151 }
Chris@161 152
Chris@161 153 QString
Chris@161 154 Analyser::addWaveform()
Chris@161 155 {
Chris@131 156 // Our waveform layer is just a shadow, light grey and taking up
Chris@120 157 // little space at the bottom
Chris@120 158
Chris@120 159 WaveformLayer *waveform = qobject_cast<WaveformLayer *>
Chris@120 160 (m_document->createMainModelLayer(LayerFactory::Waveform));
Chris@120 161
Chris@120 162 waveform->setMiddleLineHeight(0.9);
Chris@120 163 waveform->setShowMeans(false); // too small & pale for this
Chris@120 164 waveform->setBaseColour
Chris@120 165 (ColourDatabase::getInstance()->getColourIndex(tr("Grey")));
Chris@130 166 PlayParameters *params = waveform->getPlayParameters();
justin@160 167 if (params) params->setPlayPan(-1);
Chris@128 168
Chris@128 169 m_document->addLayerToView(m_pane, waveform);
Chris@120 170
Chris@128 171 m_layers[Audio] = waveform;
Chris@161 172 return "";
Chris@161 173 }
Chris@161 174
Chris@161 175 QString
Chris@161 176 Analyser::addAnalyses()
Chris@161 177 {
Chris@161 178 TransformFactory *tf = TransformFactory::getInstance();
Chris@161 179
Chris@161 180 QString plugname = "pYIN";
Chris@161 181 QString base = "vamp:pyin:pyin:";
Chris@161 182 QString f0out = "smoothedpitchtrack";
Chris@161 183 QString noteout = "notes";
Chris@120 184
Chris@83 185 Transforms transforms;
Chris@138 186
Chris@138 187 /*!!! we could have more than one pitch track...
Chris@138 188 QString cx = "vamp:cepstral-pitchtracker:cepstral-pitchtracker:f0";
Chris@138 189 if (tf->haveTransform(cx)) {
Chris@138 190 Transform tx = tf->getDefaultTransformFor(cx);
Chris@138 191 TimeValueLayer *lx = qobject_cast<TimeValueLayer *>
Chris@138 192 (m_document->createDerivedLayer(tx, m_fileModel));
Chris@138 193 lx->setVerticalScale(TimeValueLayer::AutoAlignScale);
Chris@138 194 lx->setBaseColour(ColourDatabase::getInstance()->getColourIndex(tr("Bright Red")));
Chris@138 195 m_document->addLayerToView(m_pane, lx);
Chris@138 196 }
Chris@138 197 */
Chris@138 198
Chris@140 199 QString notFound = tr("Transform \"%1\" not found. Unable to analyse audio file.<br><br>Is the %2 Vamp plugin correctly installed?");
Chris@140 200 if (!tf->haveTransform(base + f0out)) {
Chris@140 201 return notFound.arg(base + f0out).arg(plugname);
Chris@140 202 }
Chris@140 203 if (!tf->haveTransform(base + noteout)) {
Chris@140 204 return notFound.arg(base + noteout).arg(plugname);
Chris@6 205 }
Chris@6 206
Chris@83 207 Transform t = tf->getDefaultTransformFor
Chris@83 208 (base + f0out, m_fileModel->getSampleRate());
Chris@83 209 t.setStepSize(256);
Chris@83 210 t.setBlockSize(2048);
Chris@6 211
Chris@83 212 transforms.push_back(t);
Chris@83 213
Chris@83 214 t.setOutput(noteout);
Chris@83 215
Chris@83 216 transforms.push_back(t);
Chris@83 217
Chris@83 218 std::vector<Layer *> layers =
Chris@83 219 m_document->createDerivedLayers(transforms, m_fileModel);
Chris@83 220
Chris@162 221 for (int i = 0; i < (int)layers.size(); ++i) {
Chris@83 222
Chris@162 223 FlexiNoteLayer *f = qobject_cast<FlexiNoteLayer *>(layers[i]);
Chris@162 224 TimeValueLayer *t = qobject_cast<TimeValueLayer *>(layers[i]);
Chris@162 225
Chris@162 226 if (f) m_layers[Notes] = f;
Chris@162 227 if (t) m_layers[PitchTrack] = t;
Chris@162 228
Chris@162 229 m_document->addLayerToView(m_pane, layers[i]);
Chris@6 230 }
Chris@161 231
Chris@162 232 ColourDatabase *cdb = ColourDatabase::getInstance();
Chris@162 233
Chris@162 234 TimeValueLayer *pitchLayer =
Chris@162 235 qobject_cast<TimeValueLayer *>(m_layers[PitchTrack]);
Chris@162 236 if (pitchLayer) {
Chris@162 237 pitchLayer->setBaseColour(cdb->getColourIndex(tr("Black")));
Chris@162 238 PlayParameters *params = pitchLayer->getPlayParameters();
Chris@162 239 if (params) params->setPlayPan(1);
Chris@162 240 }
Chris@162 241
Chris@162 242 FlexiNoteLayer *flexiNoteLayer =
Chris@162 243 qobject_cast<FlexiNoteLayer *>(m_layers[Notes]);
Chris@162 244 if (flexiNoteLayer) {
Chris@162 245 flexiNoteLayer->setBaseColour(cdb->getColourIndex(tr("Bright Blue")));
Chris@162 246 PlayParameters *params = flexiNoteLayer->getPlayParameters();
Chris@162 247 if (params) params->setPlayPan(1);
Chris@162 248 }
Chris@162 249
Chris@162 250 return "";
Chris@162 251 }
Chris@162 252
Chris@162 253 QString
Chris@192 254 Analyser::reAnalyseSelection(Selection sel, FrequencyRange range)
Chris@162 255 {
Chris@165 256 if (sel == m_reAnalysingSelection) return "";
Chris@165 257
Chris@194 258 showPitchCandidates(false);
Chris@194 259 m_reAnalysisCandidates.clear();
Chris@194 260 m_currentCandidate = -1;
Chris@194 261 m_reAnalysingSelection = sel;
Chris@167 262
Chris@194 263 m_preAnalysis = Clipboard();
Chris@194 264 Layer *myLayer = m_layers[PitchTrack];
Chris@194 265 if (myLayer) {
Chris@194 266 myLayer->copy(m_pane, sel, m_preAnalysis);
Chris@194 267 }
Chris@165 268
Chris@162 269 TransformFactory *tf = TransformFactory::getInstance();
Chris@162 270
Chris@162 271 QString plugname = "pYIN";
Chris@162 272 QString base = "vamp:pyin:localcandidatepyin:";
Chris@162 273 QString out = "pitchtrackcandidates";
Chris@162 274
Chris@192 275 if (range.isConstrained()) {
Chris@192 276 base = "vamp:pyin:yinfc:";
Chris@192 277 out = "f0";
Chris@192 278 }
Chris@192 279
Chris@162 280 Transforms transforms;
Chris@162 281
Chris@162 282 QString notFound = tr("Transform \"%1\" not found. Unable to perform interactive analysis.<br><br>Is the %2 Vamp plugin correctly installed?");
Chris@162 283 if (!tf->haveTransform(base + out)) {
Chris@162 284 return notFound.arg(base + out).arg(plugname);
Chris@162 285 }
Chris@162 286
Chris@162 287 Transform t = tf->getDefaultTransformFor
Chris@162 288 (base + out, m_fileModel->getSampleRate());
Chris@162 289 t.setStepSize(256);
Chris@162 290 t.setBlockSize(2048);
Chris@162 291
Chris@192 292 if (range.isConstrained()) {
Chris@192 293 t.setParameter("minfreq", range.min);
Chris@192 294 t.setParameter("maxfreq", range.max);
Chris@192 295 }
Chris@192 296
Chris@164 297 RealTime start = RealTime::frame2RealTime
matthiasm@183 298 (round(sel.getStartFrame()*1.0/256) * 256 - 2*256, m_fileModel->getSampleRate());
Chris@164 299
Chris@164 300 RealTime end = RealTime::frame2RealTime
matthiasm@183 301 (round(sel.getEndFrame()*1.0/256) * 256 + 11*256, m_fileModel->getSampleRate());
Chris@164 302
Chris@164 303 RealTime duration;
Chris@164 304
Chris@164 305 if (sel.getEndFrame() > sel.getStartFrame()) {
Chris@164 306 duration = end - start;
Chris@164 307 }
Chris@164 308
Chris@164 309 t.setStartTime(start);
Chris@164 310 t.setDuration(duration);
Chris@162 311
Chris@162 312 transforms.push_back(t);
Chris@162 313
Chris@163 314 m_document->createDerivedLayersAsync(transforms, m_fileModel, this);
Chris@162 315
Chris@163 316 return "";
Chris@163 317 }
Chris@162 318
Chris@184 319 bool
Chris@184 320 Analyser::arePitchCandidatesShown() const
Chris@184 321 {
Chris@184 322 return m_candidatesVisible;
Chris@184 323 }
Chris@184 324
Chris@184 325 void
Chris@184 326 Analyser::showPitchCandidates(bool shown)
Chris@184 327 {
Chris@184 328 if (m_candidatesVisible == shown) return;
Chris@184 329
Chris@184 330 foreach (Layer *layer, m_reAnalysisCandidates) {
Chris@184 331 if (shown) {
Chris@184 332 m_document->addLayerToView(m_pane, layer);
Chris@184 333 } else {
Chris@184 334 m_document->removeLayerFromView(m_pane, layer);
Chris@184 335 }
Chris@184 336 }
Chris@184 337
Chris@184 338 m_candidatesVisible = shown;
Chris@184 339 }
Chris@184 340
Chris@163 341 void
Chris@163 342 Analyser::layersCreated(vector<Layer *> primary,
Chris@163 343 vector<Layer *> additional)
Chris@163 344 {
Chris@165 345 //!!! how do we know these came from the right selection? user
Chris@165 346 //!!! might have made another one since this request was issued
Chris@165 347
Chris@167 348 vector<Layer *> all;
Chris@163 349 for (int i = 0; i < (int)primary.size(); ++i) {
Chris@167 350 all.push_back(primary[i]);
Chris@167 351 }
Chris@167 352 for (int i = 0; i < (int)additional.size(); ++i) {
Chris@167 353 all.push_back(additional[i]);
Chris@162 354 }
Chris@162 355
Chris@167 356 for (int i = 0; i < (int)all.size(); ++i) {
Chris@167 357 TimeValueLayer *t = qobject_cast<TimeValueLayer *>(all[i]);
Chris@165 358 if (t) {
Chris@167 359 PlayParameters *params = t->getPlayParameters();
Chris@167 360 if (params) {
Chris@167 361 params->setPlayAudible(false);
Chris@167 362 }
Chris@167 363 t->setBaseColour
Chris@167 364 (ColourDatabase::getInstance()->getColourIndex(tr("Bright Orange")));
Chris@184 365 if (m_candidatesVisible) {
Chris@184 366 m_document->addLayerToView(m_pane, t);
Chris@184 367 }
Chris@165 368 m_reAnalysisCandidates.push_back(t);
Chris@165 369 }
Chris@163 370 }
Chris@187 371
Chris@187 372 emit layersChanged();
Chris@6 373 }
Chris@6 374
Chris@198 375 bool
Chris@198 376 Analyser::haveHigherPitchCandidate() const
Chris@198 377 {
Chris@198 378 if (m_reAnalysisCandidates.empty()) return false;
Chris@198 379 return (m_currentCandidate < 0 ||
Chris@198 380 (m_currentCandidate + 1 < (int)m_reAnalysisCandidates.size()));
Chris@198 381 }
Chris@198 382
Chris@198 383 bool
Chris@198 384 Analyser::haveLowerPitchCandidate() const
Chris@198 385 {
Chris@198 386 if (m_reAnalysisCandidates.empty()) return false;
Chris@198 387 return (m_currentCandidate < 0 || m_currentCandidate >= 1);
Chris@198 388 }
Chris@198 389
gyorgyf@45 390 void
Chris@167 391 Analyser::switchPitchCandidate(Selection sel, bool up)
Chris@167 392 {
Chris@167 393 if (m_reAnalysisCandidates.empty()) return;
Chris@167 394
Chris@167 395 if (up) {
Chris@167 396 m_currentCandidate = m_currentCandidate + 1;
Chris@168 397 if (m_currentCandidate >= (int)m_reAnalysisCandidates.size()) {
Chris@167 398 m_currentCandidate = 0;
Chris@167 399 }
Chris@167 400 } else {
Chris@167 401 m_currentCandidate = m_currentCandidate - 1;
Chris@167 402 if (m_currentCandidate < 0) {
Chris@168 403 m_currentCandidate = (int)m_reAnalysisCandidates.size() - 1;
Chris@167 404 }
Chris@167 405 }
Chris@167 406
Chris@167 407 Layer *pitchTrack = m_layers[PitchTrack];
Chris@167 408 if (!pitchTrack) return;
Chris@167 409
Chris@167 410 Clipboard clip;
Chris@167 411 pitchTrack->deleteSelection(sel);
Chris@167 412 m_reAnalysisCandidates[m_currentCandidate]->copy(m_pane, sel, clip);
Chris@167 413 pitchTrack->paste(m_pane, clip, 0, false);
Chris@167 414
Chris@167 415 // raise the pitch track, then notes on top (if present)
Chris@167 416 m_paneStack->setCurrentLayer(m_pane, m_layers[PitchTrack]);
Chris@167 417 if (m_layers[Notes] && !m_layers[Notes]->isLayerDormant(m_pane)) {
Chris@167 418 m_paneStack->setCurrentLayer(m_pane, m_layers[Notes]);
Chris@167 419 }
Chris@167 420 }
Chris@167 421
Chris@167 422 void
Chris@168 423 Analyser::shiftOctave(Selection sel, bool up)
Chris@168 424 {
Chris@168 425 float factor = (up ? 2.f : 0.5f);
Chris@168 426
Chris@168 427 vector<Layer *> actOn;
Chris@168 428
Chris@168 429 Layer *pitchTrack = m_layers[PitchTrack];
Chris@168 430 if (pitchTrack) actOn.push_back(pitchTrack);
Chris@168 431
Chris@168 432 foreach (Layer *layer, actOn) {
Chris@168 433
Chris@168 434 Clipboard clip;
Chris@168 435 layer->copy(m_pane, sel, clip);
Chris@168 436 layer->deleteSelection(sel);
Chris@168 437
Chris@168 438 Clipboard shifted;
Chris@168 439 foreach (Clipboard::Point p, clip.getPoints()) {
Chris@168 440 if (p.haveValue()) {
Chris@168 441 Clipboard::Point sp = p.withValue(p.getValue() * factor);
Chris@168 442 shifted.addPoint(sp);
Chris@168 443 } else {
Chris@168 444 shifted.addPoint(p);
Chris@168 445 }
Chris@168 446 }
Chris@168 447
Chris@168 448 layer->paste(m_pane, shifted, 0, false);
Chris@168 449 }
Chris@168 450 }
Chris@168 451
Chris@168 452 void
Chris@184 453 Analyser::deletePitches(Selection sel)
Chris@168 454 {
Chris@168 455 Layer *pitchTrack = m_layers[PitchTrack];
Chris@168 456 if (!pitchTrack) return;
Chris@168 457
Chris@168 458 pitchTrack->deleteSelection(sel);
Chris@168 459 }
Chris@168 460
Chris@168 461 void
Chris@194 462 Analyser::clearReAnalysis(Selection sel)
Chris@167 463 {
Chris@194 464 showPitchCandidates(false);
Chris@194 465
Chris@167 466 m_reAnalysisCandidates.clear();
Chris@167 467 m_reAnalysingSelection = Selection();
Chris@167 468 m_currentCandidate = -1;
Chris@194 469
Chris@194 470 Layer *myLayer = m_layers[PitchTrack];
Chris@194 471 if (!myLayer) return;
Chris@194 472 myLayer->deleteSelection(sel);
Chris@194 473 myLayer->paste(m_pane, m_preAnalysis, 0, false);
Chris@167 474 }
Chris@167 475
Chris@167 476 void
Chris@174 477 Analyser::takePitchTrackFrom(Layer *otherLayer)
Chris@174 478 {
Chris@174 479 Layer *myLayer = m_layers[PitchTrack];
Chris@174 480 if (!myLayer) return;
Chris@174 481
Chris@174 482 Clipboard clip;
Chris@174 483
Chris@174 484 Selection sel = Selection(myLayer->getModel()->getStartFrame(),
Chris@174 485 myLayer->getModel()->getEndFrame());
Chris@174 486 myLayer->deleteSelection(sel);
Chris@174 487
Chris@174 488 sel = Selection(otherLayer->getModel()->getStartFrame(),
Chris@174 489 otherLayer->getModel()->getEndFrame());
Chris@174 490 otherLayer->copy(m_pane, sel, clip);
Chris@174 491
Chris@174 492 myLayer->paste(m_pane, clip, 0, false);
Chris@174 493 }
Chris@174 494
Chris@174 495 void
Chris@139 496 Analyser::getEnclosingSelectionScope(size_t f, size_t &f0, size_t &f1)
Chris@139 497 {
Chris@139 498 FlexiNoteLayer *flexiNoteLayer =
Chris@139 499 qobject_cast<FlexiNoteLayer *>(m_layers[Notes]);
Chris@139 500
Chris@139 501 int f0i = f, f1i = f;
Chris@139 502 size_t res = 1;
Chris@139 503
Chris@139 504 if (!flexiNoteLayer) {
Chris@139 505 f0 = f1 = f;
Chris@139 506 return;
Chris@139 507 }
Chris@139 508
Chris@139 509 flexiNoteLayer->snapToFeatureFrame(m_pane, f0i, res, Layer::SnapLeft);
Chris@139 510 flexiNoteLayer->snapToFeatureFrame(m_pane, f1i, res, Layer::SnapRight);
Chris@139 511
Chris@139 512 f0 = (f0i < 0 ? 0 : f0i);
Chris@139 513 f1 = (f1i < 0 ? 0 : f1i);
Chris@139 514 }
Chris@139 515
Chris@139 516 void
Chris@132 517 Analyser::saveState(Component c) const
Chris@132 518 {
Chris@132 519 bool v = isVisible(c);
Chris@132 520 bool a = isAudible(c);
Chris@132 521 QSettings settings;
Chris@132 522 settings.beginGroup("Analyser");
Chris@145 523 settings.setValue(QString("visible-%1").arg(int(c)), v);
Chris@145 524 settings.setValue(QString("audible-%1").arg(int(c)), a);
Chris@132 525 settings.endGroup();
Chris@132 526 }
Chris@132 527
Chris@132 528 void
Chris@132 529 Analyser::loadState(Component c)
Chris@132 530 {
Chris@132 531 QSettings settings;
Chris@132 532 settings.beginGroup("Analyser");
Chris@145 533 bool deflt = (c == Spectrogram ? false : true);
Chris@145 534 bool v = settings.value(QString("visible-%1").arg(int(c)), deflt).toBool();
Chris@145 535 bool a = settings.value(QString("audible-%1").arg(int(c)), true).toBool();
Chris@132 536 settings.endGroup();
Chris@132 537 setVisible(c, v);
Chris@132 538 setAudible(c, a);
Chris@132 539 }
Chris@132 540
Chris@132 541 void
gyorgyf@45 542 Analyser::setIntelligentActions(bool on)
gyorgyf@45 543 {
gyorgyf@45 544 std::cerr << "toggle setIntelligentActions " << on << std::endl;
Chris@128 545
Chris@128 546 FlexiNoteLayer *flexiNoteLayer =
Chris@128 547 qobject_cast<FlexiNoteLayer *>(m_layers[Notes]);
Chris@128 548 if (flexiNoteLayer) {
Chris@128 549 flexiNoteLayer->setIntelligentActions(on);
Chris@70 550 }
gyorgyf@45 551 }
Chris@128 552
Chris@128 553 bool
Chris@128 554 Analyser::isVisible(Component c) const
Chris@128 555 {
Chris@128 556 if (m_layers[c]) {
Chris@128 557 return !m_layers[c]->isLayerDormant(m_pane);
Chris@128 558 } else {
Chris@128 559 return false;
Chris@128 560 }
Chris@128 561 }
Chris@128 562
Chris@128 563 void
Chris@128 564 Analyser::setVisible(Component c, bool v)
Chris@128 565 {
Chris@128 566 if (m_layers[c]) {
Chris@128 567 m_layers[c]->setLayerDormant(m_pane, !v);
Chris@133 568
Chris@167 569 if (v) {
Chris@167 570 if (c == Notes) {
Chris@167 571 m_paneStack->setCurrentLayer(m_pane, m_layers[c]);
Chris@167 572 } else if (c == PitchTrack) {
Chris@167 573 // raise the pitch track, then notes on top (if present)
Chris@167 574 m_paneStack->setCurrentLayer(m_pane, m_layers[c]);
Chris@167 575 if (m_layers[Notes] &&
Chris@167 576 !m_layers[Notes]->isLayerDormant(m_pane)) {
Chris@167 577 m_paneStack->setCurrentLayer(m_pane, m_layers[Notes]);
Chris@167 578 }
Chris@167 579 }
Chris@133 580 }
Chris@133 581
Chris@128 582 m_pane->layerParametersChanged();
Chris@132 583 saveState(c);
Chris@128 584 }
Chris@128 585 }
Chris@128 586
Chris@128 587 bool
Chris@128 588 Analyser::isAudible(Component c) const
Chris@128 589 {
Chris@128 590 if (m_layers[c]) {
Chris@128 591 PlayParameters *params = m_layers[c]->getPlayParameters();
Chris@128 592 if (!params) return false;
Chris@128 593 return params->isPlayAudible();
Chris@128 594 } else {
Chris@128 595 return false;
Chris@128 596 }
Chris@128 597 }
Chris@128 598
Chris@128 599 void
Chris@128 600 Analyser::setAudible(Component c, bool a)
Chris@128 601 {
Chris@128 602 if (m_layers[c]) {
Chris@128 603 PlayParameters *params = m_layers[c]->getPlayParameters();
Chris@128 604 if (!params) return;
Chris@128 605 params->setPlayAudible(a);
Chris@132 606 saveState(c);
Chris@128 607 }
Chris@128 608 }
Chris@128 609
Chris@158 610 float
Chris@158 611 Analyser::getGain(Component c) const
Chris@158 612 {
Chris@158 613 if (m_layers[c]) {
Chris@158 614 PlayParameters *params = m_layers[c]->getPlayParameters();
Chris@158 615 if (!params) return 1.f;
Chris@158 616 return params->getPlayGain();
Chris@158 617 } else {
Chris@158 618 return 1.f;
Chris@158 619 }
Chris@158 620 }
Chris@158 621
Chris@158 622 void
Chris@158 623 Analyser::setGain(Component c, float gain)
Chris@158 624 {
Chris@158 625 if (m_layers[c]) {
Chris@158 626 PlayParameters *params = m_layers[c]->getPlayParameters();
Chris@158 627 if (!params) return;
Chris@158 628 params->setPlayGain(gain);
Chris@158 629 saveState(c);
Chris@158 630 }
Chris@158 631 }
Chris@158 632
Chris@158 633 float
Chris@158 634 Analyser::getPan(Component c) const
Chris@158 635 {
Chris@158 636 if (m_layers[c]) {
Chris@158 637 PlayParameters *params = m_layers[c]->getPlayParameters();
Chris@158 638 if (!params) return 1.f;
Chris@158 639 return params->getPlayPan();
Chris@158 640 } else {
Chris@158 641 return 1.f;
Chris@158 642 }
Chris@158 643 }
Chris@158 644
Chris@158 645 void
Chris@158 646 Analyser::setPan(Component c, float pan)
Chris@158 647 {
Chris@158 648 if (m_layers[c]) {
Chris@158 649 PlayParameters *params = m_layers[c]->getPlayParameters();
Chris@158 650 if (!params) return;
Chris@158 651 params->setPlayPan(pan);
Chris@158 652 saveState(c);
Chris@158 653 }
Chris@158 654 }
Chris@158 655
Chris@158 656
Chris@158 657