annotate src/Analyser.cpp @ 160:106fdf38c6c9

added pan knobs for Audio, Pitch and Notes
author Justin Salamon <justin.salamon@nyu.edu>
date Thu, 23 Jan 2014 17:18:53 -0500
parents e1a2c175a0e0
children afaa4af03b22
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@6 34
Chris@83 35 #include <QSettings>
Chris@83 36
Chris@6 37 Analyser::Analyser() :
Chris@6 38 m_document(0),
Chris@6 39 m_fileModel(0),
Chris@133 40 m_paneStack(0),
Chris@128 41 m_pane(0)
Chris@6 42 {
Chris@83 43 QSettings settings;
Chris@83 44 settings.beginGroup("LayerDefaults");
Chris@83 45 settings.setValue
Chris@83 46 ("timevalues",
Chris@83 47 QString("<layer verticalScale=\"%1\" plotStyle=\"%2\" "
Chris@83 48 "scaleMinimum=\"%3\" scaleMaximum=\"%4\"/>")
Chris@145 49 .arg(int(TimeValueLayer::AutoAlignScale))
Chris@83 50 .arg(int(TimeValueLayer::PlotDiscreteCurves))
Chris@83 51 .arg(27.5f).arg(880.f)); // temporary values: better get the real extents of the data from the model
Chris@83 52 settings.setValue
Chris@83 53 ("flexinotes",
Chris@83 54 QString("<layer verticalScale=\"%1\"/>")
Chris@83 55 .arg(int(FlexiNoteLayer::AutoAlignScale)));
Chris@83 56 settings.endGroup();
Chris@6 57 }
Chris@6 58
Chris@6 59 Analyser::~Analyser()
Chris@6 60 {
Chris@6 61 }
Chris@6 62
Chris@140 63 QString
Chris@6 64 Analyser::newFileLoaded(Document *doc, WaveFileModel *model,
Chris@6 65 PaneStack *paneStack, Pane *pane)
Chris@6 66 {
Chris@6 67 m_document = doc;
Chris@6 68 m_fileModel = model;
Chris@133 69 m_paneStack = paneStack;
Chris@6 70 m_pane = pane;
Chris@6 71
Chris@140 72 QString plugname = "pYIN";
Chris@83 73 QString base = "vamp:pyin:pyin:";
Chris@83 74 QString f0out = "smoothedpitchtrack";
Chris@83 75 QString noteout = "notes";
Chris@6 76
Chris@120 77 // We need at least one main-model layer (time ruler, waveform or
Chris@120 78 // what have you). It could be hidden if we don't want to see it
Chris@120 79 // but it must exist.
Chris@6 80
Chris@145 81 // A spectrogram, off by default. Must go at the back because it's
Chris@145 82 // opaque
Chris@145 83
Chris@145 84 SpectrogramLayer *spectrogram = qobject_cast<SpectrogramLayer *>
Chris@145 85 (m_document->createMainModelLayer(LayerFactory::MelodicRangeSpectrogram));
Chris@145 86 spectrogram->setColourMap((int)ColourMapper::BlackOnWhite);
Chris@145 87 m_document->addLayerToView(m_pane, spectrogram);
Chris@145 88 spectrogram->setLayerDormant(m_pane, true);
Chris@145 89
Chris@145 90 m_layers[Spectrogram] = spectrogram;
Chris@145 91
Chris@131 92 // Our waveform layer is just a shadow, light grey and taking up
Chris@120 93 // little space at the bottom
Chris@120 94
Chris@120 95 WaveformLayer *waveform = qobject_cast<WaveformLayer *>
Chris@120 96 (m_document->createMainModelLayer(LayerFactory::Waveform));
Chris@120 97
Chris@120 98 waveform->setMiddleLineHeight(0.9);
Chris@120 99 waveform->setShowMeans(false); // too small & pale for this
Chris@120 100 waveform->setBaseColour
Chris@120 101 (ColourDatabase::getInstance()->getColourIndex(tr("Grey")));
Chris@130 102 PlayParameters *params = waveform->getPlayParameters();
justin@160 103 if (params) params->setPlayPan(-1);
Chris@128 104
Chris@128 105 m_document->addLayerToView(m_pane, waveform);
Chris@120 106
Chris@128 107 m_layers[Audio] = waveform;
Chris@120 108
Chris@83 109 Transforms transforms;
Chris@83 110
Chris@83 111 TransformFactory *tf = TransformFactory::getInstance();
Chris@138 112
Chris@138 113 /*!!! we could have more than one pitch track...
Chris@138 114 QString cx = "vamp:cepstral-pitchtracker:cepstral-pitchtracker:f0";
Chris@138 115 if (tf->haveTransform(cx)) {
Chris@138 116 Transform tx = tf->getDefaultTransformFor(cx);
Chris@138 117 TimeValueLayer *lx = qobject_cast<TimeValueLayer *>
Chris@138 118 (m_document->createDerivedLayer(tx, m_fileModel));
Chris@138 119 lx->setVerticalScale(TimeValueLayer::AutoAlignScale);
Chris@138 120 lx->setBaseColour(ColourDatabase::getInstance()->getColourIndex(tr("Bright Red")));
Chris@138 121 m_document->addLayerToView(m_pane, lx);
Chris@138 122 }
Chris@138 123 */
Chris@138 124
Chris@140 125 QString notFound = tr("Transform \"%1\" not found. Unable to analyse audio file.<br><br>Is the %2 Vamp plugin correctly installed?");
Chris@140 126 if (!tf->haveTransform(base + f0out)) {
Chris@140 127 return notFound.arg(base + f0out).arg(plugname);
Chris@140 128 }
Chris@140 129 if (!tf->haveTransform(base + noteout)) {
Chris@140 130 return notFound.arg(base + noteout).arg(plugname);
Chris@6 131 }
Chris@6 132
Chris@83 133 Transform t = tf->getDefaultTransformFor
Chris@83 134 (base + f0out, m_fileModel->getSampleRate());
Chris@83 135 t.setStepSize(256);
Chris@83 136 t.setBlockSize(2048);
Chris@6 137
Chris@83 138 transforms.push_back(t);
Chris@83 139
Chris@83 140 t.setOutput(noteout);
Chris@83 141
Chris@83 142 transforms.push_back(t);
Chris@83 143
Chris@83 144 std::vector<Layer *> layers =
Chris@83 145 m_document->createDerivedLayers(transforms, m_fileModel);
Chris@83 146
Chris@83 147 if (!layers.empty()) {
Chris@83 148
Chris@83 149 for (int i = 0; i < (int)layers.size(); ++i) {
Chris@83 150
Chris@128 151 FlexiNoteLayer *f = qobject_cast<FlexiNoteLayer *>(layers[i]);
Chris@128 152 TimeValueLayer *t = qobject_cast<TimeValueLayer *>(layers[i]);
Chris@83 153
Chris@128 154 if (f) m_layers[Notes] = f;
Chris@128 155 if (t) m_layers[PitchTrack] = t;
Chris@83 156
Chris@83 157 m_document->addLayerToView(m_pane, layers[i]);
Chris@83 158 }
Chris@128 159
Chris@128 160 ColourDatabase *cdb = ColourDatabase::getInstance();
Chris@83 161
Chris@128 162 TimeValueLayer *pitchLayer =
Chris@128 163 qobject_cast<TimeValueLayer *>(m_layers[PitchTrack]);
Chris@128 164 if (pitchLayer) {
Chris@128 165 pitchLayer->setBaseColour(cdb->getColourIndex(tr("Black")));
Chris@130 166 PlayParameters *params = pitchLayer->getPlayParameters();
justin@160 167 if (params) params->setPlayPan(1);
Chris@128 168 }
Chris@128 169
Chris@128 170 FlexiNoteLayer *flexiNoteLayer =
Chris@128 171 qobject_cast<FlexiNoteLayer *>(m_layers[Notes]);
Chris@128 172 if (flexiNoteLayer) {
Chris@128 173 flexiNoteLayer->setBaseColour(cdb->getColourIndex(tr("Bright Blue")));
Chris@130 174 PlayParameters *params = flexiNoteLayer->getPlayParameters();
justin@160 175 if (params) params->setPlayPan(1);
Chris@128 176 }
Chris@6 177 }
Chris@128 178
Chris@132 179 loadState(Audio);
Chris@132 180 loadState(PitchTrack);
Chris@132 181 loadState(Notes);
Chris@145 182 loadState(Spectrogram);
Chris@132 183
Chris@128 184 emit layersChanged();
Chris@140 185
Chris@140 186 return "";
Chris@6 187 }
Chris@6 188
gyorgyf@45 189 void
Chris@139 190 Analyser::getEnclosingSelectionScope(size_t f, size_t &f0, size_t &f1)
Chris@139 191 {
Chris@139 192 FlexiNoteLayer *flexiNoteLayer =
Chris@139 193 qobject_cast<FlexiNoteLayer *>(m_layers[Notes]);
Chris@139 194
Chris@139 195 int f0i = f, f1i = f;
Chris@139 196 size_t res = 1;
Chris@139 197
Chris@139 198 if (!flexiNoteLayer) {
Chris@139 199 f0 = f1 = f;
Chris@139 200 return;
Chris@139 201 }
Chris@139 202
Chris@139 203 flexiNoteLayer->snapToFeatureFrame(m_pane, f0i, res, Layer::SnapLeft);
Chris@139 204 flexiNoteLayer->snapToFeatureFrame(m_pane, f1i, res, Layer::SnapRight);
Chris@139 205
Chris@139 206 f0 = (f0i < 0 ? 0 : f0i);
Chris@139 207 f1 = (f1i < 0 ? 0 : f1i);
Chris@139 208 }
Chris@139 209
Chris@139 210 void
Chris@132 211 Analyser::saveState(Component c) const
Chris@132 212 {
Chris@132 213 bool v = isVisible(c);
Chris@132 214 bool a = isAudible(c);
Chris@132 215 QSettings settings;
Chris@132 216 settings.beginGroup("Analyser");
Chris@145 217 settings.setValue(QString("visible-%1").arg(int(c)), v);
Chris@145 218 settings.setValue(QString("audible-%1").arg(int(c)), a);
Chris@132 219 settings.endGroup();
Chris@132 220 }
Chris@132 221
Chris@132 222 void
Chris@132 223 Analyser::loadState(Component c)
Chris@132 224 {
Chris@132 225 QSettings settings;
Chris@132 226 settings.beginGroup("Analyser");
Chris@145 227 bool deflt = (c == Spectrogram ? false : true);
Chris@145 228 bool v = settings.value(QString("visible-%1").arg(int(c)), deflt).toBool();
Chris@145 229 bool a = settings.value(QString("audible-%1").arg(int(c)), true).toBool();
Chris@132 230 settings.endGroup();
Chris@132 231 setVisible(c, v);
Chris@132 232 setAudible(c, a);
Chris@132 233 }
Chris@132 234
Chris@132 235 void
gyorgyf@45 236 Analyser::setIntelligentActions(bool on)
gyorgyf@45 237 {
gyorgyf@45 238 std::cerr << "toggle setIntelligentActions " << on << std::endl;
Chris@128 239
Chris@128 240 FlexiNoteLayer *flexiNoteLayer =
Chris@128 241 qobject_cast<FlexiNoteLayer *>(m_layers[Notes]);
Chris@128 242 if (flexiNoteLayer) {
Chris@128 243 flexiNoteLayer->setIntelligentActions(on);
Chris@70 244 }
gyorgyf@45 245 }
Chris@128 246
Chris@128 247 bool
Chris@128 248 Analyser::isVisible(Component c) const
Chris@128 249 {
Chris@128 250 if (m_layers[c]) {
Chris@128 251 return !m_layers[c]->isLayerDormant(m_pane);
Chris@128 252 } else {
Chris@128 253 return false;
Chris@128 254 }
Chris@128 255 }
Chris@128 256
Chris@128 257 void
Chris@128 258 Analyser::setVisible(Component c, bool v)
Chris@128 259 {
Chris@128 260 if (m_layers[c]) {
Chris@128 261 m_layers[c]->setLayerDormant(m_pane, !v);
Chris@133 262
Chris@133 263 if (v && (c == Notes)) {
Chris@133 264 m_paneStack->setCurrentLayer(m_pane, m_layers[c]);
Chris@133 265 }
Chris@133 266
Chris@128 267 m_pane->layerParametersChanged();
Chris@132 268 saveState(c);
Chris@128 269 }
Chris@128 270 }
Chris@128 271
Chris@128 272 bool
Chris@128 273 Analyser::isAudible(Component c) const
Chris@128 274 {
Chris@128 275 if (m_layers[c]) {
Chris@128 276 PlayParameters *params = m_layers[c]->getPlayParameters();
Chris@128 277 if (!params) return false;
Chris@128 278 return params->isPlayAudible();
Chris@128 279 } else {
Chris@128 280 return false;
Chris@128 281 }
Chris@128 282 }
Chris@128 283
Chris@128 284 void
Chris@128 285 Analyser::setAudible(Component c, bool a)
Chris@128 286 {
Chris@128 287 if (m_layers[c]) {
Chris@128 288 PlayParameters *params = m_layers[c]->getPlayParameters();
Chris@128 289 if (!params) return;
Chris@128 290 params->setPlayAudible(a);
Chris@132 291 saveState(c);
Chris@128 292 }
Chris@128 293 }
Chris@128 294
Chris@158 295 float
Chris@158 296 Analyser::getGain(Component c) const
Chris@158 297 {
Chris@158 298 if (m_layers[c]) {
Chris@158 299 PlayParameters *params = m_layers[c]->getPlayParameters();
Chris@158 300 if (!params) return 1.f;
Chris@158 301 return params->getPlayGain();
Chris@158 302 } else {
Chris@158 303 return 1.f;
Chris@158 304 }
Chris@158 305 }
Chris@158 306
Chris@158 307 void
Chris@158 308 Analyser::setGain(Component c, float gain)
Chris@158 309 {
Chris@158 310 if (m_layers[c]) {
Chris@158 311 PlayParameters *params = m_layers[c]->getPlayParameters();
Chris@158 312 if (!params) return;
Chris@158 313 params->setPlayGain(gain);
Chris@158 314 saveState(c);
Chris@158 315 }
Chris@158 316 }
Chris@158 317
Chris@158 318 float
Chris@158 319 Analyser::getPan(Component c) const
Chris@158 320 {
Chris@158 321 if (m_layers[c]) {
Chris@158 322 PlayParameters *params = m_layers[c]->getPlayParameters();
Chris@158 323 if (!params) return 1.f;
Chris@158 324 return params->getPlayPan();
Chris@158 325 } else {
Chris@158 326 return 1.f;
Chris@158 327 }
Chris@158 328 }
Chris@158 329
Chris@158 330 void
Chris@158 331 Analyser::setPan(Component c, float pan)
Chris@158 332 {
Chris@158 333 if (m_layers[c]) {
Chris@158 334 PlayParameters *params = m_layers[c]->getPlayParameters();
Chris@158 335 if (!params) return;
Chris@158 336 params->setPlayPan(pan);
Chris@158 337 saveState(c);
Chris@158 338 }
Chris@158 339 }
Chris@158 340
Chris@158 341
Chris@158 342