annotate base/ViewManager.cpp @ 76:af2725b5d6fe

* Implement harmonic cursor in spectrogram * Implement layer export. This doesn't quite do the right thing for the SV XML layer export yet -- it doesn't include layer display information, so when imported, it only creates an invisible model. Could also do with fixing CSV file import so as to work correctly for note and text layers.
author Chris Cannam
date Mon, 10 Apr 2006 17:22:59 +0000
parents 163f3428bbe0
children f277a171749d
rev   line source
Chris@49 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@52 4 Sonic Visualiser
Chris@52 5 An audio file viewer and annotation editor.
Chris@52 6 Centre for Digital Music, Queen Mary, University of London.
Chris@52 7 This file copyright 2006 Chris Cannam.
Chris@0 8
Chris@52 9 This program is free software; you can redistribute it and/or
Chris@52 10 modify it under the terms of the GNU General Public License as
Chris@52 11 published by the Free Software Foundation; either version 2 of the
Chris@52 12 License, or (at your option) any later version. See the file
Chris@52 13 COPYING included with this distribution for more information.
Chris@0 14 */
Chris@0 15
Chris@0 16 #include "ViewManager.h"
Chris@0 17 #include "AudioPlaySource.h"
Chris@0 18 #include "Model.h"
Chris@45 19 #include "CommandHistory.h"
Chris@0 20
Chris@0 21 #include <iostream>
Chris@0 22
Chris@75 23 #include <QDir>
Chris@75 24 #include <QFile>
Chris@75 25
Chris@75 26 #include <cassert>
Chris@75 27
Martin@54 28 // #define DEBUG_VIEW_MANAGER 1
Chris@0 29
Chris@0 30 ViewManager::ViewManager() :
Chris@0 31 m_playSource(0),
Chris@0 32 m_globalCentreFrame(0),
Chris@0 33 m_globalZoom(1024),
Chris@24 34 m_playbackFrame(0),
Chris@42 35 m_mainModelSampleRate(0),
Chris@0 36 m_lastLeft(0),
Chris@8 37 m_lastRight(0),
Chris@8 38 m_inProgressExclusive(true),
Chris@9 39 m_toolMode(NavigateMode),
Chris@9 40 m_playLoopMode(false),
Chris@65 41 m_playSelectionMode(false),
Chris@65 42 m_overlayMode(BasicOverlays)
Chris@0 43 {
Chris@0 44 connect(this,
Chris@0 45 SIGNAL(centreFrameChanged(void *, unsigned long, bool)),
Chris@0 46 SLOT(considerSeek(void *, unsigned long, bool)));
Chris@0 47
Chris@0 48 connect(this,
Chris@0 49 SIGNAL(zoomLevelChanged(void *, unsigned long, bool)),
Chris@0 50 SLOT(considerZoomChange(void *, unsigned long, bool)));
Chris@0 51 }
Chris@0 52
Chris@75 53 ViewManager::~ViewManager()
Chris@75 54 {
Chris@75 55 if (m_tmpdir != "") deleteTemporaryDirectory(m_tmpdir);
Chris@75 56 }
Chris@75 57
Chris@0 58 unsigned long
Chris@0 59 ViewManager::getGlobalCentreFrame() const
Chris@0 60 {
Chris@0 61 #ifdef DEBUG_VIEW_MANAGER
Chris@0 62 std::cout << "ViewManager::getGlobalCentreFrame: returning " << m_globalCentreFrame << std::endl;
Chris@0 63 #endif
Chris@0 64 return m_globalCentreFrame;
Chris@0 65 }
Chris@0 66
Chris@0 67 unsigned long
Chris@0 68 ViewManager::getGlobalZoom() const
Chris@0 69 {
Chris@0 70 #ifdef DEBUG_VIEW_MANAGER
Chris@0 71 std::cout << "ViewManager::getGlobalZoom: returning " << m_globalZoom << std::endl;
Chris@0 72 #endif
Chris@0 73 return m_globalZoom;
Chris@0 74 }
Chris@0 75
Chris@24 76 unsigned long
Chris@24 77 ViewManager::getPlaybackFrame() const
Chris@24 78 {
Chris@24 79 if (m_playSource && m_playSource->isPlaying()) {
Chris@24 80 m_playbackFrame = m_playSource->getCurrentPlayingFrame();
Chris@24 81 }
Chris@24 82 return m_playbackFrame;
Chris@24 83 }
Chris@24 84
Chris@24 85 void
Chris@24 86 ViewManager::setPlaybackFrame(unsigned long f)
Chris@24 87 {
Chris@24 88 if (m_playbackFrame != f) {
Chris@24 89 m_playbackFrame = f;
Chris@60 90 emit playbackFrameChanged(f);
Chris@24 91 if (m_playSource && m_playSource->isPlaying()) {
Chris@24 92 m_playSource->play(f);
Chris@24 93 }
Chris@24 94 }
Chris@24 95 }
Chris@24 96
Chris@8 97 bool
Chris@8 98 ViewManager::haveInProgressSelection() const
Chris@8 99 {
Chris@8 100 return !m_inProgressSelection.isEmpty();
Chris@8 101 }
Chris@8 102
Chris@8 103 const Selection &
Chris@8 104 ViewManager::getInProgressSelection(bool &exclusive) const
Chris@8 105 {
Chris@8 106 exclusive = m_inProgressExclusive;
Chris@8 107 return m_inProgressSelection;
Chris@8 108 }
Chris@8 109
Chris@8 110 void
Chris@8 111 ViewManager::setInProgressSelection(const Selection &selection, bool exclusive)
Chris@8 112 {
Chris@8 113 m_inProgressExclusive = exclusive;
Chris@8 114 m_inProgressSelection = selection;
Chris@8 115 if (exclusive) clearSelections();
Chris@9 116 emit inProgressSelectionChanged();
Chris@8 117 }
Chris@8 118
Chris@8 119 void
Chris@8 120 ViewManager::clearInProgressSelection()
Chris@8 121 {
Chris@8 122 m_inProgressSelection = Selection();
Chris@9 123 emit inProgressSelectionChanged();
Chris@8 124 }
Chris@8 125
Chris@34 126 const MultiSelection &
Chris@34 127 ViewManager::getSelection() const
Chris@34 128 {
Chris@34 129 return m_selections;
Chris@34 130 }
Chris@34 131
Chris@24 132 const MultiSelection::SelectionList &
Chris@8 133 ViewManager::getSelections() const
Chris@8 134 {
Chris@24 135 return m_selections.getSelections();
Chris@8 136 }
Chris@8 137
Chris@8 138 void
Chris@8 139 ViewManager::setSelection(const Selection &selection)
Chris@8 140 {
Chris@45 141 MultiSelection ms(m_selections);
Chris@45 142 ms.setSelection(selection);
Chris@45 143 setSelections(ms);
Chris@8 144 }
Chris@8 145
Chris@8 146 void
Chris@8 147 ViewManager::addSelection(const Selection &selection)
Chris@8 148 {
Chris@45 149 MultiSelection ms(m_selections);
Chris@45 150 ms.addSelection(selection);
Chris@45 151 setSelections(ms);
Chris@8 152 }
Chris@8 153
Chris@8 154 void
Chris@8 155 ViewManager::removeSelection(const Selection &selection)
Chris@8 156 {
Chris@45 157 MultiSelection ms(m_selections);
Chris@45 158 ms.removeSelection(selection);
Chris@45 159 setSelections(ms);
Chris@8 160 }
Chris@8 161
Chris@8 162 void
Chris@8 163 ViewManager::clearSelections()
Chris@8 164 {
Chris@45 165 MultiSelection ms(m_selections);
Chris@45 166 ms.clearSelections();
Chris@45 167 setSelections(ms);
Chris@45 168 }
Chris@45 169
Chris@45 170 void
Chris@45 171 ViewManager::setSelections(const MultiSelection &ms)
Chris@45 172 {
Chris@45 173 if (m_selections.getSelections() == ms.getSelections()) return;
Chris@45 174 SetSelectionCommand *command = new SetSelectionCommand(this, ms);
Chris@45 175 CommandHistory::getInstance()->addCommand(command);
Chris@45 176 }
Chris@45 177
Chris@45 178 void
Chris@45 179 ViewManager::signalSelectionChange()
Chris@45 180 {
Chris@24 181 emit selectionChanged();
Chris@8 182 }
Chris@8 183
Chris@45 184 ViewManager::SetSelectionCommand::SetSelectionCommand(ViewManager *vm,
Chris@45 185 const MultiSelection &ms) :
Chris@45 186 m_vm(vm),
Chris@45 187 m_oldSelection(vm->m_selections),
Chris@45 188 m_newSelection(ms)
Chris@45 189 {
Chris@45 190 }
Chris@45 191
Chris@45 192 ViewManager::SetSelectionCommand::~SetSelectionCommand() { }
Chris@45 193
Chris@45 194 void
Chris@45 195 ViewManager::SetSelectionCommand::execute()
Chris@45 196 {
Chris@45 197 m_vm->m_selections = m_newSelection;
Chris@45 198 m_vm->signalSelectionChange();
Chris@45 199 }
Chris@45 200
Chris@45 201 void
Chris@45 202 ViewManager::SetSelectionCommand::unexecute()
Chris@45 203 {
Chris@45 204 m_vm->m_selections = m_oldSelection;
Chris@45 205 m_vm->signalSelectionChange();
Chris@45 206 }
Chris@45 207
Chris@45 208 QString
Chris@45 209 ViewManager::SetSelectionCommand::getName() const
Chris@45 210 {
Chris@45 211 if (m_newSelection.getSelections().empty()) return tr("Clear Selection");
Chris@45 212 else return tr("Select");
Chris@45 213 }
Chris@45 214
Chris@9 215 Selection
Chris@36 216 ViewManager::getContainingSelection(size_t frame, bool defaultToFollowing) const
Chris@9 217 {
Chris@24 218 return m_selections.getContainingSelection(frame, defaultToFollowing);
Chris@9 219 }
Chris@9 220
Chris@8 221 void
Chris@8 222 ViewManager::setToolMode(ToolMode mode)
Chris@8 223 {
Chris@8 224 m_toolMode = mode;
Chris@8 225
Chris@8 226 emit toolModeChanged();
Chris@8 227 }
Chris@8 228
Chris@0 229 void
Chris@9 230 ViewManager::setPlayLoopMode(bool mode)
Chris@9 231 {
Chris@9 232 m_playLoopMode = mode;
Chris@9 233
Chris@9 234 emit playLoopModeChanged();
Chris@9 235 }
Chris@9 236
Chris@9 237 void
Chris@9 238 ViewManager::setPlaySelectionMode(bool mode)
Chris@9 239 {
Chris@9 240 m_playSelectionMode = mode;
Chris@9 241
Chris@9 242 emit playSelectionModeChanged();
Chris@9 243 }
Chris@9 244
Chris@40 245 size_t
Chris@40 246 ViewManager::getPlaybackSampleRate() const
Chris@40 247 {
Chris@40 248 if (m_playSource) {
Chris@40 249 return m_playSource->getTargetSampleRate();
Chris@40 250 }
Chris@40 251 return 0;
Chris@40 252 }
Chris@40 253
Chris@9 254 void
Chris@0 255 ViewManager::setAudioPlaySource(AudioPlaySource *source)
Chris@0 256 {
Chris@0 257 if (!m_playSource) {
Chris@0 258 QTimer::singleShot(100, this, SLOT(checkPlayStatus()));
Chris@0 259 }
Chris@0 260 m_playSource = source;
Chris@0 261 }
Chris@0 262
Chris@0 263 void
Chris@10 264 ViewManager::playStatusChanged(bool playing)
Chris@10 265 {
Chris@10 266 checkPlayStatus();
Chris@10 267 }
Chris@10 268
Chris@10 269 void
Chris@0 270 ViewManager::checkPlayStatus()
Chris@0 271 {
Chris@0 272 if (m_playSource && m_playSource->isPlaying()) {
Chris@0 273
Chris@0 274 float left = 0, right = 0;
Chris@0 275 if (m_playSource->getOutputLevels(left, right)) {
Chris@0 276 if (left != m_lastLeft || right != m_lastRight) {
Chris@0 277 emit outputLevelsChanged(left, right);
Chris@0 278 m_lastLeft = left;
Chris@0 279 m_lastRight = right;
Chris@0 280 }
Chris@0 281 }
Chris@0 282
Chris@24 283 m_playbackFrame = m_playSource->getCurrentPlayingFrame();
Chris@0 284
Chris@0 285 #ifdef DEBUG_VIEW_MANAGER
Chris@24 286 std::cout << "ViewManager::checkPlayStatus: Playing, frame " << m_playbackFrame << ", levels " << m_lastLeft << "," << m_lastRight << std::endl;
Chris@0 287 #endif
Chris@0 288
Chris@24 289 emit playbackFrameChanged(m_playbackFrame);
Chris@0 290
Chris@0 291 QTimer::singleShot(20, this, SLOT(checkPlayStatus()));
Chris@0 292
Chris@0 293 } else {
Chris@0 294
Chris@0 295 QTimer::singleShot(100, this, SLOT(checkPlayStatus()));
Chris@0 296
Chris@0 297 if (m_lastLeft != 0.0 || m_lastRight != 0.0) {
Chris@0 298 emit outputLevelsChanged(0.0, 0.0);
Chris@0 299 m_lastLeft = 0.0;
Chris@0 300 m_lastRight = 0.0;
Chris@0 301 }
Chris@0 302
Chris@0 303 #ifdef DEBUG_VIEW_MANAGER
Chris@0 304 // std::cout << "ViewManager::checkPlayStatus: Not playing" << std::endl;
Chris@0 305 #endif
Chris@0 306 }
Chris@0 307 }
Chris@0 308
Chris@8 309 bool
Chris@8 310 ViewManager::isPlaying() const
Chris@8 311 {
Chris@8 312 return m_playSource && m_playSource->isPlaying();
Chris@8 313 }
Chris@8 314
Chris@0 315 void
Chris@0 316 ViewManager::considerSeek(void *p, unsigned long f, bool locked)
Chris@0 317 {
Chris@0 318 if (locked) {
Chris@0 319 m_globalCentreFrame = f;
Chris@0 320 }
Chris@0 321
Chris@0 322 #ifdef DEBUG_VIEW_MANAGER
Chris@0 323 std::cout << "ViewManager::considerSeek(" << p << ", " << f << ", " << locked << ")" << std::endl;
Chris@0 324 #endif
Chris@0 325
Chris@0 326 if (p == this || !locked) return;
Chris@0 327
Chris@0 328 if (m_playSource && m_playSource->isPlaying()) {
Chris@0 329 unsigned long playFrame = m_playSource->getCurrentPlayingFrame();
Chris@0 330 unsigned long diff = std::max(f, playFrame) - std::min(f, playFrame);
Chris@0 331 if (diff > 20000) {
Chris@24 332 m_playbackFrame = f;
Chris@0 333 m_playSource->play(f);
Chris@0 334 #ifdef DEBUG_VIEW_MANAGER
Chris@0 335 std::cout << "ViewManager::considerSeek: reseeking from " << playFrame << " to " << f << std::endl;
Chris@0 336 #endif
Chris@0 337 }
Chris@24 338 } else {
Chris@24 339 m_playbackFrame = f; //!!! only if that view is in scroll mode?
Chris@0 340 }
Chris@0 341 }
Chris@0 342
Chris@0 343 void
Chris@0 344 ViewManager::considerZoomChange(void *p, unsigned long z, bool locked)
Chris@0 345 {
Chris@0 346 if (locked) {
Chris@0 347 m_globalZoom = z;
Chris@0 348 }
Chris@0 349
Chris@0 350 #ifdef DEBUG_VIEW_MANAGER
Chris@0 351 std::cout << "ViewManager::considerZoomChange(" << p << ", " << z << ", " << locked << ")" << std::endl;
Chris@0 352 #endif
Chris@0 353 }
Chris@0 354
Chris@65 355 void
Chris@65 356 ViewManager::setOverlayMode(OverlayMode mode)
Chris@65 357 {
Chris@65 358 if (m_overlayMode != mode) {
Chris@65 359 m_overlayMode = mode;
Chris@65 360 emit overlayModeChanged();
Chris@65 361 }
Chris@65 362 }
Chris@65 363
Chris@75 364 QString
Chris@75 365 ViewManager::getTemporaryDirectory()
Chris@75 366 {
Chris@75 367 if (m_tmpdir != "") return m_tmpdir;
Chris@75 368
Chris@75 369 // Generate a temporary directory. Qt4.1 doesn't seem to be able
Chris@75 370 // to do this for us, and mkdtemp is not standard. This method is
Chris@75 371 // based on the way glibc does mkdtemp.
Chris@75 372
Chris@75 373 static QString chars =
Chris@75 374 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Chris@75 375
Chris@75 376 QString suffix;
Chris@75 377 int padlen = 6, attempts = 100;
Chris@75 378 unsigned int r = time(0) ^ getpid();
Chris@75 379
Chris@75 380 for (int i = 0; i < padlen; ++i) {
Chris@75 381 suffix += "X";
Chris@75 382 }
Chris@75 383
Chris@75 384 for (int j = 0; j < attempts; ++j) {
Chris@75 385
Chris@75 386 unsigned int v = r;
Chris@75 387
Chris@75 388 for (int i = 0; i < padlen; ++i) {
Chris@75 389 suffix[i] = chars[v % 62];
Chris@75 390 v /= 62;
Chris@75 391 }
Chris@75 392
Chris@75 393 QString candidate = QString("sv_%1").arg(suffix);
Chris@75 394
Chris@75 395 if (QDir::temp().mkpath(candidate)) {
Chris@75 396 m_tmpdir = QDir::temp().filePath(candidate);
Chris@75 397 break;
Chris@75 398 }
Chris@75 399
Chris@75 400 r = r + 7777;
Chris@75 401 }
Chris@75 402
Chris@75 403 if (m_tmpdir == "") {
Chris@75 404 std::cerr << "ERROR: ViewManager::getTemporaryDirectory: "
Chris@75 405 << "Unable to create a temporary directory!" << std::endl;
Chris@75 406 assert(0);
Chris@75 407 }
Chris@75 408
Chris@75 409 return m_tmpdir;
Chris@75 410 }
Chris@75 411
Chris@75 412 void
Chris@75 413 ViewManager::deleteTemporaryDirectory(QString tmpdir)
Chris@75 414 {
Chris@75 415 if (tmpdir == "") return;
Chris@75 416
Chris@75 417 QDir dir(tmpdir);
Chris@75 418 dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
Chris@75 419
Chris@75 420 for (unsigned int i = 0; i < dir.count(); ++i) {
Chris@75 421
Chris@75 422 QFileInfo fi(dir.filePath(dir[i]));
Chris@75 423
Chris@75 424 if (fi.isDir()) {
Chris@75 425 deleteTemporaryDirectory(fi.absoluteFilePath());
Chris@75 426 } else {
Chris@75 427 if (!QFile(fi.absoluteFilePath()).remove()) {
Chris@75 428 std::cerr << "WARNING: ViewManager::deleteTemporaryDirectory: "
Chris@75 429 << "Failed to unlink file \""
Chris@75 430 << fi.absoluteFilePath().toStdString() << "\""
Chris@75 431 << std::endl;
Chris@75 432 }
Chris@75 433 }
Chris@75 434 }
Chris@75 435
Chris@75 436 QString dirname = dir.dirName();
Chris@75 437 if (dirname != "") {
Chris@75 438 if (!dir.cdUp()) {
Chris@75 439 std::cerr << "WARNING: ViewManager::deleteTemporaryDirectory: "
Chris@75 440 << "Failed to cd to parent directory of "
Chris@75 441 << tmpdir.toStdString() << std::endl;
Chris@75 442 return;
Chris@75 443 }
Chris@75 444 if (!dir.rmdir(dirname)) {
Chris@75 445 std::cerr << "WARNING: ViewManager::deleteTemporaryDirectory: "
Chris@75 446 << "Failed to remove directory "
Chris@75 447 << dirname.toStdString() << std::endl;
Chris@75 448 }
Chris@75 449 }
Chris@75 450 }
Chris@75 451
Chris@0 452 #ifdef INCLUDE_MOCFILES
Chris@0 453 #include "ViewManager.moc.cpp"
Chris@0 454 #endif
Chris@0 455