annotate base/Selection.cpp @ 1520:954d0cf29ca7 import-audio-data

Switch the normalisation option in WritableWaveFileModel from normalising on read to normalising on write, so that the saved file is already normalised and therefore can be read again without having to remember to normalise it
author Chris Cannam
date Wed, 12 Sep 2018 13:56:56 +0100
parents 48e9f538e6e9
children 796ae7eecced
rev   line source
Chris@49 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@8 2
Chris@8 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@8 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@8 14 */
Chris@8 15
Chris@8 16 #include "Selection.h"
Chris@314 17 #include <QTextStream>
Chris@8 18
Chris@8 19 Selection::Selection() :
Chris@8 20 m_startFrame(0),
Chris@8 21 m_endFrame(0)
Chris@8 22 {
Chris@8 23 }
Chris@8 24
Chris@1038 25 Selection::Selection(sv_frame_t startFrame, sv_frame_t endFrame) :
Chris@8 26 m_startFrame(startFrame),
Chris@8 27 m_endFrame(endFrame)
Chris@8 28 {
Chris@8 29 if (m_startFrame > m_endFrame) {
Chris@1429 30 sv_frame_t tmp = m_endFrame;
Chris@1429 31 m_endFrame = m_startFrame;
Chris@1429 32 m_startFrame = tmp;
Chris@8 33 }
Chris@8 34 }
Chris@8 35
Chris@8 36 Selection::Selection(const Selection &s) :
Chris@8 37 m_startFrame(s.m_startFrame),
Chris@8 38 m_endFrame(s.m_endFrame)
Chris@8 39 {
Chris@8 40 }
Chris@8 41
Chris@8 42 Selection &
Chris@8 43 Selection::operator=(const Selection &s)
Chris@8 44 {
Chris@8 45 if (this != &s) {
Chris@1429 46 m_startFrame = s.m_startFrame;
Chris@1429 47 m_endFrame = s.m_endFrame;
Chris@8 48 }
Chris@8 49 return *this;
Chris@8 50 }
Chris@8 51
Chris@8 52 Selection::~Selection()
Chris@8 53 {
Chris@8 54 }
Chris@8 55
Chris@8 56 bool
Chris@8 57 Selection::isEmpty() const
Chris@8 58 {
Chris@8 59 return m_startFrame == m_endFrame;
Chris@8 60 }
Chris@8 61
Chris@1038 62 sv_frame_t
Chris@8 63 Selection::getStartFrame() const
Chris@8 64 {
Chris@8 65 return m_startFrame;
Chris@8 66 }
Chris@8 67
Chris@1038 68 sv_frame_t
Chris@8 69 Selection::getEndFrame() const
Chris@8 70 {
Chris@8 71 return m_endFrame;
Chris@8 72 }
Chris@8 73
Chris@8 74 bool
Chris@1038 75 Selection::contains(sv_frame_t frame) const
Chris@9 76 {
Chris@9 77 return (frame >= m_startFrame) && (frame < m_endFrame);
Chris@9 78 }
Chris@9 79
Chris@9 80 bool
Chris@8 81 Selection::operator<(const Selection &s) const
Chris@8 82 {
Chris@9 83 if (isEmpty()) {
Chris@1429 84 if (s.isEmpty()) return false;
Chris@1429 85 else return true;
Chris@9 86 } else {
Chris@1429 87 if (s.isEmpty()) return false;
Chris@1429 88 else return (m_startFrame < s.m_startFrame);
Chris@9 89 }
Chris@8 90 }
Chris@8 91
Chris@8 92 bool
Chris@8 93 Selection::operator==(const Selection &s) const
Chris@8 94 {
Chris@9 95 if (isEmpty()) return s.isEmpty();
Chris@9 96
Chris@8 97 return (m_startFrame == s.m_startFrame &&
Chris@1429 98 m_endFrame == s.m_endFrame);
Chris@8 99 }
Chris@8 100
Chris@24 101
Chris@24 102 MultiSelection::MultiSelection()
Chris@24 103 {
Chris@24 104 }
Chris@24 105
Chris@24 106 MultiSelection::~MultiSelection()
Chris@24 107 {
Chris@24 108 }
Chris@24 109
Chris@24 110 const MultiSelection::SelectionList &
Chris@24 111 MultiSelection::getSelections() const
Chris@24 112 {
Chris@24 113 return m_selections;
Chris@24 114 }
Chris@24 115
Chris@24 116 void
Chris@24 117 MultiSelection::setSelection(const Selection &selection)
Chris@24 118 {
Chris@24 119 clearSelections();
Chris@24 120 addSelection(selection);
Chris@24 121 }
Chris@24 122
Chris@24 123 void
Chris@24 124 MultiSelection::addSelection(const Selection &selection)
Chris@24 125 {
Chris@24 126 m_selections.insert(selection);
Chris@24 127
Chris@24 128 // Cope with a sitation where the new selection overlaps one or
Chris@24 129 // more existing ones. This is a terribly inefficient way to do
Chris@24 130 // this, but that probably isn't significant in real life.
Chris@24 131
Chris@24 132 // It's essential for the correct operation of
Chris@24 133 // getContainingSelection that the selections do not overlap, so
Chris@24 134 // this is not just a frill.
Chris@24 135
Chris@24 136 for (SelectionList::iterator i = m_selections.begin();
Chris@1429 137 i != m_selections.end(); ) {
Chris@1429 138
Chris@1429 139 SelectionList::iterator j = i;
Chris@1429 140 if (++j == m_selections.end()) break;
Chris@24 141
Chris@1429 142 if (i->getEndFrame() >= j->getStartFrame()) {
Chris@1429 143 Selection merged(i->getStartFrame(),
Chris@1429 144 std::max(i->getEndFrame(), j->getEndFrame()));
Chris@1429 145 m_selections.erase(i);
Chris@1429 146 m_selections.erase(j);
Chris@1429 147 m_selections.insert(merged);
Chris@1429 148 i = m_selections.begin();
Chris@1429 149 } else {
Chris@1429 150 ++i;
Chris@1429 151 }
Chris@24 152 }
Chris@24 153 }
Chris@24 154
Chris@24 155 void
Chris@24 156 MultiSelection::removeSelection(const Selection &selection)
Chris@24 157 {
Chris@24 158 //!!! Likewise this needs to cope correctly with the situation
Chris@24 159 //where selection is not one of the original selection set but
Chris@24 160 //simply overlaps one of them (cutting down the original selection
Chris@24 161 //appropriately)
Chris@24 162
Chris@24 163 if (m_selections.find(selection) != m_selections.end()) {
Chris@1429 164 m_selections.erase(selection);
Chris@24 165 }
Chris@24 166 }
Chris@24 167
Chris@24 168 void
Chris@24 169 MultiSelection::clearSelections()
Chris@24 170 {
Chris@24 171 if (!m_selections.empty()) {
Chris@1429 172 m_selections.clear();
Chris@24 173 }
Chris@24 174 }
Chris@24 175
Chris@300 176 void
Chris@1038 177 MultiSelection::getExtents(sv_frame_t &startFrame, sv_frame_t &endFrame) const
Chris@300 178 {
Chris@300 179 startFrame = 0;
Chris@300 180 endFrame = 0;
Chris@300 181
Chris@300 182 for (SelectionList::const_iterator i = m_selections.begin();
Chris@1429 183 i != m_selections.end(); ++i) {
Chris@300 184
Chris@300 185 if (i == m_selections.begin() || i->getStartFrame() < startFrame) {
Chris@300 186 startFrame = i->getStartFrame();
Chris@300 187 }
Chris@300 188
Chris@300 189 if (i == m_selections.begin() || i->getEndFrame() > endFrame) {
Chris@300 190 endFrame = i->getEndFrame();
Chris@300 191 }
Chris@300 192 }
Chris@300 193 }
Chris@300 194
Chris@24 195 Selection
Chris@1038 196 MultiSelection::getContainingSelection(sv_frame_t frame, bool defaultToFollowing) const
Chris@24 197 {
Chris@24 198 // This scales very badly with the number of selections, but it's
Chris@24 199 // more efficient for very small numbers of selections than a more
Chris@24 200 // scalable method, and I think that may be what we need
Chris@24 201
Chris@24 202 for (SelectionList::const_iterator i = m_selections.begin();
Chris@1429 203 i != m_selections.end(); ++i) {
Chris@24 204
Chris@1429 205 if (i->contains(frame)) return *i;
Chris@24 206
Chris@1429 207 if (i->getStartFrame() > frame) {
Chris@1429 208 if (defaultToFollowing) return *i;
Chris@1429 209 else return Selection();
Chris@1429 210 }
Chris@24 211 }
Chris@24 212
Chris@24 213 return Selection();
Chris@24 214 }
Chris@46 215
Chris@314 216 void
Chris@314 217 MultiSelection::toXml(QTextStream &stream, QString indent,
Chris@314 218 QString extraAttributes) const
Chris@46 219 {
Chris@314 220 stream << indent << QString("<selections %1>\n").arg(extraAttributes);
Chris@46 221 for (SelectionList::iterator i = m_selections.begin();
Chris@1429 222 i != m_selections.end(); ++i) {
Chris@1429 223 stream << indent
Chris@314 224 << QString(" <selection start=\"%1\" end=\"%2\"/>\n")
Chris@1429 225 .arg(i->getStartFrame()).arg(i->getEndFrame());
Chris@46 226 }
Chris@314 227 stream << indent << "</selections>\n";
Chris@46 228 }
Chris@46 229