# HG changeset patch # User Chris Cannam # Date 1552577519 0 # Node ID 29a20719796e578564b43db937dcae21167be53c # Parent b429750e64a8deb7ad0223727ae89fd5491a4d3c Rework NoteModel commands (not entirely successfully); remove FlexiNoteModel as it has always been almost entirely identical to NoteModel (unlike its layer counterpart) diff -r b429750e64a8 -r 29a20719796e base/Event.h --- a/base/Event.h Thu Mar 14 13:11:47 2019 +0000 +++ b/base/Event.h Thu Mar 14 15:31:59 2019 +0000 @@ -27,12 +27,12 @@ #include /** - * An immutable type used for point and event representation in sparse - * models, as well as for interchange within the clipboard. An event - * always has a frame and (possibly empty) label, and optionally has - * numerical value, level, duration in frames, and a mapped reference - * frame. Event has an operator< defining a total ordering, by frame - * first and then by the other properties. + * An immutable(-ish) type used for point and event representation in + * sparse models, as well as for interchange within the clipboard. An + * event always has a frame and (possibly empty) label, and optionally + * has numerical value, level, duration in frames, and a mapped + * reference frame. Event has an operator< defining a total ordering, + * by frame first and then by the other properties. * * Event is based on the Clipboard::Point type up to SV v3.2.1 and is * intended also to replace the custom point types previously found in @@ -83,6 +83,10 @@ } Event(const Event &event) =default; + + // We would ideally like Event to be immutable - but we have to + // have these because otherwise we can't put Events in vectors + // etc. Let's call it conceptually immutable Event &operator=(const Event &event) =default; Event &operator=(Event &&event) =default; diff -r b429750e64a8 -r 29a20719796e data/model/FlexiNoteModel.h --- a/data/model/FlexiNoteModel.h Thu Mar 14 13:11:47 2019 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,274 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#ifndef SV_FLEXINOTE_MODEL_H -#define SV_FLEXINOTE_MODEL_H - -#include "IntervalModel.h" -#include "base/NoteData.h" -#include "base/NoteExportable.h" -#include "base/RealTime.h" -#include "base/Pitch.h" -#include "base/PlayParameterRepository.h" - -/** - * FlexiNoteModel -- a concrete IntervalModel for notes. - */ - -/** - * Extension of the NoteModel for more flexible note interaction. - * The original NoteModel rationale is given below, will need to be - * updated for FlexiNoteModel: - * - * Note type for use in a sparse model. All we mean by a "note" is - * something that has an onset time, a single value, a duration, and a - * level. Like other points, it can also have a label. With this - * point type, the model can be thought of as representing a simple - * MIDI-type piano roll, except that the y coordinates (values) do not - * have to be discrete integers. - */ - -struct FlexiNote -{ -public: - FlexiNote(sv_frame_t _frame) : frame(_frame), value(0.0f), duration(0), level(1.f) { } - FlexiNote(sv_frame_t _frame, float _value, sv_frame_t _duration, float _level, QString _label) : - frame(_frame), value(_value), duration(_duration), level(_level), label(_label) { } - - int getDimensions() const { return 3; } - - sv_frame_t frame; - float value; - sv_frame_t duration; - float level; - QString label; - - QString getLabel() const { return label; } - - void toXml(QTextStream &stream, - QString indent = "", - QString extraAttributes = "") const - { - stream << - QString("%1\n") - .arg(indent).arg(frame).arg(value).arg(duration).arg(level) - .arg(XmlExportable::encodeEntities(label)).arg(extraAttributes); - } - - QString toDelimitedDataString(QString delimiter, DataExportOptions opts, sv_samplerate_t sampleRate) const - { - QStringList list; - list << RealTime::frame2RealTime(frame, sampleRate).toString().c_str(); - list << QString("%1").arg(value); - list << RealTime::frame2RealTime(duration, sampleRate).toString().c_str(); - if (!(opts & DataExportOmitLevels)) { - list << QString("%1").arg(level); - } - if (label != "") list << label; - return list.join(delimiter); - } - - struct Comparator { - bool operator()(const FlexiNote &p1, - const FlexiNote &p2) const { - if (p1.frame != p2.frame) return p1.frame < p2.frame; - if (p1.value != p2.value) return p1.value < p2.value; - if (p1.duration != p2.duration) return p1.duration < p2.duration; - if (p1.level != p2.level) return p1.level < p2.level; - return p1.label < p2.label; - } - }; - - struct OrderComparator { - bool operator()(const FlexiNote &p1, - const FlexiNote &p2) const { - return p1.frame < p2.frame; - } - }; -}; - - -class FlexiNoteModel : public IntervalModel, public NoteExportable -{ - Q_OBJECT - -public: - FlexiNoteModel(sv_samplerate_t sampleRate, int resolution, - bool notifyOnAdd = true) : - IntervalModel(sampleRate, resolution, notifyOnAdd), - m_valueQuantization(0) - { - PlayParameterRepository::getInstance()->addPlayable(this); - } - - FlexiNoteModel(sv_samplerate_t sampleRate, int resolution, - float valueMinimum, float valueMaximum, - bool notifyOnAdd = true) : - IntervalModel(sampleRate, resolution, - valueMinimum, valueMaximum, - notifyOnAdd), - m_valueQuantization(0) - { - PlayParameterRepository::getInstance()->addPlayable(this); - } - - virtual ~FlexiNoteModel() - { - PlayParameterRepository::getInstance()->removePlayable(this); - } - - float getValueQuantization() const { return m_valueQuantization; } - void setValueQuantization(float q) { m_valueQuantization = q; } - float getValueMinimum() const override { return 33; } - float getValueMaximum() const override { return 88; } - - QString getTypeName() const override { return tr("FlexiNote"); } - - bool canPlay() const override { return true; } - - QString getDefaultPlayClipId() const override - { - return "elecpiano"; - } - - void toXml(QTextStream &out, - QString indent = "", - QString extraAttributes = "") const override - { - std::cerr << "FlexiNoteModel::toXml: extraAttributes = \"" - << extraAttributes.toStdString() << std::endl; - - IntervalModel::toXml - (out, - indent, - QString("%1 subtype=\"flexinote\" valueQuantization=\"%2\"") - .arg(extraAttributes).arg(m_valueQuantization)); - } - - /** - * TabularModel methods. - */ - - int getColumnCount() const override - { - return 6; - } - - QString getHeading(int column) const override - { - switch (column) { - case 0: return tr("Time"); - case 1: return tr("Frame"); - case 2: return tr("Pitch"); - case 3: return tr("Duration"); - case 4: return tr("Level"); - case 5: return tr("Label"); - default: return tr("Unknown"); - } - } - - QVariant getData(int row, int column, int role) const override - { - if (column < 4) { - return IntervalModel::getData(row, column, role); - } - - PointListConstIterator i = getPointListIteratorForRow(row); - if (i == m_points.end()) return QVariant(); - - switch (column) { - case 4: return i->level; - case 5: return i->label; - default: return QVariant(); - } - } - - Command *getSetDataCommand(int row, int column, const QVariant &value, int role) override - { - if (column < 4) { - return IntervalModel::getSetDataCommand - (row, column, value, role); - } - - if (role != Qt::EditRole) return 0; - PointListConstIterator i = getPointListIteratorForRow(row); - if (i == m_points.end()) return 0; - EditCommand *command = new EditCommand(this, tr("Edit Data")); - - Point point(*i); - command->deletePoint(point); - - switch (column) { - case 4: point.level = float(value.toDouble()); break; - case 5: point.label = value.toString(); break; - } - - command->addPoint(point); - return command->finish(); - } - - SortType getSortType(int column) const override - { - if (column == 5) return SortAlphabetical; - return SortNumeric; - } - - /** - * NoteExportable methods. - */ - - NoteList getNotes() const - override { - return getNotesStartingWithin(getStartFrame(), getEndFrame()); - } - - //!!!: - NoteList getNotesActiveAt(sv_frame_t) const override { - return {}; - } - - NoteList getNotesStartingWithin(sv_frame_t startFrame, sv_frame_t endFrame) const - override { - PointList points = getPoints(startFrame, endFrame); - NoteList notes; - for (PointList::iterator pli = points.begin(); pli != points.end(); ++pli) { - sv_frame_t duration = pli->duration; - if (duration == 0 || duration == 1) { - duration = sv_frame_t(getSampleRate() / 20); - } - int pitch = int(lrintf(pli->value)); - - int velocity = 100; - if (pli->level > 0.f && pli->level <= 1.f) { - velocity = int(lrintf(pli->level * 127)); - } - - NoteData note(pli->frame, duration, pitch, velocity); - - if (getScaleUnits() == "Hz") { - note.frequency = pli->value; - note.midiPitch = Pitch::getPitchForFrequency(note.frequency); - note.isMidiPitchQuantized = false; - } - notes.push_back(note); - } - return notes; - } - -protected: - float m_valueQuantization; -}; - -#endif diff -r b429750e64a8 -r 29a20719796e data/model/NoteModel.h --- a/data/model/NoteModel.h Thu Mar 14 13:11:47 2019 +0000 +++ b/data/model/NoteModel.h Thu Mar 14 15:31:59 2019 +0000 @@ -37,9 +37,16 @@ Q_OBJECT public: + enum Subtype { + NORMAL_NOTE, + FLEXI_NOTE + }; + NoteModel(sv_samplerate_t sampleRate, int resolution, - bool notifyOnAdd = true) : + bool notifyOnAdd = true, + Subtype subtype = NORMAL_NOTE) : + m_subtype(subtype), m_sampleRate(sampleRate), m_resolution(resolution), m_valueMinimum(0.f), @@ -52,12 +59,18 @@ m_sinceLastNotifyMin(-1), m_sinceLastNotifyMax(-1), m_completion(0) { + if (subtype == FLEXI_NOTE) { + m_valueMinimum = 33.f; + m_valueMaximum = 88.f; + } PlayParameterRepository::getInstance()->addPlayable(this); } NoteModel(sv_samplerate_t sampleRate, int resolution, float valueMinimum, float valueMaximum, - bool notifyOnAdd = true) : + bool notifyOnAdd = true, + Subtype subtype = NORMAL_NOTE) : + m_subtype(subtype), m_sampleRate(sampleRate), m_resolution(resolution), m_valueMinimum(valueMinimum), @@ -76,8 +89,9 @@ virtual ~NoteModel() { PlayParameterRepository::getInstance()->removePlayable(this); } - + QString getTypeName() const override { return tr("Note"); } + Subtype getSubtype() const { return m_subtype; } bool isOK() const override { return true; } sv_frame_t getStartFrame() const override { return m_events.getStartFrame(); } @@ -186,7 +200,7 @@ public: //!!! borrowed ptr EditCommand(NoteModel *model, QString name) : - m_model(model), m_name(name) { } + m_model(model), m_executed(false), m_name(name) { } QString getName() const override { return m_name; @@ -197,45 +211,44 @@ } void add(Event e) { - m_add.insert(e); + m_adding.insert(e); + m_model->add(e); + m_executed = true; } void remove(Event e) { - m_remove.insert(e); + m_removing.insert(e); + m_model->remove(e); + m_executed = true; } void execute() override { - for (const Event &e: m_add) { - m_model->add(e); - } - for (const Event &e: m_remove) { - m_model->remove(e); - } + if (m_executed) return; + for (const Event &e: m_adding) m_model->add(e); + for (const Event &e: m_removing) m_model->remove(e); + m_executed = true; } void unexecute() override { - for (const Event &e: m_remove) { - m_model->add(e); - } - for (const Event &e: m_add) { - m_model->remove(e); - } + for (const Event &e: m_removing) m_model->add(e); + for (const Event &e: m_adding) m_model->remove(e); + m_executed = false; } EditCommand *finish() { - if (m_add.empty() && m_remove.empty()) { + if (m_adding.empty() && m_removing.empty()) { delete this; return nullptr; } else { - execute(); return this; } } private: NoteModel *m_model; - std::set m_add; - std::set m_remove; + bool m_executed; + std::set m_adding; + std::set m_removing; QString m_name; }; @@ -426,22 +439,24 @@ (out, indent, QString("type=\"sparse\" dimensions=\"3\" resolution=\"%1\" " - "notifyOnAdd=\"%2\" dataset=\"%3\" subtype=\"note\" " - "valueQuantization=\"%4\" minimum=\"%5\" maximum=\"%6\" " - "units=\"%7\" %8") + "notifyOnAdd=\"%2\" dataset=\"%3\" subtype=\"%4\" " + "valueQuantization=\"%5\" minimum=\"%6\" maximum=\"%7\" " + "units=\"%8\" %9") .arg(m_resolution) .arg(m_notifyOnAdd ? "true" : "false") .arg(getObjectExportId(&m_events)) + .arg(m_subtype == FLEXI_NOTE ? "flexinote" : "note") .arg(m_valueQuantization) .arg(m_valueMinimum) .arg(m_valueMaximum) .arg(m_units) .arg(extraAttributes)); - + m_events.toXml(out, indent, QString("dimensions=\"3\"")); } protected: + Subtype m_subtype; sv_samplerate_t m_sampleRate; int m_resolution; diff -r b429750e64a8 -r 29a20719796e files.pri --- a/files.pri Thu Mar 14 13:11:47 2019 +0000 +++ b/files.pri Thu Mar 14 15:31:59 2019 +0000 @@ -87,7 +87,6 @@ data/model/Model.h \ data/model/ModelDataTableModel.h \ data/model/NoteModel.h \ - data/model/FlexiNoteModel.h \ data/model/PathModel.h \ data/model/PowerOfSqrtTwoZoomConstraint.h \ data/model/PowerOfTwoZoomConstraint.h \ diff -r b429750e64a8 -r 29a20719796e transform/FeatureExtractionModelTransformer.cpp --- a/transform/FeatureExtractionModelTransformer.cpp Thu Mar 14 13:11:47 2019 +0000 +++ b/transform/FeatureExtractionModelTransformer.cpp Thu Mar 14 15:31:59 2019 +0000 @@ -28,7 +28,6 @@ #include "data/model/EditableDenseThreeDimensionalModel.h" #include "data/model/DenseTimeValueModel.h" #include "data/model/NoteModel.h" -#include "data/model/FlexiNoteModel.h" #include "data/model/RegionModel.h" #include "data/model/FFTModel.h" #include "data/model/WaveFileModel.h" @@ -410,13 +409,8 @@ // count > 1). But we don't. QSettings settings; - settings.beginGroup("Transformer"); - bool flexi = settings.value("use-flexi-note-model", false).toBool(); - settings.endGroup(); - cerr << "flexi = " << flexi << endl; - - if (isNoteModel && !flexi) { + if (isNoteModel) { NoteModel *model; if (haveExtents) { @@ -429,19 +423,6 @@ model->setScaleUnits(m_descriptors[n]->unit.c_str()); out = model; - } else if (isNoteModel && flexi) { - - FlexiNoteModel *model; - if (haveExtents) { - model = new FlexiNoteModel - (modelRate, modelResolution, minValue, maxValue, false); - } else { - model = new FlexiNoteModel - (modelRate, modelResolution, false); - } - model->setScaleUnits(m_descriptors[n]->unit.c_str()); - out = model; - } else { RegionModel *model; @@ -1027,7 +1008,7 @@ (SparseTimeValueModel::Point(frame, value, label)); } - } else if (isOutput(n) || isOutput(n) || isOutput(n)) { //GF: Added Note Model + } else if (isOutput(n) || isOutput(n)) { int index = 0; @@ -1045,24 +1026,7 @@ } } - if (isOutput(n)) { // GF: added for flexi note model - - float velocity = 100; - if ((int)feature.values.size() > index) { - velocity = feature.values[index++]; - } - if (velocity < 0) velocity = 127; - if (velocity > 127) velocity = 127; - - FlexiNoteModel *model = getConformingOutput(n); - if (!model) return; - model->addPoint(FlexiNoteModel::Point(frame, - value, // value is pitch - duration, - velocity / 127.f, - feature.label.c_str())); - // GF: end -- added for flexi note model - } else if (isOutput(n)) { + if (isOutput(n)) { float velocity = 100; if ((int)feature.values.size() > index) { @@ -1160,13 +1124,6 @@ if (model->isAbandoning()) abandon(); model->setCompletion(completion, true); - } else if (isOutput(n)) { - - FlexiNoteModel *model = getConformingOutput(n); - if (!model) return; - if (model->isAbandoning()) abandon(); - model->setCompletion(completion, true); - } else if (isOutput(n)) { RegionModel *model = getConformingOutput(n);