diff options
author | David Robillard <d@drobilla.net> | 2007-08-28 17:48:37 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2007-08-28 17:48:37 +0000 |
commit | 056b2a59d5cb28042926dab61f56e49917c8eec4 (patch) | |
tree | 7c5ae738749667bc5800da51db63205fb0793659 | |
parent | 23949886e6f207e423d11b330b8d7e9ad5a949bf (diff) |
Split MidiModel::Note out to ARDOUR::Note in it's own file (midi_model.h was getting fat).
Initial work on MidiModel iterator.
git-svn-id: svn://localhost/ardour2/trunk@2355 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r-- | gtk2_ardour/canvas-hit.h | 2 | ||||
-rw-r--r-- | gtk2_ardour/canvas-midi-event.cc | 2 | ||||
-rw-r--r-- | gtk2_ardour/canvas-midi-event.h | 14 | ||||
-rw-r--r-- | gtk2_ardour/canvas-note.h | 2 | ||||
-rw-r--r-- | gtk2_ardour/midi_region_view.cc | 6 | ||||
-rw-r--r-- | gtk2_ardour/midi_region_view.h | 4 | ||||
-rw-r--r-- | gtk2_ardour/midi_streamview.cc | 4 | ||||
-rw-r--r-- | libs/ardour/SConscript | 1 | ||||
-rw-r--r-- | libs/ardour/ardour/automation_event.h | 4 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_event.h | 14 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_model.h | 78 | ||||
-rw-r--r-- | libs/ardour/ardour/note.h | 71 | ||||
-rw-r--r-- | libs/ardour/ardour/parameter.h | 3 | ||||
-rw-r--r-- | libs/ardour/automation_event.cc | 2 | ||||
-rw-r--r-- | libs/ardour/midi_model.cc | 195 | ||||
-rw-r--r-- | libs/ardour/note.cc | 89 | ||||
-rw-r--r-- | libs/ardour/smf_source.cc | 2 |
17 files changed, 374 insertions, 119 deletions
diff --git a/gtk2_ardour/canvas-hit.h b/gtk2_ardour/canvas-hit.h index 114d608a89..b924f981bb 100644 --- a/gtk2_ardour/canvas-hit.h +++ b/gtk2_ardour/canvas-hit.h @@ -29,7 +29,7 @@ namespace Canvas { class CanvasHit : public Diamond, public CanvasMidiEvent { public: - CanvasHit(MidiRegionView& region, Group& group, double size, const ARDOUR::MidiModel::Note* note=NULL) + CanvasHit(MidiRegionView& region, Group& group, double size, const ARDOUR::Note* note=NULL) : Diamond(group, size), CanvasMidiEvent(region, this, note) {} // FIXME diff --git a/gtk2_ardour/canvas-midi-event.cc b/gtk2_ardour/canvas-midi-event.cc index 0ff479eaf3..642ae170b1 100644 --- a/gtk2_ardour/canvas-midi-event.cc +++ b/gtk2_ardour/canvas-midi-event.cc @@ -31,7 +31,7 @@ namespace Gnome { namespace Canvas { -CanvasMidiEvent::CanvasMidiEvent(MidiRegionView& region, Item* item, const ARDOUR::MidiModel::Note* note) +CanvasMidiEvent::CanvasMidiEvent(MidiRegionView& region, Item* item, const ARDOUR::Note* note) : _region(region) , _item(item) , _state(None) diff --git a/gtk2_ardour/canvas-midi-event.h b/gtk2_ardour/canvas-midi-event.h index ce49b580b4..63b32cf0ca 100644 --- a/gtk2_ardour/canvas-midi-event.h +++ b/gtk2_ardour/canvas-midi-event.h @@ -43,7 +43,7 @@ namespace Canvas { */ class CanvasMidiEvent { public: - CanvasMidiEvent(MidiRegionView& region, Item* item, const ARDOUR::MidiModel::Note* note = NULL); + CanvasMidiEvent(MidiRegionView& region, Item* item, const ARDOUR::Note* note = NULL); virtual ~CanvasMidiEvent() {} bool on_event(GdkEvent* ev); @@ -62,16 +62,16 @@ public: const Item* item() const { return _item; } Item* item() { return _item; } - const ARDOUR::MidiModel::Note* note() { return _note; } + const ARDOUR::Note* note() { return _note; } protected: enum State { None, Pressed, Dragging }; - MidiRegionView& _region; - Item* const _item; - State _state; - const ARDOUR::MidiModel::Note* _note; - bool _selected; + MidiRegionView& _region; + Item* const _item; + State _state; + const ARDOUR::Note* _note; + bool _selected; }; } // namespace Gnome diff --git a/gtk2_ardour/canvas-note.h b/gtk2_ardour/canvas-note.h index 398d7d1abb..b12958a8ab 100644 --- a/gtk2_ardour/canvas-note.h +++ b/gtk2_ardour/canvas-note.h @@ -30,7 +30,7 @@ namespace Canvas { class CanvasNote : public SimpleRect, public CanvasMidiEvent { public: - CanvasNote(MidiRegionView& region, Group& group, const ARDOUR::MidiModel::Note* note=NULL) + CanvasNote(MidiRegionView& region, Group& group, const ARDOUR::Note* note=NULL) : SimpleRect(group), CanvasMidiEvent(region, this, note) { } diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc index b12f8ef4d9..2d70eb1c95 100644 --- a/gtk2_ardour/midi_region_view.cc +++ b/gtk2_ardour/midi_region_view.cc @@ -359,7 +359,7 @@ MidiRegionView::create_note_at(double x, double y, double dur) //double dur = m.frames_per_bar(t, trackview.session().frame_rate()) / m.beats_per_bar(); // Add a 1 beat long note (for now) - const MidiModel::Note new_note(stamp, dur, (uint8_t)note, 0x40); + const Note new_note(stamp, dur, (uint8_t)note, 0x40); view->update_bounds(new_note.note()); @@ -629,7 +629,7 @@ MidiRegionView::extend_active_notes() * duration so they can be drawn in full immediately. */ void -MidiRegionView::add_note (const MidiModel::Note& note) +MidiRegionView::add_note (const Note& note) { assert(note.time() >= 0); //assert(note.time() < _region->length()); @@ -777,7 +777,7 @@ MidiRegionView::note_dropped(CanvasMidiEvent* ev, double dt, uint8_t dnote) for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) { command_remove_note(*i); - MidiModel::Note copy(*(*i)->note()); + Note copy(*(*i)->note()); copy.set_time((*i)->note()->time() + dt); copy.set_note((*i)->note()->note() + dnote); diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h index be05556ce0..1d37ed26e5 100644 --- a/gtk2_ardour/midi_region_view.h +++ b/gtk2_ardour/midi_region_view.h @@ -77,7 +77,7 @@ class MidiRegionView : public RegionView GhostRegion* add_ghost (AutomationTimeAxisView&); void add_event(const ARDOUR::MidiEvent& ev); - void add_note(const ARDOUR::MidiModel::Note& note); + void add_note(const ARDOUR::Note& note); void begin_write(); void end_write(); @@ -99,7 +99,7 @@ class MidiRegionView : public RegionView _delta_command = _model->new_delta_command(); } - void command_add_note(ARDOUR::MidiModel::Note& note) { + void command_add_note(ARDOUR::Note& note) { if (_delta_command) _delta_command->add(note); } diff --git a/gtk2_ardour/midi_streamview.cc b/gtk2_ardour/midi_streamview.cc index 21eae23f90..3e33142b4d 100644 --- a/gtk2_ardour/midi_streamview.cc +++ b/gtk2_ardour/midi_streamview.cc @@ -149,7 +149,7 @@ MidiStreamView::display_region(MidiRegionView* region_view, bool load_model) if (source->model()) { // Find our note range for (size_t i=0; i < source->model()->n_notes(); ++i) { - const MidiModel::Note& note = source->model()->note_at(i); + const Note& note = source->model()->note_at(i); update_bounds(note.note()); } } @@ -469,7 +469,7 @@ MidiStreamView::update_rec_regions (boost::shared_ptr<MidiModel> data, nframes_t MidiRegionView* mrv = (MidiRegionView*)iter->second; // FIXME: slow for (size_t i=0; i < data->n_notes(); ++i) { - const MidiModel::Note& note = data->note_at(i); + const Note& note = data->note_at(i); if (note.time() > start + dur) break; diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript index a0070117e1..9150f8ba41 100644 --- a/libs/ardour/SConscript +++ b/libs/ardour/SConscript @@ -62,6 +62,7 @@ midi_playlist.cc midi_track.cc midi_region.cc midi_model.cc +note.cc smf_source.cc auditioner.cc automation.cc diff --git a/libs/ardour/ardour/automation_event.h b/libs/ardour/ardour/automation_event.h index 1675dbc822..e2a98e50b0 100644 --- a/libs/ardour/ardour/automation_event.h +++ b/libs/ardour/ardour/automation_event.h @@ -84,8 +84,8 @@ class AutomationList : public PBD::StatefulDestructible AutomationList& operator= (const AutomationList&); bool operator== (const AutomationList&); - Parameter parameter() const { return _parameter; } - void set_parameter(Parameter p) { _parameter = p; } + const Parameter& parameter() const { return _parameter; } + void set_parameter(Parameter p) { _parameter = p; } void freeze(); void thaw (); diff --git a/libs/ardour/ardour/midi_event.h b/libs/ardour/ardour/midi_event.h index 61e6b8af6e..a04a19cec8 100644 --- a/libs/ardour/ardour/midi_event.h +++ b/libs/ardour/ardour/midi_event.h @@ -21,7 +21,9 @@ #ifndef __ardour_midi_event_h__ #define __ardour_midi_event_h__ +#include <ardour/types.h> #include <ardour/midi_events.h> +#include <stdint.h> /** If this is not defined, all methods of MidiEvent are RT safe * but MidiEvent will never deep copy and (depending on the scenario) @@ -38,7 +40,7 @@ namespace ARDOUR { */ struct MidiEvent { #ifdef MIDI_EVENT_ALLOW_ALLOC - MidiEvent(double t=0, size_t s=0, Byte* b=NULL, bool owns_buffer=false) + MidiEvent(double t=0, uint32_t s=0, Byte* b=NULL, bool owns_buffer=false) : _time(t) , _size(s) , _buffer(b) @@ -96,7 +98,15 @@ struct MidiEvent { } inline bool owns_buffer() const { return _owns_buffer; } - inline void set_buffer(Byte* buf) { assert(!_owns_buffer); _buffer = buf; } + + inline void set_buffer(Byte* buf) { + if (_owns_buffer) { + free(_buffer); + _buffer = NULL; + } + _buffer = buf; + _owns_buffer = false; + } #else diff --git a/libs/ardour/ardour/midi_model.h b/libs/ardour/ardour/midi_model.h index 27a11fa9fc..41382b1be3 100644 --- a/libs/ardour/ardour/midi_model.h +++ b/libs/ardour/ardour/midi_model.h @@ -22,6 +22,7 @@ #define __ardour_midi_model_h__ #include <queue> +#include <utility> #include <boost/utility.hpp> #include <glibmm/thread.h> #include <pbd/command.h> @@ -29,11 +30,16 @@ #include <ardour/midi_buffer.h> #include <ardour/midi_ring_buffer.h> #include <ardour/automatable.h> +#include <ardour/note.h> namespace ARDOUR { class Session; class MidiSource; + +// x , y +typedef std::pair<boost::shared_ptr<const AutomationList>, std::pair<double,double> > + MidiControlIterator; /** This is a slightly higher level (than MidiBuffer) model of MIDI note data. @@ -44,45 +50,13 @@ class MidiSource; */ class MidiModel : public boost::noncopyable, public Automatable { public: - struct Note { - Note(double time=0, double dur=0, uint8_t note=0, uint8_t vel=0x40); - Note(const Note& copy); - - const MidiModel::Note& operator=(const MidiModel::Note& copy); - - inline bool operator==(const Note& other) - { return time() == other.time() && note() == other.note(); } - - inline double time() const { return _on_event.time(); } - inline double end_time() const { return _off_event.time(); } - inline uint8_t note() const { return _on_event.note(); } - inline uint8_t velocity() const { return _on_event.velocity(); } - inline double duration() const { return _off_event.time() - _on_event.time(); } - - inline void set_time(double t) { _off_event.time() = t + duration(); _on_event.time() = t; } - inline void set_note(uint8_t n) { _on_event.buffer()[1] = n; _off_event.buffer()[1] = n; } - inline void set_velocity(uint8_t n) { _on_event.buffer()[2] = n; } - inline void set_duration(double d) { _off_event.time() = _on_event.time() + d; } - - inline MidiEvent& on_event() { return _on_event; } - inline MidiEvent& off_event() { return _off_event; } - - inline const MidiEvent& on_event() const { return _on_event; } - inline const MidiEvent& off_event() const { return _off_event; } - - private: - // Event buffers are self-contained - MidiEvent _on_event; - MidiEvent _off_event; - }; - MidiModel(Session& s, size_t size=0); // This is crap. - void write_lock() { _lock.writer_lock(); _automation_lock.lock(); } - void write_unlock() { _lock.writer_unlock(); _automation_lock.unlock(); } - void read_lock() { _lock.reader_lock(); _automation_lock.lock(); } - void read_unlock() { _lock.reader_unlock(); _automation_lock.unlock(); } + void write_lock() { _lock.writer_lock(); _automation_lock.lock(); } + void write_unlock() { _lock.writer_unlock(); _automation_lock.unlock(); } + void read_lock() const { _lock.reader_lock(); _automation_lock.lock(); } + void read_unlock() const { _lock.reader_unlock(); _automation_lock.unlock(); } void clear() { _notes.clear(); } @@ -90,7 +64,7 @@ public: void set_note_mode(NoteMode mode) { _note_mode = mode; } void start_write(); - bool currently_writing() const { return _writing; } + bool writing() const { return _writing; } void end_write(bool delete_stuck=false); size_t read (MidiRingBuffer& dst, nframes_t start, nframes_t nframes, nframes_t stamp_offset) const; @@ -99,7 +73,6 @@ public: void append(const MidiBuffer& data); /** Resizes vector if necessary (NOT realtime safe) */ - //void append(double time, size_t size, const Byte* in_buffer); void append(const MidiEvent& ev); inline const Note& note_at(unsigned i) const { return _notes[i]; } @@ -164,11 +137,37 @@ public: sigc::signal<void> ContentsChanged; + /** Read iterator */ + class const_iterator { + public: + const_iterator(MidiModel& model, double t); + ~const_iterator(); + + const MidiEvent& operator*() const { return _event; } + + const const_iterator& operator++(); // prefix only + + private: + const MidiModel& _model; + MidiEvent _event; + + typedef std::priority_queue<const Note*,std::vector<const Note*>, LaterNoteEndComparator> + ActiveNotes; + mutable ActiveNotes _active_notes; + + Notes::iterator _note_iter; + + std::vector<MidiControlIterator> _control_iters; + }; + private: friend class DeltaCommand; void add_note_unlocked(const Note& note); void remove_note_unlocked(const Note& note); + friend class const_iterator; + bool control_to_midi_event(MidiEvent& ev, const MidiControlIterator& iter); + #ifndef NDEBUG bool is_sorted() const; #endif @@ -177,7 +176,7 @@ private: void append_note_off_unlocked(double time, uint8_t note); void append_cc_unlocked(double time, uint8_t number, uint8_t value); - Glib::RWLock _lock; + mutable Glib::RWLock _lock; Notes _notes; NoteMode _note_mode; @@ -188,6 +187,7 @@ private: bool _edited; // note state for read(): + // (TODO: Remove and replace with iterator) typedef std::priority_queue<const Note*,std::vector<const Note*>, LaterNoteEndComparator> ActiveNotes; diff --git a/libs/ardour/ardour/note.h b/libs/ardour/ardour/note.h new file mode 100644 index 0000000000..d88ecd05b0 --- /dev/null +++ b/libs/ardour/ardour/note.h @@ -0,0 +1,71 @@ +/* + Copyright (C) 2007 Paul Davis + Author: Dave Robillard + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __ardour_note_h__ +#define __ardour_note_h__ + +#include <stdint.h> +#include <ardour/midi_event.h> + +namespace ARDOUR { + + +/** A MIDI Note. + * + * A note is (unfortunately) special and not just another MidiEvent as it + * has a duration and two separate MIDI events (on and off). + */ +class Note { +public: + Note(double time=0, double dur=0, uint8_t note=0, uint8_t vel=0x40); + Note(const Note& copy); + + const Note& operator=(const Note& copy); + + inline bool operator==(const Note& other) + { return time() == other.time() && note() == other.note(); } + + inline double time() const { return _on_event.time(); } + inline double end_time() const { return _off_event.time(); } + inline uint8_t note() const { return _on_event.note(); } + inline uint8_t velocity() const { return _on_event.velocity(); } + inline double duration() const { return _off_event.time() - _on_event.time(); } + + inline void set_time(double t) { _off_event.time() = t + duration(); _on_event.time() = t; } + inline void set_note(uint8_t n) { _on_event.buffer()[1] = n; _off_event.buffer()[1] = n; } + inline void set_velocity(uint8_t n) { _on_event.buffer()[2] = n; } + inline void set_duration(double d) { _off_event.time() = _on_event.time() + d; } + + inline MidiEvent& on_event() { return _on_event; } + inline MidiEvent& off_event() { return _off_event; } + + inline const MidiEvent& on_event() const { return _on_event; } + inline const MidiEvent& off_event() const { return _off_event; } + +private: + // Event buffers are self-contained + MidiEvent _on_event; + MidiEvent _off_event; +}; + + +} // namespace ARDOUR + +#endif /* __ardour_note_h__ */ diff --git a/libs/ardour/ardour/parameter.h b/libs/ardour/ardour/parameter.h index 803bd889cb..d56124ee53 100644 --- a/libs/ardour/ardour/parameter.h +++ b/libs/ardour/ardour/parameter.h @@ -90,9 +90,10 @@ public: /** Arbitrary but fixed ordering, so we're comparable (usable in std::map) */ inline bool operator<(const Parameter& id) const { - // FIXME: branch a performance problem? #ifdef DEBUG? +#ifndef NDEBUG if (_type == NullAutomation) PBD::warning << "Uninitialized Parameter compared." << endmsg; +#endif return (_type < id._type || _id < id._id); } diff --git a/libs/ardour/automation_event.cc b/libs/ardour/automation_event.cc index 31f88c3ced..955acf0082 100644 --- a/libs/ardour/automation_event.cc +++ b/libs/ardour/automation_event.cc @@ -1077,7 +1077,7 @@ AutomationList::rt_safe_earliest_event_discrete (double start, double end, doubl build_search_cache_if_necessary(start, end); - pair<const_iterator,const_iterator> range = _search_cache.range; + const pair<const_iterator,const_iterator>& range = _search_cache.range; if (range.first != _events.end()) { const ControlEvent* const first = *range.first; diff --git a/libs/ardour/midi_model.cc b/libs/ardour/midi_model.cc index 7c80ed9a3b..4df4cf0b37 100644 --- a/libs/ardour/midi_model.cc +++ b/libs/ardour/midi_model.cc @@ -18,8 +18,11 @@ */ +#define __STDC_LIMIT_MACROS 1 + #include <iostream> #include <algorithm> +#include <stdint.h> #include <pbd/enumwriter.h> #include <ardour/midi_model.h> #include <ardour/midi_events.h> @@ -30,72 +33,53 @@ using namespace std; using namespace ARDOUR; -// Note -MidiModel::Note::Note(double t, double d, uint8_t n, uint8_t v) - : _on_event(t, 3, NULL, true) - , _off_event(t + d, 3, NULL, true) +// Read iterator (const_iterator) + +MidiModel::const_iterator::const_iterator(MidiModel& model, double t) + : _model(model) { - _on_event.buffer()[0] = MIDI_CMD_NOTE_ON; - _on_event.buffer()[1] = n; - _on_event.buffer()[2] = v; - - _off_event.buffer()[0] = MIDI_CMD_NOTE_OFF; - _off_event.buffer()[1] = n; - _off_event.buffer()[2] = 0x40; - - assert(time() == t); - assert(duration() == d); - assert(note() == n); - assert(velocity() == v); -} + model.read_lock(); + + _note_iter = model.notes().end(); + for (MidiModel::Notes::iterator i = model.notes().begin(); i != model.notes().end(); ++i) { + if ((*i).time() >= t) { + _note_iter = i; + break; + } + } + MidiControlIterator earliest_control = make_pair(boost::shared_ptr<AutomationList>(), make_pair(DBL_MAX, 0.0)); + + _control_iters.reserve(model.controls().size()); + for (Automatable::Controls::const_iterator i = model.controls().begin(); + i != model.controls().end(); ++i) { + double x, y; + i->second->list()->rt_safe_earliest_event(t, DBL_MAX, x, y); + + const MidiControlIterator new_iter = make_pair(i->second->list(), make_pair(x, y)); + + if (x < earliest_control.second.first) + earliest_control = new_iter; + + _control_iters.push_back(new_iter); + } + + if (_note_iter != model.notes().end()) + _event = MidiEvent(_note_iter->on_event(), false); + + if (earliest_control.first != 0 && earliest_control.second.first < _event.time()) + model.control_to_midi_event(_event, earliest_control); -MidiModel::Note::Note(const Note& copy) - : _on_event(copy._on_event, true) - , _off_event(copy._off_event, true) -{ - /* - assert(copy._on_event.size == 3); - _on_event.buffer = _on_event_buffer; - memcpy(_on_event_buffer, copy._on_event_buffer, 3); - - assert(copy._off_event.size == 3); - _off_event.buffer = _off_event_buffer; - memcpy(_off_event_buffer, copy._off_event_buffer, 3); - */ - - assert(time() == copy.time()); - assert(end_time() == copy.end_time()); - assert(note() == copy.note()); - assert(velocity() == copy.velocity()); - assert(duration() == copy.duration()); } -const MidiModel::Note& -MidiModel::Note::operator=(const Note& copy) +MidiModel::const_iterator::~const_iterator() { - _on_event = copy._on_event; - _off_event = copy._off_event; - /*_on_event.time = copy._on_event.time; - assert(copy._on_event.size == 3); - memcpy(_on_event_buffer, copy._on_event_buffer, 3); - - _off_event.time = copy._off_event.time; - assert(copy._off_event.size == 3); - memcpy(_off_event_buffer, copy._off_event_buffer, 3); - */ - - assert(time() == copy.time()); - assert(end_time() == copy.end_time()); - assert(note() == copy.note()); - assert(velocity() == copy.velocity()); - assert(duration() == copy.duration()); - - return *this; + _model.read_unlock(); } + // MidiModel MidiModel::MidiModel(Session& s, size_t size) @@ -180,7 +164,106 @@ MidiModel::read (MidiRingBuffer& dst, nframes_t start, nframes_t nframes, nframe return read_events; } + + +bool +MidiModel::control_to_midi_event(MidiEvent& ev, const MidiControlIterator& iter) +{ + if (iter.first->parameter().type() == MidiCCAutomation) { + if (!ev.owns_buffer() || ev.size() < 3) + ev = MidiEvent(iter.second.first, 3, (Byte*)malloc(3), true); + + assert(iter.first); + assert(iter.first->parameter().id() <= INT8_MAX); + assert(iter.second.second <= INT8_MAX); + ev.buffer()[0] = MIDI_CMD_CONTROL; + ev.buffer()[1] = (Byte)iter.first->parameter().id(); + ev.buffer()[2] = (Byte)iter.second.second; + ev.time() = iter.second.first; // x + ev.size() = 3; + return true; + } else { + return false; + } +} + + +/** Return the earliest MIDI event in the given range. + * + * \return true if \a output has been set to the earliest event in the given range. + */ +#if 0 +bool +MidiModel::earliest_note_event(MidiEvent& output, nframes_t start, nframes_t nframes) const +{ + /* FIXME: cache last lookup value to avoid O(n) search every time */ + + const Note* const earliest_on = NULL; + const Note* const earliest_off = NULL; + const MidiEvent* const earliest_cc = NULL; + + /* Notes */ + + if (_note_mode == Sustained) { + + for (Notes::const_iterator n = _notes.begin(); n != _notes.end(); ++n) { + + if ( ! _active_notes.empty() ) { + const Note* const earliest_off = _active_notes.top(); + const MidiEvent& off_ev = earliest_off->off_event(); + if (off_ev.time() < start + nframes && off_ev.time() <= n->time()) { + output = off_ev; + //dst.write(off_ev.time() + stamp_offset, off_ev.size(), off_ev.buffer()); + _active_notes.pop(); + return true; + } + } + + if (n->time() >= start + nframes) + break; + // Note on + if (n->time() >= start) { + earliest_on = &n->on_event(); + //dst.write(on_ev.time() + stamp_offset, on_ev.size(), on_ev.buffer()); + _active_notes.push(&(*n)); + return true; + } + + } + + // Write any trailing note offs + while ( ! _active_notes.empty() ) { + const Note* const earliest_off = _active_notes.top(); + const MidiEvent& off_ev = earliest_off->off_event(); + if (off_ev.time() < start + nframes) { + dst.write(off_ev.time() + stamp_offset, off_ev.size(), off_ev.buffer()); + _active_notes.pop(); + ++read_events; + } else { + break; + } + } + + // Percussive + } else { + for (Notes::const_iterator n = _notes.begin(); n != _notes.end(); ++n) { + // Note on + if (n->time() >= start) { + if (n->time() < start + nframes) { + const MidiEvent& ev = n->on_event(); + dst.write(ev.time() + stamp_offset, ev.size(), ev.buffer()); + ++read_events; + } else { + break; + } + } + } + } + + return read_events; +} +#endif /** Begin a write of events to the model. * diff --git a/libs/ardour/note.cc b/libs/ardour/note.cc new file mode 100644 index 0000000000..029daab3ba --- /dev/null +++ b/libs/ardour/note.cc @@ -0,0 +1,89 @@ +/* + Copyright (C) 2007 Paul Davis + Author: Dave Robillard + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include <ardour/note.h> + +namespace ARDOUR { + +Note::Note(double t, double d, uint8_t n, uint8_t v) + : _on_event(t, 3, NULL, true) + , _off_event(t + d, 3, NULL, true) +{ + _on_event.buffer()[0] = MIDI_CMD_NOTE_ON; + _on_event.buffer()[1] = n; + _on_event.buffer()[2] = v; + + _off_event.buffer()[0] = MIDI_CMD_NOTE_OFF; + _off_event.buffer()[1] = n; + _off_event.buffer()[2] = 0x40; + + assert(time() == t); + assert(duration() == d); + assert(note() == n); + assert(velocity() == v); +} + + +Note::Note(const Note& copy) + : _on_event(copy._on_event, true) + , _off_event(copy._off_event, true) +{ + /* + assert(copy._on_event.size == 3); + _on_event.buffer = _on_event_buffer; + memcpy(_on_event_buffer, copy._on_event_buffer, 3); + + assert(copy._off_event.size == 3); + _off_event.buffer = _off_event_buffer; + memcpy(_off_event_buffer, copy._off_event_buffer, 3); + */ + + assert(time() == copy.time()); + assert(end_time() == copy.end_time()); + assert(note() == copy.note()); + assert(velocity() == copy.velocity()); + assert(duration() == copy.duration()); +} + + +const Note& +Note::operator=(const Note& copy) +{ + _on_event = copy._on_event; + _off_event = copy._off_event; + /*_on_event.time = copy._on_event.time; + assert(copy._on_event.size == 3); + memcpy(_on_event_buffer, copy._on_event_buffer, 3); + + _off_event.time = copy._off_event.time; + assert(copy._off_event.size == 3); + memcpy(_off_event_buffer, copy._off_event_buffer, 3); + */ + + assert(time() == copy.time()); + assert(end_time() == copy.end_time()); + assert(note() == copy.note()); + assert(velocity() == copy.velocity()); + assert(duration() == copy.duration()); + + return *this; +} + +} // namespace ARDOUR diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc index 32f012e389..0cfdd51feb 100644 --- a/libs/ardour/smf_source.cc +++ b/libs/ardour/smf_source.cc @@ -398,7 +398,7 @@ SMFSource::write_unlocked (MidiRingBuffer& src, nframes_t cnt) size_t buf_capacity = 4; Byte* buf = (Byte*)malloc(buf_capacity); - if (_model && ! _model->currently_writing()) + if (_model && ! _model->writing()) _model->start_write(); while (true) { |