summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gtk2_ardour/canvas-hit.h2
-rw-r--r--gtk2_ardour/canvas-midi-event.cc2
-rw-r--r--gtk2_ardour/canvas-midi-event.h14
-rw-r--r--gtk2_ardour/canvas-note.h2
-rw-r--r--gtk2_ardour/midi_region_view.cc6
-rw-r--r--gtk2_ardour/midi_region_view.h4
-rw-r--r--gtk2_ardour/midi_streamview.cc4
-rw-r--r--libs/ardour/SConscript1
-rw-r--r--libs/ardour/ardour/automation_event.h4
-rw-r--r--libs/ardour/ardour/midi_event.h14
-rw-r--r--libs/ardour/ardour/midi_model.h78
-rw-r--r--libs/ardour/ardour/note.h71
-rw-r--r--libs/ardour/ardour/parameter.h3
-rw-r--r--libs/ardour/automation_event.cc2
-rw-r--r--libs/ardour/midi_model.cc195
-rw-r--r--libs/ardour/note.cc89
-rw-r--r--libs/ardour/smf_source.cc2
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) {