fix up marshall/unmarshall of note data for MidiModel::DiffCommand
authorPaul Davis <paul@linuxaudiosystems.com>
Mon, 14 Sep 2009 16:01:32 +0000 (16:01 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Mon, 14 Sep 2009 16:01:32 +0000 (16:01 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@5662 d708f5d6-7413-0410-9779-e7cbd77b26cf

libs/ardour/midi_diskstream.cc
libs/ardour/midi_model.cc
libs/ardour/midi_ring_buffer.cc
libs/ardour/midi_track.cc
libs/ardour/smf_source.cc
libs/evoral/evoral/Note.hpp
libs/evoral/evoral/SMF.hpp
libs/evoral/evoral/types.hpp
libs/evoral/src/Note.cpp
libs/evoral/src/SMF.cpp

index b486a0fce060dfbbcc19635b20e82a78cdd98be9..9c8c9e8620101683593ec0583b14fc899c7a46be 100644 (file)
@@ -949,8 +949,8 @@ MidiDiskstream::read (nframes_t& start, nframes_t dur, bool reversed)
                                // Synthesize LoopEvent here, because the next events
                                // written will have non-monotonic timestamps.
                                _playback_buf->write(loop_end - 1, LoopEventType, 0, 0);
-                               //cout << "Pushing LoopEvent ts=" << loop_end-1 
-                               //     << " start+this_read " << start+this_read << endl;
+                               cout << "Pushing LoopEvent ts=" << loop_end-1 
+                                    << " start+this_read " << start+this_read << endl;
 
                                start = loop_start;
                        } else {
index 80c5759896ae26204f670dd8b4f2ab55c55fa608..79e59ecde429b1507c3e7b384580db152bed7115 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "ardour/midi_model.h"
 #include "ardour/midi_source.h"
+#include "ardour/smf_source.h"
 #include "ardour/types.h"
 #include "ardour/session.h"
 
@@ -458,45 +459,63 @@ MidiModel::DiffCommand::marshal_change(const NotePropertyChange& change)
 
        {
                ostringstream old_value_str (ios::ate);
-               old_value_str << (unsigned int) change.old_value;
+               if (change.property == StartTime || change.property == Length) {
+                       old_value_str << change.old_time;
+               } else {
+                       old_value_str << (unsigned int) change.old_value;
+               }
                xml_change->add_property ("old", old_value_str.str());
        }
 
        {
                ostringstream new_value_str (ios::ate);
-               new_value_str << (unsigned int) change.old_value;
+               if (change.property == StartTime || change.property == Length) {
+                       new_value_str << change.new_time;
+               } else {
+                       new_value_str << (unsigned int) change.new_value;
+               }
                xml_change->add_property ("new", new_value_str.str());
        }
 
        /* now the rest of the note */
+
+       const SMFSource* smf = dynamic_cast<const SMFSource*> (_model->midi_source());
        
        if (change.property != NoteNumber) {
-               ostringstream note_str(ios::ate);
+               ostringstream note_str;
                note_str << int(change.note->note());
                xml_change->add_property("note", note_str.str());
        }
        
        if (change.property != Channel) {
-               ostringstream channel_str(ios::ate);
+               ostringstream channel_str;
                channel_str << int(change.note->channel());
                xml_change->add_property("channel", channel_str.str());
        }
 
        if (change.property != StartTime) {
-               ostringstream time_str(ios::ate);
-               time_str << int(change.note->time());
+               ostringstream time_str;
+               if (smf) {
+                       time_str << smf->round_to_file_precision (change.note->time());
+               } else {
+                       time_str << change.note->time();
+               }
                xml_change->add_property("time", time_str.str());
        }
 
        if (change.property != Length) {
-               ostringstream length_str(ios::ate);
-               length_str <<(unsigned int) change.note->length();
-               xml_change->add_property("length", length_str.str());
+               ostringstream length_str;
+               if (smf) {
+                       length_str << smf->round_to_file_precision (change.note->length());
+               } else {
+                       length_str << change.note->length();
+               }
+               xml_change->add_property ("length", length_str.str());
        }
 
        if (change.property != Velocity) {
-               ostringstream velocity_str(ios::ate);
-               velocity_str << (unsigned int) change.note->velocity();
+               ostringstream velocity_str;
+               velocity_str << int (change.note->velocity());
                xml_change->add_property("velocity", velocity_str.str());
        }
 
@@ -510,9 +529,9 @@ MidiModel::DiffCommand::unmarshal_change(XMLNode *xml_change)
        NotePropertyChange change;
        unsigned int note;
        unsigned int channel;
-       unsigned int time;
-       unsigned int length;
        unsigned int velocity;
+       Evoral::MusicalTime time;
+       Evoral::MusicalTime length;
 
        if ((prop = xml_change->property("property")) != 0) {
                change.property = (Property) string_2_enum (prop->value(), change.property);
@@ -523,7 +542,13 @@ MidiModel::DiffCommand::unmarshal_change(XMLNode *xml_change)
 
        if ((prop = xml_change->property ("old")) != 0) {
                istringstream old_str (prop->value());
-               old_str >> change.old_value;
+               if (change.property == StartTime || change.property == Length) {
+                       old_str >> change.old_time;
+               } else {
+                       int integer_value_so_that_istream_does_the_right_thing;
+                       old_str >> integer_value_so_that_istream_does_the_right_thing;
+                       change.old_value = integer_value_so_that_istream_does_the_right_thing;
+               }
        } else {
                fatal << "!!!" << endmsg;
                /*NOTREACHED*/
@@ -531,7 +556,13 @@ MidiModel::DiffCommand::unmarshal_change(XMLNode *xml_change)
 
        if ((prop = xml_change->property ("new")) != 0) {
                istringstream new_str (prop->value());
-               new_str >> change.new_value;
+               if (change.property == StartTime || change.property == Length) {
+                       new_str >> change.new_time;
+               } else {
+                       int integer_value_so_that_istream_does_the_right_thing;
+                       new_str >> integer_value_so_that_istream_does_the_right_thing;
+                       change.new_value = integer_value_so_that_istream_does_the_right_thing;
+               }
        } else {
                fatal << "!!!" << endmsg;
                /*NOTREACHED*/
@@ -570,7 +601,7 @@ MidiModel::DiffCommand::unmarshal_change(XMLNode *xml_change)
                        time = 0;
                }
        } else {
-               time = change.new_value;
+               time = change.new_time;
        }
 
        if (change.property != Length) {
@@ -582,7 +613,7 @@ MidiModel::DiffCommand::unmarshal_change(XMLNode *xml_change)
                        length = 1;
                }
        } else {
-               length = change.new_value;
+               length = change.new_time;
        }
 
        if (change.property != Velocity) {
@@ -600,13 +631,13 @@ MidiModel::DiffCommand::unmarshal_change(XMLNode *xml_change)
        /* we must point at the instance of the note that is actually in the model.
           so go look for it ...
        */
-
+       
        boost::shared_ptr<Evoral::Note<TimeType> > new_note (new Evoral::Note<TimeType> (channel, time, length, note, velocity));
 
        change.note = _model->find_note (new_note);
 
        if (!change.note) {
-               warning << "MIDI note not found in model - programmers should investigate this" << endmsg;
+               warning << "MIDI note " << *new_note << " not found in model - programmers should investigate this" << endmsg;
                /* use the actual new note */
                change.note = new_note;
        }
@@ -627,7 +658,7 @@ MidiModel::DiffCommand::set_state(const XMLNode& diff_command)
 
        if (changed_notes) {
                XMLNodeList notes = changed_notes->children();
-               
+
                transform (notes.begin(), notes.end(), back_inserter(_changes),
                           sigc::mem_fun(*this, &DiffCommand::unmarshal_change));
        }
@@ -688,11 +719,15 @@ MidiModel::get_state()
 boost::shared_ptr<Evoral::Note<MidiModel::TimeType> >
 MidiModel::find_note (boost::shared_ptr<Evoral::Note<TimeType> > other) 
 {
-       Notes::iterator i = find (notes().begin(), notes().end(), other);
+       for (Notes::iterator x = notes().begin(); x != notes().end(); ++x) {
+               if (**x == *other) {
+                       return *x;
+               }
 
-       if (i == notes().end()) {
-               return boost::shared_ptr<Evoral::Note<TimeType> > ();
+               /* XXX optimize by using a stored iterator and break out 
+                  when passed start time.
+               */
        }
-       
-       return *i;
+
+       return boost::shared_ptr<Evoral::Note<TimeType> > ();
 }
index 007d5271c8ee82d31d679ca911c05de991dea740..88064c87986b990a3b468e519ee057009034d5c7 100644 (file)
@@ -66,8 +66,8 @@ MidiRingBuffer<T>::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes
                // This event marks a loop end (i.e. the next event's timestamp will be non-monotonic)
                if (ev_type == LoopEventType) {
                        /*ev_time -= start;
-                       ev_time += offset;
-                       cerr << "MRB loop boundary @ " << ev_time << endl;*/
+                         ev_time += offset;*/
+                       cerr << "MRB loop boundary @ " << ev_time << endl;
 
                        // Return without reading data or writing to buffer (loop events have no data)
                        // FIXME: This is not correct, loses events after the loop this cycle
index 7324196512f7046eabba1b59576d9f87202176bb..000143f3d545e77f2a4776d0a476326ddc038753 100644 (file)
@@ -456,6 +456,7 @@ MidiTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
 
                if (did_loop) {
                        /* add necessary note offs */
+                       cerr << "DID LOOP, RESOLVE NOTES\n";
                        _midi_state_tracker.resolve_notes (mbuf, end_frame-start_frame - 1);
                }
 
index 40848dc9edfe5c21a13de406551eddec08fa88f4..7db027124b8c09c9b15ff368960cf4cdee1ed62a 100644 (file)
@@ -256,7 +256,7 @@ SMFSource::append_event_unlocked_beats (const Evoral::Event<double>& ev)
        
        const double delta_time_beats   = ev.time() - _last_ev_time_beats;
        const uint32_t delta_time_ticks = (uint32_t)lrint(delta_time_beats * (double)ppqn());
-
+       
        Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer());
        _last_ev_time_beats = ev.time();
 
@@ -396,7 +396,7 @@ SMFSource::load_model (bool lock, bool force_reload)
        while ((ret = read_event(&delta_t, &size, &buf)) >= 0) {
                time += delta_t;
                ev.set(buf, size, time / (double)ppqn());
-               
+
                if (ret > 0) { // didn't skip (meta) event
                        ev.set_event_type(EventTypeMap::instance().midi_event_type(buf[0]));
                        _model->append(ev);
index e92094ae788375bcd092077ab4ba46a4d5980dcb..b636df46e2bbbfa4f55e680be16d5bc5bc07752f 100644 (file)
@@ -38,11 +38,11 @@ public:
        const Note<Time>& operator=(const Note<Time>& copy);
 
        inline bool operator==(const Note<Time>& other) {
-               return time() == other.time() && 
-                note() == other.note() && 
-                length() == other.length() &&
-                velocity() == other.velocity() &&
-                channel()  == other.channel();
+               return musical_time_equal (time(), other.time()) && 
+                       note() == other.note() && 
+                       musical_time_equal (length(), other.length()) && 
+                       velocity() == other.velocity() &&
+                       channel()  == other.channel();
        }
 
        inline Time        time()     const { return _on_event.time(); }
index 4a6b21870b05312293e53dc0b95e5587b9d73ce2..b921a80e6d8529c34ffe923e29d91c389086f5d1 100644 (file)
@@ -64,6 +64,8 @@ public:
        
        void flush() {};
 
+        double round_to_file_precision (double val) const;
+
 private:
        std::string  _file_path;
        smf_t*       _smf;
index e9ce50306831de511fb85466abe76c688944e063..9e48a68e3c1b8d2ae50e7cf133ab788bb65aa67b 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <stdint.h>
 #include <list>
+#include <cmath>
 
 namespace Evoral {
 
@@ -30,6 +31,11 @@ typedef uint32_t FrameTime;
 /** Musical time: beats relative to some defined origin */
 typedef double MusicalTime;
 
+static inline bool musical_time_equal (MusicalTime a, MusicalTime b) {
+        /* acceptable tolerance is 1 tick. Nice if there was no magic number here */
+       return fabs (a - b) <= (1.0/1920.0); 
+}
+
 /** Type of an event (opaque, mapped by application) */
 typedef uint32_t EventType;
 
index 9440cde2733cb14d13b1a61dc6c03d0968fc8b82..d97cfef4295613913ba7597d997603c24a73e022 100644 (file)
@@ -39,7 +39,7 @@ Note<Time>::Note(uint8_t chan, Time t, Time l, uint8_t n, uint8_t v)
        _off_event.buffer()[2] = 0x40;
        
        assert(time() == t);
-       assert(length() - l <= 1.0/1920.0); /* acceptable tolerance is 1/ppqn. Nice if there was no magic number here */
+       assert(musical_time_equal (length(), l));
        assert(note() == n);
        assert(velocity() == v);
        assert(_on_event.channel() == _off_event.channel());
index 372c37c0bb79b4ba5a493d8dd830dec5b6fc001f..2103ad8eae7afad837e68bd710874db886cea1fd 100644 (file)
@@ -19,6 +19,7 @@
 
 #define __STDC_LIMIT_MACROS 1
 #include <cassert>
+#include <cmath>
 #include <iostream>
 #include <stdint.h>
 #include "libsmf/smf.h"
@@ -262,5 +263,13 @@ SMF::end_write() THROW_FILE_ERROR
                throw FileError();
 }
 
+double
+SMF::round_to_file_precision (double val) const
+{
+       double div = ppqn();
+
+       return round (val * div) / div;
+}
+
 
 } // namespace Evoral