Chris@1611: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@1611: Chris@1611: /* Chris@1611: Sonic Visualiser Chris@1611: An audio file viewer and annotation editor. Chris@1611: Centre for Digital Music, Queen Mary, University of London. Chris@1611: This file copyright 2006 Chris Cannam. Chris@1611: Chris@1611: This program is free software; you can redistribute it and/or Chris@1611: modify it under the terms of the GNU General Public License as Chris@1611: published by the Free Software Foundation; either version 2 of the Chris@1611: License, or (at your option) any later version. See the file Chris@1611: COPYING included with this distribution for more information. Chris@1611: */ Chris@1611: Chris@1615: #ifndef SV_EVENT_H Chris@1615: #define SV_EVENT_H Chris@1615: Chris@1615: #include "BaseTypes.h" Chris@1615: #include "NoteData.h" Chris@1615: #include "XmlExportable.h" Chris@1615: Chris@1615: #include Chris@1615: #include Chris@1611: Chris@1611: #include Chris@1611: Chris@1615: /** Chris@1615: * An immutable type used for point and event representation in sparse Chris@1615: * models, as well as for interchange within the clipboard. An event Chris@1615: * always has a frame and (possibly empty) label, and optionally has Chris@1615: * numerical value, level, duration in frames, and a mapped reference Chris@1615: * frame. Event has an operator< defining a total ordering, by frame Chris@1615: * first and then by the other properties. Chris@1615: * Chris@1615: * Event is based on the Clipboard::Point type up to SV v3.2.1 and is Chris@1615: * intended also to replace the custom point types previously found in Chris@1615: * sparse models. Chris@1615: */ Chris@1615: class Event Chris@1611: { Chris@1611: public: Chris@1615: Event(sv_frame_t frame) : Chris@1615: m_haveValue(false), m_haveLevel(false), m_haveReferenceFrame(false), Chris@1615: m_value(0.f), m_level(0.f), m_frame(frame), Chris@1615: m_duration(0), m_referenceFrame(0), m_label() { } Chris@1615: Chris@1615: Event(sv_frame_t frame, QString label) : Chris@1612: m_haveValue(false), m_haveLevel(false), m_haveReferenceFrame(false), Chris@1611: m_value(0.f), m_level(0.f), m_frame(frame), Chris@1611: m_duration(0), m_referenceFrame(0), m_label(label) { } Chris@1611: Chris@1615: Event(sv_frame_t frame, float value, QString label) : Chris@1612: m_haveValue(true), m_haveLevel(false), m_haveReferenceFrame(false), Chris@1611: m_value(value), m_level(0.f), m_frame(frame), Chris@1611: m_duration(0), m_referenceFrame(0), m_label(label) { } Chris@1611: Chris@1615: Event(sv_frame_t frame, float value, sv_frame_t duration, QString label) : Chris@1612: m_haveValue(true), m_haveLevel(false), m_haveReferenceFrame(false), Chris@1611: m_value(value), m_level(0.f), m_frame(frame), Chris@1615: m_duration(duration), m_referenceFrame(0), m_label(label) { Chris@1615: if (m_duration < 0) throw std::logic_error("duration must be >= 0"); Chris@1615: } Chris@1611: Chris@1615: Event(sv_frame_t frame, float value, sv_frame_t duration, Chris@1612: float level, QString label) : Chris@1612: m_haveValue(true), m_haveLevel(true), m_haveReferenceFrame(false), Chris@1611: m_value(value), m_level(level), m_frame(frame), Chris@1615: m_duration(duration), m_referenceFrame(0), m_label(label) { Chris@1615: if (m_duration < 0) throw std::logic_error("duration must be >= 0"); Chris@1615: } Chris@1611: Chris@1615: Event(const Event &event) =default; Chris@1615: Event &operator=(const Event &event) =default; Chris@1615: Event &operator=(Event &&event) =default; Chris@1611: Chris@1611: sv_frame_t getFrame() const { return m_frame; } Chris@1611: Chris@1615: Event withFrame(sv_frame_t frame) const { Chris@1615: Event p(*this); Chris@1611: p.m_frame = frame; Chris@1611: return p; Chris@1611: } Chris@1611: Chris@1615: bool hasValue() const { return m_haveValue; } Chris@1611: float getValue() const { return m_value; } Chris@1611: Chris@1615: Event withValue(float value) const { Chris@1615: Event p(*this); Chris@1611: p.m_haveValue = true; Chris@1611: p.m_value = value; Chris@1611: return p; Chris@1611: } Chris@1615: Event withoutValue() const { Chris@1615: Event p(*this); Chris@1615: p.m_haveValue = false; Chris@1615: p.m_value = 0.f; Chris@1615: return p; Chris@1615: } Chris@1611: Chris@1615: bool hasDuration() const { return m_duration != 0; } Chris@1611: sv_frame_t getDuration() const { return m_duration; } Chris@1611: Chris@1615: Event withDuration(sv_frame_t duration) const { Chris@1615: Event p(*this); Chris@1611: p.m_duration = duration; Chris@1615: if (duration < 0) throw std::logic_error("duration must be >= 0"); Chris@1615: return p; Chris@1615: } Chris@1615: Event withoutDuration() const { Chris@1615: Event p(*this); Chris@1615: p.m_duration = 0; Chris@1611: return p; Chris@1611: } Chris@1611: Chris@1611: QString getLabel() const { return m_label; } Chris@1611: Chris@1615: Event withLabel(QString label) const { Chris@1615: Event p(*this); Chris@1611: p.m_label = label; Chris@1611: return p; Chris@1611: } Chris@1611: Chris@1615: bool hasLevel() const { return m_haveLevel; } Chris@1611: float getLevel() const { return m_level; } Chris@1615: Chris@1615: Event withLevel(float level) const { Chris@1615: Event p(*this); Chris@1611: p.m_haveLevel = true; Chris@1611: p.m_level = level; Chris@1611: return p; Chris@1611: } Chris@1615: Event withoutLevel() const { Chris@1615: Event p(*this); Chris@1615: p.m_haveLevel = false; Chris@1615: p.m_level = 0.f; Chris@1615: return p; Chris@1615: } Chris@1611: Chris@1615: bool hasReferenceFrame() const { return m_haveReferenceFrame; } Chris@1611: sv_frame_t getReferenceFrame() const { return m_referenceFrame; } Chris@1611: Chris@1615: bool referenceFrameDiffers() const { // from event frame Chris@1611: return m_haveReferenceFrame && (m_referenceFrame != m_frame); Chris@1611: } Chris@1611: Chris@1615: Event withReferenceFrame(sv_frame_t frame) const { Chris@1615: Event p(*this); Chris@1611: p.m_haveReferenceFrame = true; Chris@1611: p.m_referenceFrame = frame; Chris@1611: return p; Chris@1611: } Chris@1615: Event withoutReferenceFrame() const { Chris@1615: Event p(*this); Chris@1615: p.m_haveReferenceFrame = false; Chris@1615: p.m_referenceFrame = 0; Chris@1615: return p; Chris@1615: } Chris@1612: Chris@1615: bool operator==(const Event &p) const { Chris@1612: Chris@1612: if (m_frame != p.m_frame) return false; Chris@1615: if (m_duration != p.m_duration) return false; Chris@1612: Chris@1612: if (m_haveValue != p.m_haveValue) return false; Chris@1612: if (m_haveValue && (m_value != p.m_value)) return false; Chris@1612: Chris@1612: if (m_haveLevel != p.m_haveLevel) return false; Chris@1612: if (m_haveLevel && (m_level != p.m_level)) return false; Chris@1612: Chris@1612: if (m_haveReferenceFrame != p.m_haveReferenceFrame) return false; Chris@1612: if (m_haveReferenceFrame && Chris@1612: (m_referenceFrame != p.m_referenceFrame)) return false; Chris@1612: Chris@1612: if (m_label != p.m_label) return false; Chris@1612: Chris@1612: return true; Chris@1612: } Chris@1612: Chris@1615: bool operator<(const Event &p) const { Chris@1612: Chris@1612: if (m_frame != p.m_frame) return m_frame < p.m_frame; Chris@1615: if (m_duration != p.m_duration) return m_duration < p.m_duration; Chris@1612: Chris@1615: // events without a property sort before events with that property Chris@1612: Chris@1612: if (m_haveValue != p.m_haveValue) return !m_haveValue; Chris@1612: if (m_haveValue && (m_value != p.m_value)) return m_value < p.m_value; Chris@1612: Chris@1612: if (m_haveLevel != p.m_haveLevel) return !m_haveLevel; Chris@1612: if (m_haveLevel && (m_level != p.m_level)) return m_level < p.m_level; Chris@1612: Chris@1612: if (m_haveReferenceFrame != p.m_haveReferenceFrame) { Chris@1612: return !m_haveReferenceFrame; Chris@1612: } Chris@1612: if (m_haveReferenceFrame && (m_referenceFrame != p.m_referenceFrame)) { Chris@1612: return m_referenceFrame < p.m_referenceFrame; Chris@1612: } Chris@1612: Chris@1612: return m_label < p.m_label; Chris@1612: } Chris@1612: Chris@1612: void toXml(QTextStream &stream, Chris@1612: QString indent = "", Chris@1612: QString extraAttributes = "") const { Chris@1612: Chris@1615: // For I/O purposes these are points, not events Chris@1612: stream << indent << QString("\n"; Chris@1612: } Chris@1612: Chris@1612: QString toXmlString(QString indent = "", Chris@1612: QString extraAttributes = "") const { Chris@1612: QString s; Chris@1612: QTextStream out(&s); Chris@1612: toXml(out, indent, extraAttributes); Chris@1612: out.flush(); Chris@1612: return s; Chris@1612: } Chris@1615: Chris@1615: NoteData toNoteData(sv_samplerate_t sampleRate, bool valueIsMidiPitch) { Chris@1615: Chris@1615: sv_frame_t duration; Chris@1615: if (m_duration > 0) { Chris@1615: duration = m_duration; Chris@1615: } else { Chris@1615: duration = sv_frame_t(sampleRate / 6); // arbitrary short duration Chris@1615: } Chris@1615: Chris@1615: int midiPitch; Chris@1615: float frequency = 0.f; Chris@1615: if (m_haveValue) { Chris@1615: if (valueIsMidiPitch) { Chris@1615: midiPitch = int(roundf(m_value)); Chris@1615: } else { Chris@1615: frequency = m_value; Chris@1615: midiPitch = Pitch::getPitchForFrequency(frequency); Chris@1615: } Chris@1615: } else { Chris@1615: midiPitch = 64; Chris@1615: valueIsMidiPitch = true; Chris@1615: } Chris@1615: Chris@1615: int velocity = 100; Chris@1615: if (m_haveLevel) { Chris@1615: if (m_level > 0.f && m_level <= 1.f) { Chris@1615: velocity = int(roundf(m_level * 127.f)); Chris@1615: } Chris@1615: } Chris@1615: Chris@1615: NoteData n(m_frame, duration, midiPitch, velocity); Chris@1615: n.isMidiPitchQuantized = valueIsMidiPitch; Chris@1615: if (!valueIsMidiPitch) { Chris@1615: n.frequency = frequency; Chris@1615: } Chris@1615: Chris@1615: return n; Chris@1615: } Chris@1611: Chris@1611: private: Chris@1611: // The order of fields here is chosen to minimise overall size of struct. Chris@1612: // We potentially store very many of these objects. Chris@1611: // If you change something, check what difference it makes to packing. Chris@1611: bool m_haveValue : 1; Chris@1611: bool m_haveLevel : 1; Chris@1611: bool m_haveReferenceFrame : 1; Chris@1611: float m_value; Chris@1611: float m_level; Chris@1611: sv_frame_t m_frame; Chris@1611: sv_frame_t m_duration; Chris@1611: sv_frame_t m_referenceFrame; Chris@1611: QString m_label; Chris@1611: }; Chris@1611: Chris@1615: typedef std::vector EventVector; Chris@1612: Chris@1611: #endif