diff options
-rw-r--r-- | libs/ardour/midi_diskstream.cc | 4 | ||||
-rw-r--r-- | libs/ardour/midi_model.cc | 85 | ||||
-rw-r--r-- | libs/ardour/midi_ring_buffer.cc | 4 | ||||
-rw-r--r-- | libs/ardour/midi_track.cc | 1 | ||||
-rw-r--r-- | libs/ardour/smf_source.cc | 4 | ||||
-rw-r--r-- | libs/evoral/evoral/Note.hpp | 10 | ||||
-rw-r--r-- | libs/evoral/evoral/SMF.hpp | 2 | ||||
-rw-r--r-- | libs/evoral/evoral/types.hpp | 6 | ||||
-rw-r--r-- | libs/evoral/src/Note.cpp | 2 | ||||
-rw-r--r-- | libs/evoral/src/SMF.cpp | 9 |
10 files changed, 90 insertions, 37 deletions
diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc index b486a0fce0..9c8c9e8620 100644 --- a/libs/ardour/midi_diskstream.cc +++ b/libs/ardour/midi_diskstream.cc @@ -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 { diff --git a/libs/ardour/midi_model.cc b/libs/ardour/midi_model.cc index 80c5759896..79e59ecde4 100644 --- a/libs/ardour/midi_model.cc +++ b/libs/ardour/midi_model.cc @@ -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> > (); } diff --git a/libs/ardour/midi_ring_buffer.cc b/libs/ardour/midi_ring_buffer.cc index 007d5271c8..88064c8798 100644 --- a/libs/ardour/midi_ring_buffer.cc +++ b/libs/ardour/midi_ring_buffer.cc @@ -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 diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc index 7324196512..000143f3d5 100644 --- a/libs/ardour/midi_track.cc +++ b/libs/ardour/midi_track.cc @@ -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); } diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc index 40848dc9ed..7db027124b 100644 --- a/libs/ardour/smf_source.cc +++ b/libs/ardour/smf_source.cc @@ -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); diff --git a/libs/evoral/evoral/Note.hpp b/libs/evoral/evoral/Note.hpp index e92094ae78..b636df46e2 100644 --- a/libs/evoral/evoral/Note.hpp +++ b/libs/evoral/evoral/Note.hpp @@ -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(); } diff --git a/libs/evoral/evoral/SMF.hpp b/libs/evoral/evoral/SMF.hpp index 4a6b21870b..b921a80e6d 100644 --- a/libs/evoral/evoral/SMF.hpp +++ b/libs/evoral/evoral/SMF.hpp @@ -64,6 +64,8 @@ public: void flush() {}; + double round_to_file_precision (double val) const; + private: std::string _file_path; smf_t* _smf; diff --git a/libs/evoral/evoral/types.hpp b/libs/evoral/evoral/types.hpp index e9ce503068..9e48a68e3c 100644 --- a/libs/evoral/evoral/types.hpp +++ b/libs/evoral/evoral/types.hpp @@ -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; diff --git a/libs/evoral/src/Note.cpp b/libs/evoral/src/Note.cpp index 9440cde273..d97cfef429 100644 --- a/libs/evoral/src/Note.cpp +++ b/libs/evoral/src/Note.cpp @@ -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()); diff --git a/libs/evoral/src/SMF.cpp b/libs/evoral/src/SMF.cpp index 372c37c0bb..2103ad8eae 100644 --- a/libs/evoral/src/SMF.cpp +++ b/libs/evoral/src/SMF.cpp @@ -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 |