Chris@441: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@441:
Chris@441: /*
Chris@441: Sonic Visualiser
Chris@441: An audio file viewer and annotation editor.
Chris@441: Centre for Digital Music, Queen Mary, University of London.
Chris@441: This file copyright 2006 Chris Cannam.
Chris@441:
Chris@441: This program is free software; you can redistribute it and/or
Chris@441: modify it under the terms of the GNU General Public License as
Chris@441: published by the Free Software Foundation; either version 2 of the
Chris@441: License, or (at your option) any later version. See the file
Chris@441: COPYING included with this distribution for more information.
Chris@441: */
Chris@441:
Chris@1581: #ifndef SV_REGION_MODEL_H
Chris@1581: #define SV_REGION_MODEL_H
Chris@441:
Chris@441: #include "IntervalModel.h"
Chris@441: #include "base/RealTime.h"
Chris@441:
Chris@441: /**
Chris@441: * RegionModel -- a concrete IntervalModel for intervals associated
Chris@441: * with a value, which we call regions for no very compelling reason.
Chris@441: */
Chris@441:
Chris@441: /**
Chris@441: * Region "point" type. A region is something that has an onset time,
Chris@441: * a single value, and a duration. Like other points, it can also
Chris@441: * have a label.
Chris@441: *
Chris@441: * This is called RegionRec instead of Region to avoid name collisions
Chris@441: * with the X11 Region struct. Bah.
Chris@441: */
Chris@441:
Chris@441: struct RegionRec
Chris@441: {
Chris@441: public:
Chris@631: RegionRec() : frame(0), value(0.f), duration(0) { }
Chris@1038: RegionRec(sv_frame_t _frame) : frame(_frame), value(0.0f), duration(0) { }
Chris@1038: RegionRec(sv_frame_t _frame, float _value, sv_frame_t _duration, QString _label) :
Chris@1429: frame(_frame), value(_value), duration(_duration), label(_label) { }
Chris@441:
Chris@441: int getDimensions() const { return 3; }
Chris@441:
Chris@1038: sv_frame_t frame;
Chris@441: float value;
Chris@1038: sv_frame_t duration;
Chris@441: QString label;
Chris@441:
Chris@441: QString getLabel() const { return label; }
Chris@441:
Chris@441: void toXml(QTextStream &stream,
Chris@441: QString indent = "",
Chris@441: QString extraAttributes = "") const
Chris@441: {
Chris@1429: stream <<
Chris@441: QString("%1\n")
Chris@1429: .arg(indent).arg(frame).arg(value).arg(duration)
Chris@627: .arg(XmlExportable::encodeEntities(label)).arg(extraAttributes);
Chris@441: }
Chris@441:
Chris@1060: QString toDelimitedDataString(QString delimiter, DataExportOptions, sv_samplerate_t sampleRate) const
Chris@441: {
Chris@441: QStringList list;
Chris@441: list << RealTime::frame2RealTime(frame, sampleRate).toString().c_str();
Chris@441: list << QString("%1").arg(value);
Chris@441: list << RealTime::frame2RealTime(duration, sampleRate).toString().c_str();
Chris@441: if (label != "") list << label;
Chris@441: return list.join(delimiter);
Chris@441: }
Chris@441:
Chris@441: struct Comparator {
Chris@1429: bool operator()(const RegionRec &p1,
Chris@1429: const RegionRec &p2) const {
Chris@1429: if (p1.frame != p2.frame) return p1.frame < p2.frame;
Chris@1429: if (p1.value != p2.value) return p1.value < p2.value;
Chris@1429: if (p1.duration != p2.duration) return p1.duration < p2.duration;
Chris@1429: return p1.label < p2.label;
Chris@1429: }
Chris@441: };
Chris@441:
Chris@441: struct OrderComparator {
Chris@1429: bool operator()(const RegionRec &p1,
Chris@1429: const RegionRec &p2) const {
Chris@1429: return p1.frame < p2.frame;
Chris@1429: }
Chris@441: };
Chris@441: };
Chris@441:
Chris@441:
Chris@441: class RegionModel : public IntervalModel
Chris@441: {
Chris@441: Q_OBJECT
Chris@441:
Chris@441: public:
Chris@1040: RegionModel(sv_samplerate_t sampleRate, int resolution,
Chris@441: bool notifyOnAdd = true) :
Chris@1429: IntervalModel(sampleRate, resolution, notifyOnAdd),
Chris@1429: m_valueQuantization(0),
Chris@442: m_haveDistinctValues(false)
Chris@441: {
Chris@441: }
Chris@441:
Chris@1040: RegionModel(sv_samplerate_t sampleRate, int resolution,
Chris@459: float valueMinimum, float valueMaximum,
Chris@459: bool notifyOnAdd = true) :
Chris@1429: IntervalModel(sampleRate, resolution,
Chris@441: valueMinimum, valueMaximum,
Chris@441: notifyOnAdd),
Chris@1429: m_valueQuantization(0),
Chris@442: m_haveDistinctValues(false)
Chris@441: {
Chris@441: }
Chris@441:
Chris@441: virtual ~RegionModel()
Chris@441: {
Chris@441: }
Chris@441:
Chris@441: float getValueQuantization() const { return m_valueQuantization; }
Chris@441: void setValueQuantization(float q) { m_valueQuantization = q; }
Chris@441:
Chris@442: bool haveDistinctValues() const { return m_haveDistinctValues; }
Chris@442:
Chris@1580: QString getTypeName() const override { return tr("Region"); }
Chris@441:
Chris@1580: void toXml(QTextStream &out,
Chris@441: QString indent = "",
Chris@1580: QString extraAttributes = "") const override
Chris@441: {
Chris@441: std::cerr << "RegionModel::toXml: extraAttributes = \""
Chris@441: << extraAttributes.toStdString() << std::endl;
Chris@441:
Chris@441: IntervalModel::toXml
Chris@1429: (out,
Chris@441: indent,
Chris@1429: QString("%1 subtype=\"region\" valueQuantization=\"%2\"")
Chris@1429: .arg(extraAttributes).arg(m_valueQuantization));
Chris@441: }
Chris@441:
Chris@441: /**
Chris@441: * TabularModel methods.
Chris@441: */
Chris@441:
Chris@1580: int getColumnCount() const override
Chris@441: {
Chris@618: return 5;
Chris@441: }
Chris@441:
Chris@1580: QString getHeading(int column) const override
Chris@441: {
Chris@441: switch (column) {
Chris@441: case 0: return tr("Time");
Chris@441: case 1: return tr("Frame");
Chris@441: case 2: return tr("Value");
Chris@441: case 3: return tr("Duration");
Chris@441: case 4: return tr("Label");
Chris@441: default: return tr("Unknown");
Chris@441: }
Chris@441: }
Chris@441:
Chris@1580: QVariant getData(int row, int column, int role) const override
Chris@441: {
Chris@441: if (column < 4) {
Chris@441: return IntervalModel::getData(row, column, role);
Chris@441: }
Chris@441:
Chris@608: PointListConstIterator i = getPointListIteratorForRow(row);
Chris@441: if (i == m_points.end()) return QVariant();
Chris@441:
Chris@441: switch (column) {
Chris@441: case 4: return i->label;
Chris@441: default: return QVariant();
Chris@441: }
Chris@441: }
Chris@441:
Chris@1580: Command *getSetDataCommand(int row, int column, const QVariant &value, int role) override
Chris@441: {
Chris@441: if (column < 4) {
Chris@441: return IntervalModel::getSetDataCommand
Chris@441: (row, column, value, role);
Chris@441: }
Chris@441:
Chris@740: if (role != Qt::EditRole) return 0;
Chris@441: PointListIterator i = getPointListIteratorForRow(row);
Chris@740: if (i == m_points.end()) return 0;
Chris@441: EditCommand *command = new EditCommand(this, tr("Edit Data"));
Chris@441:
Chris@441: Point point(*i);
Chris@441: command->deletePoint(point);
Chris@441:
Chris@441: switch (column) {
Chris@441: case 4: point.label = value.toString(); break;
Chris@441: }
Chris@441:
Chris@441: command->addPoint(point);
Chris@441: return command->finish();
Chris@441: }
Chris@441:
Chris@1580: SortType getSortType(int column) const override
Chris@441: {
Chris@618: if (column == 4) return SortAlphabetical;
Chris@441: return SortNumeric;
Chris@441: }
Chris@441:
Chris@1580: void addPoint(const Point &point) override
Chris@442: {
Chris@442: if (point.value != 0.f) m_haveDistinctValues = true;
Chris@442: IntervalModel::addPoint(point);
Chris@442: }
Chris@442:
Chris@441: protected:
Chris@441: float m_valueQuantization;
Chris@442: bool m_haveDistinctValues;
Chris@441: };
Chris@441:
Chris@441: #endif