refactor JACK MIDI port to allow writing from a non-process() thread, and move ARDOUR::MidiEvent into MIDI namespace along with midi_events.h header

git-svn-id: svn://localhost/ardour2/branches/3.0@3155 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2008-03-18 03:42:32 +00:00
parent d69f4e9e3d
commit eb4a1fdbb8
27 changed files with 214 additions and 109 deletions

View file

@ -29,7 +29,6 @@
#include <ardour/midi_source.h> #include <ardour/midi_source.h>
#include <ardour/midi_diskstream.h> #include <ardour/midi_diskstream.h>
#include <ardour/midi_track.h> #include <ardour/midi_track.h>
#include <ardour/midi_events.h>
#include <ardour/smf_source.h> #include <ardour/smf_source.h>
#include <ardour/region_factory.h> #include <ardour/region_factory.h>

View file

@ -32,7 +32,6 @@
#include <ardour/midi_region.h> #include <ardour/midi_region.h>
#include <ardour/midi_source.h> #include <ardour/midi_source.h>
#include <ardour/midi_diskstream.h> #include <ardour/midi_diskstream.h>
#include <ardour/midi_events.h>
#include <ardour/midi_model.h> #include <ardour/midi_model.h>
#include "streamview.h" #include "streamview.h"

View file

@ -29,7 +29,6 @@
#include <ardour/midi_source.h> #include <ardour/midi_source.h>
#include <ardour/midi_diskstream.h> #include <ardour/midi_diskstream.h>
#include <ardour/midi_track.h> #include <ardour/midi_track.h>
#include <ardour/midi_events.h>
#include <ardour/smf_source.h> #include <ardour/smf_source.h>
#include <ardour/region_factory.h> #include <ardour/region_factory.h>

View file

@ -20,8 +20,8 @@
#ifndef __ardour_midi_buffer_h__ #ifndef __ardour_midi_buffer_h__
#define __ardour_midi_buffer_h__ #define __ardour_midi_buffer_h__
#include <midi++/event.h>
#include <ardour/buffer.h> #include <ardour/buffer.h>
#include <ardour/midi_event.h>
namespace ARDOUR { namespace ARDOUR {
@ -39,7 +39,7 @@ public:
void copy(const MidiBuffer& copy); void copy(const MidiBuffer& copy);
bool push_back(const ARDOUR::MidiEvent& event); bool push_back(const MIDI::Event& event);
bool push_back(const jack_midi_event_t& event); bool push_back(const jack_midi_event_t& event);
Byte* reserve(double time, size_t size); Byte* reserve(double time, size_t size);
@ -50,7 +50,7 @@ public:
struct iterator { struct iterator {
iterator(MidiBuffer& b, size_t i) : buffer(b), index(i) {} iterator(MidiBuffer& b, size_t i) : buffer(b), index(i) {}
inline MidiEvent& operator*() const { return buffer[index]; } inline MIDI::Event& operator*() const { return buffer[index]; }
inline iterator& operator++() { ++index; return *this; } // prefix inline iterator& operator++() { ++index; return *this; } // prefix
inline bool operator!=(const iterator& other) const { return index != other.index; } inline bool operator!=(const iterator& other) const { return index != other.index; }
@ -61,7 +61,7 @@ public:
struct const_iterator { struct const_iterator {
const_iterator(const MidiBuffer& b, size_t i) : buffer(b), index(i) {} const_iterator(const MidiBuffer& b, size_t i) : buffer(b), index(i) {}
inline const MidiEvent& operator*() const { return buffer[index]; } inline const MIDI::Event& operator*() const { return buffer[index]; }
inline const_iterator& operator++() { ++index; return *this; } // prefix inline const_iterator& operator++() { ++index; return *this; } // prefix
inline bool operator!=(const const_iterator& other) const { return index != other.index; } inline bool operator!=(const const_iterator& other) const { return index != other.index; }
@ -80,8 +80,8 @@ private:
friend class iterator; friend class iterator;
friend class const_iterator; friend class const_iterator;
const MidiEvent& operator[](size_t i) const { assert(i < _size); return _events[i]; } const MIDI::Event& operator[](size_t i) const { assert(i < _size); return _events[i]; }
MidiEvent& operator[](size_t i) { assert(i < _size); return _events[i]; } MIDI::Event& operator[](size_t i) { assert(i < _size); return _events[i]; }
// FIXME: Eliminate this // FIXME: Eliminate this
static const size_t MAX_EVENT_SIZE = 4; // bytes static const size_t MAX_EVENT_SIZE = 4; // bytes
@ -92,7 +92,7 @@ private:
/* FIXME: this is utter crap. rewrite as a flat/packed buffer like MidiRingBuffer */ /* FIXME: this is utter crap. rewrite as a flat/packed buffer like MidiRingBuffer */
MidiEvent* _events; ///< Event structs that point to offsets in _data MIDI::Event* _events; ///< Event structs that point to offsets in _data
Byte* _data; ///< MIDI, straight up. No time stamps. Byte* _data; ///< MIDI, straight up. No time stamps.
}; };

View file

@ -75,7 +75,7 @@ public:
size_t read (MidiRingBuffer& dst, nframes_t start, nframes_t nframes, nframes_t stamp_offset) const; size_t read (MidiRingBuffer& dst, nframes_t start, nframes_t nframes, nframes_t stamp_offset) const;
/** Resizes vector if necessary (NOT realtime safe) */ /** Resizes vector if necessary (NOT realtime safe) */
void append(const MidiEvent& ev); void append(const MIDI::Event& ev);
inline const boost::shared_ptr<const Note> note_at(unsigned i) const { return _notes[i]; } inline const boost::shared_ptr<const Note> note_at(unsigned i) const { return _notes[i]; }
inline const boost::shared_ptr<Note> note_at(unsigned i) { return _notes[i]; } inline const boost::shared_ptr<Note> note_at(unsigned i) { return _notes[i]; }
@ -151,8 +151,8 @@ public:
inline bool locked() const { return _locked; } inline bool locked() const { return _locked; }
const MidiEvent& operator*() const { return _event; } const MIDI::Event& operator*() const { return _event; }
const MidiEvent* operator->() const { return &_event; } const MIDI::Event* operator->() const { return &_event; }
const const_iterator& operator++(); // prefix only const const_iterator& operator++(); // prefix only
bool operator==(const const_iterator& other) const; bool operator==(const const_iterator& other) const;
@ -164,7 +164,7 @@ public:
friend class MidiModel; friend class MidiModel;
const MidiModel* _model; const MidiModel* _model;
MidiEvent _event; MIDI::Event _event;
typedef std::priority_queue< typedef std::priority_queue<
boost::shared_ptr<Note>, std::deque< boost::shared_ptr<Note> >, boost::shared_ptr<Note>, std::deque< boost::shared_ptr<Note> >,
@ -189,7 +189,7 @@ private:
void remove_note_unlocked(const boost::shared_ptr<const Note> note); void remove_note_unlocked(const boost::shared_ptr<const Note> note);
friend class const_iterator; friend class const_iterator;
bool control_to_midi_event(MidiEvent& ev, const MidiControlIterator& iter) const; bool control_to_midi_event(MIDI::Event& ev, const MidiControlIterator& iter) const;
#ifndef NDEBUG #ifndef NDEBUG
bool is_sorted() const; bool is_sorted() const;

View file

@ -307,7 +307,7 @@ MidiRingBuffer::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes_t
if (read_space() == 0) if (read_space() == 0)
return 0; return 0;
MidiEvent ev; MIDI::Event ev;
size_t count = 0; size_t count = 0;

View file

@ -58,7 +58,7 @@ class MidiSource : public Source
virtual nframes_t midi_read (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, nframes_t stamp_offset) const; virtual nframes_t midi_read (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, nframes_t stamp_offset) const;
virtual nframes_t midi_write (MidiRingBuffer& src, nframes_t cnt); virtual nframes_t midi_write (MidiRingBuffer& src, nframes_t cnt);
virtual void append_event_unlocked(EventTimeUnit unit, const MidiEvent& ev) = 0; virtual void append_event_unlocked(EventTimeUnit unit, const MIDI::Event& ev) = 0;
virtual void mark_for_remove() = 0; virtual void mark_for_remove() = 0;
virtual void mark_streaming_midi_write_started (NoteMode mode, nframes_t start_time); virtual void mark_streaming_midi_write_started (NoteMode mode, nframes_t start_time);

View file

@ -21,7 +21,7 @@
#ifndef __ardour_midi_util_h__ #ifndef __ardour_midi_util_h__
#define __ardour_midi_util_h__ #define __ardour_midi_util_h__
#include <ardour/midi_events.h> #include <midi++/events.h>
namespace ARDOUR { namespace ARDOUR {

View file

@ -22,14 +22,14 @@
#define __ardour_note_h__ #define __ardour_note_h__
#include <stdint.h> #include <stdint.h>
#include <ardour/midi_event.h> #include <midi++/event.h>
namespace ARDOUR { namespace ARDOUR {
/** A MIDI Note. /** A MIDI Note.
* *
* A note is (unfortunately) special and not just another MidiEvent as it * A note is (unfortunately) special and not just another MIDI::Event as it
* has a duration and two separate MIDI events (on and off). * has a duration and two separate MIDI events (on and off).
*/ */
class Note { class Note {
@ -53,16 +53,16 @@ public:
inline void set_velocity(uint8_t n) { _on_event.buffer()[2] = 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 void set_duration(double d) { _off_event.time() = _on_event.time() + d; }
inline MidiEvent& on_event() { return _on_event; } inline MIDI::Event& on_event() { return _on_event; }
inline MidiEvent& off_event() { return _off_event; } inline MIDI::Event& off_event() { return _off_event; }
inline const MidiEvent& on_event() const { return _on_event; } inline const MIDI::Event& on_event() const { return _on_event; }
inline const MidiEvent& off_event() const { return _off_event; } inline const MIDI::Event& off_event() const { return _off_event; }
private: private:
// Event buffers are self-contained // Event buffers are self-contained
MidiEvent _on_event; MIDI::Event _on_event;
MidiEvent _off_event; MIDI::Event _off_event;
}; };

View file

@ -71,7 +71,7 @@ class SMFSource : public MidiSource {
void set_allow_remove_if_empty (bool yn); void set_allow_remove_if_empty (bool yn);
void mark_for_remove(); void mark_for_remove();
void append_event_unlocked(EventTimeUnit unit, const MidiEvent& ev); void append_event_unlocked(EventTimeUnit unit, const MIDI::Event& ev);
int flush_header (); int flush_header ();
int flush_footer (); int flush_footer ();

View file

@ -29,6 +29,8 @@
#include <pbd/stacktrace.h> #include <pbd/stacktrace.h>
#include <pbd/unknown_type.h> #include <pbd/unknown_type.h>
#include <midi++/jack.h>
#include <ardour/audioengine.h> #include <ardour/audioengine.h>
#include <ardour/buffer.h> #include <ardour/buffer.h>
#include <ardour/port.h> #include <ardour/port.h>
@ -113,6 +115,7 @@ _thread_init_callback (void *arg)
*/ */
PBD::ThreadCreatedWithRequestSize (pthread_self(), X_("Audioengine"), 4096); PBD::ThreadCreatedWithRequestSize (pthread_self(), X_("Audioengine"), 4096);
MIDI::JACK_MidiPort::set_process_thread (pthread_self());
} }
int int

View file

@ -412,21 +412,6 @@ ARDOUR::get_ardour_revision ()
return "$Rev$"; return "$Rev$";
} }
static bool sae_binding_filter (const string& str, void* arg)
{
/* Not a dotfile, has a prefix before a period, suffix is ".bindings" and contains -sae- */
return str[0] != '.' && str.length() > 13 && str.find (".bindings") == (str.length() - 9)
&& str.find ("SAE-") != string::npos;
}
static bool binding_filter (const string& str, void* arg)
{
/* Not a dotfile, has a prefix before a period, suffix is ".bindings" */
return str[0] != '.' && str.length() > 9 && str.find (".bindings") == (str.length() - 9);
}
void void
ARDOUR::find_bindings_files (map<string,string>& files) ARDOUR::find_bindings_files (map<string,string>& files)
{ {

View file

@ -308,7 +308,7 @@ static void
write_midi_data_to_new_files (SMFReader* source, Session::import_status& status, write_midi_data_to_new_files (SMFReader* source, Session::import_status& status,
vector<boost::shared_ptr<Source> >& newfiles) vector<boost::shared_ptr<Source> >& newfiles)
{ {
MidiEvent ev(0.0, 4, NULL, true); MIDI::Event ev(0.0, 4, NULL, true);
status.progress = 0.0f; status.progress = 0.0f;

View file

@ -82,7 +82,7 @@ JackMidiPort::cycle_end (nframes_t nframes, nframes_t offset)
jack_midi_clear_buffer (jack_buffer); jack_midi_clear_buffer (jack_buffer);
for (MidiBuffer::iterator i = _buffer->begin(); i != _buffer->end(); ++i) { for (MidiBuffer::iterator i = _buffer->begin(); i != _buffer->end(); ++i) {
const MidiEvent& ev = *i; const MIDI::Event& ev = *i;
// event times should be frames, relative to cycle start // event times should be frames, relative to cycle start
assert(ev.time() >= 0); assert(ev.time() >= 0);
assert(ev.time() < nframes); assert(ev.time() < nframes);

View file

@ -47,7 +47,7 @@ PeakMeter::run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_f
// GUI needs a better MIDI meter, not much information can be // GUI needs a better MIDI meter, not much information can be
// expressed through peaks alone // expressed through peaks alone
for (MidiBuffer::iterator i = bufs.get_midi(n).begin(); i != bufs.get_midi(n).end(); ++i) { for (MidiBuffer::iterator i = bufs.get_midi(n).begin(); i != bufs.get_midi(n).end(); ++i) {
const MidiEvent& ev = *i; const MIDI::Event& ev = *i;
if (ev.is_note_on()) { if (ev.is_note_on()) {
const float this_vel = log(ev.buffer()[2] / 127.0 * (M_E*M_E-M_E) + M_E) - 1.0; const float this_vel = log(ev.buffer()[2] / 127.0 * (M_E*M_E-M_E) + M_E) - 1.0;
//printf("V %d -> %f\n", (int)((Byte)ev.buffer[2]), this_vel); //printf("V %d -> %f\n", (int)((Byte)ev.buffer[2]), this_vel);

View file

@ -74,10 +74,10 @@ MidiBuffer::resize (size_t size)
_capacity = size; _capacity = size;
#ifdef NO_POSIX_MEMALIGN #ifdef NO_POSIX_MEMALIGN
_events = (MidiEvent *) malloc(sizeof(MidiEvent) * _capacity); _events = (MIDI::Event *) malloc(sizeof(MIDI::Event) * _capacity);
_data = (Byte *) malloc(sizeof(Byte) * _capacity * MAX_EVENT_SIZE); _data = (Byte *) malloc(sizeof(Byte) * _capacity * MAX_EVENT_SIZE);
#else #else
posix_memalign((void**)&_events, CPU_CACHE_ALIGN, sizeof(MidiEvent) * _capacity); posix_memalign((void**)&_events, CPU_CACHE_ALIGN, sizeof(MIDI::Event) * _capacity);
posix_memalign((void**)&_data, CPU_CACHE_ALIGN, sizeof(Byte) * _capacity * MAX_EVENT_SIZE); posix_memalign((void**)&_data, CPU_CACHE_ALIGN, sizeof(Byte) * _capacity * MAX_EVENT_SIZE);
#endif #endif
assert(_data); assert(_data);
@ -115,7 +115,7 @@ MidiBuffer::read_from(const Buffer& src, nframes_t nframes, nframes_t offset)
// FIXME: slow // FIXME: slow
for (size_t i=0; i < msrc.size(); ++i) { for (size_t i=0; i < msrc.size(); ++i) {
const MidiEvent& ev = msrc[i]; const MIDI::Event& ev = msrc[i];
if (ev.time() >= offset && ev.time() < offset+nframes) { if (ev.time() >= offset && ev.time() < offset+nframes) {
//cout << "MidiBuffer::read_from got event, " << ev.time() << endl; //cout << "MidiBuffer::read_from got event, " << ev.time() << endl;
push_back(ev); push_back(ev);
@ -136,7 +136,7 @@ MidiBuffer::read_from(const Buffer& src, nframes_t nframes, nframes_t offset)
* @return false if operation failed (not enough room) * @return false if operation failed (not enough room)
*/ */
bool bool
MidiBuffer::push_back(const MidiEvent& ev) MidiBuffer::push_back(const MIDI::Event& ev)
{ {
if (_size == _capacity) if (_size == _capacity)
return false; return false;
@ -222,7 +222,7 @@ MidiBuffer::silence(nframes_t dur, nframes_t offset)
if (offset != 0) if (offset != 0)
cerr << "WARNING: MidiBuffer::silence w/ offset != 0 (not implemented)" << endl; cerr << "WARNING: MidiBuffer::silence w/ offset != 0 (not implemented)" << endl;
memset(_events, 0, sizeof(MidiEvent) * _capacity); memset(_events, 0, sizeof(MIDI::Event) * _capacity);
memset(_data, 0, sizeof(Byte) * _capacity * MAX_EVENT_SIZE); memset(_data, 0, sizeof(Byte) * _capacity * MAX_EVENT_SIZE);
_size = 0; _size = 0;
_silent = true; _silent = true;
@ -261,8 +261,8 @@ MidiBuffer::merge(const MidiBuffer& a, const MidiBuffer& b)
push_back(b[b_index]); push_back(b[b_index]);
++b_index; ++b_index;
} else { } else {
const MidiEvent& a_ev = a[a_index]; const MIDI::Event& a_ev = a[a_index];
const MidiEvent& b_ev = b[b_index]; const MIDI::Event& b_ev = b[b_index];
if (a_ev.time() <= b_ev.time()) { if (a_ev.time() <= b_ev.time()) {
push_back(a_ev); push_back(a_ev);

View file

@ -548,7 +548,7 @@ MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_t
MidiBuffer::iterator port_iter = _source_port->get_midi_buffer().begin(); MidiBuffer::iterator port_iter = _source_port->get_midi_buffer().begin();
for (size_t i=0; i < to_write; ++i) { for (size_t i=0; i < to_write; ++i) {
const MidiEvent& ev = *port_iter; const MIDI::Event& ev = *port_iter;
_capture_buf->write(ev.time() + transport_frame, ev.size(), ev.buffer()); _capture_buf->write(ev.time() + transport_frame, ev.size(), ev.buffer());
++port_iter; ++port_iter;
} }

View file

@ -25,8 +25,9 @@
#include <stdexcept> #include <stdexcept>
#include <stdint.h> #include <stdint.h>
#include <pbd/enumwriter.h> #include <pbd/enumwriter.h>
#include <midi++/events.h>
#include <ardour/midi_model.h> #include <ardour/midi_model.h>
#include <ardour/midi_events.h>
#include <ardour/midi_source.h> #include <ardour/midi_source.h>
#include <ardour/types.h> #include <ardour/types.h>
#include <ardour/session.h> #include <ardour/session.h>
@ -92,7 +93,7 @@ MidiModel::const_iterator::const_iterator(const MidiModel& model, double t)
} }
if (_note_iter != model.notes().end()) { if (_note_iter != model.notes().end()) {
_event = MidiEvent((*_note_iter)->on_event(), false); _event = MIDI::Event((*_note_iter)->on_event(), false);
_active_notes.push(*_note_iter); _active_notes.push(*_note_iter);
++_note_iter; ++_note_iter;
} }
@ -182,12 +183,12 @@ MidiModel::const_iterator::operator++()
if (type == NOTE_ON) { if (type == NOTE_ON) {
//cerr << "********** MIDI Iterator = note on" << endl; //cerr << "********** MIDI Iterator = note on" << endl;
_event = MidiEvent((*_note_iter)->on_event(), false); _event = MIDI::Event((*_note_iter)->on_event(), false);
_active_notes.push(*_note_iter); _active_notes.push(*_note_iter);
++_note_iter; ++_note_iter;
} else if (type == NOTE_OFF) { } else if (type == NOTE_OFF) {
//cerr << "********** MIDI Iterator = note off" << endl; //cerr << "********** MIDI Iterator = note off" << endl;
_event = MidiEvent(_active_notes.top()->off_event(), false); _event = MIDI::Event(_active_notes.top()->off_event(), false);
_active_notes.pop(); _active_notes.pop();
} else if (type == CC) { } else if (type == CC) {
//cerr << "********** MIDI Iterator = CC" << endl; //cerr << "********** MIDI Iterator = CC" << endl;
@ -291,7 +292,7 @@ MidiModel::read(MidiRingBuffer& dst, nframes_t start, nframes_t nframes, nframes
bool bool
MidiModel::control_to_midi_event(MidiEvent& ev, const MidiControlIterator& iter) const MidiModel::control_to_midi_event(MIDI::Event& ev, const MidiControlIterator& iter) const
{ {
if (iter.first->parameter().type() == MidiCCAutomation) { if (iter.first->parameter().type() == MidiCCAutomation) {
if (ev.size() < 3) if (ev.size() < 3)
@ -378,7 +379,7 @@ MidiModel::end_write(bool delete_stuck)
* and MUST be >= the latest event currently in the model. * and MUST be >= the latest event currently in the model.
*/ */
void void
MidiModel::append(const MidiEvent& ev) MidiModel::append(const MIDI::Event& ev)
{ {
write_lock(); write_lock();
@ -643,7 +644,7 @@ MidiModel::write_to(boost::shared_ptr<MidiSource> source)
/* Percussive /* Percussive
for (Notes::const_iterator n = _notes.begin(); n != _notes.end(); ++n) { for (Notes::const_iterator n = _notes.begin(); n != _notes.end(); ++n) {
const MidiEvent& ev = n->on_event(); const MIDI::Event& ev = n->on_event();
source->append_event_unlocked(ev); source->append_event_unlocked(ev);
}*/ }*/
@ -658,7 +659,7 @@ MidiModel::write_to(boost::shared_ptr<MidiSource> source)
// Write any pending note offs earlier than this note on // Write any pending note offs earlier than this note on
while ( ! active_notes.empty() ) { while ( ! active_notes.empty() ) {
const boost::shared_ptr<const Note> earliest_off = active_notes.top(); const boost::shared_ptr<const Note> earliest_off = active_notes.top();
const MidiEvent& off_ev = earliest_off->off_event(); const MIDI::Event& off_ev = earliest_off->off_event();
if (off_ev.time() <= (*n)->time()) { if (off_ev.time() <= (*n)->time()) {
source->append_event_unlocked(Frames, off_ev); source->append_event_unlocked(Frames, off_ev);
active_notes.pop(); active_notes.pop();

View file

@ -91,7 +91,7 @@ MidiStretch::run (boost::shared_ptr<Region> r)
const double new_time = i->time() * _request.time_fraction; const double new_time = i->time() * _request.time_fraction;
// FIXME: double copy // FIXME: double copy
MidiEvent ev = MidiEvent(*i, true); MIDI::Event ev = MIDI::Event(*i, true);
ev.time() = new_time; ev.time() = new_time;
new_model->append(ev); new_model->append(ev);
} }
@ -101,7 +101,7 @@ MidiStretch::run (boost::shared_ptr<Region> r)
const int ret = finish (region, nsrcs, new_name); const int ret = finish (region, nsrcs, new_name);
results[0]->set_length(r->length() * _request.time_fraction, NULL); results[0]->set_length((nframes_t) floor (r->length() * _request.time_fraction), NULL);
return ret; return ret;
} }

View file

@ -22,6 +22,7 @@
#include <sigc++/bind.h> #include <sigc++/bind.h>
#include <pbd/enumwriter.h> #include <pbd/enumwriter.h>
#include <midi++/events.h>
#include <ardour/midi_track.h> #include <ardour/midi_track.h>
#include <ardour/midi_diskstream.h> #include <ardour/midi_diskstream.h>
@ -36,7 +37,7 @@
#include <ardour/utils.h> #include <ardour/utils.h>
#include <ardour/buffer_set.h> #include <ardour/buffer_set.h>
#include <ardour/meter.h> #include <ardour/meter.h>
#include <ardour/midi_events.h>
#include "i18n.h" #include "i18n.h"
@ -587,7 +588,7 @@ MidiTrack::write_controller_messages(MidiBuffer& output_buf, nframes_t start_fra
Byte buf[3]; // CC = 3 bytes Byte buf[3]; // CC = 3 bytes
buf[0] = MIDI_CMD_CONTROL; buf[0] = MIDI_CMD_CONTROL;
MidiEvent ev(0, 3, buf, false); MIDI::Event ev(0, 3, buf, false);
// Write track controller automation // Write track controller automation
#if 0 #if 0

View file

@ -21,8 +21,9 @@
#include <cassert> #include <cassert>
#include <iostream> #include <iostream>
#include <glibmm/miscutils.h> #include <glibmm/miscutils.h>
#include <midi++/events.h>
#include <ardour/smf_reader.h> #include <ardour/smf_reader.h>
#include <ardour/midi_events.h>
#include <ardour/midi_util.h> #include <ardour/midi_util.h>
using namespace std; using namespace std;

View file

@ -432,7 +432,7 @@ SMFSource::write_unlocked (MidiRingBuffer& src, nframes_t cnt)
assert(time >= _timeline_position); assert(time >= _timeline_position);
time -= _timeline_position; time -= _timeline_position;
const MidiEvent ev(time, size, buf); const MIDI::Event ev(time, size, buf);
append_event_unlocked(Frames, ev); append_event_unlocked(Frames, ev);
if (_model) if (_model)
@ -452,7 +452,7 @@ SMFSource::write_unlocked (MidiRingBuffer& src, nframes_t cnt)
void void
SMFSource::append_event_unlocked(EventTimeUnit unit, const MidiEvent& ev) SMFSource::append_event_unlocked(EventTimeUnit unit, const MIDI::Event& ev)
{ {
/*printf("%s - append chan = %u, time = %lf, size = %u, data = ", _path.c_str(), /*printf("%s - append chan = %u, time = %lf, size = %u, data = ", _path.c_str(),
(unsigned)ev.channel(), ev.time(), ev.size()); (unsigned)ev.channel(), ev.time(), ev.size());
@ -886,7 +886,7 @@ SMFSource::load_model(bool lock, bool force_reload)
fseek(_fd, _header_size, 0); fseek(_fd, _header_size, 0);
uint64_t time = 0; /* in SMF ticks */ uint64_t time = 0; /* in SMF ticks */
MidiEvent ev; MIDI::Event ev;
size_t scratch_size = 0; // keep track of scratch and minimize reallocs size_t scratch_size = 0; // keep track of scratch and minimize reallocs

View file

@ -7,7 +7,13 @@ import glob
Import('env libraries install_prefix') Import('env libraries install_prefix')
midi2 = env.Copy() midi2 = env.Copy()
midi2.Merge([ libraries['sigc2'], libraries['xml'], libraries['glibmm2'], libraries['glib2'], libraries['pbd'], libraries['jack'] ]) midi2.Merge([ libraries['sigc2'],
libraries['xml'],
libraries['glibmm2'],
libraries['glib2'],
libraries['pbd'],
libraries['jack']
])
if midi2['IS_OSX']: if midi2['IS_OSX']:
midi2.Append (LINKFLAGS="-Xlinker -headerpad -Xlinker 2048") midi2.Append (LINKFLAGS="-Xlinker -headerpad -Xlinker 2048")

View file

@ -30,12 +30,15 @@ using namespace std;
using namespace MIDI; using namespace MIDI;
using namespace PBD; using namespace PBD;
pthread_t JACK_MidiPort::_process_thread;
JACK_MidiPort::JACK_MidiPort(const XMLNode& node, jack_client_t* jack_client) JACK_MidiPort::JACK_MidiPort(const XMLNode& node, jack_client_t* jack_client)
: Port(node) : Port(node)
, _jack_client(jack_client) , _jack_client(jack_client)
, _jack_input_port(NULL) , _jack_input_port(NULL)
, _jack_output_port(NULL) , _jack_output_port(NULL)
, _last_read_index(0) , _last_read_index(0)
, non_process_thread_fifo (5 * 1024)
{ {
int err = create_ports (node); int err = create_ports (node);
@ -55,23 +58,85 @@ JACK_MidiPort::cycle_start (nframes_t nframes)
Port::cycle_start(nframes); Port::cycle_start(nframes);
assert(_nframes_this_cycle == nframes); assert(_nframes_this_cycle == nframes);
_last_read_index = 0; _last_read_index = 0;
jack_midi_clear_buffer(jack_port_get_buffer(_jack_output_port, nframes));
void *buffer = jack_port_get_buffer (_jack_output_port, nframes);
jack_midi_clear_buffer (buffer);
flush (buffer);
} }
int int
JACK_MidiPort::write(byte * msg, size_t msglen, timestamp_t timestamp) JACK_MidiPort::write(byte * msg, size_t msglen, timestamp_t timestamp)
{ {
if (!_currently_in_cycle) { if (!is_process_thread()) {
error << "JACK MIDI write ignored - not in cycle ... FIX ME PAUL!" << endmsg;
return msglen; Glib::Mutex::Lock lm (non_process_thread_fifo_lock);
RingBuffer<Event>::rw_vector vec;
non_process_thread_fifo.get_write_vector (&vec);
cerr << "Non-process thread writes " << msglen << " to " << name() << endl;
if (vec.len[0] + vec.len[1] < 1) {
error << "no space in FIFO for non-process thread MIDI write"
<< endmsg;
return 0;
} }
if (vec.len[0]) {
vec.buf[0]->set (msg, msglen, timestamp);
} else {
vec.buf[1]->set (msg, msglen, timestamp);
}
non_process_thread_fifo.increment_write_idx (1);
return msglen;
} else {
assert(_currently_in_cycle);
assert(timestamp < _nframes_this_cycle); assert(timestamp < _nframes_this_cycle);
assert(_jack_output_port); assert(_jack_output_port);
// FIXME: return value correct? // FIXME: return value correct?
return jack_midi_event_write ( return jack_midi_event_write (jack_port_get_buffer (_jack_output_port, _nframes_this_cycle),
jack_port_get_buffer(_jack_output_port, _nframes_this_cycle),
timestamp, msg, msglen); timestamp, msg, msglen);
}
}
void
JACK_MidiPort::flush (void* jack_port_buffer)
{
RingBuffer<Event>::rw_vector vec;
size_t written;
non_process_thread_fifo.get_read_vector (&vec);
if (vec.len[0] + vec.len[1]) {
cerr << "Flush " << vec.len[0] + vec.len[1] << "events from non-process FIFO\n";
}
if (vec.len[0]) {
Event* evp = vec.buf[0];
for (size_t n = 0; n < vec.len[0]; ++n, ++evp) {
jack_midi_event_write (jack_port_buffer,
(timestamp_t) evp->time(), evp->buffer(), evp->size());
}
}
if (vec.len[1]) {
Event* evp = vec.buf[1];
for (size_t n = 0; n < vec.len[1]; ++n, ++evp) {
jack_midi_event_write (jack_port_buffer,
(timestamp_t) evp->time(), evp->buffer(), evp->size());
}
}
if ((written = vec.len[0] + vec.len[1]) != 0) {
non_process_thread_fifo.increment_read_idx (written);
}
} }
int int
@ -137,3 +202,15 @@ void
JACK_MidiPort::set_state (const XMLNode& node) JACK_MidiPort::set_state (const XMLNode& node)
{ {
} }
void
JACK_MidiPort::set_process_thread (pthread_t thr)
{
_process_thread = thr;
}
bool
JACK_MidiPort::is_process_thread()
{
return (pthread_self() == _process_thread);
}

View file

@ -18,19 +18,24 @@
*/ */
#ifndef __ardour_midi_event_h__ #ifndef __libmidipp_midi_event_h__
#define __ardour_midi_event_h__ #define __libmidipp_midi_event_h__
#include <ardour/types.h>
#include <ardour/midi_events.h>
#include <stdint.h> #include <stdint.h>
#include <cstdlib>
#include <cstring>
#include <assert.h>
#include <midi++/types.h>
#include <midi++/events.h>
/** If this is not defined, all methods of MidiEvent are RT safe /** If this is not defined, all methods of MidiEvent are RT safe
* but MidiEvent will never deep copy and (depending on the scenario) * but MidiEvent will never deep copy and (depending on the scenario)
* may not be usable in STL containers, signals, etc. */ * may not be usable in STL containers, signals, etc.
*/
#define MIDI_EVENT_ALLOW_ALLOC 1 #define MIDI_EVENT_ALLOW_ALLOC 1
namespace ARDOUR { namespace MIDI {
/** Identical to jack_midi_event_t, but with double timestamp /** Identical to jack_midi_event_t, but with double timestamp
@ -38,16 +43,16 @@ namespace ARDOUR {
* time is either a frame time (from/to Jack) or a beat time (internal * time is either a frame time (from/to Jack) or a beat time (internal
* tempo time, used in MidiModel) depending on context. * tempo time, used in MidiModel) depending on context.
*/ */
struct MidiEvent { struct Event {
#ifdef MIDI_EVENT_ALLOW_ALLOC #ifdef MIDI_EVENT_ALLOW_ALLOC
MidiEvent(double t=0, uint32_t s=0, Byte* b=NULL, bool owns_buffer=false) Event(double t=0, uint32_t s=0, uint8_t* b=NULL, bool owns_buffer=false)
: _time(t) : _time(t)
, _size(s) , _size(s)
, _buffer(b) , _buffer(b)
, _owns_buffer(owns_buffer) , _owns_buffer(owns_buffer)
{ {
if (owns_buffer) { if (owns_buffer) {
_buffer = (Byte*)malloc(_size); _buffer = (uint8_t*)malloc(_size);
if (b) if (b)
memcpy(_buffer, b, _size); memcpy(_buffer, b, _size);
else else
@ -61,14 +66,14 @@ struct MidiEvent {
* is NOT REALTIME SAFE. Otherwise both events share a buffer and * is NOT REALTIME SAFE. Otherwise both events share a buffer and
* memory management semantics are the caller's problem. * memory management semantics are the caller's problem.
*/ */
MidiEvent(const MidiEvent& copy, bool owns_buffer) Event(const Event& copy, bool owns_buffer)
: _time(copy._time) : _time(copy._time)
, _size(copy._size) , _size(copy._size)
, _buffer(copy._buffer) , _buffer(copy._buffer)
, _owns_buffer(owns_buffer) , _owns_buffer(owns_buffer)
{ {
if (owns_buffer) { if (owns_buffer) {
_buffer = (Byte*)malloc(_size); _buffer = (uint8_t*)malloc(_size);
if (copy._buffer) if (copy._buffer)
memcpy(_buffer, copy._buffer, _size); memcpy(_buffer, copy._buffer, _size);
else else
@ -76,17 +81,17 @@ struct MidiEvent {
} }
} }
~MidiEvent() { ~Event() {
if (_owns_buffer) if (_owns_buffer)
free(_buffer); free(_buffer);
} }
inline const MidiEvent& operator=(const MidiEvent& copy) { inline const Event& operator=(const Event& copy) {
_time = copy._time; _time = copy._time;
if (_owns_buffer) { if (_owns_buffer) {
if (copy._buffer) { if (copy._buffer) {
if (!_buffer || _size < copy._size) if (!_buffer || _size < copy._size)
_buffer = (Byte*)::realloc(_buffer, copy._size); _buffer = (uint8_t*)::realloc(_buffer, copy._size);
memcpy(_buffer, copy._buffer, copy._size); memcpy(_buffer, copy._buffer, copy._size);
} else { } else {
free(_buffer); free(_buffer);
@ -100,7 +105,22 @@ struct MidiEvent {
return *this; return *this;
} }
inline bool operator==(const MidiEvent& other) const { inline void set (uint8_t* msg, size_t msglen, timestamp_t t) {
if (_owns_buffer) {
if (_size < msglen) {
free (_buffer);
_buffer = (uint8_t*) malloc (msglen);
}
} else {
_buffer = (uint8_t*) malloc (msglen);
_owns_buffer = true;
}
memcpy (_buffer, msg, msglen);
_time = t;
}
inline bool operator==(const Event& other) const {
if (_time != other._time) if (_time != other._time)
return false; return false;
@ -117,11 +137,11 @@ struct MidiEvent {
return true; return true;
} }
inline bool operator!=(const MidiEvent& other) const { return ! operator==(other); } inline bool operator!=(const Event& other) const { return ! operator==(other); }
inline bool owns_buffer() const { return _owns_buffer; } inline bool owns_buffer() const { return _owns_buffer; }
inline void set_buffer(Byte* buf, bool own) { inline void set_buffer(uint8_t* buf, bool own) {
if (_owns_buffer) { if (_owns_buffer) {
free(_buffer); free(_buffer);
_buffer = NULL; _buffer = NULL;
@ -132,12 +152,12 @@ struct MidiEvent {
inline void realloc(size_t size) { inline void realloc(size_t size) {
assert(_owns_buffer); assert(_owns_buffer);
_buffer = (Byte*) ::realloc(_buffer, size); _buffer = (uint8_t*) ::realloc(_buffer, size);
} }
#else #else
inline void set_buffer(Byte* buf) { _buffer = buf; } inline void set_buffer(uint8_t* buf) { _buffer = buf; }
#endif // MIDI_EVENT_ALLOW_ALLOC #endif // MIDI_EVENT_ALLOW_ALLOC
@ -155,13 +175,13 @@ struct MidiEvent {
inline uint8_t velocity() const { return (_buffer[2]); } inline uint8_t velocity() const { return (_buffer[2]); }
inline uint8_t cc_number() const { return (_buffer[1]); } inline uint8_t cc_number() const { return (_buffer[1]); }
inline uint8_t cc_value() const { return (_buffer[2]); } inline uint8_t cc_value() const { return (_buffer[2]); }
inline const Byte* buffer() const { return _buffer; } inline const uint8_t* buffer() const { return _buffer; }
inline Byte*& buffer() { return _buffer; } inline uint8_t*& buffer() { return _buffer; }
private: private:
double _time; /**< Sample index (or beat time) at which event is valid */ double _time; /**< Sample index (or beat time) at which event is valid */
uint32_t _size; /**< Number of bytes of data in \a buffer */ uint32_t _size; /**< Number of uint8_ts of data in \a buffer */
Byte* _buffer; /**< Raw MIDI data */ uint8_t* _buffer; /**< Raw MIDI data */
#ifdef MIDI_EVENT_ALLOW_ALLOC #ifdef MIDI_EVENT_ALLOW_ALLOC
bool _owns_buffer; /**< Whether buffer is locally allocated */ bool _owns_buffer; /**< Whether buffer is locally allocated */
@ -169,6 +189,6 @@ private:
}; };
} // namespace ARDOUR }
#endif /* __ardour_midi_event_h__ */ #endif /* __libmidipp_midi_event_h__ */

View file

@ -28,9 +28,13 @@
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <glibmm/thread.h>
#include <pbd/ringbuffer.h>
#include <jack/jack.h> #include <jack/jack.h>
#include <jack/midiport.h> #include <jack/midiport.h>
#include <midi++/port.h> #include <midi++/port.h>
#include <midi++/event.h>
namespace MIDI namespace MIDI
{ {
@ -52,6 +56,8 @@ public:
virtual XMLNode& get_state () const; virtual XMLNode& get_state () const;
virtual void set_state (const XMLNode&); virtual void set_state (const XMLNode&);
static void set_process_thread (pthread_t);
protected: protected:
std::string get_typestring () const { std::string get_typestring () const {
return typestring; return typestring;
@ -69,6 +75,14 @@ private:
jack_port_t* _jack_input_port; jack_port_t* _jack_input_port;
jack_port_t* _jack_output_port; jack_port_t* _jack_output_port;
nframes_t _last_read_index; nframes_t _last_read_index;
void flush (void* jack_port_buffer);
static pthread_t _process_thread;
static bool is_process_thread();
RingBuffer<MIDI::Event> non_process_thread_fifo;
Glib::Mutex non_process_thread_fifo_lock;
}; };