annotate data/model/EditableDenseThreeDimensionalModel.cpp @ 458:f60360209e5c

* Fix race condition in FFTFileCache when reading from the same FFT model from multiple threads (e.g. when applying more than one plugin at once)
author Chris Cannam
date Wed, 15 Oct 2008 12:08:02 +0000
parents beb2948baa77
children 1405f4a2caf3
rev   line source
Chris@152 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@152 2
Chris@152 3 /*
Chris@152 4 Sonic Visualiser
Chris@152 5 An audio file viewer and annotation editor.
Chris@152 6 Centre for Digital Music, Queen Mary, University of London.
Chris@202 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@152 8
Chris@152 9 This program is free software; you can redistribute it and/or
Chris@152 10 modify it under the terms of the GNU General Public License as
Chris@152 11 published by the Free Software Foundation; either version 2 of the
Chris@152 12 License, or (at your option) any later version. See the file
Chris@152 13 COPYING included with this distribution for more information.
Chris@152 14 */
Chris@152 15
Chris@152 16 #include "EditableDenseThreeDimensionalModel.h"
Chris@152 17
Chris@152 18 #include <QTextStream>
Chris@152 19
Chris@387 20 #include <QStringList>
Chris@387 21
Chris@181 22 #include <iostream>
Chris@181 23
Chris@256 24 #include <cmath>
Chris@256 25
Chris@152 26 EditableDenseThreeDimensionalModel::EditableDenseThreeDimensionalModel(size_t sampleRate,
Chris@152 27 size_t resolution,
Chris@152 28 size_t yBinCount,
Chris@152 29 bool notifyOnAdd) :
Chris@152 30 m_sampleRate(sampleRate),
Chris@152 31 m_resolution(resolution),
Chris@152 32 m_yBinCount(yBinCount),
Chris@152 33 m_minimum(0.0),
Chris@152 34 m_maximum(0.0),
Chris@256 35 m_haveExtents(false),
Chris@152 36 m_notifyOnAdd(notifyOnAdd),
Chris@152 37 m_sinceLastNotifyMin(-1),
Chris@152 38 m_sinceLastNotifyMax(-1),
Chris@152 39 m_completion(100)
Chris@152 40 {
Chris@152 41 }
Chris@152 42
Chris@152 43 bool
Chris@152 44 EditableDenseThreeDimensionalModel::isOK() const
Chris@152 45 {
Chris@152 46 return true;
Chris@152 47 }
Chris@152 48
Chris@152 49 size_t
Chris@152 50 EditableDenseThreeDimensionalModel::getSampleRate() const
Chris@152 51 {
Chris@152 52 return m_sampleRate;
Chris@152 53 }
Chris@152 54
Chris@152 55 size_t
Chris@152 56 EditableDenseThreeDimensionalModel::getStartFrame() const
Chris@152 57 {
Chris@152 58 return 0;
Chris@152 59 }
Chris@152 60
Chris@152 61 size_t
Chris@152 62 EditableDenseThreeDimensionalModel::getEndFrame() const
Chris@152 63 {
Chris@152 64 return m_resolution * m_data.size() + (m_resolution - 1);
Chris@152 65 }
Chris@152 66
Chris@152 67 Model *
Chris@152 68 EditableDenseThreeDimensionalModel::clone() const
Chris@152 69 {
Chris@152 70 EditableDenseThreeDimensionalModel *model =
Chris@152 71 new EditableDenseThreeDimensionalModel
Chris@152 72 (m_sampleRate, m_resolution, m_yBinCount);
Chris@152 73
Chris@152 74 model->m_minimum = m_minimum;
Chris@152 75 model->m_maximum = m_maximum;
Chris@256 76 model->m_haveExtents = m_haveExtents;
Chris@152 77
Chris@152 78 for (size_t i = 0; i < m_data.size(); ++i) {
Chris@182 79 model->setColumn(i, m_data[i]);
Chris@152 80 }
Chris@152 81
Chris@152 82 return model;
Chris@152 83 }
Chris@152 84
Chris@152 85 size_t
Chris@152 86 EditableDenseThreeDimensionalModel::getResolution() const
Chris@152 87 {
Chris@152 88 return m_resolution;
Chris@152 89 }
Chris@152 90
Chris@152 91 void
Chris@152 92 EditableDenseThreeDimensionalModel::setResolution(size_t sz)
Chris@152 93 {
Chris@152 94 m_resolution = sz;
Chris@152 95 }
Chris@152 96
Chris@152 97 size_t
Chris@182 98 EditableDenseThreeDimensionalModel::getWidth() const
Chris@182 99 {
Chris@182 100 return m_data.size();
Chris@182 101 }
Chris@182 102
Chris@182 103 size_t
Chris@182 104 EditableDenseThreeDimensionalModel::getHeight() const
Chris@152 105 {
Chris@152 106 return m_yBinCount;
Chris@152 107 }
Chris@152 108
Chris@152 109 void
Chris@182 110 EditableDenseThreeDimensionalModel::setHeight(size_t sz)
Chris@152 111 {
Chris@152 112 m_yBinCount = sz;
Chris@152 113 }
Chris@152 114
Chris@152 115 float
Chris@152 116 EditableDenseThreeDimensionalModel::getMinimumLevel() const
Chris@152 117 {
Chris@152 118 return m_minimum;
Chris@152 119 }
Chris@152 120
Chris@152 121 void
Chris@152 122 EditableDenseThreeDimensionalModel::setMinimumLevel(float level)
Chris@152 123 {
Chris@152 124 m_minimum = level;
Chris@152 125 }
Chris@152 126
Chris@152 127 float
Chris@152 128 EditableDenseThreeDimensionalModel::getMaximumLevel() const
Chris@152 129 {
Chris@152 130 return m_maximum;
Chris@152 131 }
Chris@152 132
Chris@152 133 void
Chris@152 134 EditableDenseThreeDimensionalModel::setMaximumLevel(float level)
Chris@152 135 {
Chris@152 136 m_maximum = level;
Chris@152 137 }
Chris@152 138
Chris@152 139 void
Chris@182 140 EditableDenseThreeDimensionalModel::getColumn(size_t index,
Chris@182 141 Column &result) const
Chris@152 142 {
Chris@152 143 QMutexLocker locker(&m_mutex);
Chris@152 144
Chris@182 145 if (index < m_data.size()) {
Chris@152 146 result = m_data[index];
Chris@152 147 } else {
Chris@152 148 result.clear();
Chris@152 149 }
Chris@152 150
Chris@152 151 while (result.size() < m_yBinCount) result.push_back(m_minimum);
Chris@152 152 }
Chris@152 153
Chris@152 154 float
Chris@182 155 EditableDenseThreeDimensionalModel::getValueAt(size_t index, size_t n) const
Chris@152 156 {
Chris@152 157 QMutexLocker locker(&m_mutex);
Chris@152 158
Chris@182 159 if (index < m_data.size()) {
Chris@182 160 const Column &s = m_data[index];
Chris@256 161 // std::cerr << "index " << index << ", n " << n << ", res " << m_resolution << ", size " << s.size()
Chris@256 162 // << std::endl;
Chris@152 163 if (n < s.size()) return s[n];
Chris@152 164 }
Chris@152 165
Chris@152 166 return m_minimum;
Chris@152 167 }
Chris@152 168
Chris@152 169 void
Chris@182 170 EditableDenseThreeDimensionalModel::setColumn(size_t index,
Chris@182 171 const Column &values)
Chris@152 172 {
Chris@152 173 QMutexLocker locker(&m_mutex);
Chris@152 174
Chris@182 175 while (index >= m_data.size()) {
Chris@182 176 m_data.push_back(Column());
Chris@152 177 }
Chris@152 178
Chris@152 179 bool allChange = false;
Chris@152 180
Chris@439 181 if (values.size() > m_yBinCount) m_yBinCount = values.size();
Chris@439 182
Chris@152 183 for (size_t i = 0; i < values.size(); ++i) {
Chris@256 184 float value = values[i];
Chris@257 185 if (std::isnan(value) || std::isinf(value)) {
Chris@256 186 continue;
Chris@256 187 }
Chris@256 188 if (!m_haveExtents || value < m_minimum) {
Chris@256 189 m_minimum = value;
Chris@152 190 allChange = true;
Chris@152 191 }
Chris@256 192 if (!m_haveExtents || value > m_maximum) {
Chris@256 193 m_maximum = value;
Chris@152 194 allChange = true;
Chris@152 195 }
Chris@256 196 m_haveExtents = true;
Chris@152 197 }
Chris@152 198
Chris@152 199 m_data[index] = values;
Chris@152 200
Chris@182 201 long windowStart = index;
Chris@182 202 windowStart *= m_resolution;
Chris@182 203
Chris@152 204 if (m_notifyOnAdd) {
Chris@152 205 if (allChange) {
Chris@152 206 emit modelChanged();
Chris@152 207 } else {
Chris@152 208 emit modelChanged(windowStart, windowStart + m_resolution);
Chris@152 209 }
Chris@152 210 } else {
Chris@152 211 if (allChange) {
Chris@152 212 m_sinceLastNotifyMin = -1;
Chris@152 213 m_sinceLastNotifyMax = -1;
Chris@152 214 emit modelChanged();
Chris@152 215 } else {
Chris@152 216 if (m_sinceLastNotifyMin == -1 ||
Chris@152 217 windowStart < m_sinceLastNotifyMin) {
Chris@152 218 m_sinceLastNotifyMin = windowStart;
Chris@152 219 }
Chris@152 220 if (m_sinceLastNotifyMax == -1 ||
Chris@152 221 windowStart > m_sinceLastNotifyMax) {
Chris@152 222 m_sinceLastNotifyMax = windowStart;
Chris@152 223 }
Chris@152 224 }
Chris@152 225 }
Chris@152 226 }
Chris@152 227
Chris@152 228 QString
Chris@152 229 EditableDenseThreeDimensionalModel::getBinName(size_t n) const
Chris@152 230 {
Chris@152 231 if (m_binNames.size() > n) return m_binNames[n];
Chris@152 232 else return "";
Chris@152 233 }
Chris@152 234
Chris@152 235 void
Chris@152 236 EditableDenseThreeDimensionalModel::setBinName(size_t n, QString name)
Chris@152 237 {
Chris@152 238 while (m_binNames.size() <= n) m_binNames.push_back("");
Chris@152 239 m_binNames[n] = name;
Chris@152 240 emit modelChanged();
Chris@152 241 }
Chris@152 242
Chris@152 243 void
Chris@152 244 EditableDenseThreeDimensionalModel::setBinNames(std::vector<QString> names)
Chris@152 245 {
Chris@152 246 m_binNames = names;
Chris@152 247 emit modelChanged();
Chris@152 248 }
Chris@152 249
Chris@152 250 void
Chris@333 251 EditableDenseThreeDimensionalModel::setCompletion(int completion, bool update)
Chris@152 252 {
Chris@152 253 if (m_completion != completion) {
Chris@152 254 m_completion = completion;
Chris@152 255
Chris@152 256 if (completion == 100) {
Chris@152 257
Chris@152 258 m_notifyOnAdd = true; // henceforth
Chris@152 259 emit modelChanged();
Chris@152 260
Chris@152 261 } else if (!m_notifyOnAdd) {
Chris@152 262
Chris@333 263 if (update &&
Chris@333 264 m_sinceLastNotifyMin >= 0 &&
Chris@152 265 m_sinceLastNotifyMax >= 0) {
Chris@152 266 emit modelChanged(m_sinceLastNotifyMin,
Chris@152 267 m_sinceLastNotifyMax + m_resolution);
Chris@152 268 m_sinceLastNotifyMin = m_sinceLastNotifyMax = -1;
Chris@152 269 } else {
Chris@152 270 emit completionChanged();
Chris@152 271 }
Chris@152 272 } else {
Chris@152 273 emit completionChanged();
Chris@152 274 }
Chris@152 275 }
Chris@152 276 }
Chris@152 277
Chris@318 278 QString
Chris@318 279 EditableDenseThreeDimensionalModel::toDelimitedDataString(QString delimiter) const
Chris@318 280 {
Chris@318 281 QString s;
Chris@318 282 for (size_t i = 0; i < m_data.size(); ++i) {
Chris@318 283 QStringList list;
Chris@318 284 for (size_t j = 0; j < m_data[i].size(); ++j) {
Chris@318 285 list << QString("%1").arg(m_data[i][j]);
Chris@318 286 }
Chris@318 287 s += list.join(delimiter) + "\n";
Chris@318 288 }
Chris@318 289 return s;
Chris@318 290 }
Chris@318 291
Chris@152 292 void
Chris@152 293 EditableDenseThreeDimensionalModel::toXml(QTextStream &out,
Chris@314 294 QString indent,
Chris@314 295 QString extraAttributes) const
Chris@152 296 {
Chris@152 297 // For historical reasons we read and write "resolution" as "windowSize"
Chris@152 298
Chris@318 299 std::cerr << "EditableDenseThreeDimensionalModel::toXml" << std::endl;
Chris@318 300
Chris@314 301 Model::toXml
Chris@314 302 (out, indent,
Chris@314 303 QString("type=\"dense\" dimensions=\"3\" windowSize=\"%1\" yBinCount=\"%2\" minimum=\"%3\" maximum=\"%4\" dataset=\"%5\" %6")
Chris@152 304 .arg(m_resolution)
Chris@152 305 .arg(m_yBinCount)
Chris@152 306 .arg(m_minimum)
Chris@152 307 .arg(m_maximum)
Chris@152 308 .arg(getObjectExportId(&m_data))
Chris@152 309 .arg(extraAttributes));
Chris@152 310
Chris@152 311 out << indent;
Chris@152 312 out << QString("<dataset id=\"%1\" dimensions=\"3\" separator=\" \">\n")
Chris@152 313 .arg(getObjectExportId(&m_data));
Chris@152 314
Chris@152 315 for (size_t i = 0; i < m_binNames.size(); ++i) {
Chris@152 316 if (m_binNames[i] != "") {
Chris@152 317 out << indent + " ";
Chris@152 318 out << QString("<bin number=\"%1\" name=\"%2\"/>\n")
Chris@152 319 .arg(i).arg(m_binNames[i]);
Chris@152 320 }
Chris@152 321 }
Chris@152 322
Chris@152 323 for (size_t i = 0; i < m_data.size(); ++i) {
Chris@152 324 out << indent + " ";
Chris@152 325 out << QString("<row n=\"%1\">").arg(i);
Chris@152 326 for (size_t j = 0; j < m_data[i].size(); ++j) {
Chris@152 327 if (j > 0) out << " ";
Chris@152 328 out << m_data[i][j];
Chris@152 329 }
Chris@152 330 out << QString("</row>\n");
Chris@318 331 out.flush();
Chris@152 332 }
Chris@152 333
Chris@152 334 out << indent + "</dataset>\n";
Chris@152 335 }
Chris@152 336
Chris@152 337