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
This commit is contained in:
parent
23949886e6
commit
056b2a59d5
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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__ */
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
MidiModel::const_iterator::~const_iterator()
|
||||
{
|
||||
/*
|
||||
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());
|
||||
_model.read_unlock();
|
||||
}
|
||||
|
||||
|
||||
const MidiModel::Note&
|
||||
MidiModel::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;
|
||||
}
|
||||
|
||||
// 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.
|
||||
*
|
||||
|
|
|
@ -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
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue