From eb4a1fdbb8fec1f8aa5dfe33f882064e85792a84 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Tue, 18 Mar 2008 03:42:32 +0000 Subject: 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 --- gtk2_ardour/automation_streamview.cc | 1 - gtk2_ardour/midi_region_view.cc | 1 - gtk2_ardour/midi_streamview.cc | 1 - libs/ardour/ardour/midi_buffer.h | 14 +-- libs/ardour/ardour/midi_event.h | 174 ------------------------------ libs/ardour/ardour/midi_events.h | 136 ------------------------ libs/ardour/ardour/midi_model.h | 10 +- libs/ardour/ardour/midi_ring_buffer.h | 2 +- libs/ardour/ardour/midi_source.h | 2 +- libs/ardour/ardour/midi_util.h | 2 +- libs/ardour/ardour/note.h | 16 +-- libs/ardour/ardour/smf_source.h | 2 +- libs/ardour/audioengine.cc | 3 + libs/ardour/globals.cc | 15 --- libs/ardour/import.cc | 2 +- libs/ardour/jack_midi_port.cc | 2 +- libs/ardour/meter.cc | 2 +- libs/ardour/midi_buffer.cc | 14 +-- libs/ardour/midi_diskstream.cc | 2 +- libs/ardour/midi_model.cc | 17 +-- libs/ardour/midi_stretch.cc | 4 +- libs/ardour/midi_track.cc | 5 +- libs/ardour/smf_reader.cc | 3 +- libs/ardour/smf_source.cc | 6 +- libs/midi++2/SConscript | 8 +- libs/midi++2/jack_midiport.cc | 95 +++++++++++++++-- libs/midi++2/midi++/event.h | 194 ++++++++++++++++++++++++++++++++++ libs/midi++2/midi++/events.h | 136 ++++++++++++++++++++++++ libs/midi++2/midi++/jack.h | 14 +++ 29 files changed, 494 insertions(+), 389 deletions(-) delete mode 100644 libs/ardour/ardour/midi_event.h delete mode 100644 libs/ardour/ardour/midi_events.h create mode 100644 libs/midi++2/midi++/event.h create mode 100644 libs/midi++2/midi++/events.h diff --git a/gtk2_ardour/automation_streamview.cc b/gtk2_ardour/automation_streamview.cc index 2ede053c7b..d068c51e5e 100644 --- a/gtk2_ardour/automation_streamview.cc +++ b/gtk2_ardour/automation_streamview.cc @@ -29,7 +29,6 @@ #include #include #include -#include #include #include diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc index feff47595f..69b97b93d9 100644 --- a/gtk2_ardour/midi_region_view.cc +++ b/gtk2_ardour/midi_region_view.cc @@ -32,7 +32,6 @@ #include #include #include -#include #include #include "streamview.h" diff --git a/gtk2_ardour/midi_streamview.cc b/gtk2_ardour/midi_streamview.cc index 81be583496..1dd33820d9 100644 --- a/gtk2_ardour/midi_streamview.cc +++ b/gtk2_ardour/midi_streamview.cc @@ -29,7 +29,6 @@ #include #include #include -#include #include #include 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 #include -#include 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_event.h b/libs/ardour/ardour/midi_event.h deleted file mode 100644 index 7dafb0fbcf..0000000000 --- a/libs/ardour/ardour/midi_event.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - 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_midi_event_h__ -#define __ardour_midi_event_h__ - -#include -#include -#include - -/** 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. */ -#define MIDI_EVENT_ALLOW_ALLOC 1 - -namespace ARDOUR { - - -/** Identical to jack_midi_event_t, but with double timestamp - * - * time is either a frame time (from/to Jack) or a beat time (internal - * tempo time, used in MidiModel) depending on context. - */ -struct MidiEvent { -#ifdef MIDI_EVENT_ALLOW_ALLOC - MidiEvent(double t=0, uint32_t s=0, Byte* b=NULL, bool owns_buffer=false) - : _time(t) - , _size(s) - , _buffer(b) - , _owns_buffer(owns_buffer) - { - if (owns_buffer) { - _buffer = (Byte*)malloc(_size); - if (b) - memcpy(_buffer, b, _size); - else - memset(_buffer, 0, _size); - } - } - - /** Copy \a copy. - * - * If \a owns_buffer is true, the buffer will be copied and this method - * 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) - : _time(copy._time) - , _size(copy._size) - , _buffer(copy._buffer) - , _owns_buffer(owns_buffer) - { - if (owns_buffer) { - _buffer = (Byte*)malloc(_size); - if (copy._buffer) - memcpy(_buffer, copy._buffer, _size); - else - memset(_buffer, 0, _size); - } - } - - ~MidiEvent() { - if (_owns_buffer) - free(_buffer); - } - - inline const MidiEvent& operator=(const MidiEvent& copy) { - _time = copy._time; - if (_owns_buffer) { - if (copy._buffer) { - if (!_buffer || _size < copy._size) - _buffer = (Byte*)::realloc(_buffer, copy._size); - memcpy(_buffer, copy._buffer, copy._size); - } else { - free(_buffer); - _buffer = NULL; - } - } else { - _buffer = copy._buffer; - } - - _size = copy._size; - return *this; - } - - inline bool operator==(const MidiEvent& other) const { - if (_time != other._time) - return false; - - if (_size != other._size) - return false; - - if (_buffer == other._buffer) - return true; - - for (size_t i=0; i < _size; ++i) - if (_buffer[i] != other._buffer[i]) - return false; - - return true; - } - - inline bool operator!=(const MidiEvent& other) const { return ! operator==(other); } - - inline bool owns_buffer() const { return _owns_buffer; } - - inline void set_buffer(Byte* buf, bool own) { - if (_owns_buffer) { - free(_buffer); - _buffer = NULL; - } - _buffer = buf; - _owns_buffer = own; - } - - inline void realloc(size_t size) { - assert(_owns_buffer); - _buffer = (Byte*) ::realloc(_buffer, size); - } - -#else - - inline void set_buffer(Byte* buf) { _buffer = buf; } - -#endif // MIDI_EVENT_ALLOW_ALLOC - - inline double time() const { return _time; } - inline double& time() { return _time; } - inline uint32_t size() const { return _size; } - 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() 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; } - -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 */ - -#ifdef MIDI_EVENT_ALLOW_ALLOC - bool _owns_buffer; /**< Whether buffer is locally allocated */ -#endif -}; - - -} // namespace ARDOUR - -#endif /* __ardour_midi_event_h__ */ diff --git a/libs/ardour/ardour/midi_events.h b/libs/ardour/ardour/midi_events.h deleted file mode 100644 index f7e2442109..0000000000 --- a/libs/ardour/ardour/midi_events.h +++ /dev/null @@ -1,136 +0,0 @@ -/* Definitions to ease working with raw MIDI. - * - * Adapted from ALSA's asounddef.h - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef MIDI_H -#define MIDI_H - - -/** - * \defgroup midi MIDI Definitions - * MIDI command and controller number definitions. - * \{ - */ - -// Commands: - -#define MIDI_CMD_NOTE_OFF 0x80 /**< note off */ -#define MIDI_CMD_NOTE_ON 0x90 /**< note on */ -#define MIDI_CMD_NOTE_PRESSURE 0xA0 /**< key pressure */ -#define MIDI_CMD_CONTROL 0xB0 /**< control change */ -#define MIDI_CMD_PGM_CHANGE 0xC0 /**< program change */ -#define MIDI_CMD_CHANNEL_PRESSURE 0xD0 /**< channel pressure */ -#define MIDI_CMD_BENDER 0xE0 /**< pitch bender */ - -#define MIDI_CMD_COMMON_SYSEX 0xF0 /**< sysex (system exclusive) begin */ -#define MIDI_CMD_COMMON_MTC_QUARTER 0xF1 /**< MTC quarter frame */ -#define MIDI_CMD_COMMON_SONG_POS 0xF2 /**< song position */ -#define MIDI_CMD_COMMON_SONG_SELECT 0xF3 /**< song select */ -#define MIDI_CMD_COMMON_TUNE_REQUEST 0xF6 /**< tune request */ -#define MIDI_CMD_COMMON_SYSEX_END 0xF7 /**< end of sysex */ -#define MIDI_CMD_COMMON_CLOCK 0xF8 /**< clock */ -#define MIDI_CMD_COMMON_TICK 0xF9 /**< tick */ -#define MIDI_CMD_COMMON_START 0xFA /**< start */ -#define MIDI_CMD_COMMON_CONTINUE 0xFB /**< continue */ -#define MIDI_CMD_COMMON_STOP 0xFC /**< stop */ -#define MIDI_CMD_COMMON_SENSING 0xFE /**< active sensing */ -#define MIDI_CMD_COMMON_RESET 0xFF /**< reset */ - - -// Controllers: - -#define MIDI_CTL_MSB_BANK 0x00 /**< Bank selection */ -#define MIDI_CTL_MSB_MODWHEEL 0x01 /**< Modulation */ -#define MIDI_CTL_MSB_BREATH 0x02 /**< Breath */ -#define MIDI_CTL_MSB_FOOT 0x04 /**< Foot */ -#define MIDI_CTL_MSB_PORTAMENTO_TIME 0x05 /**< Portamento time */ -#define MIDI_CTL_MSB_DATA_ENTRY 0x06 /**< Data entry */ -#define MIDI_CTL_MSB_MAIN_VOLUME 0x07 /**< Main volume */ -#define MIDI_CTL_MSB_BALANCE 0x08 /**< Balance */ -#define MIDI_CTL_MSB_PAN 0x0A /**< Panpot */ -#define MIDI_CTL_MSB_EXPRESSION 0x0B /**< Expression */ -#define MIDI_CTL_MSB_EFFECT1 0x0C /**< Effect1 */ -#define MIDI_CTL_MSB_EFFECT2 0x0D /**< Effect2 */ -#define MIDI_CTL_MSB_GENERAL_PURPOSE1 0x10 /**< General purpose 1 */ -#define MIDI_CTL_MSB_GENERAL_PURPOSE2 0x11 /**< General purpose 2 */ -#define MIDI_CTL_MSB_GENERAL_PURPOSE3 0x12 /**< General purpose 3 */ -#define MIDI_CTL_MSB_GENERAL_PURPOSE4 0x13 /**< General purpose 4 */ -#define MIDI_CTL_LSB_BANK 0x20 /**< Bank selection */ -#define MIDI_CTL_LSB_MODWHEEL 0x21 /**< Modulation */ -#define MIDI_CTL_LSB_BREATH 0x22 /**< Breath */ -#define MIDI_CTL_LSB_FOOT 0x24 /**< Foot */ -#define MIDI_CTL_LSB_PORTAMENTO_TIME 0x25 /**< Portamento time */ -#define MIDI_CTL_LSB_DATA_ENTRY 0x26 /**< Data entry */ -#define MIDI_CTL_LSB_MAIN_VOLUME 0x27 /**< Main volume */ -#define MIDI_CTL_LSB_BALANCE 0x28 /**< Balance */ -#define MIDI_CTL_LSB_PAN 0x2A /**< Panpot */ -#define MIDI_CTL_LSB_EXPRESSION 0x2B /**< Expression */ -#define MIDI_CTL_LSB_EFFECT1 0x2C /**< Effect1 */ -#define MIDI_CTL_LSB_EFFECT2 0x2D /**< Effect2 */ -#define MIDI_CTL_LSB_GENERAL_PURPOSE1 0x30 /**< General purpose 1 */ -#define MIDI_CTL_LSB_GENERAL_PURPOSE2 0x31 /**< General purpose 2 */ -#define MIDI_CTL_LSB_GENERAL_PURPOSE3 0x32 /**< General purpose 3 */ -#define MIDI_CTL_LSB_GENERAL_PURPOSE4 0x33 /**< General purpose 4 */ -#define MIDI_CTL_SUSTAIN 0x40 /**< Sustain pedal */ -#define MIDI_CTL_PORTAMENTO 0x41 /**< Portamento */ -#define MIDI_CTL_SOSTENUTO 0x42 /**< Sostenuto */ -#define MIDI_CTL_SUSTENUTO 0x42 /**< Sostenuto (a typo in the older version) */ -#define MIDI_CTL_SOFT_PEDAL 0x43 /**< Soft pedal */ -#define MIDI_CTL_LEGATO_FOOTSWITCH 0x44 /**< Legato foot switch */ -#define MIDI_CTL_HOLD2 0x45 /**< Hold2 */ -#define MIDI_CTL_SC1_SOUND_VARIATION 0x46 /**< SC1 Sound Variation */ -#define MIDI_CTL_SC2_TIMBRE 0x47 /**< SC2 Timbre */ -#define MIDI_CTL_SC3_RELEASE_TIME 0x48 /**< SC3 Release Time */ -#define MIDI_CTL_SC4_ATTACK_TIME 0x49 /**< SC4 Attack Time */ -#define MIDI_CTL_SC5_BRIGHTNESS 0x4A /**< SC5 Brightness */ -#define MIDI_CTL_SC6 0x4B /**< SC6 */ -#define MIDI_CTL_SC7 0x4C /**< SC7 */ -#define MIDI_CTL_SC8 0x4D /**< SC8 */ -#define MIDI_CTL_SC9 0x4E /**< SC9 */ -#define MIDI_CTL_SC10 0x4F /**< SC10 */ -#define MIDI_CTL_GENERAL_PURPOSE5 0x50 /**< General purpose 5 */ -#define MIDI_CTL_GENERAL_PURPOSE6 0x51 /**< General purpose 6 */ -#define MIDI_CTL_GENERAL_PURPOSE7 0x52 /**< General purpose 7 */ -#define MIDI_CTL_GENERAL_PURPOSE8 0x53 /**< General purpose 8 */ -#define MIDI_CTL_PORTAMENTO_CONTROL 0x54 /**< Portamento control */ -#define MIDI_CTL_E1_REVERB_DEPTH 0x5B /**< E1 Reverb Depth */ -#define MIDI_CTL_E2_TREMOLO_DEPTH 0x5C /**< E2 Tremolo Depth */ -#define MIDI_CTL_E3_CHORUS_DEPTH 0x5D /**< E3 Chorus Depth */ -#define MIDI_CTL_E4_DETUNE_DEPTH 0x5E /**< E4 Detune Depth */ -#define MIDI_CTL_E5_PHASER_DEPTH 0x5F /**< E5 Phaser Depth */ -#define MIDI_CTL_DATA_INCREMENT 0x60 /**< Data Increment */ -#define MIDI_CTL_DATA_DECREMENT 0x61 /**< Data Decrement */ -#define MIDI_CTL_NONREG_PARM_NUM_LSB 0x62 /**< Non-registered parameter number */ -#define MIDI_CTL_NONREG_PARM_NUM_MSB 0x63 /**< Non-registered parameter number */ -#define MIDI_CTL_REGIST_PARM_NUM_LSB 0x64 /**< Registered parameter number */ -#define MIDI_CTL_REGIST_PARM_NUM_MSB 0x65 /**< Registered parameter number */ -#define MIDI_CTL_ALL_SOUNDS_OFF 0x78 /**< All sounds off */ -#define MIDI_CTL_RESET_CONTROLLERS 0x79 /**< Reset Controllers */ -#define MIDI_CTL_LOCAL_CONTROL_SWITCH 0x7A /**< Local control switch */ -#define MIDI_CTL_ALL_NOTES_OFF 0x7B /**< All notes off */ -#define MIDI_CTL_OMNI_OFF 0x7C /**< Omni off */ -#define MIDI_CTL_OMNI_ON 0x7D /**< Omni on */ -#define MIDI_CTL_MONO1 0x7E /**< Mono1 */ -#define MIDI_CTL_MONO2 0x7F /**< Mono2 */ -//@} - - -/** \} */ - -#endif /* MIDI_H */ 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 note_at(unsigned i) const { return _notes[i]; } inline const boost::shared_ptr 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, std::deque< boost::shared_ptr >, @@ -189,7 +189,7 @@ private: void remove_note_unlocked(const boost::shared_ptr 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 +#include 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 -#include +#include 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 #include +#include + #include #include #include @@ -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& 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 >& 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 #include #include +#include + #include -#include #include #include #include @@ -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 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 source) // Write any pending note offs earlier than this note on while ( ! active_notes.empty() ) { const boost::shared_ptr 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 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 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 #include +#include #include #include @@ -36,7 +37,7 @@ #include #include #include -#include + #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 #include #include +#include + #include -#include #include 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::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::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/midi++2/midi++/event.h b/libs/midi++2/midi++/event.h new file mode 100644 index 0000000000..6ef1c49ee9 --- /dev/null +++ b/libs/midi++2/midi++/event.h @@ -0,0 +1,194 @@ +/* + 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 __libmidipp_midi_event_h__ +#define __libmidipp_midi_event_h__ + +#include +#include +#include +#include + +#include +#include + +/** 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. + */ +#define MIDI_EVENT_ALLOW_ALLOC 1 + +namespace MIDI { + + +/** Identical to jack_midi_event_t, but with double timestamp + * + * time is either a frame time (from/to Jack) or a beat time (internal + * tempo time, used in MidiModel) depending on context. + */ +struct Event { +#ifdef MIDI_EVENT_ALLOW_ALLOC + 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 = (uint8_t*)malloc(_size); + if (b) + memcpy(_buffer, b, _size); + else + memset(_buffer, 0, _size); + } + } + + /** Copy \a copy. + * + * If \a owns_buffer is true, the buffer will be copied and this method + * is NOT REALTIME SAFE. Otherwise both events share a buffer and + * memory management semantics are the caller's problem. + */ + Event(const Event& copy, bool owns_buffer) + : _time(copy._time) + , _size(copy._size) + , _buffer(copy._buffer) + , _owns_buffer(owns_buffer) + { + if (owns_buffer) { + _buffer = (uint8_t*)malloc(_size); + if (copy._buffer) + memcpy(_buffer, copy._buffer, _size); + else + memset(_buffer, 0, _size); + } + } + + ~Event() { + if (_owns_buffer) + free(_buffer); + } + + inline const Event& operator=(const Event& copy) { + _time = copy._time; + if (_owns_buffer) { + if (copy._buffer) { + if (!_buffer || _size < copy._size) + _buffer = (uint8_t*)::realloc(_buffer, copy._size); + memcpy(_buffer, copy._buffer, copy._size); + } else { + free(_buffer); + _buffer = NULL; + } + } else { + _buffer = copy._buffer; + } + + _size = copy._size; + return *this; + } + + 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; + + if (_size != other._size) + return false; + + if (_buffer == other._buffer) + return true; + + for (size_t i=0; i < _size; ++i) + if (_buffer[i] != other._buffer[i]) + return false; + + return true; + } + + inline bool operator!=(const Event& other) const { return ! operator==(other); } + + inline bool owns_buffer() const { return _owns_buffer; } + + inline void set_buffer(uint8_t* buf, bool own) { + if (_owns_buffer) { + free(_buffer); + _buffer = NULL; + } + _buffer = buf; + _owns_buffer = own; + } + + inline void realloc(size_t size) { + assert(_owns_buffer); + _buffer = (uint8_t*) ::realloc(_buffer, size); + } + +#else + + inline void set_buffer(uint8_t* buf) { _buffer = buf; } + +#endif // MIDI_EVENT_ALLOW_ALLOC + + inline double time() const { return _time; } + inline double& time() { return _time; } + inline uint32_t size() const { return _size; } + 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() 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 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 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 */ +#endif +}; + + +} + +#endif /* __libmidipp_midi_event_h__ */ diff --git a/libs/midi++2/midi++/events.h b/libs/midi++2/midi++/events.h new file mode 100644 index 0000000000..f7e2442109 --- /dev/null +++ b/libs/midi++2/midi++/events.h @@ -0,0 +1,136 @@ +/* Definitions to ease working with raw MIDI. + * + * Adapted from ALSA's asounddef.h + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef MIDI_H +#define MIDI_H + + +/** + * \defgroup midi MIDI Definitions + * MIDI command and controller number definitions. + * \{ + */ + +// Commands: + +#define MIDI_CMD_NOTE_OFF 0x80 /**< note off */ +#define MIDI_CMD_NOTE_ON 0x90 /**< note on */ +#define MIDI_CMD_NOTE_PRESSURE 0xA0 /**< key pressure */ +#define MIDI_CMD_CONTROL 0xB0 /**< control change */ +#define MIDI_CMD_PGM_CHANGE 0xC0 /**< program change */ +#define MIDI_CMD_CHANNEL_PRESSURE 0xD0 /**< channel pressure */ +#define MIDI_CMD_BENDER 0xE0 /**< pitch bender */ + +#define MIDI_CMD_COMMON_SYSEX 0xF0 /**< sysex (system exclusive) begin */ +#define MIDI_CMD_COMMON_MTC_QUARTER 0xF1 /**< MTC quarter frame */ +#define MIDI_CMD_COMMON_SONG_POS 0xF2 /**< song position */ +#define MIDI_CMD_COMMON_SONG_SELECT 0xF3 /**< song select */ +#define MIDI_CMD_COMMON_TUNE_REQUEST 0xF6 /**< tune request */ +#define MIDI_CMD_COMMON_SYSEX_END 0xF7 /**< end of sysex */ +#define MIDI_CMD_COMMON_CLOCK 0xF8 /**< clock */ +#define MIDI_CMD_COMMON_TICK 0xF9 /**< tick */ +#define MIDI_CMD_COMMON_START 0xFA /**< start */ +#define MIDI_CMD_COMMON_CONTINUE 0xFB /**< continue */ +#define MIDI_CMD_COMMON_STOP 0xFC /**< stop */ +#define MIDI_CMD_COMMON_SENSING 0xFE /**< active sensing */ +#define MIDI_CMD_COMMON_RESET 0xFF /**< reset */ + + +// Controllers: + +#define MIDI_CTL_MSB_BANK 0x00 /**< Bank selection */ +#define MIDI_CTL_MSB_MODWHEEL 0x01 /**< Modulation */ +#define MIDI_CTL_MSB_BREATH 0x02 /**< Breath */ +#define MIDI_CTL_MSB_FOOT 0x04 /**< Foot */ +#define MIDI_CTL_MSB_PORTAMENTO_TIME 0x05 /**< Portamento time */ +#define MIDI_CTL_MSB_DATA_ENTRY 0x06 /**< Data entry */ +#define MIDI_CTL_MSB_MAIN_VOLUME 0x07 /**< Main volume */ +#define MIDI_CTL_MSB_BALANCE 0x08 /**< Balance */ +#define MIDI_CTL_MSB_PAN 0x0A /**< Panpot */ +#define MIDI_CTL_MSB_EXPRESSION 0x0B /**< Expression */ +#define MIDI_CTL_MSB_EFFECT1 0x0C /**< Effect1 */ +#define MIDI_CTL_MSB_EFFECT2 0x0D /**< Effect2 */ +#define MIDI_CTL_MSB_GENERAL_PURPOSE1 0x10 /**< General purpose 1 */ +#define MIDI_CTL_MSB_GENERAL_PURPOSE2 0x11 /**< General purpose 2 */ +#define MIDI_CTL_MSB_GENERAL_PURPOSE3 0x12 /**< General purpose 3 */ +#define MIDI_CTL_MSB_GENERAL_PURPOSE4 0x13 /**< General purpose 4 */ +#define MIDI_CTL_LSB_BANK 0x20 /**< Bank selection */ +#define MIDI_CTL_LSB_MODWHEEL 0x21 /**< Modulation */ +#define MIDI_CTL_LSB_BREATH 0x22 /**< Breath */ +#define MIDI_CTL_LSB_FOOT 0x24 /**< Foot */ +#define MIDI_CTL_LSB_PORTAMENTO_TIME 0x25 /**< Portamento time */ +#define MIDI_CTL_LSB_DATA_ENTRY 0x26 /**< Data entry */ +#define MIDI_CTL_LSB_MAIN_VOLUME 0x27 /**< Main volume */ +#define MIDI_CTL_LSB_BALANCE 0x28 /**< Balance */ +#define MIDI_CTL_LSB_PAN 0x2A /**< Panpot */ +#define MIDI_CTL_LSB_EXPRESSION 0x2B /**< Expression */ +#define MIDI_CTL_LSB_EFFECT1 0x2C /**< Effect1 */ +#define MIDI_CTL_LSB_EFFECT2 0x2D /**< Effect2 */ +#define MIDI_CTL_LSB_GENERAL_PURPOSE1 0x30 /**< General purpose 1 */ +#define MIDI_CTL_LSB_GENERAL_PURPOSE2 0x31 /**< General purpose 2 */ +#define MIDI_CTL_LSB_GENERAL_PURPOSE3 0x32 /**< General purpose 3 */ +#define MIDI_CTL_LSB_GENERAL_PURPOSE4 0x33 /**< General purpose 4 */ +#define MIDI_CTL_SUSTAIN 0x40 /**< Sustain pedal */ +#define MIDI_CTL_PORTAMENTO 0x41 /**< Portamento */ +#define MIDI_CTL_SOSTENUTO 0x42 /**< Sostenuto */ +#define MIDI_CTL_SUSTENUTO 0x42 /**< Sostenuto (a typo in the older version) */ +#define MIDI_CTL_SOFT_PEDAL 0x43 /**< Soft pedal */ +#define MIDI_CTL_LEGATO_FOOTSWITCH 0x44 /**< Legato foot switch */ +#define MIDI_CTL_HOLD2 0x45 /**< Hold2 */ +#define MIDI_CTL_SC1_SOUND_VARIATION 0x46 /**< SC1 Sound Variation */ +#define MIDI_CTL_SC2_TIMBRE 0x47 /**< SC2 Timbre */ +#define MIDI_CTL_SC3_RELEASE_TIME 0x48 /**< SC3 Release Time */ +#define MIDI_CTL_SC4_ATTACK_TIME 0x49 /**< SC4 Attack Time */ +#define MIDI_CTL_SC5_BRIGHTNESS 0x4A /**< SC5 Brightness */ +#define MIDI_CTL_SC6 0x4B /**< SC6 */ +#define MIDI_CTL_SC7 0x4C /**< SC7 */ +#define MIDI_CTL_SC8 0x4D /**< SC8 */ +#define MIDI_CTL_SC9 0x4E /**< SC9 */ +#define MIDI_CTL_SC10 0x4F /**< SC10 */ +#define MIDI_CTL_GENERAL_PURPOSE5 0x50 /**< General purpose 5 */ +#define MIDI_CTL_GENERAL_PURPOSE6 0x51 /**< General purpose 6 */ +#define MIDI_CTL_GENERAL_PURPOSE7 0x52 /**< General purpose 7 */ +#define MIDI_CTL_GENERAL_PURPOSE8 0x53 /**< General purpose 8 */ +#define MIDI_CTL_PORTAMENTO_CONTROL 0x54 /**< Portamento control */ +#define MIDI_CTL_E1_REVERB_DEPTH 0x5B /**< E1 Reverb Depth */ +#define MIDI_CTL_E2_TREMOLO_DEPTH 0x5C /**< E2 Tremolo Depth */ +#define MIDI_CTL_E3_CHORUS_DEPTH 0x5D /**< E3 Chorus Depth */ +#define MIDI_CTL_E4_DETUNE_DEPTH 0x5E /**< E4 Detune Depth */ +#define MIDI_CTL_E5_PHASER_DEPTH 0x5F /**< E5 Phaser Depth */ +#define MIDI_CTL_DATA_INCREMENT 0x60 /**< Data Increment */ +#define MIDI_CTL_DATA_DECREMENT 0x61 /**< Data Decrement */ +#define MIDI_CTL_NONREG_PARM_NUM_LSB 0x62 /**< Non-registered parameter number */ +#define MIDI_CTL_NONREG_PARM_NUM_MSB 0x63 /**< Non-registered parameter number */ +#define MIDI_CTL_REGIST_PARM_NUM_LSB 0x64 /**< Registered parameter number */ +#define MIDI_CTL_REGIST_PARM_NUM_MSB 0x65 /**< Registered parameter number */ +#define MIDI_CTL_ALL_SOUNDS_OFF 0x78 /**< All sounds off */ +#define MIDI_CTL_RESET_CONTROLLERS 0x79 /**< Reset Controllers */ +#define MIDI_CTL_LOCAL_CONTROL_SWITCH 0x7A /**< Local control switch */ +#define MIDI_CTL_ALL_NOTES_OFF 0x7B /**< All notes off */ +#define MIDI_CTL_OMNI_OFF 0x7C /**< Omni off */ +#define MIDI_CTL_OMNI_ON 0x7D /**< Omni on */ +#define MIDI_CTL_MONO1 0x7E /**< Mono1 */ +#define MIDI_CTL_MONO2 0x7F /**< Mono2 */ +//@} + + +/** \} */ + +#endif /* MIDI_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 #include +#include + +#include #include #include #include +#include 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 non_process_thread_fifo; + Glib::Mutex non_process_thread_fifo_lock; }; -- cgit v1.2.3