Mercurial > hg > svcore
changeset 1615:24dc8cb42755 single-point
Rename a number of classes and methods (including Point -> Event); comments
author | Chris Cannam |
---|---|
date | Thu, 07 Mar 2019 15:44:09 +0000 |
parents | 2e14a7876945 |
children | de446dd905e6 |
files | base/Clipboard.cpp base/Clipboard.h base/Event.h base/EventSeries.h base/NoteData.h base/Point.h base/PointSeries.h base/test/TestEventSeries.h base/test/TestPointSeries.h base/test/files.pri base/test/svcore-base-test.cpp data/fileio/MIDIFileWriter.cpp data/model/FlexiNoteModel.h data/model/NoteData.h data/model/NoteModel.h data/model/SparseOneDimensionalModel.h files.pri |
diffstat | 17 files changed, 824 insertions(+), 723 deletions(-) [+] |
line wrap: on
line diff
--- a/base/Clipboard.cpp Thu Mar 07 14:35:57 2019 +0000 +++ b/base/Clipboard.cpp Thu Mar 07 15:44:09 2019 +0000 @@ -30,20 +30,20 @@ return m_points.empty(); } -const PointVector & +const EventVector & Clipboard::getPoints() const { return m_points; } void -Clipboard::setPoints(const PointVector &pl) +Clipboard::setPoints(const EventVector &pl) { m_points = pl; } void -Clipboard::addPoint(const Point &point) +Clipboard::addPoint(const Event &point) { m_points.push_back(point); } @@ -51,9 +51,9 @@ bool Clipboard::haveReferenceFrames() const { - for (PointVector::const_iterator i = m_points.begin(); + for (EventVector::const_iterator i = m_points.begin(); i != m_points.end(); ++i) { - if (i->haveReferenceFrame()) return true; + if (i->hasReferenceFrame()) return true; } return false; } @@ -61,7 +61,7 @@ bool Clipboard::referenceFramesDiffer() const { - for (PointVector::const_iterator i = m_points.begin(); + for (EventVector::const_iterator i = m_points.begin(); i != m_points.end(); ++i) { if (i->referenceFrameDiffers()) return true; }
--- a/base/Clipboard.h Thu Mar 07 14:35:57 2019 +0000 +++ b/base/Clipboard.h Thu Mar 07 15:44:09 2019 +0000 @@ -18,7 +18,7 @@ #include <vector> -#include "Point.h" +#include "Event.h" class Clipboard { @@ -28,15 +28,15 @@ void clear(); bool empty() const; - const PointVector &getPoints() const; - void setPoints(const PointVector &points); - void addPoint(const Point &point); + const EventVector &getPoints() const; + void setPoints(const EventVector &points); + void addPoint(const Event &point); bool haveReferenceFrames() const; bool referenceFramesDiffer() const; protected: - PointVector m_points; + EventVector m_points; }; #endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/base/Event.h Thu Mar 07 15:44:09 2019 +0000 @@ -0,0 +1,284 @@ +/* -*- 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_EVENT_H +#define SV_EVENT_H + +#include "BaseTypes.h" +#include "NoteData.h" +#include "XmlExportable.h" + +#include <vector> +#include <stdexcept> + +#include <QString> + +/** + * 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. + * + * 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 + * sparse models. + */ +class Event +{ +public: + Event(sv_frame_t frame) : + m_haveValue(false), m_haveLevel(false), m_haveReferenceFrame(false), + m_value(0.f), m_level(0.f), m_frame(frame), + m_duration(0), m_referenceFrame(0), m_label() { } + + Event(sv_frame_t frame, QString label) : + m_haveValue(false), m_haveLevel(false), m_haveReferenceFrame(false), + m_value(0.f), m_level(0.f), m_frame(frame), + m_duration(0), m_referenceFrame(0), m_label(label) { } + + Event(sv_frame_t frame, float value, QString label) : + m_haveValue(true), m_haveLevel(false), m_haveReferenceFrame(false), + m_value(value), m_level(0.f), m_frame(frame), + m_duration(0), m_referenceFrame(0), m_label(label) { } + + Event(sv_frame_t frame, float value, sv_frame_t duration, QString label) : + m_haveValue(true), m_haveLevel(false), m_haveReferenceFrame(false), + m_value(value), m_level(0.f), m_frame(frame), + m_duration(duration), m_referenceFrame(0), m_label(label) { + if (m_duration < 0) throw std::logic_error("duration must be >= 0"); + } + + Event(sv_frame_t frame, float value, sv_frame_t duration, + float level, QString label) : + m_haveValue(true), m_haveLevel(true), m_haveReferenceFrame(false), + m_value(value), m_level(level), m_frame(frame), + m_duration(duration), m_referenceFrame(0), m_label(label) { + if (m_duration < 0) throw std::logic_error("duration must be >= 0"); + } + + Event(const Event &event) =default; + Event &operator=(const Event &event) =default; + Event &operator=(Event &&event) =default; + + sv_frame_t getFrame() const { return m_frame; } + + Event withFrame(sv_frame_t frame) const { + Event p(*this); + p.m_frame = frame; + return p; + } + + bool hasValue() const { return m_haveValue; } + float getValue() const { return m_value; } + + Event withValue(float value) const { + Event p(*this); + p.m_haveValue = true; + p.m_value = value; + return p; + } + Event withoutValue() const { + Event p(*this); + p.m_haveValue = false; + p.m_value = 0.f; + return p; + } + + bool hasDuration() const { return m_duration != 0; } + sv_frame_t getDuration() const { return m_duration; } + + Event withDuration(sv_frame_t duration) const { + Event p(*this); + p.m_duration = duration; + if (duration < 0) throw std::logic_error("duration must be >= 0"); + return p; + } + Event withoutDuration() const { + Event p(*this); + p.m_duration = 0; + return p; + } + + QString getLabel() const { return m_label; } + + Event withLabel(QString label) const { + Event p(*this); + p.m_label = label; + return p; + } + + bool hasLevel() const { return m_haveLevel; } + float getLevel() const { return m_level; } + + Event withLevel(float level) const { + Event p(*this); + p.m_haveLevel = true; + p.m_level = level; + return p; + } + Event withoutLevel() const { + Event p(*this); + p.m_haveLevel = false; + p.m_level = 0.f; + return p; + } + + bool hasReferenceFrame() const { return m_haveReferenceFrame; } + sv_frame_t getReferenceFrame() const { return m_referenceFrame; } + + bool referenceFrameDiffers() const { // from event frame + return m_haveReferenceFrame && (m_referenceFrame != m_frame); + } + + Event withReferenceFrame(sv_frame_t frame) const { + Event p(*this); + p.m_haveReferenceFrame = true; + p.m_referenceFrame = frame; + return p; + } + Event withoutReferenceFrame() const { + Event p(*this); + p.m_haveReferenceFrame = false; + p.m_referenceFrame = 0; + return p; + } + + bool operator==(const Event &p) const { + + if (m_frame != p.m_frame) return false; + if (m_duration != p.m_duration) return false; + + if (m_haveValue != p.m_haveValue) return false; + if (m_haveValue && (m_value != p.m_value)) return false; + + if (m_haveLevel != p.m_haveLevel) return false; + if (m_haveLevel && (m_level != p.m_level)) return false; + + if (m_haveReferenceFrame != p.m_haveReferenceFrame) return false; + if (m_haveReferenceFrame && + (m_referenceFrame != p.m_referenceFrame)) return false; + + if (m_label != p.m_label) return false; + + return true; + } + + bool operator<(const Event &p) const { + + if (m_frame != p.m_frame) return m_frame < p.m_frame; + if (m_duration != p.m_duration) return m_duration < p.m_duration; + + // events without a property sort before events with that property + + if (m_haveValue != p.m_haveValue) return !m_haveValue; + if (m_haveValue && (m_value != p.m_value)) return m_value < p.m_value; + + if (m_haveLevel != p.m_haveLevel) return !m_haveLevel; + if (m_haveLevel && (m_level != p.m_level)) return m_level < p.m_level; + + if (m_haveReferenceFrame != p.m_haveReferenceFrame) { + return !m_haveReferenceFrame; + } + if (m_haveReferenceFrame && (m_referenceFrame != p.m_referenceFrame)) { + return m_referenceFrame < p.m_referenceFrame; + } + + return m_label < p.m_label; + } + + void toXml(QTextStream &stream, + QString indent = "", + QString extraAttributes = "") const { + + // For I/O purposes these are points, not events + stream << indent << QString("<point frame=\"%1\" ").arg(m_frame); + if (m_haveValue) stream << QString("value=\"%1\" ").arg(m_value); + if (m_duration) stream << QString("duration=\"%1\" ").arg(m_duration); + if (m_haveLevel) stream << QString("level=\"%1\" ").arg(m_level); + if (m_haveReferenceFrame) stream << QString("referenceFrame=\"%1\" ") + .arg(m_referenceFrame); + stream << QString("label=\"%1\" ") + .arg(XmlExportable::encodeEntities(m_label)); + stream << extraAttributes << ">\n"; + } + + QString toXmlString(QString indent = "", + QString extraAttributes = "") const { + QString s; + QTextStream out(&s); + toXml(out, indent, extraAttributes); + out.flush(); + return s; + } + + NoteData toNoteData(sv_samplerate_t sampleRate, bool valueIsMidiPitch) { + + sv_frame_t duration; + if (m_duration > 0) { + duration = m_duration; + } else { + duration = sv_frame_t(sampleRate / 6); // arbitrary short duration + } + + int midiPitch; + float frequency = 0.f; + if (m_haveValue) { + if (valueIsMidiPitch) { + midiPitch = int(roundf(m_value)); + } else { + frequency = m_value; + midiPitch = Pitch::getPitchForFrequency(frequency); + } + } else { + midiPitch = 64; + valueIsMidiPitch = true; + } + + int velocity = 100; + if (m_haveLevel) { + if (m_level > 0.f && m_level <= 1.f) { + velocity = int(roundf(m_level * 127.f)); + } + } + + NoteData n(m_frame, duration, midiPitch, velocity); + n.isMidiPitchQuantized = valueIsMidiPitch; + if (!valueIsMidiPitch) { + n.frequency = frequency; + } + + return n; + } + +private: + // The order of fields here is chosen to minimise overall size of struct. + // We potentially store very many of these objects. + // If you change something, check what difference it makes to packing. + bool m_haveValue : 1; + bool m_haveLevel : 1; + bool m_haveReferenceFrame : 1; + float m_value; + float m_level; + sv_frame_t m_frame; + sv_frame_t m_duration; + sv_frame_t m_referenceFrame; + QString m_label; +}; + +typedef std::vector<Event> EventVector; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/base/EventSeries.h Thu Mar 07 15:44:09 2019 +0000 @@ -0,0 +1,241 @@ +/* -*- 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 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_EVENT_SERIES_H +#define SV_EVENT_SERIES_H + +#include "Event.h" + +#include <set> + +//#define DEBUG_EVENT_SERIES 1 + +/** + * Container storing a series of events, with or without durations, + * and supporting the ability to query which events span a given frame + * time. To that end, in addition to the series of events, it stores a + * series of "seam points", which are the frame positions at which the + * set of simultaneous events changes (i.e. an event of non-zero + * duration starts or ends). These are updated when event is added or + * removed. + */ +class EventSeries +{ +public: + EventSeries() : m_count(0) { } + + void add(const Event &p) { + + m_events.insert(p); + ++m_count; + + if (p.hasDuration()) { + sv_frame_t frame = p.getFrame(); + sv_frame_t endFrame = p.getFrame() + p.getDuration(); + + createSeam(frame); + createSeam(endFrame); + + auto i0 = m_seams.find(frame); // must succeed after createSeam + auto i1 = m_seams.find(endFrame); // likewise + + for (auto i = i0; i != i1; ++i) { + if (i == m_seams.end()) { + SVCERR << "ERROR: EventSeries::add: " + << "reached end of seam map" + << endl; + break; + } + i->second.insert(p); + } + } + +#ifdef DEBUG_EVENT_SERIES + std::cerr << "after add:" << std::endl; + dumpEvents(); + dumpSeams(); +#endif + } + + void remove(const Event &p) { + + // erase first itr that matches p; if there is more than one + // p, erase(p) would remove all of them, but we only want to + // remove (any) one + auto pitr = m_events.find(p); + if (pitr == m_events.end()) { + return; // we don't know this event + } else { + m_events.erase(pitr); + --m_count; + } + + if (p.hasDuration()) { + sv_frame_t frame = p.getFrame(); + sv_frame_t endFrame = p.getFrame() + p.getDuration(); + + auto i0 = m_seams.find(frame); + auto i1 = m_seams.find(endFrame); + +#ifdef DEBUG_EVENT_SERIES + // This should be impossible if we found p in m_events above + if (i0 == m_seams.end() || i1 == m_seams.end()) { + SVCERR << "ERROR: EventSeries::remove: either frame " << frame + << " or endFrame " << endFrame + << " for event not found in seam map: event is " + << p.toXmlString() << endl; + } +#endif + + for (auto i = i0; i != i1; ++i) { + if (i == m_seams.end()) { + // This can happen only if we have a negative + // duration, which Event forbids, but we don't + // protect against it in this class, so we'll + // leave this check in + SVCERR << "ERROR: EventSeries::remove: " + << "reached end of seam map" + << endl; + break; + } + // Can't just erase(p) as that would erase all of + // them, if there are several identical ones + auto si = i->second.find(p); + if (si != i->second.end()) { + i->second.erase(si); + } + } + + // Shall we "garbage-collect" here? We could be leaving + // lots of empty event-sets, or consecutive identical + // ones, which are a pure irrelevance that take space and + // slow us down. But a lot depends on whether callers ever + // really delete anything much. + } + +#ifdef DEBUG_EVENT_SERIES + std::cerr << "after remove:" << std::endl; + dumpEvents(); + dumpSeams(); +#endif + } + + bool contains(const Event &p) { + return m_events.find(p) != m_events.end(); + } + + int count() const { + return m_count; + } + + bool isEmpty() const { + return m_count == 0; + } + + void clear() { + m_events.clear(); + m_seams.clear(); + m_count = 0; + } + + /** + * Retrieve all events that span the given frame. A event without + * duration spans a frame if its own frame is equal to it. A event + * with duration spans a frame if its start frame is less than or + * equal to it and its end frame (start + duration) is greater + * than it. + */ + EventVector getEventsSpanning(sv_frame_t frame) const { + EventVector span; + + // first find any zero-duration events + auto pitr = m_events.lower_bound(Event(frame, QString())); + if (pitr != m_events.end()) { + while (pitr->getFrame() == frame) { + if (!pitr->hasDuration()) { + span.push_back(*pitr); + } + ++pitr; + } + } + + // now any non-zero-duration ones from the seam map + auto sitr = m_seams.lower_bound(frame); + if (sitr == m_seams.end() || sitr->first > frame) { + if (sitr != m_seams.begin()) { + --sitr; + } + } + if (sitr != m_seams.end() && sitr->first <= frame) { + for (auto p: sitr->second) { + span.push_back(p); + } + } + + return span; + } + +private: + int m_count; + + typedef std::multiset<Event> EventMultiset; + EventMultiset m_events; + + typedef std::map<sv_frame_t, std::multiset<Event>> FrameEventsMap; + FrameEventsMap m_seams; + + /** Create a seam at the given frame, copying from the prior seam + * if there is one. If a seam already exists at the given frame, + * leave it untouched. + */ + void createSeam(sv_frame_t frame) { + auto itr = m_seams.lower_bound(frame); + if (itr == m_seams.end() || itr->first > frame) { + if (itr != m_seams.begin()) { + --itr; + } + } + if (itr == m_seams.end()) { + m_seams[frame] = {}; + } else if (itr->first < frame) { + m_seams[frame] = itr->second; + } else if (itr->first > frame) { // itr must be begin() + m_seams[frame] = {}; + } + } + +#ifdef DEBUG_EVENT_SERIES + void dumpEvents() const { + std::cerr << "EVENTS [" << std::endl; + for (const auto &p: m_events) { + std::cerr << p.toXmlString(" "); + } + std::cerr << "]" << std::endl; + } + + void dumpSeams() const { + std::cerr << "SEAMS [" << std::endl; + for (const auto &s: m_seams) { + std::cerr << " " << s.first << " -> {" << std::endl; + for (const auto &p: s.second) { + std::cerr << p.toXmlString(" "); + } + std::cerr << " }" << std::endl; + } + std::cerr << "]" << std::endl; + } +#endif +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/base/NoteData.h Thu Mar 07 15:44:09 2019 +0000 @@ -0,0 +1,57 @@ +/* -*- 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 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_NOTE_DATA_H +#define SV_NOTE_DATA_H + +#include <vector> + +#include "Pitch.h" + +/** + * Note record used when constructing synthetic events for sonification. + */ +struct NoteData +{ + NoteData(sv_frame_t _start, sv_frame_t _dur, int _mp, int _vel) : + start(_start), duration(_dur), midiPitch(_mp), frequency(0), + isMidiPitchQuantized(true), velocity(_vel), channel(0) { }; + + sv_frame_t start; // audio sample frame + sv_frame_t duration; // in audio sample frames + int midiPitch; // 0-127 + float frequency; // Hz, to be used if isMidiPitchQuantized false + bool isMidiPitchQuantized; + int velocity; // MIDI-style 0-127 + int channel; // MIDI 0-15 + + float getFrequency() const { + if (isMidiPitchQuantized) { + return float(Pitch::getFrequencyForPitch(midiPitch)); + } else { + return frequency; + } + } +}; + +typedef std::vector<NoteData> NoteList; + +class NoteExportable +{ +public: + virtual NoteList getNotes() const = 0; + virtual NoteList getNotesWithin(sv_frame_t startFrame, sv_frame_t endFrame) const = 0; +}; + +#endif
--- a/base/Point.h Thu Mar 07 14:35:57 2019 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,201 +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_POINT_H -#define SV_POINT_H - -#include <QString> -#include <vector> - -#include "BaseTypes.h" -#include "XmlExportable.h" - -//!!! given that these can have size (i.e. duration), maybe Point -//!!! isn't really an ideal name... perhaps I should go back to dull -//!!! old Event - -class Point -{ -public: - Point(sv_frame_t frame, QString label) : - m_haveValue(false), m_haveLevel(false), m_haveReferenceFrame(false), - m_value(0.f), m_level(0.f), m_frame(frame), - m_duration(0), m_referenceFrame(0), m_label(label) { } - - Point(sv_frame_t frame, float value, QString label) : - m_haveValue(true), m_haveLevel(false), m_haveReferenceFrame(false), - m_value(value), m_level(0.f), m_frame(frame), - m_duration(0), m_referenceFrame(0), m_label(label) { } - - Point(sv_frame_t frame, float value, sv_frame_t duration, QString label) : - m_haveValue(true), m_haveLevel(false), m_haveReferenceFrame(false), - m_value(value), m_level(0.f), m_frame(frame), - m_duration(duration), m_referenceFrame(0), m_label(label) { } - - Point(sv_frame_t frame, float value, sv_frame_t duration, - float level, QString label) : - m_haveValue(true), m_haveLevel(true), m_haveReferenceFrame(false), - m_value(value), m_level(level), m_frame(frame), - m_duration(duration), m_referenceFrame(0), m_label(label) { } - - Point(const Point &point) =default; - Point &operator=(const Point &point) =default; - Point &operator=(Point &&point) =default; - - sv_frame_t getFrame() const { return m_frame; } - - Point withFrame(sv_frame_t frame) const { - Point p(*this); - p.m_frame = frame; - return p; - } - - bool haveValue() const { return m_haveValue; } - float getValue() const { return m_value; } - - Point withValue(float value) const { - Point p(*this); - p.m_haveValue = true; - p.m_value = value; - return p; - } - - bool haveDuration() const { return m_duration != 0; } - sv_frame_t getDuration() const { return m_duration; } - - Point withDuration(sv_frame_t duration) const { - Point p(*this); - p.m_duration = duration; - return p; - } - - QString getLabel() const { return m_label; } - - Point withLabel(QString label) const { - Point p(*this); - p.m_label = label; - return p; - } - - bool haveLevel() const { return m_haveLevel; } - float getLevel() const { return m_level; } - Point withLevel(float level) const { - Point p(*this); - p.m_haveLevel = true; - p.m_level = level; - return p; - } - - bool haveReferenceFrame() const { return m_haveReferenceFrame; } - sv_frame_t getReferenceFrame() const { return m_referenceFrame; } - - bool referenceFrameDiffers() const { // from point frame - return m_haveReferenceFrame && (m_referenceFrame != m_frame); - } - - Point withReferenceFrame(sv_frame_t frame) const { - Point p(*this); - p.m_haveReferenceFrame = true; - p.m_referenceFrame = frame; - return p; - } - - bool operator==(const Point &p) const { - - if (m_frame != p.m_frame) return false; - - if (m_haveValue != p.m_haveValue) return false; - if (m_haveValue && (m_value != p.m_value)) return false; - - if (m_duration != p.m_duration) return false; - - if (m_haveLevel != p.m_haveLevel) return false; - if (m_haveLevel && (m_level != p.m_level)) return false; - - if (m_haveReferenceFrame != p.m_haveReferenceFrame) return false; - if (m_haveReferenceFrame && - (m_referenceFrame != p.m_referenceFrame)) return false; - - if (m_label != p.m_label) return false; - - return true; - } - - bool operator<(const Point &p) const { - - if (m_frame != p.m_frame) return m_frame < p.m_frame; - - // points without a property sort before points with that property - - if (m_haveValue != p.m_haveValue) return !m_haveValue; - if (m_haveValue && (m_value != p.m_value)) return m_value < p.m_value; - - if (m_duration != p.m_duration) return m_duration < p.m_duration; - - if (m_haveLevel != p.m_haveLevel) return !m_haveLevel; - if (m_haveLevel && (m_level != p.m_level)) return m_level < p.m_level; - - if (m_haveReferenceFrame != p.m_haveReferenceFrame) { - return !m_haveReferenceFrame; - } - if (m_haveReferenceFrame && (m_referenceFrame != p.m_referenceFrame)) { - return m_referenceFrame < p.m_referenceFrame; - } - - return m_label < p.m_label; - } - - void toXml(QTextStream &stream, - QString indent = "", - QString extraAttributes = "") const { - - stream << indent << QString("<point frame=\"%1\" ").arg(m_frame); - if (m_haveValue) stream << QString("value=\"%1\" ").arg(m_value); - if (m_duration) stream << QString("duration=\"%1\" ").arg(m_duration); - if (m_haveLevel) stream << QString("level=\"%1\" ").arg(m_level); - if (m_haveReferenceFrame) stream << QString("referenceFrame=\"%1\" ") - .arg(m_referenceFrame); - stream << QString("label=\"%1\" ") - .arg(XmlExportable::encodeEntities(m_label)); - stream << extraAttributes << ">\n"; - } - - QString toXmlString(QString indent = "", - QString extraAttributes = "") const { - QString s; - QTextStream out(&s); - toXml(out, indent, extraAttributes); - out.flush(); - return s; - } - -private: - // The order of fields here is chosen to minimise overall size of struct. - // We potentially store very many of these objects. - // If you change something, check what difference it makes to packing. - bool m_haveValue : 1; - bool m_haveLevel : 1; - bool m_haveReferenceFrame : 1; - float m_value; - float m_level; - sv_frame_t m_frame; - sv_frame_t m_duration; - sv_frame_t m_referenceFrame; - QString m_label; -}; - -typedef std::vector<Point> PointVector; - -#endif
--- a/base/PointSeries.h Thu Mar 07 14:35:57 2019 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,228 +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 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_POINT_SERIES_H -#define SV_POINT_SERIES_H - -#include "Point.h" - -#include <set> - -//#define DEBUG_POINT_SERIES 1 - -class PointSeries -{ -public: - PointSeries() : m_count(0) { } - - void add(const Point &p) { - - m_points.insert(p); - ++m_count; - - if (p.haveDuration()) { - sv_frame_t frame = p.getFrame(); - sv_frame_t endFrame = p.getFrame() + p.getDuration(); - - createSeam(frame); - createSeam(endFrame); - - auto i0 = m_seams.find(frame); // must succeed after createSeam - auto i1 = m_seams.find(endFrame); // likewise - - for (auto i = i0; i != i1; ++i) { - if (i == m_seams.end()) { - SVCERR << "ERROR: PointSeries::add: " - << "reached end of seam map" - << endl; - break; - } - i->second.insert(p); - } - } - -#ifdef DEBUG_POINT_SERIES - std::cerr << "after add:" << std::endl; - dumpPoints(); - dumpSeams(); -#endif - } - - void remove(const Point &p) { - - // erase first itr that matches p; if there is more than one - // p, erase(p) would remove all of them, but we only want to - // remove (any) one - auto pitr = m_points.find(p); - if (pitr == m_points.end()) { - return; // we don't know this point - } else { - m_points.erase(pitr); - --m_count; - } - - if (p.haveDuration()) { - sv_frame_t frame = p.getFrame(); - sv_frame_t endFrame = p.getFrame() + p.getDuration(); - - auto i0 = m_seams.find(frame); - auto i1 = m_seams.find(endFrame); - -#ifdef DEBUG_POINT_SERIES - // This should be impossible if we found p in m_points above - if (i0 == m_seams.end() || i1 == m_seams.end()) { - SVCERR << "ERROR: PointSeries::remove: either frame " << frame - << " or endFrame " << endFrame - << " for point not found in seam map: point is " - << p.toXmlString() << endl; - } -#endif - - for (auto i = i0; i != i1; ++i) { - if (i == m_seams.end()) { - SVCERR << "ERROR: PointSeries::remove: " - << "reached end of seam map" - << endl; - break; - } - // Can't just erase(p) as that would erase all of - // them, if there are several identical ones - auto si = i->second.find(p); - if (si != i->second.end()) { - i->second.erase(si); - } - } - - // Shall we "garbage-collect" here? We could be leaving - // lots of empty point-sets, or consecutive identical - // ones, which are a pure irrelevance that take space and - // slow us down. But a lot depends on whether callers ever - // really delete anything much. - } - -#ifdef DEBUG_POINT_SERIES - std::cerr << "after remove:" << std::endl; - dumpPoints(); - dumpSeams(); -#endif - } - - bool contains(const Point &p) { - return m_points.find(p) != m_points.end(); - } - - int count() const { - return m_count; - } - - bool isEmpty() const { - return m_count == 0; - } - - void clear() { - m_points.clear(); - m_seams.clear(); - m_count = 0; - } - - /** - * Retrieve all points that span the given frame. A point without - * duration spans a frame if its own frame is equal to it. A point - * with duration spans a frame if its start frame is less than or - * equal to it and its end frame (start + duration) is greater - * than it. - */ - PointVector getPointsSpanning(sv_frame_t frame) const { - PointVector span; - - // first find any zero-duration points - auto pitr = m_points.lower_bound(Point(frame, QString())); - if (pitr != m_points.end()) { - while (pitr->getFrame() == frame) { - if (!pitr->haveDuration()) { - span.push_back(*pitr); - } - ++pitr; - } - } - - // now any non-zero-duration ones from the seam map - auto sitr = m_seams.lower_bound(frame); - if (sitr == m_seams.end() || sitr->first > frame) { - if (sitr != m_seams.begin()) { - --sitr; - } - } - if (sitr != m_seams.end() && sitr->first <= frame) { - for (auto p: sitr->second) { - span.push_back(p); - } - } - - return span; - } - -private: - int m_count; - - typedef std::multiset<Point> PointMultiset; - PointMultiset m_points; - - typedef std::map<sv_frame_t, std::multiset<Point>> FramePointsMap; - FramePointsMap m_seams; - - /** Create a seam at the given frame, copying from the prior seam - * if there is one. If a seam already exists at the given frame, - * leave it untouched. - */ - void createSeam(sv_frame_t frame) { - auto itr = m_seams.lower_bound(frame); - if (itr == m_seams.end() || itr->first > frame) { - if (itr != m_seams.begin()) { - --itr; - } - } - if (itr == m_seams.end()) { - m_seams[frame] = {}; - } else if (itr->first < frame) { - m_seams[frame] = itr->second; - } else if (itr->first > frame) { // itr must be begin() - m_seams[frame] = {}; - } - } - -#ifdef DEBUG_POINT_SERIES - void dumpPoints() const { - std::cerr << "POINTS [" << std::endl; - for (const auto &p: m_points) { - std::cerr << p.toXmlString(" "); - } - std::cerr << "]" << std::endl; - } - - void dumpSeams() const { - std::cerr << "SEAMS [" << std::endl; - for (const auto &s: m_seams) { - std::cerr << " " << s.first << " -> {" << std::endl; - for (const auto &p: s.second) { - std::cerr << p.toXmlString(" "); - } - std::cerr << " }" << std::endl; - } - std::cerr << "]" << std::endl; - } -#endif -}; - -#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/base/test/TestEventSeries.h Thu Mar 07 15:44:09 2019 +0000 @@ -0,0 +1,221 @@ +/* -*- 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 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 TEST_EVENT_SERIES_H +#define TEST_EVENT_SERIES_H + +#include "../EventSeries.h" + +#include <QObject> +#include <QtTest> + +#include <iostream> + +using namespace std; + +class TestEventSeries : public QObject +{ + Q_OBJECT + +private slots: + void empty() { + + EventSeries s; + QCOMPARE(s.isEmpty(), true); + QCOMPARE(s.count(), 0); + + Event p(10, QString()); + QCOMPARE(s.contains(p), false); + QCOMPARE(s.getEventsSpanning(400), EventVector()); + } + + void singleEvent() { + + EventSeries s; + Event p(10, QString()); + s.add(p); + QCOMPARE(s.isEmpty(), false); + QCOMPARE(s.count(), 1); + QCOMPARE(s.contains(p), true); + + s.remove(p); + QCOMPARE(s.isEmpty(), true); + QCOMPARE(s.contains(p), false); + } + + void singleEventSpan() { + + EventSeries s; + Event p(10, QString()); + s.add(p); + EventVector span; + span.push_back(p); + QCOMPARE(s.getEventsSpanning(10), span); + QCOMPARE(s.getEventsSpanning(11), EventVector()); + QCOMPARE(s.getEventsSpanning(9), EventVector()); + } + + void singleEventWithDurationSpan() { + + EventSeries s; + Event p(10, 1.0, 20, QString()); + s.add(p); + EventVector span; + span.push_back(p); + QCOMPARE(s.getEventsSpanning(10), span); + QCOMPARE(s.getEventsSpanning(11), span); + QCOMPARE(s.getEventsSpanning(29), span); + QCOMPARE(s.getEventsSpanning(30), EventVector()); + QCOMPARE(s.getEventsSpanning(9), EventVector()); + } + + void identicalEventsSpan() { + + EventSeries s; + Event p(10, QString()); + s.add(p); + s.add(p); + + EventVector span; + span.push_back(p); + span.push_back(p); + QCOMPARE(s.getEventsSpanning(10), span); + QCOMPARE(s.getEventsSpanning(11), EventVector()); + QCOMPARE(s.getEventsSpanning(9), EventVector()); + + s.remove(p); + span.clear(); + span.push_back(p); + QCOMPARE(s.getEventsSpanning(10), span); + QCOMPARE(s.getEventsSpanning(11), EventVector()); + QCOMPARE(s.getEventsSpanning(9), EventVector()); + } + + void identicalEventsWithDurationSpan() { + + EventSeries s; + Event p(10, 1.0, 20, QString()); + s.add(p); + s.add(p); + EventVector span; + span.push_back(p); + span.push_back(p); + QCOMPARE(s.getEventsSpanning(10), span); + QCOMPARE(s.getEventsSpanning(11), span); + QCOMPARE(s.getEventsSpanning(29), span); + QCOMPARE(s.getEventsSpanning(30), EventVector()); + QCOMPARE(s.getEventsSpanning(9), EventVector()); + + s.remove(p); + span.clear(); + span.push_back(p); + QCOMPARE(s.getEventsSpanning(10), span); + QCOMPARE(s.getEventsSpanning(11), span); + QCOMPARE(s.getEventsSpanning(29), span); + QCOMPARE(s.getEventsSpanning(30), EventVector()); + QCOMPARE(s.getEventsSpanning(9), EventVector()); + } + + void multipleEventsSpan() { + + EventSeries s; + Event a(10, QString("a")); + Event b(11, QString("b")); + Event c(40, QString("c")); + s.add(c); + s.add(a); + s.add(b); + s.remove(a); + s.add(a); + s.add(c); + s.remove(c); + QCOMPARE(s.count(), 3); + EventVector span; + span.push_back(a); + QCOMPARE(s.getEventsSpanning(10), span); + span.clear(); + span.push_back(c); + QCOMPARE(s.getEventsSpanning(40), span); + QCOMPARE(s.getEventsSpanning(9), EventVector()); + } + + void disjointEventsWithDurationSpan() { + + EventSeries s; + Event a(10, 1.0f, 20, QString("a")); + Event b(100, 1.2f, 30, QString("b")); + s.add(a); + s.add(b); + QCOMPARE(s.getEventsSpanning(0), EventVector()); + QCOMPARE(s.getEventsSpanning(10), EventVector({ a })); + QCOMPARE(s.getEventsSpanning(15), EventVector({ a })); + QCOMPARE(s.getEventsSpanning(30), EventVector()); + QCOMPARE(s.getEventsSpanning(99), EventVector()); + QCOMPARE(s.getEventsSpanning(100), EventVector({ b })); + QCOMPARE(s.getEventsSpanning(120), EventVector({ b })); + QCOMPARE(s.getEventsSpanning(130), EventVector()); + } + + void overlappingEventsWithAndWithoutDurationSpan() { + + EventSeries s; + Event p(20, QString("p")); + Event a(10, 1.0, 20, QString("a")); + s.add(p); + s.add(a); + EventVector span; + span.push_back(a); + QCOMPARE(s.getEventsSpanning(15), span); + QCOMPARE(s.getEventsSpanning(25), span); + span.clear(); + span.push_back(p); + span.push_back(a); + QCOMPARE(s.getEventsSpanning(20), span); + } + + void overlappingEventsWithDurationSpan() { + + EventSeries s; + Event a(20, 1.0, 10, QString("a")); + Event b(10, 1.0, 20, QString("b")); + Event c(10, 1.0, 40, QString("c")); + s.add(a); + s.add(b); + s.add(c); + QCOMPARE(s.getEventsSpanning(10), EventVector({ b, c })); + QCOMPARE(s.getEventsSpanning(20), EventVector({ b, c, a })); + QCOMPARE(s.getEventsSpanning(25), EventVector({ b, c, a })); + QCOMPARE(s.getEventsSpanning(30), EventVector({ c })); + QCOMPARE(s.getEventsSpanning(40), EventVector({ c })); + QCOMPARE(s.getEventsSpanning(50), EventVector()); + } + + void eventPatternSpan() { + + EventSeries s; + Event a(0, 1.0, 18, QString("a")); + Event b(3, 2.0, 6, QString("b")); + Event c(5, 3.0, 2, QString("c")); + Event d(6, 4.0, 10, QString("d")); + Event e(14, 5.0, 3, QString("e")); + s.add(b); + s.add(c); + s.add(d); + s.add(a); + s.add(e); + QCOMPARE(s.getEventsSpanning(8), EventVector({ a, b, d })); + } +}; + +#endif
--- a/base/test/TestPointSeries.h Thu Mar 07 14:35:57 2019 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,221 +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 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 TEST_POINT_SERIES_H -#define TEST_POINT_SERIES_H - -#include "../PointSeries.h" - -#include <QObject> -#include <QtTest> - -#include <iostream> - -using namespace std; - -class TestPointSeries : public QObject -{ - Q_OBJECT - -private slots: - void empty() { - - PointSeries s; - QCOMPARE(s.isEmpty(), true); - QCOMPARE(s.count(), 0); - - Point p(10, QString()); - QCOMPARE(s.contains(p), false); - QCOMPARE(s.getPointsSpanning(400), PointVector()); - } - - void singlePoint() { - - PointSeries s; - Point p(10, QString()); - s.add(p); - QCOMPARE(s.isEmpty(), false); - QCOMPARE(s.count(), 1); - QCOMPARE(s.contains(p), true); - - s.remove(p); - QCOMPARE(s.isEmpty(), true); - QCOMPARE(s.contains(p), false); - } - - void singlePointSpan() { - - PointSeries s; - Point p(10, QString()); - s.add(p); - PointVector span; - span.push_back(p); - QCOMPARE(s.getPointsSpanning(10), span); - QCOMPARE(s.getPointsSpanning(11), PointVector()); - QCOMPARE(s.getPointsSpanning(9), PointVector()); - } - - void singlePointWithDurationSpan() { - - PointSeries s; - Point p(10, 1.0, 20, QString()); - s.add(p); - PointVector span; - span.push_back(p); - QCOMPARE(s.getPointsSpanning(10), span); - QCOMPARE(s.getPointsSpanning(11), span); - QCOMPARE(s.getPointsSpanning(29), span); - QCOMPARE(s.getPointsSpanning(30), PointVector()); - QCOMPARE(s.getPointsSpanning(9), PointVector()); - } - - void identicalPointsSpan() { - - PointSeries s; - Point p(10, QString()); - s.add(p); - s.add(p); - - PointVector span; - span.push_back(p); - span.push_back(p); - QCOMPARE(s.getPointsSpanning(10), span); - QCOMPARE(s.getPointsSpanning(11), PointVector()); - QCOMPARE(s.getPointsSpanning(9), PointVector()); - - s.remove(p); - span.clear(); - span.push_back(p); - QCOMPARE(s.getPointsSpanning(10), span); - QCOMPARE(s.getPointsSpanning(11), PointVector()); - QCOMPARE(s.getPointsSpanning(9), PointVector()); - } - - void identicalPointsWithDurationSpan() { - - PointSeries s; - Point p(10, 1.0, 20, QString()); - s.add(p); - s.add(p); - PointVector span; - span.push_back(p); - span.push_back(p); - QCOMPARE(s.getPointsSpanning(10), span); - QCOMPARE(s.getPointsSpanning(11), span); - QCOMPARE(s.getPointsSpanning(29), span); - QCOMPARE(s.getPointsSpanning(30), PointVector()); - QCOMPARE(s.getPointsSpanning(9), PointVector()); - - s.remove(p); - span.clear(); - span.push_back(p); - QCOMPARE(s.getPointsSpanning(10), span); - QCOMPARE(s.getPointsSpanning(11), span); - QCOMPARE(s.getPointsSpanning(29), span); - QCOMPARE(s.getPointsSpanning(30), PointVector()); - QCOMPARE(s.getPointsSpanning(9), PointVector()); - } - - void multiplePointsSpan() { - - PointSeries s; - Point a(10, QString("a")); - Point b(11, QString("b")); - Point c(40, QString("c")); - s.add(c); - s.add(a); - s.add(b); - s.remove(a); - s.add(a); - s.add(c); - s.remove(c); - QCOMPARE(s.count(), 3); - PointVector span; - span.push_back(a); - QCOMPARE(s.getPointsSpanning(10), span); - span.clear(); - span.push_back(c); - QCOMPARE(s.getPointsSpanning(40), span); - QCOMPARE(s.getPointsSpanning(9), PointVector()); - } - - void disjointPointsWithDurationSpan() { - - PointSeries s; - Point a(10, 1.0f, 20, QString("a")); - Point b(100, 1.2f, 30, QString("b")); - s.add(a); - s.add(b); - QCOMPARE(s.getPointsSpanning(0), PointVector()); - QCOMPARE(s.getPointsSpanning(10), PointVector({ a })); - QCOMPARE(s.getPointsSpanning(15), PointVector({ a })); - QCOMPARE(s.getPointsSpanning(30), PointVector()); - QCOMPARE(s.getPointsSpanning(99), PointVector()); - QCOMPARE(s.getPointsSpanning(100), PointVector({ b })); - QCOMPARE(s.getPointsSpanning(120), PointVector({ b })); - QCOMPARE(s.getPointsSpanning(130), PointVector()); - } - - void overlappingPointsWithAndWithoutDurationSpan() { - - PointSeries s; - Point p(20, QString("p")); - Point a(10, 1.0, 20, QString("a")); - s.add(p); - s.add(a); - PointVector span; - span.push_back(a); - QCOMPARE(s.getPointsSpanning(15), span); - QCOMPARE(s.getPointsSpanning(25), span); - span.clear(); - span.push_back(p); - span.push_back(a); - QCOMPARE(s.getPointsSpanning(20), span); - } - - void overlappingPointsWithDurationSpan() { - - PointSeries s; - Point a(20, 1.0, 10, QString("a")); - Point b(10, 1.0, 20, QString("b")); - Point c(10, 1.0, 40, QString("c")); - s.add(a); - s.add(b); - s.add(c); - QCOMPARE(s.getPointsSpanning(10), PointVector({ b, c })); - QCOMPARE(s.getPointsSpanning(20), PointVector({ b, c, a })); - QCOMPARE(s.getPointsSpanning(25), PointVector({ b, c, a })); - QCOMPARE(s.getPointsSpanning(30), PointVector({ c })); - QCOMPARE(s.getPointsSpanning(40), PointVector({ c })); - QCOMPARE(s.getPointsSpanning(50), PointVector()); - } - - void pointPatternSpan() { - - PointSeries s; - Point a(0, 1.0, 18, QString("a")); - Point b(3, 2.0, 6, QString("b")); - Point c(5, 3.0, 2, QString("c")); - Point d(6, 4.0, 10, QString("d")); - Point e(14, 5.0, 3, QString("e")); - s.add(b); - s.add(c); - s.add(d); - s.add(a); - s.add(e); - QCOMPARE(s.getPointsSpanning(8), PointVector({ a, b, d })); - } -}; - -#endif
--- a/base/test/files.pri Thu Mar 07 14:35:57 2019 +0000 +++ b/base/test/files.pri Thu Mar 07 15:44:09 2019 +0000 @@ -4,7 +4,7 @@ TestMovingMedian.h \ TestOurRealTime.h \ TestPitch.h \ - TestPointSeries.h \ + TestEventSeries.h \ TestRangeMapper.h \ TestScaleTickIntervals.h \ TestStringBits.h \
--- a/base/test/svcore-base-test.cpp Thu Mar 07 14:35:57 2019 +0000 +++ b/base/test/svcore-base-test.cpp Thu Mar 07 15:44:09 2019 +0000 @@ -20,7 +20,7 @@ #include "TestVampRealTime.h" #include "TestColumnOp.h" #include "TestMovingMedian.h" -#include "TestPointSeries.h" +#include "TestEventSeries.h" #include "system/Init.h" @@ -86,7 +86,7 @@ else ++bad; } { - TestPointSeries t; + TestEventSeries t; if (QTest::qExec(&t, argc, argv) == 0) ++good; else ++bad; }
--- a/data/fileio/MIDIFileWriter.cpp Thu Mar 07 14:35:57 2019 +0000 +++ b/data/fileio/MIDIFileWriter.cpp Thu Mar 07 15:44:09 2019 +0000 @@ -23,8 +23,8 @@ #include "MIDIFileWriter.h" #include "data/midi/MIDIEvent.h" -#include "model/NoteData.h" +#include "base/NoteData.h" #include "base/Pitch.h" #include <QCoreApplication>
--- a/data/model/FlexiNoteModel.h Thu Mar 07 14:35:57 2019 +0000 +++ b/data/model/FlexiNoteModel.h Thu Mar 07 15:44:09 2019 +0000 @@ -17,7 +17,7 @@ #define SV_FLEXINOTE_MODEL_H #include "IntervalModel.h" -#include "NoteData.h" +#include "base/NoteData.h" #include "base/RealTime.h" #include "base/Pitch.h" #include "base/PlayParameterRepository.h"
--- a/data/model/NoteData.h Thu Mar 07 14:35:57 2019 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +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 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_NOTE_DATA_H -#define SV_NOTE_DATA_H - -#include <vector> - -#include "base/Pitch.h" - -struct NoteData -{ - NoteData(sv_frame_t _start, sv_frame_t _dur, int _mp, int _vel) : - start(_start), duration(_dur), midiPitch(_mp), frequency(0), - isMidiPitchQuantized(true), velocity(_vel), channel(0) { }; - - sv_frame_t start; // audio sample frame - sv_frame_t duration; // in audio sample frames - int midiPitch; // 0-127 - float frequency; // Hz, to be used if isMidiPitchQuantized false - bool isMidiPitchQuantized; - int velocity; // MIDI-style 0-127 - int channel; // MIDI 0-15 - - float getFrequency() const { - if (isMidiPitchQuantized) { - return float(Pitch::getFrequencyForPitch(midiPitch)); - } else { - return frequency; - } - } -}; - -typedef std::vector<NoteData> NoteList; - -class NoteExportable -{ -public: - virtual NoteList getNotes() const = 0; - virtual NoteList getNotesWithin(sv_frame_t startFrame, sv_frame_t endFrame) const = 0; -}; - -#endif
--- a/data/model/NoteModel.h Thu Mar 07 14:35:57 2019 +0000 +++ b/data/model/NoteModel.h Thu Mar 07 15:44:09 2019 +0000 @@ -17,7 +17,7 @@ #define SV_NOTE_MODEL_H #include "IntervalModel.h" -#include "NoteData.h" +#include "base/NoteData.h" #include "base/RealTime.h" #include "base/PlayParameterRepository.h" #include "base/Pitch.h"
--- a/data/model/SparseOneDimensionalModel.h Thu Mar 07 14:35:57 2019 +0000 +++ b/data/model/SparseOneDimensionalModel.h Thu Mar 07 15:44:09 2019 +0000 @@ -17,7 +17,7 @@ #define SV_SPARSE_ONE_DIMENSIONAL_MODEL_H #include "SparseModel.h" -#include "NoteData.h" +#include "base/NoteData.h" #include "base/PlayParameterRepository.h" #include "base/RealTime.h"
--- a/files.pri Thu Mar 07 14:35:57 2019 +0000 +++ b/files.pri Thu Mar 07 15:44:09 2019 +0000 @@ -7,16 +7,18 @@ base/ColumnOp.h \ base/Command.h \ base/Debug.h \ + base/Event.h \ + base/EventSeries.h \ base/Exceptions.h \ base/HelperExecPath.h \ base/HitCount.h \ base/LogRange.h \ base/MagnitudeRange.h \ + base/NoteData.h \ base/Pitch.h \ base/Playable.h \ base/PlayParameterRepository.h \ base/PlayParameters.h \ - base/Point.h \ base/Preferences.h \ base/Profiler.h \ base/ProgressPrinter.h \