annotate base/ViewManager.cpp @ 20:742e6882e187

* Refactor sparse models. Previously the 1D and time-value models duplicated a lot of code; now there is a base class (SparseModel) templated on the stored point type, and the subclasses define point types with the necessary characteristics. * Add NoteModel, a new SparseModel subclass. * Reorganise local feature description display. Instead of asking the layer to draw its own, just query it for a textual description and draw that in Pane. Greatly simplifies this part of the layer code. * Add local feature descriptions to colour 3D plot and waveform layers. * Add pitch in MIDI-pitch-and-cents to spectrogram layer. * Give AudioGenerator its own mutex to shorten lock times in CallbackPlaySource. * Minor adjustments to layers menu &c
author Chris Cannam
date Thu, 02 Feb 2006 16:10:19 +0000
parents 4563a72c1d8b
children bb9291d84810
rev   line source
Chris@0 1 /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@0 4 A waveform viewer and audio annotation editor.
Chris@2 5 Chris Cannam, Queen Mary University of London, 2005-2006
Chris@0 6
Chris@0 7 This is experimental software. Not for distribution.
Chris@0 8 */
Chris@0 9
Chris@0 10 #include "ViewManager.h"
Chris@0 11 #include "AudioPlaySource.h"
Chris@0 12 #include "PlayParameters.h"
Chris@0 13 #include "Model.h"
Chris@0 14
Chris@0 15 #include <iostream>
Chris@0 16
Chris@18 17 //#define DEBUG_VIEW_MANAGER 1
Chris@0 18
Chris@0 19 ViewManager::ViewManager() :
Chris@0 20 m_playSource(0),
Chris@0 21 m_globalCentreFrame(0),
Chris@0 22 m_globalZoom(1024),
Chris@0 23 m_lastLeft(0),
Chris@8 24 m_lastRight(0),
Chris@8 25 m_inProgressExclusive(true),
Chris@9 26 m_toolMode(NavigateMode),
Chris@9 27 m_playLoopMode(false),
Chris@20 28 m_playSelectionMode(false)
Chris@0 29 {
Chris@0 30 connect(this,
Chris@0 31 SIGNAL(centreFrameChanged(void *, unsigned long, bool)),
Chris@0 32 SLOT(considerSeek(void *, unsigned long, bool)));
Chris@0 33
Chris@0 34 connect(this,
Chris@0 35 SIGNAL(zoomLevelChanged(void *, unsigned long, bool)),
Chris@0 36 SLOT(considerZoomChange(void *, unsigned long, bool)));
Chris@0 37 }
Chris@0 38
Chris@0 39 unsigned long
Chris@0 40 ViewManager::getGlobalCentreFrame() const
Chris@0 41 {
Chris@0 42 #ifdef DEBUG_VIEW_MANAGER
Chris@0 43 std::cout << "ViewManager::getGlobalCentreFrame: returning " << m_globalCentreFrame << std::endl;
Chris@0 44 #endif
Chris@0 45 return m_globalCentreFrame;
Chris@0 46 }
Chris@0 47
Chris@0 48 unsigned long
Chris@0 49 ViewManager::getGlobalZoom() const
Chris@0 50 {
Chris@0 51 #ifdef DEBUG_VIEW_MANAGER
Chris@0 52 std::cout << "ViewManager::getGlobalZoom: returning " << m_globalZoom << std::endl;
Chris@0 53 #endif
Chris@0 54 return m_globalZoom;
Chris@0 55 }
Chris@0 56
Chris@8 57 bool
Chris@8 58 ViewManager::haveInProgressSelection() const
Chris@8 59 {
Chris@8 60 return !m_inProgressSelection.isEmpty();
Chris@8 61 }
Chris@8 62
Chris@8 63 const Selection &
Chris@8 64 ViewManager::getInProgressSelection(bool &exclusive) const
Chris@8 65 {
Chris@8 66 exclusive = m_inProgressExclusive;
Chris@8 67 return m_inProgressSelection;
Chris@8 68 }
Chris@8 69
Chris@8 70 void
Chris@8 71 ViewManager::setInProgressSelection(const Selection &selection, bool exclusive)
Chris@8 72 {
Chris@8 73 m_inProgressExclusive = exclusive;
Chris@8 74 m_inProgressSelection = selection;
Chris@8 75 if (exclusive) clearSelections();
Chris@9 76 emit inProgressSelectionChanged();
Chris@8 77 }
Chris@8 78
Chris@8 79 void
Chris@8 80 ViewManager::clearInProgressSelection()
Chris@8 81 {
Chris@8 82 m_inProgressSelection = Selection();
Chris@9 83 emit inProgressSelectionChanged();
Chris@8 84 }
Chris@8 85
Chris@8 86 const ViewManager::SelectionList &
Chris@8 87 ViewManager::getSelections() const
Chris@8 88 {
Chris@8 89 return m_selections;
Chris@8 90 }
Chris@8 91
Chris@8 92 void
Chris@8 93 ViewManager::setSelection(const Selection &selection)
Chris@8 94 {
Chris@8 95 clearSelections();
Chris@8 96 addSelection(selection);
Chris@8 97 }
Chris@8 98
Chris@8 99 void
Chris@8 100 ViewManager::addSelection(const Selection &selection)
Chris@8 101 {
Chris@8 102 m_selections.insert(selection);
Chris@8 103
Chris@8 104 // Cope with a sitation where the new selection overlaps one or
Chris@8 105 // more existing ones. This is a terribly inefficient way to do
Chris@8 106 // this, but that probably isn't significant in real life.
Chris@8 107
Chris@9 108 // It's essential for the correct operation of
Chris@9 109 // getContainingSelection that the selections do not overlap, so
Chris@9 110 // this is not just a frill.
Chris@9 111
Chris@9 112 for (SelectionList::iterator i = m_selections.begin();
Chris@8 113 i != m_selections.end(); ) {
Chris@8 114
Chris@8 115 SelectionList::iterator j = i;
Chris@8 116 if (++j == m_selections.end()) break;
Chris@8 117
Chris@8 118 if (i->getEndFrame() >= j->getStartFrame()) {
Chris@8 119 Selection merged(i->getStartFrame(),
Chris@8 120 std::max(i->getEndFrame(), j->getEndFrame()));
Chris@8 121 m_selections.erase(i);
Chris@8 122 m_selections.erase(j);
Chris@8 123 m_selections.insert(merged);
Chris@8 124 i = m_selections.begin();
Chris@8 125 } else {
Chris@8 126 ++i;
Chris@8 127 }
Chris@8 128 }
Chris@8 129
Chris@8 130 emit selectionChanged();
Chris@8 131 }
Chris@8 132
Chris@8 133 void
Chris@8 134 ViewManager::removeSelection(const Selection &selection)
Chris@8 135 {
Chris@8 136 //!!! Likewise this needs to cope correctly with the situation
Chris@8 137 //where selection is not one of the original selection set but
Chris@8 138 //simply overlaps one of them (cutting down the original selection
Chris@8 139 //appropriately)
Chris@8 140
Chris@10 141 if (m_selections.find(selection) != m_selections.end()) {
Chris@10 142 m_selections.erase(selection);
Chris@10 143 emit selectionChanged();
Chris@10 144 }
Chris@8 145 }
Chris@8 146
Chris@8 147 void
Chris@8 148 ViewManager::clearSelections()
Chris@8 149 {
Chris@10 150 if (!m_selections.empty()) {
Chris@10 151 m_selections.clear();
Chris@10 152 emit selectionChanged();
Chris@10 153 }
Chris@8 154 }
Chris@8 155
Chris@9 156 Selection
Chris@9 157 ViewManager::getContainingSelection(size_t frame, bool defaultToFollowing)
Chris@9 158 {
Chris@9 159 // This scales very badly with the number of selections, but it's
Chris@9 160 // more efficient for very small numbers of selections than a more
Chris@9 161 // scalable method, and I think that may be what we need
Chris@9 162
Chris@9 163 for (SelectionList::const_iterator i = m_selections.begin();
Chris@9 164 i != m_selections.end(); ++i) {
Chris@9 165
Chris@9 166 if (i->contains(frame)) return *i;
Chris@9 167
Chris@9 168 if (i->getStartFrame() > frame) {
Chris@9 169 if (defaultToFollowing) return *i;
Chris@9 170 else return Selection();
Chris@9 171 }
Chris@9 172 }
Chris@9 173
Chris@9 174 return Selection();
Chris@9 175 }
Chris@9 176
Chris@8 177 void
Chris@8 178 ViewManager::setToolMode(ToolMode mode)
Chris@8 179 {
Chris@8 180 m_toolMode = mode;
Chris@8 181
Chris@8 182 emit toolModeChanged();
Chris@8 183 }
Chris@8 184
Chris@0 185 void
Chris@9 186 ViewManager::setPlayLoopMode(bool mode)
Chris@9 187 {
Chris@9 188 m_playLoopMode = mode;
Chris@9 189
Chris@9 190 emit playLoopModeChanged();
Chris@9 191 }
Chris@9 192
Chris@9 193 void
Chris@9 194 ViewManager::setPlaySelectionMode(bool mode)
Chris@9 195 {
Chris@9 196 m_playSelectionMode = mode;
Chris@9 197
Chris@9 198 emit playSelectionModeChanged();
Chris@9 199 }
Chris@9 200
Chris@9 201 void
Chris@0 202 ViewManager::setAudioPlaySource(AudioPlaySource *source)
Chris@0 203 {
Chris@0 204 if (!m_playSource) {
Chris@0 205 QTimer::singleShot(100, this, SLOT(checkPlayStatus()));
Chris@0 206 }
Chris@0 207 m_playSource = source;
Chris@0 208 }
Chris@0 209
Chris@0 210 PlayParameters *
Chris@0 211 ViewManager::getPlayParameters(const Model *model)
Chris@0 212 {
Chris@0 213 if (m_playParameters.find(model) == m_playParameters.end()) {
Chris@0 214 // Give all models the same type of play parameters for the moment
Chris@0 215 m_playParameters[model] = new PlayParameters;
Chris@0 216 }
Chris@0 217
Chris@0 218 return m_playParameters[model];
Chris@0 219 }
Chris@0 220
Chris@0 221 void
Chris@0 222 ViewManager::clearPlayParameters()
Chris@0 223 {
Chris@0 224 while (!m_playParameters.empty()) {
Chris@0 225 delete m_playParameters.begin()->second;
Chris@0 226 m_playParameters.erase(m_playParameters.begin());
Chris@0 227 }
Chris@0 228 }
Chris@0 229
Chris@0 230 void
Chris@10 231 ViewManager::playStatusChanged(bool playing)
Chris@10 232 {
Chris@10 233 checkPlayStatus();
Chris@10 234 }
Chris@10 235
Chris@10 236 void
Chris@0 237 ViewManager::checkPlayStatus()
Chris@0 238 {
Chris@0 239 if (m_playSource && m_playSource->isPlaying()) {
Chris@0 240
Chris@0 241 float left = 0, right = 0;
Chris@0 242 if (m_playSource->getOutputLevels(left, right)) {
Chris@0 243 if (left != m_lastLeft || right != m_lastRight) {
Chris@0 244 emit outputLevelsChanged(left, right);
Chris@0 245 m_lastLeft = left;
Chris@0 246 m_lastRight = right;
Chris@0 247 }
Chris@0 248 }
Chris@0 249
Chris@0 250 m_globalCentreFrame = m_playSource->getCurrentPlayingFrame();
Chris@0 251
Chris@0 252 #ifdef DEBUG_VIEW_MANAGER
Chris@0 253 std::cout << "ViewManager::checkPlayStatus: Playing, frame " << m_globalCentreFrame << ", levels " << m_lastLeft << "," << m_lastRight << std::endl;
Chris@0 254 #endif
Chris@0 255
Chris@0 256 emit playbackFrameChanged(m_globalCentreFrame);
Chris@0 257
Chris@0 258 QTimer::singleShot(20, this, SLOT(checkPlayStatus()));
Chris@0 259
Chris@0 260 } else {
Chris@0 261
Chris@0 262 QTimer::singleShot(100, this, SLOT(checkPlayStatus()));
Chris@0 263
Chris@0 264 if (m_lastLeft != 0.0 || m_lastRight != 0.0) {
Chris@0 265 emit outputLevelsChanged(0.0, 0.0);
Chris@0 266 m_lastLeft = 0.0;
Chris@0 267 m_lastRight = 0.0;
Chris@0 268 }
Chris@0 269
Chris@0 270 #ifdef DEBUG_VIEW_MANAGER
Chris@0 271 // std::cout << "ViewManager::checkPlayStatus: Not playing" << std::endl;
Chris@0 272 #endif
Chris@0 273 }
Chris@0 274 }
Chris@0 275
Chris@8 276 bool
Chris@8 277 ViewManager::isPlaying() const
Chris@8 278 {
Chris@8 279 return m_playSource && m_playSource->isPlaying();
Chris@8 280 }
Chris@8 281
Chris@0 282 void
Chris@0 283 ViewManager::considerSeek(void *p, unsigned long f, bool locked)
Chris@0 284 {
Chris@0 285 if (locked) {
Chris@0 286 m_globalCentreFrame = f;
Chris@0 287 }
Chris@0 288
Chris@0 289 #ifdef DEBUG_VIEW_MANAGER
Chris@0 290 std::cout << "ViewManager::considerSeek(" << p << ", " << f << ", " << locked << ")" << std::endl;
Chris@0 291 #endif
Chris@0 292
Chris@0 293 if (p == this || !locked) return;
Chris@0 294
Chris@0 295 if (m_playSource && m_playSource->isPlaying()) {
Chris@0 296 unsigned long playFrame = m_playSource->getCurrentPlayingFrame();
Chris@0 297 unsigned long diff = std::max(f, playFrame) - std::min(f, playFrame);
Chris@0 298 if (diff > 20000) {
Chris@0 299 m_playSource->play(f);
Chris@0 300 #ifdef DEBUG_VIEW_MANAGER
Chris@0 301 std::cout << "ViewManager::considerSeek: reseeking from " << playFrame << " to " << f << std::endl;
Chris@0 302 #endif
Chris@0 303 }
Chris@0 304 }
Chris@0 305 }
Chris@0 306
Chris@0 307 void
Chris@0 308 ViewManager::considerZoomChange(void *p, unsigned long z, bool locked)
Chris@0 309 {
Chris@0 310 if (locked) {
Chris@0 311 m_globalZoom = z;
Chris@0 312 }
Chris@0 313
Chris@0 314 #ifdef DEBUG_VIEW_MANAGER
Chris@0 315 std::cout << "ViewManager::considerZoomChange(" << p << ", " << z << ", " << locked << ")" << std::endl;
Chris@0 316 #endif
Chris@0 317 }
Chris@0 318
Chris@0 319 #ifdef INCLUDE_MOCFILES
Chris@0 320 #include "ViewManager.moc.cpp"
Chris@0 321 #endif
Chris@0 322