diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2008-03-18 03:42:32 +0000 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2008-03-18 03:42:32 +0000 |
commit | eb4a1fdbb8fec1f8aa5dfe33f882064e85792a84 (patch) | |
tree | b97aadaf2a8593e33ceaf1e4da78ab39d2608702 /libs | |
parent | d69f4e9e3dde0e400c80bca37f7bfcc555fbbf1b (diff) |
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
Diffstat (limited to 'libs')
24 files changed, 212 insertions, 104 deletions
diff --git a/libs/ardour/ardour/midi_buffer.h b/libs/ardour/ardour/midi_buffer.h index b35264217a..a6cbb49118 100644 --- a/libs/ardour/ardour/midi_buffer.h +++ b/libs/ardour/ardour/midi_buffer.h @@ -20,8 +20,8 @@ #ifndef __ardour_midi_buffer_h__ #define __ardour_midi_buffer_h__ +#include <midi++/event.h> #include <ardour/buffer.h> -#include <ardour/midi_event.h> namespace ARDOUR { @@ -39,7 +39,7 @@ public: 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); Byte* reserve(double time, size_t size); @@ -50,7 +50,7 @@ public: struct iterator { 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 bool operator!=(const iterator& other) const { return index != other.index; } @@ -61,7 +61,7 @@ public: struct const_iterator { 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 bool operator!=(const const_iterator& other) const { return index != other.index; } @@ -80,8 +80,8 @@ private: friend class iterator; friend class const_iterator; - const MidiEvent& operator[](size_t i) const { assert(i < _size); return _events[i]; } - MidiEvent& operator[](size_t i) { assert(i < _size); return _events[i]; } + const MIDI::Event& operator[](size_t i) const { assert(i < _size); return _events[i]; } + MIDI::Event& operator[](size_t i) { assert(i < _size); return _events[i]; } // FIXME: Eliminate this 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 */ - 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. }; diff --git a/libs/ardour/ardour/midi_model.h b/libs/ardour/ardour/midi_model.h index de31d0505e..11ef4e0f76 100644 --- a/libs/ardour/ardour/midi_model.h +++ b/libs/ardour/ardour/midi_model.h @@ -75,7 +75,7 @@ public: size_t read (MidiRingBuffer& dst, nframes_t start, nframes_t nframes, nframes_t stamp_offset) const; /** 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<Note> note_at(unsigned i) { return _notes[i]; } @@ -151,8 +151,8 @@ public: inline bool locked() const { return _locked; } - const MidiEvent& operator*() const { return _event; } - const MidiEvent* operator->() const { return &_event; } + const MIDI::Event& operator*() const { return _event; } + const MIDI::Event* operator->() const { return &_event; } const const_iterator& operator++(); // prefix only bool operator==(const const_iterator& other) const; @@ -164,7 +164,7 @@ public: friend class MidiModel; const MidiModel* _model; - MidiEvent _event; + MIDI::Event _event; typedef std::priority_queue< 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); 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 bool is_sorted() const; diff --git a/libs/ardour/ardour/midi_ring_buffer.h b/libs/ardour/ardour/midi_ring_buffer.h index a0078061ee..1b3ab50f91 100644 --- a/libs/ardour/ardour/midi_ring_buffer.h +++ b/libs/ardour/ardour/midi_ring_buffer.h @@ -307,7 +307,7 @@ MidiRingBuffer::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes_t if (read_space() == 0) return 0; - MidiEvent ev; + MIDI::Event ev; size_t count = 0; diff --git a/libs/ardour/ardour/midi_source.h b/libs/ardour/ardour/midi_source.h index 5e41e3ff5b..d465506819 100644 --- a/libs/ardour/ardour/midi_source.h +++ b/libs/ardour/ardour/midi_source.h @@ -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_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_streaming_midi_write_started (NoteMode mode, nframes_t start_time); diff --git a/libs/ardour/ardour/midi_util.h b/libs/ardour/ardour/midi_util.h index 1f121fbd68..efcb6a7cd5 100644 --- a/libs/ardour/ardour/midi_util.h +++ b/libs/ardour/ardour/midi_util.h @@ -21,7 +21,7 @@ #ifndef __ardour_midi_util_h__ #define __ardour_midi_util_h__ -#include <ardour/midi_events.h> +#include <midi++/events.h> namespace ARDOUR { diff --git a/libs/ardour/ardour/note.h b/libs/ardour/ardour/note.h index ea598573e8..41c18358d3 100644 --- a/libs/ardour/ardour/note.h +++ b/libs/ardour/ardour/note.h @@ -22,14 +22,14 @@ #define __ardour_note_h__ #include <stdint.h> -#include <ardour/midi_event.h> +#include <midi++/event.h> namespace ARDOUR { /** 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). */ class Note { @@ -53,16 +53,16 @@ public: 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 MIDI::Event& on_event() { return _on_event; } + inline MIDI::Event& off_event() { return _off_event; } - inline const MidiEvent& on_event() const { return _on_event; } - inline const MidiEvent& off_event() const { return _off_event; } + inline const MIDI::Event& on_event() const { return _on_event; } + inline const MIDI::Event& off_event() const { return _off_event; } private: // Event buffers are self-contained - MidiEvent _on_event; - MidiEvent _off_event; + MIDI::Event _on_event; + MIDI::Event _off_event; }; diff --git a/libs/ardour/ardour/smf_source.h b/libs/ardour/ardour/smf_source.h index 937e08e44c..626aa64def 100644 --- a/libs/ardour/ardour/smf_source.h +++ b/libs/ardour/ardour/smf_source.h @@ -71,7 +71,7 @@ class SMFSource : public MidiSource { void set_allow_remove_if_empty (bool yn); 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_footer (); diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index bdc1e8f0e4..84fd06d079 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -29,6 +29,8 @@ #include <pbd/stacktrace.h> #include <pbd/unknown_type.h> +#include <midi++/jack.h> + #include <ardour/audioengine.h> #include <ardour/buffer.h> #include <ardour/port.h> @@ -113,6 +115,7 @@ _thread_init_callback (void *arg) */ PBD::ThreadCreatedWithRequestSize (pthread_self(), X_("Audioengine"), 4096); + MIDI::JACK_MidiPort::set_process_thread (pthread_self()); } int diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc index 9a71303927..02c4a5ced6 100644 --- a/libs/ardour/globals.cc +++ b/libs/ardour/globals.cc @@ -412,21 +412,6 @@ ARDOUR::get_ardour_revision () 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 ARDOUR::find_bindings_files (map<string,string>& files) { diff --git a/libs/ardour/import.cc b/libs/ardour/import.cc index a29cc1817b..104bef35c3 100644 --- a/libs/ardour/import.cc +++ b/libs/ardour/import.cc @@ -308,7 +308,7 @@ static void write_midi_data_to_new_files (SMFReader* source, Session::import_status& status, 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; diff --git a/libs/ardour/jack_midi_port.cc b/libs/ardour/jack_midi_port.cc index 0b8d96f4db..6d8e4c8c5d 100644 --- a/libs/ardour/jack_midi_port.cc +++ b/libs/ardour/jack_midi_port.cc @@ -82,7 +82,7 @@ JackMidiPort::cycle_end (nframes_t nframes, nframes_t offset) jack_midi_clear_buffer (jack_buffer); 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 assert(ev.time() >= 0); assert(ev.time() < nframes); diff --git a/libs/ardour/meter.cc b/libs/ardour/meter.cc index f85fd3ec33..e75c1d89ca 100644 --- a/libs/ardour/meter.cc +++ b/libs/ardour/meter.cc @@ -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 // expressed through peaks alone 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()) { 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); diff --git a/libs/ardour/midi_buffer.cc b/libs/ardour/midi_buffer.cc index 1ca6a5db72..a77a608fcd 100644 --- a/libs/ardour/midi_buffer.cc +++ b/libs/ardour/midi_buffer.cc @@ -74,10 +74,10 @@ MidiBuffer::resize (size_t size) _capacity = size; #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); #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); #endif assert(_data); @@ -115,7 +115,7 @@ MidiBuffer::read_from(const Buffer& src, nframes_t nframes, nframes_t offset) // FIXME: slow 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) { //cout << "MidiBuffer::read_from got event, " << ev.time() << endl; 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) */ bool -MidiBuffer::push_back(const MidiEvent& ev) +MidiBuffer::push_back(const MIDI::Event& ev) { if (_size == _capacity) return false; @@ -222,7 +222,7 @@ MidiBuffer::silence(nframes_t dur, nframes_t offset) if (offset != 0) 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); _size = 0; _silent = true; @@ -261,8 +261,8 @@ MidiBuffer::merge(const MidiBuffer& a, const MidiBuffer& b) push_back(b[b_index]); ++b_index; } else { - const MidiEvent& a_ev = a[a_index]; - const MidiEvent& b_ev = b[b_index]; + const MIDI::Event& a_ev = a[a_index]; + const MIDI::Event& b_ev = b[b_index]; if (a_ev.time() <= b_ev.time()) { push_back(a_ev); diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc index 7c3bc73fb8..51f093919c 100644 --- a/libs/ardour/midi_diskstream.cc +++ b/libs/ardour/midi_diskstream.cc @@ -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(); 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()); ++port_iter; } diff --git a/libs/ardour/midi_model.cc b/libs/ardour/midi_model.cc index 6bd351a6dc..a49094df91 100644 --- a/libs/ardour/midi_model.cc +++ b/libs/ardour/midi_model.cc @@ -25,8 +25,9 @@ #include <stdexcept> #include <stdint.h> #include <pbd/enumwriter.h> +#include <midi++/events.h> + #include <ardour/midi_model.h> -#include <ardour/midi_events.h> #include <ardour/midi_source.h> #include <ardour/types.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()) { - _event = MidiEvent((*_note_iter)->on_event(), false); + _event = MIDI::Event((*_note_iter)->on_event(), false); _active_notes.push(*_note_iter); ++_note_iter; } @@ -182,12 +183,12 @@ MidiModel::const_iterator::operator++() if (type == NOTE_ON) { //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); ++_note_iter; } else if (type == NOTE_OFF) { //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(); } else if (type == CC) { //cerr << "********** MIDI Iterator = CC" << endl; @@ -291,7 +292,7 @@ MidiModel::read(MidiRingBuffer& dst, nframes_t start, nframes_t nframes, nframes 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 (ev.size() < 3) @@ -378,7 +379,7 @@ MidiModel::end_write(bool delete_stuck) * and MUST be >= the latest event currently in the model. */ void -MidiModel::append(const MidiEvent& ev) +MidiModel::append(const MIDI::Event& ev) { write_lock(); @@ -643,7 +644,7 @@ MidiModel::write_to(boost::shared_ptr<MidiSource> source) /* Percussive 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); }*/ @@ -658,7 +659,7 @@ MidiModel::write_to(boost::shared_ptr<MidiSource> source) // Write any pending note offs earlier than this note on while ( ! active_notes.empty() ) { 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()) { source->append_event_unlocked(Frames, off_ev); active_notes.pop(); diff --git a/libs/ardour/midi_stretch.cc b/libs/ardour/midi_stretch.cc index f214bde0be..f33c58a0fd 100644 --- a/libs/ardour/midi_stretch.cc +++ b/libs/ardour/midi_stretch.cc @@ -91,7 +91,7 @@ MidiStretch::run (boost::shared_ptr<Region> r) const double new_time = i->time() * _request.time_fraction; // FIXME: double copy - MidiEvent ev = MidiEvent(*i, true); + MIDI::Event ev = MIDI::Event(*i, true); ev.time() = new_time; new_model->append(ev); } @@ -101,7 +101,7 @@ MidiStretch::run (boost::shared_ptr<Region> r) 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; } diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc index e1fa109342..bf97b19106 100644 --- a/libs/ardour/midi_track.cc +++ b/libs/ardour/midi_track.cc @@ -22,6 +22,7 @@ #include <sigc++/bind.h> #include <pbd/enumwriter.h> +#include <midi++/events.h> #include <ardour/midi_track.h> #include <ardour/midi_diskstream.h> @@ -36,7 +37,7 @@ #include <ardour/utils.h> #include <ardour/buffer_set.h> #include <ardour/meter.h> -#include <ardour/midi_events.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 buf[0] = MIDI_CMD_CONTROL; - MidiEvent ev(0, 3, buf, false); + MIDI::Event ev(0, 3, buf, false); // Write track controller automation #if 0 diff --git a/libs/ardour/smf_reader.cc b/libs/ardour/smf_reader.cc index 20204f1d32..63a020f141 100644 --- a/libs/ardour/smf_reader.cc +++ b/libs/ardour/smf_reader.cc @@ -21,8 +21,9 @@ #include <cassert> #include <iostream> #include <glibmm/miscutils.h> +#include <midi++/events.h> + #include <ardour/smf_reader.h> -#include <ardour/midi_events.h> #include <ardour/midi_util.h> using namespace std; diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc index bd4f837780..720626e936 100644 --- a/libs/ardour/smf_source.cc +++ b/libs/ardour/smf_source.cc @@ -432,7 +432,7 @@ SMFSource::write_unlocked (MidiRingBuffer& src, nframes_t cnt) assert(time >= _timeline_position); time -= _timeline_position; - const MidiEvent ev(time, size, buf); + const MIDI::Event ev(time, size, buf); append_event_unlocked(Frames, ev); if (_model) @@ -452,7 +452,7 @@ SMFSource::write_unlocked (MidiRingBuffer& src, nframes_t cnt) 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(), (unsigned)ev.channel(), ev.time(), ev.size()); @@ -886,7 +886,7 @@ SMFSource::load_model(bool lock, bool force_reload) fseek(_fd, _header_size, 0); uint64_t time = 0; /* in SMF ticks */ - MidiEvent ev; + MIDI::Event ev; size_t scratch_size = 0; // keep track of scratch and minimize reallocs diff --git a/libs/midi++2/SConscript b/libs/midi++2/SConscript index 14c0282396..3e2e204fbd 100644 --- a/libs/midi++2/SConscript +++ b/libs/midi++2/SConscript @@ -7,7 +7,13 @@ import glob Import('env libraries install_prefix') 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']: midi2.Append (LINKFLAGS="-Xlinker -headerpad -Xlinker 2048") diff --git a/libs/midi++2/jack_midiport.cc b/libs/midi++2/jack_midiport.cc index 52d05a5cfb..9b2f07d326 100644 --- a/libs/midi++2/jack_midiport.cc +++ b/libs/midi++2/jack_midiport.cc @@ -30,12 +30,15 @@ using namespace std; using namespace MIDI; using namespace PBD; +pthread_t JACK_MidiPort::_process_thread; + JACK_MidiPort::JACK_MidiPort(const XMLNode& node, jack_client_t* jack_client) : Port(node) , _jack_client(jack_client) , _jack_input_port(NULL) , _jack_output_port(NULL) , _last_read_index(0) + , non_process_thread_fifo (5 * 1024) { int err = create_ports (node); @@ -55,23 +58,85 @@ JACK_MidiPort::cycle_start (nframes_t nframes) Port::cycle_start(nframes); assert(_nframes_this_cycle == nframes); _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 JACK_MidiPort::write(byte * msg, size_t msglen, timestamp_t timestamp) { - if (!_currently_in_cycle) { - error << "JACK MIDI write ignored - not in cycle ... FIX ME PAUL!" << endmsg; + if (!is_process_thread()) { + + 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(_jack_output_port); + + // FIXME: return value correct? + return jack_midi_event_write (jack_port_get_buffer (_jack_output_port, _nframes_this_cycle), + timestamp, msg, msglen); } - assert(timestamp < _nframes_this_cycle); - assert(_jack_output_port); +} + +void +JACK_MidiPort::flush (void* jack_port_buffer) +{ + RingBuffer<Event>::rw_vector vec; + size_t written; - // FIXME: return value correct? - return jack_midi_event_write ( - jack_port_get_buffer(_jack_output_port, _nframes_this_cycle), - timestamp, msg, msglen); + 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 @@ -137,3 +202,15 @@ void 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); +} diff --git a/libs/ardour/ardour/midi_event.h b/libs/midi++2/midi++/event.h index 7dafb0fbcf..6ef1c49ee9 100644 --- a/libs/ardour/ardour/midi_event.h +++ b/libs/midi++2/midi++/event.h @@ -18,19 +18,24 @@ */ -#ifndef __ardour_midi_event_h__ -#define __ardour_midi_event_h__ +#ifndef __libmidipp_midi_event_h__ +#define __libmidipp_midi_event_h__ -#include <ardour/types.h> -#include <ardour/midi_events.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 * 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 -namespace ARDOUR { +namespace MIDI { /** 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 * tempo time, used in MidiModel) depending on context. */ -struct MidiEvent { +struct Event { #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) , _size(s) , _buffer(b) , _owns_buffer(owns_buffer) { if (owns_buffer) { - _buffer = (Byte*)malloc(_size); + _buffer = (uint8_t*)malloc(_size); if (b) memcpy(_buffer, b, _size); else @@ -61,14 +66,14 @@ struct MidiEvent { * is NOT REALTIME SAFE. Otherwise both events share a buffer and * 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) , _size(copy._size) , _buffer(copy._buffer) , _owns_buffer(owns_buffer) { if (owns_buffer) { - _buffer = (Byte*)malloc(_size); + _buffer = (uint8_t*)malloc(_size); if (copy._buffer) memcpy(_buffer, copy._buffer, _size); else @@ -76,17 +81,17 @@ struct MidiEvent { } } - ~MidiEvent() { + ~Event() { if (_owns_buffer) free(_buffer); } - inline const MidiEvent& operator=(const MidiEvent& copy) { + inline const Event& operator=(const Event& copy) { _time = copy._time; if (_owns_buffer) { if (copy._buffer) { if (!_buffer || _size < copy._size) - _buffer = (Byte*)::realloc(_buffer, copy._size); + _buffer = (uint8_t*)::realloc(_buffer, copy._size); memcpy(_buffer, copy._buffer, copy._size); } else { free(_buffer); @@ -100,7 +105,22 @@ struct MidiEvent { 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) return false; @@ -117,11 +137,11 @@ struct MidiEvent { 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 void set_buffer(Byte* buf, bool own) { + inline void set_buffer(uint8_t* buf, bool own) { if (_owns_buffer) { free(_buffer); _buffer = NULL; @@ -132,12 +152,12 @@ struct MidiEvent { inline void realloc(size_t size) { assert(_owns_buffer); - _buffer = (Byte*) ::realloc(_buffer, size); + _buffer = (uint8_t*) ::realloc(_buffer, size); } #else - inline void set_buffer(Byte* buf) { _buffer = buf; } + inline void set_buffer(uint8_t* buf) { _buffer = buf; } #endif // MIDI_EVENT_ALLOW_ALLOC @@ -147,21 +167,21 @@ struct MidiEvent { inline uint32_t& size() { return _size; } inline uint8_t type() const { return (_buffer[0] & 0xF0); } inline uint8_t channel() const { return (_buffer[0] & 0x0F); } - inline bool is_note_on() const { return (type() == MIDI_CMD_NOTE_ON); } - inline bool is_note_off() const { return (type() == MIDI_CMD_NOTE_OFF); } - inline bool is_cc() const { return (type() == MIDI_CMD_CONTROL); } + inline bool is_note_on() const { return (type() == MIDI_CMD_NOTE_ON); } + inline bool is_note_off() const { return (type() == MIDI_CMD_NOTE_OFF); } + inline bool is_cc() const { return (type() == MIDI_CMD_CONTROL); } inline bool is_note() const { return (is_note_on() || is_note_off()); } inline uint8_t note() const { return (_buffer[1]); } inline uint8_t velocity() const { return (_buffer[2]); } inline uint8_t cc_number() const { return (_buffer[1]); } inline uint8_t cc_value() const { return (_buffer[2]); } - inline const Byte* buffer() const { return _buffer; } - inline Byte*& buffer() { return _buffer; } + inline const uint8_t* buffer() const { return _buffer; } + inline uint8_t*& buffer() { return _buffer; } private: double _time; /**< Sample index (or beat time) at which event is valid */ - uint32_t _size; /**< Number of bytes of data in \a buffer */ - Byte* _buffer; /**< Raw MIDI data */ + uint32_t _size; /**< Number of uint8_ts of data in \a buffer */ + uint8_t* _buffer; /**< Raw MIDI data */ #ifdef MIDI_EVENT_ALLOW_ALLOC 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__ */ diff --git a/libs/ardour/ardour/midi_events.h b/libs/midi++2/midi++/events.h index f7e2442109..f7e2442109 100644 --- a/libs/ardour/ardour/midi_events.h +++ b/libs/midi++2/midi++/events.h diff --git a/libs/midi++2/midi++/jack.h b/libs/midi++2/midi++/jack.h index 845dd0c229..291b87f835 100644 --- a/libs/midi++2/midi++/jack.h +++ b/libs/midi++2/midi++/jack.h @@ -28,9 +28,13 @@ #include <fcntl.h> #include <unistd.h> +#include <glibmm/thread.h> + +#include <pbd/ringbuffer.h> #include <jack/jack.h> #include <jack/midiport.h> #include <midi++/port.h> +#include <midi++/event.h> namespace MIDI { @@ -52,6 +56,8 @@ public: virtual XMLNode& get_state () const; virtual void set_state (const XMLNode&); + static void set_process_thread (pthread_t); + protected: std::string get_typestring () const { return typestring; @@ -69,6 +75,14 @@ private: jack_port_t* _jack_input_port; jack_port_t* _jack_output_port; 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; }; |