diff base/Event.h @ 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 base/Point.h@23a29e5dc0e9
children 2f9deb8d3295
line wrap: on
line diff
--- /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