refactor JACK MIDI port to allow writing from a non-process() thread, and move ARDOUR...
authorPaul Davis <paul@linuxaudiosystems.com>
Tue, 18 Mar 2008 03:42:32 +0000 (03:42 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Tue, 18 Mar 2008 03:42:32 +0000 (03:42 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@3155 d708f5d6-7413-0410-9779-e7cbd77b26cf

29 files changed:
gtk2_ardour/automation_streamview.cc
gtk2_ardour/midi_region_view.cc
gtk2_ardour/midi_streamview.cc
libs/ardour/ardour/midi_buffer.h
libs/ardour/ardour/midi_event.h [deleted file]
libs/ardour/ardour/midi_events.h [deleted file]
libs/ardour/ardour/midi_model.h
libs/ardour/ardour/midi_ring_buffer.h
libs/ardour/ardour/midi_source.h
libs/ardour/ardour/midi_util.h
libs/ardour/ardour/note.h
libs/ardour/ardour/smf_source.h
libs/ardour/audioengine.cc
libs/ardour/globals.cc
libs/ardour/import.cc
libs/ardour/jack_midi_port.cc
libs/ardour/meter.cc
libs/ardour/midi_buffer.cc
libs/ardour/midi_diskstream.cc
libs/ardour/midi_model.cc
libs/ardour/midi_stretch.cc
libs/ardour/midi_track.cc
libs/ardour/smf_reader.cc
libs/ardour/smf_source.cc
libs/midi++2/SConscript
libs/midi++2/jack_midiport.cc
libs/midi++2/midi++/event.h [new file with mode: 0644]
libs/midi++2/midi++/events.h [new file with mode: 0644]
libs/midi++2/midi++/jack.h

index 2ede053c7b7a2062de85ae3a394957e9a9ff4bca..d068c51e5ee85ab51978de829f28d480686c94ec 100644 (file)
@@ -29,7 +29,6 @@
 #include <ardour/midi_source.h>
 #include <ardour/midi_diskstream.h>
 #include <ardour/midi_track.h>
-#include <ardour/midi_events.h>
 #include <ardour/smf_source.h>
 #include <ardour/region_factory.h>
 
index feff47595f9b6beeadd5924d7b833191564c47d1..69b97b93d91c3eb9ded93b8ec2245f65f7bbca6e 100644 (file)
@@ -32,7 +32,6 @@
 #include <ardour/midi_region.h>
 #include <ardour/midi_source.h>
 #include <ardour/midi_diskstream.h>
-#include <ardour/midi_events.h>
 #include <ardour/midi_model.h>
 
 #include "streamview.h"
index 81be5834964e08eeaf0a1b1d11b3afcf88d5d1f4..1dd33820d9aa58d5afa6afa1d2a600058081888f 100644 (file)
@@ -29,7 +29,6 @@
 #include <ardour/midi_source.h>
 #include <ardour/midi_diskstream.h>
 #include <ardour/midi_track.h>
-#include <ardour/midi_events.h>
 #include <ardour/smf_source.h>
 #include <ardour/region_factory.h>
 
index b35264217adb44e12f3a29b112e1caf501684d46..a6cbb4911824c6b1656bca1d6fc3b0d8a8e99708 100644 (file)
@@ -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_event.h b/libs/ardour/ardour/midi_event.h
deleted file mode 100644 (file)
index 7dafb0f..0000000
+++ /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 <ardour/types.h>
-#include <ardour/midi_events.h>
-#include <stdint.h>
-
-/** If this is not defined, all methods of MidiEvent are RT safe
- * but MidiEvent will never deep copy and (depending on the scenario)
- * 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 (file)
index f7e2442..0000000
+++ /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 */
index de31d0505efc8855c32bcee0ac3c3e1e1b1f73f4..11ef4e0f764e418a47f7750a827dfa9cfd6bf740 100644 (file)
@@ -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;
index a0078061ee20b240b374a28b20e0a0d4a3ccd55d..1b3ab50f919f9cca4318ce00fcfb6a827fe3b4c7 100644 (file)
@@ -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;
 
index 5e41e3ff5b029cb61984f3a7d684fd8a557d515d..d465506819b954590882c317b00b57f55e6de545 100644 (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_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);
index 1f121fbd683bf9e5c1d356dcef721071f714799e..efcb6a7cd519802cfd17ea04b6f5afa150009852 100644 (file)
@@ -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 {
 
index ea598573e8141b5c323a89db05cd4e549afe04d1..41c18358d378d0511fc29ad028ff4bccb2c5f148 100644 (file)
 #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;
 };
 
 
index 937e08e44c4bcb3ac8134bf68b0a9f3dcdc8eeb2..626aa64defc5f70b70ef4ea345552b931273d46a 100644 (file)
@@ -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 ();
index bdc1e8f0e4944754d2349ca99612a4496d8dd398..84fd06d0790039ab569b591ebd9b2614038c7a5a 100644 (file)
@@ -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
index 9a7130392740d91ae38c2e1b430494726ff6e0d1..02c4a5ced604c8897e468596c08f27c588b7b408 100644 (file)
@@ -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)
 {
index a29cc1817b54a914d019af03732db2e57f7d74b0..104bef35c3a2ff20398e6a98b052456eef81baf2 100644 (file)
@@ -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;
 
index 0b8d96f4db2507772a0b2c1d1c692ef75639524d..6d8e4c8c5d24966bcd0770e4b5067b623d98802d 100644 (file)
@@ -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);
index f85fd3ec33a8d33fa3c72dc83bb244c817f791e5..e75c1d89caf5cad0ba0d428ffa9b1b90b643b2ec 100644 (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
                // 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);
index 1ca6a5db7212b308d4add9e3af93170a403f843e..a77a608fcdb6636d5f6921c662b9013b95bc10f0 100644 (file)
@@ -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);
index 7c3bc73fb82c49cb4f76f5b9eba2ff7b5277b3cb..51f093919c7b69e3c6192bb4452bebc2ed8a14f2 100644 (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();
 
                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;
                }
index 6bd351a6dc1405e40cb72ea50afa49a0a4b90577..a49094df91a320bdca2e4c808bb9d5b107e79fe3 100644 (file)
@@ -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();
index f214bde0beb4e5344abc2569a2f9a4da378007e4..f33c58a0fd2f6c5e1dea6599c967af2aa4e7b954 100644 (file)
@@ -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;
 }
index e1fa109342489f1e4b83b54aa44e3f86ede9c96a..bf97b1910690b860c63915c5efafbd80aac4fe7c 100644 (file)
@@ -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
index 20204f1d32d09779c6b73116e15cf31358c82305..63a020f141a9ba71447fbe45066f0d6230cc30cd 100644 (file)
@@ -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;
index bd4f837780afec90722da69f7a07afb62dac5ca7..720626e93642e5863d840f0d8e34161274007073 100644 (file)
@@ -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
        
index 14c02823960d5b1abf51ac2713fd47fe30a95f20..3e2e204fbd778cacbf32c243ad8cbce552de289e 100644 (file)
@@ -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")
index 52d05a5cfb46a365e89a5f7ce7bce65e380eb11d..9b2f07d3263b82219ebe8df0ffe0c1e149b7031d 100644 (file)
@@ -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/midi++2/midi++/event.h b/libs/midi++2/midi++/event.h
new file mode 100644 (file)
index 0000000..6ef1c49
--- /dev/null
@@ -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 <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. 
+ */
+#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 (file)
index 0000000..f7e2442
--- /dev/null
@@ -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 */
index 845dd0c229c1e4e3d44db44672c152ee8e62c293..291b87f83506d6b5a2050161df568d1ea913cae4 100644 (file)
 #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;
 };