annotate src/Analyser.cpp @ 194:34797795a76c

Clearing the selection by hitting Esc now restores the selected region of the pitch track to its contents from before the selection was made (and any alternate candidate chosen). Fixes feature #885
author Chris Cannam
date Wed, 05 Mar 2014 10:38:23 +0000
parents 431a95c9d14d
children 73fafd70996e
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
gyorgyf@45 375 void
Chris@167 376 Analyser::switchPitchCandidate(Selection sel, bool up)
Chris@167 377 {
Chris@167 378 if (m_reAnalysisCandidates.empty()) return;
Chris@167 379
Chris@167 380 if (up) {
Chris@167 381 m_currentCandidate = m_currentCandidate + 1;
Chris@168 382 if (m_currentCandidate >= (int)m_reAnalysisCandidates.size()) {
Chris@167 383 m_currentCandidate = 0;
Chris@167 384 }
Chris@167 385 } else {
Chris@167 386 m_currentCandidate = m_currentCandidate - 1;
Chris@167 387 if (m_currentCandidate < 0) {
Chris@168 388 m_currentCandidate = (int)m_reAnalysisCandidates.size() - 1;
Chris@167 389 }
Chris@167 390 }
Chris@167 391
Chris@167 392 Layer *pitchTrack = m_layers[PitchTrack];
Chris@167 393 if (!pitchTrack) return;
Chris@167 394
Chris@167 395 Clipboard clip;
Chris@167 396 pitchTrack->deleteSelection(sel);
Chris@167 397 m_reAnalysisCandidates[m_currentCandidate]->copy(m_pane, sel, clip);
Chris@167 398 pitchTrack->paste(m_pane, clip, 0, false);
Chris@167 399
Chris@167 400 // raise the pitch track, then notes on top (if present)
Chris@167 401 m_paneStack->setCurrentLayer(m_pane, m_layers[PitchTrack]);
Chris@167 402 if (m_layers[Notes] && !m_layers[Notes]->isLayerDormant(m_pane)) {
Chris@167 403 m_paneStack->setCurrentLayer(m_pane, m_layers[Notes]);
Chris@167 404 }
Chris@167 405 }
Chris@167 406
Chris@167 407 void
Chris@168 408 Analyser::shiftOctave(Selection sel, bool up)
Chris@168 409 {
Chris@168 410 float factor = (up ? 2.f : 0.5f);
Chris@168 411
Chris@168 412 vector<Layer *> actOn;
Chris@168 413
Chris@168 414 Layer *pitchTrack = m_layers[PitchTrack];
Chris@168 415 if (pitchTrack) actOn.push_back(pitchTrack);
Chris@168 416
Chris@168 417 foreach (Layer *c, m_reAnalysisCandidates) {
Chris@168 418 actOn.push_back(c);
Chris@168 419 }
Chris@168 420
Chris@168 421 foreach (Layer *layer, actOn) {
Chris@168 422
Chris@168 423 Clipboard clip;
Chris@168 424 layer->copy(m_pane, sel, clip);
Chris@168 425 layer->deleteSelection(sel);
Chris@168 426
Chris@168 427 Clipboard shifted;
Chris@168 428 foreach (Clipboard::Point p, clip.getPoints()) {
Chris@168 429 if (p.haveValue()) {
Chris@168 430 Clipboard::Point sp = p.withValue(p.getValue() * factor);
Chris@168 431 shifted.addPoint(sp);
Chris@168 432 } else {
Chris@168 433 shifted.addPoint(p);
Chris@168 434 }
Chris@168 435 }
Chris@168 436
Chris@168 437 layer->paste(m_pane, shifted, 0, false);
Chris@168 438 }
Chris@168 439 }
Chris@168 440
Chris@168 441 void
Chris@184 442 Analyser::deletePitches(Selection sel)
Chris@168 443 {
Chris@168 444 Layer *pitchTrack = m_layers[PitchTrack];
Chris@168 445 if (!pitchTrack) return;
Chris@168 446
Chris@168 447 pitchTrack->deleteSelection(sel);
Chris@168 448 }
Chris@168 449
Chris@168 450 void
Chris@194 451 Analyser::clearReAnalysis(Selection sel)
Chris@167 452 {
Chris@194 453 showPitchCandidates(false);
Chris@194 454
Chris@167 455 m_reAnalysisCandidates.clear();
Chris@167 456 m_reAnalysingSelection = Selection();
Chris@167 457 m_currentCandidate = -1;
Chris@194 458
Chris@194 459 Layer *myLayer = m_layers[PitchTrack];
Chris@194 460 if (!myLayer) return;
Chris@194 461 myLayer->deleteSelection(sel);
Chris@194 462 myLayer->paste(m_pane, m_preAnalysis, 0, false);
Chris@167 463 }
Chris@167 464
Chris@167 465 void
Chris@174 466 Analyser::takePitchTrackFrom(Layer *otherLayer)
Chris@174 467 {
Chris@174 468 Layer *myLayer = m_layers[PitchTrack];
Chris@174 469 if (!myLayer) return;
Chris@174 470
Chris@174 471 Clipboard clip;
Chris@174 472
Chris@174 473 Selection sel = Selection(myLayer->getModel()->getStartFrame(),
Chris@174 474 myLayer->getModel()->getEndFrame());
Chris@174 475 myLayer->deleteSelection(sel);
Chris@174 476
Chris@174 477 sel = Selection(otherLayer->getModel()->getStartFrame(),
Chris@174 478 otherLayer->getModel()->getEndFrame());
Chris@174 479 otherLayer->copy(m_pane, sel, clip);
Chris@174 480
Chris@174 481 myLayer->paste(m_pane, clip, 0, false);
Chris@174 482 }
Chris@174 483
Chris@174 484 void
Chris@139 485 Analyser::getEnclosingSelectionScope(size_t f, size_t &f0, size_t &f1)
Chris@139 486 {
Chris@139 487 FlexiNoteLayer *flexiNoteLayer =
Chris@139 488 qobject_cast<FlexiNoteLayer *>(m_layers[Notes]);
Chris@139 489
Chris@139 490 int f0i = f, f1i = f;
Chris@139 491 size_t res = 1;
Chris@139 492
Chris@139 493 if (!flexiNoteLayer) {
Chris@139 494 f0 = f1 = f;
Chris@139 495 return;
Chris@139 496 }
Chris@139 497
Chris@139 498 flexiNoteLayer->snapToFeatureFrame(m_pane, f0i, res, Layer::SnapLeft);
Chris@139 499 flexiNoteLayer->snapToFeatureFrame(m_pane, f1i, res, Layer::SnapRight);
Chris@139 500
Chris@139 501 f0 = (f0i < 0 ? 0 : f0i);
Chris@139 502 f1 = (f1i < 0 ? 0 : f1i);
Chris@139 503 }
Chris@139 504
Chris@139 505 void
Chris@132 506 Analyser::saveState(Component c) const
Chris@132 507 {
Chris@132 508 bool v = isVisible(c);
Chris@132 509 bool a = isAudible(c);
Chris@132 510 QSettings settings;
Chris@132 511 settings.beginGroup("Analyser");
Chris@145 512 settings.setValue(QString("visible-%1").arg(int(c)), v);
Chris@145 513 settings.setValue(QString("audible-%1").arg(int(c)), a);
Chris@132 514 settings.endGroup();
Chris@132 515 }
Chris@132 516
Chris@132 517 void
Chris@132 518 Analyser::loadState(Component c)
Chris@132 519 {
Chris@132 520 QSettings settings;
Chris@132 521 settings.beginGroup("Analyser");
Chris@145 522 bool deflt = (c == Spectrogram ? false : true);
Chris@145 523 bool v = settings.value(QString("visible-%1").arg(int(c)), deflt).toBool();
Chris@145 524 bool a = settings.value(QString("audible-%1").arg(int(c)), true).toBool();
Chris@132 525 settings.endGroup();
Chris@132 526 setVisible(c, v);
Chris@132 527 setAudible(c, a);
Chris@132 528 }
Chris@132 529
Chris@132 530 void
gyorgyf@45 531 Analyser::setIntelligentActions(bool on)
gyorgyf@45 532 {
gyorgyf@45 533 std::cerr << "toggle setIntelligentActions " << on << std::endl;
Chris@128 534
Chris@128 535 FlexiNoteLayer *flexiNoteLayer =
Chris@128 536 qobject_cast<FlexiNoteLayer *>(m_layers[Notes]);
Chris@128 537 if (flexiNoteLayer) {
Chris@128 538 flexiNoteLayer->setIntelligentActions(on);
Chris@70 539 }
gyorgyf@45 540 }
Chris@128 541
Chris@128 542 bool
Chris@128 543 Analyser::isVisible(Component c) const
Chris@128 544 {
Chris@128 545 if (m_layers[c]) {
Chris@128 546 return !m_layers[c]->isLayerDormant(m_pane);
Chris@128 547 } else {
Chris@128 548 return false;
Chris@128 549 }
Chris@128 550 }
Chris@128 551
Chris@128 552 void
Chris@128 553 Analyser::setVisible(Component c, bool v)
Chris@128 554 {
Chris@128 555 if (m_layers[c]) {
Chris@128 556 m_layers[c]->setLayerDormant(m_pane, !v);
Chris@133 557
Chris@167 558 if (v) {
Chris@167 559 if (c == Notes) {
Chris@167 560 m_paneStack->setCurrentLayer(m_pane, m_layers[c]);
Chris@167 561 } else if (c == PitchTrack) {
Chris@167 562 // raise the pitch track, then notes on top (if present)
Chris@167 563 m_paneStack->setCurrentLayer(m_pane, m_layers[c]);
Chris@167 564 if (m_layers[Notes] &&
Chris@167 565 !m_layers[Notes]->isLayerDormant(m_pane)) {
Chris@167 566 m_paneStack->setCurrentLayer(m_pane, m_layers[Notes]);
Chris@167 567 }
Chris@167 568 }
Chris@133 569 }
Chris@133 570
Chris@128 571 m_pane->layerParametersChanged();
Chris@132 572 saveState(c);
Chris@128 573 }
Chris@128 574 }
Chris@128 575
Chris@128 576 bool
Chris@128 577 Analyser::isAudible(Component c) const
Chris@128 578 {
Chris@128 579 if (m_layers[c]) {
Chris@128 580 PlayParameters *params = m_layers[c]->getPlayParameters();
Chris@128 581 if (!params) return false;
Chris@128 582 return params->isPlayAudible();
Chris@128 583 } else {
Chris@128 584 return false;
Chris@128 585 }
Chris@128 586 }
Chris@128 587
Chris@128 588 void
Chris@128 589 Analyser::setAudible(Component c, bool a)
Chris@128 590 {
Chris@128 591 if (m_layers[c]) {
Chris@128 592 PlayParameters *params = m_layers[c]->getPlayParameters();
Chris@128 593 if (!params) return;
Chris@128 594 params->setPlayAudible(a);
Chris@132 595 saveState(c);
Chris@128 596 }
Chris@128 597 }
Chris@128 598
Chris@158 599 float
Chris@158 600 Analyser::getGain(Component c) const
Chris@158 601 {
Chris@158 602 if (m_layers[c]) {
Chris@158 603 PlayParameters *params = m_layers[c]->getPlayParameters();
Chris@158 604 if (!params) return 1.f;
Chris@158 605 return params->getPlayGain();
Chris@158 606 } else {
Chris@158 607 return 1.f;
Chris@158 608 }
Chris@158 609 }
Chris@158 610
Chris@158 611 void
Chris@158 612 Analyser::setGain(Component c, float gain)
Chris@158 613 {
Chris@158 614 if (m_layers[c]) {
Chris@158 615 PlayParameters *params = m_layers[c]->getPlayParameters();
Chris@158 616 if (!params) return;
Chris@158 617 params->setPlayGain(gain);
Chris@158 618 saveState(c);
Chris@158 619 }
Chris@158 620 }
Chris@158 621
Chris@158 622 float
Chris@158 623 Analyser::getPan(Component c) const
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 1.f;
Chris@158 628 return params->getPlayPan();
Chris@158 629 } else {
Chris@158 630 return 1.f;
Chris@158 631 }
Chris@158 632 }
Chris@158 633
Chris@158 634 void
Chris@158 635 Analyser::setPan(Component c, float pan)
Chris@158 636 {
Chris@158 637 if (m_layers[c]) {
Chris@158 638 PlayParameters *params = m_layers[c]->getPlayParameters();
Chris@158 639 if (!params) return;
Chris@158 640 params->setPlayPan(pan);
Chris@158 641 saveState(c);
Chris@158 642 }
Chris@158 643 }
Chris@158 644
Chris@158 645
Chris@158 646