changeset 852:d6bd5751b8f6 tonioni_multi_transform

Add NoteExportable base class, use it in MIDI export (and also elsewhere in playback)
author Chris Cannam
date Mon, 02 Dec 2013 17:11:20 +0000
parents dba8a02b0413
children 23ecd10c2eb6
files data/fileio/MIDIFileWriter.cpp data/fileio/MIDIFileWriter.h data/model/FlexiNoteModel.h data/model/NoteData.h data/model/NoteModel.h data/model/SparseOneDimensionalModel.h
diffstat 6 files changed, 191 insertions(+), 47 deletions(-) [+]
line wrap: on
line diff
--- a/data/fileio/MIDIFileWriter.cpp	Mon Dec 02 12:29:09 2013 +0000
+++ b/data/fileio/MIDIFileWriter.cpp	Mon Dec 02 17:11:20 2013 +0000
@@ -23,8 +23,7 @@
 #include "MIDIFileWriter.h"
 
 #include "data/midi/MIDIEvent.h"
-
-#include "model/NoteModel.h"
+#include "model/NoteData.h"
 
 #include "base/Pitch.h"
 
@@ -37,14 +36,13 @@
 
 using namespace MIDIConstants;
 
-MIDIFileWriter::MIDIFileWriter(QString path, NoteModel *model, float tempo) :
+MIDIFileWriter::MIDIFileWriter(QString path, const NoteExportable *exportable,
+                               int sampleRate, float tempo) :
     m_path(path),
-    m_model(model),
-    m_modelUsesHz(false),
+    m_exportable(exportable),
+    m_sampleRate(sampleRate),
     m_tempo(tempo)
 {
-    if (model->getScaleUnits().toLower() == "hz") m_modelUsesHz = true;
-
     if (!convert()) {
         m_error = "Conversion from model to internal MIDI format failed";
     }
@@ -342,42 +340,28 @@
 
     // Omit time signature
 
-    const NoteModel::PointList &notes =
-        static_cast<SparseModel<Note> *>(m_model)->getPoints();
+    NoteList notes = m_exportable->getNotes();
 
-    for (NoteModel::PointList::const_iterator i = notes.begin();
-         i != notes.end(); ++i) {
+    for (NoteList::const_iterator i = notes.begin(); i != notes.end(); ++i) {
 
-        long frame = i->frame;
-        float value = i->value;
+        size_t frame = i->start;
         size_t duration = i->duration;
-
-        int pitch;
-
-        if (m_modelUsesHz) {
-            pitch = Pitch::getPitchForFrequency(value);
-        } else {
-            pitch = lrintf(value);
-        }
+        int pitch = i->midiPitch;
+        int velocity = i->velocity;
 
         if (pitch < 0) pitch = 0;
         if (pitch > 127) pitch = 127;
 
         // Convert frame to MIDI time
 
-        double seconds = double(frame) / double(m_model->getSampleRate());
+        double seconds = double(frame) / double(m_sampleRate);
         double quarters = (seconds * m_tempo) / 60.0;
-        unsigned long midiTime = lrint(quarters * m_timingDivision);
-
-        int velocity = 100;
-        if (i->level > 0.f && i->level <= 1.f) {
-            velocity = lrintf(i->level * 127.f);
-        }
+        unsigned long midiTime = int(quarters * m_timingDivision + 0.5);
 
         // Get the sounding time for the matching NOTE_OFF
-        seconds = double(frame + duration) / double(m_model->getSampleRate());
+        seconds = double(frame + duration) / double(m_sampleRate);
         quarters = (seconds * m_tempo) / 60.0;
-        unsigned long endTime = lrint(quarters * m_timingDivision);
+        unsigned long endTime = int(quarters * m_timingDivision + 0.5);
 
         // At this point all the notes we insert have absolute times
         // in the delta time fields.  We resolve these into delta
--- a/data/fileio/MIDIFileWriter.h	Mon Dec 02 12:29:09 2013 +0000
+++ b/data/fileio/MIDIFileWriter.h	Mon Dec 02 17:11:20 2013 +0000
@@ -32,7 +32,7 @@
 #include <fstream>
 
 class MIDIEvent;
-class NoteModel;
+class NoteExportable;
 
 /**
  * Write a MIDI file.  This includes file write code for generic
@@ -43,7 +43,10 @@
 class MIDIFileWriter 
 {
 public:
-    MIDIFileWriter(QString path, NoteModel *model, float tempo = 120.f);
+    MIDIFileWriter(QString path, 
+                   const NoteExportable *exportable, 
+                   int sampleRate, // used to convert exportable sample timings
+                   float tempo = 120.f);
     virtual ~MIDIFileWriter();
 
     virtual bool isOK() const;
@@ -74,18 +77,18 @@
     
     bool convert();
 
-    QString             m_path;
-    NoteModel          *m_model;
-    bool                m_modelUsesHz;
-    float               m_tempo;
-    int                 m_timingDivision;   // pulses per quarter note
-    MIDIFileFormatType  m_format;
-    unsigned int        m_numberOfTracks;
+    QString               m_path;
+    const NoteExportable *m_exportable;
+    int                   m_sampleRate;
+    float                 m_tempo;
+    int                   m_timingDivision;   // pulses per quarter note
+    MIDIFileFormatType    m_format;
+    unsigned int          m_numberOfTracks;
 
-    MIDIComposition     m_midiComposition;
+    MIDIComposition       m_midiComposition;
 
-    std::ofstream      *m_midiFile;
-    QString             m_error;
+    std::ofstream        *m_midiFile;
+    QString               m_error;
 };
 
 #endif
--- a/data/model/FlexiNoteModel.h	Mon Dec 02 12:29:09 2013 +0000
+++ b/data/model/FlexiNoteModel.h	Mon Dec 02 17:11:20 2013 +0000
@@ -16,10 +16,10 @@
 #ifndef _FLEXINOTE_MODEL_H_
 #define _FLEXINOTE_MODEL_H_
 
-// #include "NotelikeModel.h" // GF: reomved as this is an uncommitted experiment for now
-
 #include "IntervalModel.h"
+#include "NoteData.h"
 #include "base/RealTime.h"
+#include "base/Pitch.h"
 #include "base/PlayParameterRepository.h"
 
 /**
@@ -97,7 +97,7 @@
 };
 
 
-class FlexiNoteModel : public IntervalModel<FlexiNote>
+class FlexiNoteModel : public IntervalModel<FlexiNote>, public NoteExportable
 {
     Q_OBJECT
     
@@ -227,6 +227,48 @@
         return SortNumeric;
     }
 
+    /**
+     * NoteExportable methods.
+     */
+
+    NoteList getNotes() const {
+        return getNotes(getStartFrame(), getEndFrame());
+    }
+
+    NoteList getNotes(size_t startFrame, size_t endFrame) const {
+        
+	PointList points = getPoints(startFrame, endFrame);
+        NoteList notes;
+
+        for (PointList::iterator pli =
+		 points.begin(); pli != points.end(); ++pli) {
+
+	    size_t duration = pli->duration;
+            if (duration == 0 || duration == 1) {
+                duration = getSampleRate() / 20;
+            }
+
+            int pitch = lrintf(pli->value);
+            
+            int velocity = 100;
+            if (pli->level > 0.f && pli->level <= 1.f) {
+                velocity = 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;
 };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/model/NoteData.h	Mon Dec 02 17:11:20 2013 +0000
@@ -0,0 +1,43 @@
+/* -*- 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 NOTE_DATA_H
+#define NOTE_DATA_H
+
+#include <vector>
+
+struct NoteData
+{
+    NoteData(size_t _start, size_t _dur, int _mp, int _vel) :
+	start(_start), duration(_dur), midiPitch(_mp), frequency(0),
+	isMidiPitchQuantized(true), velocity(_vel) { };
+            
+    size_t start;     // audio sample frame
+    size_t duration;  // in audio sample frames
+    int midiPitch; // 0-127
+    int frequency; // Hz, to be used if isMidiPitchQuantized false
+    bool isMidiPitchQuantized;
+    int velocity;  // MIDI-style 0-127
+};
+
+typedef std::vector<NoteData> NoteList;
+
+class NoteExportable
+{
+public:
+    virtual NoteList getNotes() const = 0;
+    virtual NoteList getNotes(size_t startFrame, size_t endFrame) const = 0;
+};
+
+#endif
--- a/data/model/NoteModel.h	Mon Dec 02 12:29:09 2013 +0000
+++ b/data/model/NoteModel.h	Mon Dec 02 17:11:20 2013 +0000
@@ -17,8 +17,10 @@
 #define _NOTE_MODEL_H_
 
 #include "IntervalModel.h"
+#include "NoteData.h"
 #include "base/RealTime.h"
 #include "base/PlayParameterRepository.h"
+#include "base/Pitch.h"
 
 /**
  * NoteModel -- a concrete IntervalModel for notes.
@@ -91,7 +93,7 @@
 };
 
 
-class NoteModel : public IntervalModel<Note>
+class NoteModel : public IntervalModel<Note>, public NoteExportable
 {
     Q_OBJECT
     
@@ -219,6 +221,48 @@
         return SortNumeric;
     }
 
+    /**
+     * NoteExportable methods.
+     */
+
+    NoteList getNotes() const {
+        return getNotes(getStartFrame(), getEndFrame());
+    }
+
+    NoteList getNotes(size_t startFrame, size_t endFrame) const {
+        
+	PointList points = getPoints(startFrame, endFrame);
+        NoteList notes;
+
+        for (PointList::iterator pli =
+		 points.begin(); pli != points.end(); ++pli) {
+
+	    size_t duration = pli->duration;
+            if (duration == 0 || duration == 1) {
+                duration = getSampleRate() / 20;
+            }
+
+            int pitch = lrintf(pli->value);
+            
+            int velocity = 100;
+            if (pli->level > 0.f && pli->level <= 1.f) {
+                velocity = 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;
 };
--- a/data/model/SparseOneDimensionalModel.h	Mon Dec 02 12:29:09 2013 +0000
+++ b/data/model/SparseOneDimensionalModel.h	Mon Dec 02 17:11:20 2013 +0000
@@ -17,6 +17,7 @@
 #define _SPARSE_ONE_DIMENSIONAL_MODEL_H_
 
 #include "SparseModel.h"
+#include "NoteData.h"
 #include "base/PlayParameterRepository.h"
 #include "base/RealTime.h"
 
@@ -69,7 +70,8 @@
 };
 
 
-class SparseOneDimensionalModel : public SparseModel<OneDimensionalPoint>
+class SparseOneDimensionalModel : public SparseModel<OneDimensionalPoint>,
+                                  public NoteExportable
 {
     Q_OBJECT
     
@@ -181,6 +183,32 @@
         if (column == 2) return SortAlphabetical;
         return SortNumeric;
     }
+
+    /**
+     * NoteExportable methods.
+     */
+
+    NoteList getNotes() const {
+        return getNotes(getStartFrame(), getEndFrame());
+    }
+
+    NoteList getNotes(size_t startFrame, size_t endFrame) const {
+        
+	PointList points = getPoints(startFrame, endFrame);
+        NoteList notes;
+
+	for (PointList::iterator pli =
+		 points.begin(); pli != points.end(); ++pli) {
+
+            notes.push_back
+                (NoteData(pli->frame,
+                          getSampleRate() / 6, // arbitrary short duration
+                          64,   // default pitch
+                          100)); // default velocity
+        }
+
+        return notes;
+    }
 };
 
 #endif