Move event specific ringbuffer stuff to evoral.
authorDavid Robillard <d@drobilla.net>
Mon, 22 Sep 2008 16:28:02 +0000 (16:28 +0000)
committerDavid Robillard <d@drobilla.net>
Mon, 22 Sep 2008 16:28:02 +0000 (16:28 +0000)
Sane event type interface between evoral and libardour (no more shared magic numbers).
Cleanup Evoral::Sequence iterator, fix bugs, probably introduce new ones.
Move MIDI specific event functions to Evoral::MIDIEvent (is-a Evoral::Event).

git-svn-id: svn://localhost/ardour2/branches/3.0@3785 d708f5d6-7413-0410-9779-e7cbd77b26cf

36 files changed:
gtk2_ardour/canvas-program-change.cc
gtk2_ardour/midi_region_view.cc
gtk2_ardour/midi_streamview.cc
libs/ardour/SConscript
libs/ardour/ardour/automatable.h
libs/ardour/ardour/event_type_map.h [new file with mode: 0644]
libs/ardour/ardour/midi_buffer.h
libs/ardour/ardour/midi_ring_buffer.h
libs/ardour/ardour/parameter.h
libs/ardour/event_type_map.cc [new file with mode: 0644]
libs/ardour/import.cc
libs/ardour/meter.cc
libs/ardour/midi_buffer.cc
libs/ardour/midi_diskstream.cc
libs/ardour/midi_model.cc
libs/ardour/midi_track.cc
libs/ardour/quantize.cc
libs/ardour/smf_source.cc
libs/evoral/SConscript
libs/evoral/evoral/Event.hpp
libs/evoral/evoral/EventRingBuffer.hpp [new file with mode: 0644]
libs/evoral/evoral/EventSink.hpp
libs/evoral/evoral/MIDIEvent.hpp [new file with mode: 0644]
libs/evoral/evoral/MIDIParameters.hpp
libs/evoral/evoral/Note.hpp
libs/evoral/evoral/RingBuffer.hpp [new file with mode: 0644]
libs/evoral/evoral/Sequence.hpp
libs/evoral/evoral/TypeMap.hpp [new file with mode: 0644]
libs/evoral/evoral/types.hpp
libs/evoral/src/ControlList.cpp
libs/evoral/src/Event.cpp
libs/evoral/src/MIDIEvent.cpp [new file with mode: 0644]
libs/evoral/src/Note.cpp
libs/evoral/src/Sequence.cpp
libs/midi++2/midi++/event.h
libs/midi++2/midnam_patch.cc

index e5a7768f348d05ca1d5060220f64218b9ac74265..bd9c0e89dbcfb9c085b00690d8e659a6a6457846 100644 (file)
@@ -20,7 +20,7 @@ CanvasProgramChange::CanvasProgramChange(
        , _rect(0)
 {
        char pgm_str[4];
-       snprintf(pgm_str, 4, "%d", (int)event->pgm_number());
+       snprintf(pgm_str, 4, "%d", (int)(((Evoral::MIDIEvent*)event.get())->pgm_number()));
        _text = new Text(*this, 0.0, 0.0, pgm_str);
        _text->property_justification() = Gtk::JUSTIFY_CENTER;
        _text->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MidiProgramChangeOutline.get();
index bfd23f900eec96bc3d925a3b962464e19ace1117..c67d0a5c5e219bc30ae8ca143a75ba4800a56b27 100644 (file)
@@ -366,7 +366,7 @@ MidiRegionView::canvas_event(GdkEvent* ev)
 
 /** Add a note to the model, and the view, at a canvas (click) coordinate */
 void
-MidiRegionView::create_note_at(double x, double y, double duration)
+MidiRegionView::create_note_at(double x, double y, double length)
 {
        MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
        MidiStreamView* const view = mtv->midi_view();
@@ -383,7 +383,7 @@ MidiRegionView::create_note_at(double x, double y, double duration)
        /*
        const Meter& m = trackview.session().tempo_map().meter_at(new_note_time);
        const Tempo& t = trackview.session().tempo_map().tempo_at(new_note_time);
-       double duration = m.frames_per_bar(t, trackview.session().frame_rate()) / m.beats_per_bar();
+       double length = m.frames_per_bar(t, trackview.session().frame_rate()) / m.beats_per_bar();
        */
        
        // we need to snap here again in nframes64_t in order to be sample accurate 
@@ -392,13 +392,13 @@ MidiRegionView::create_note_at(double x, double y, double duration)
        nframes64_t new_note_time_position_relative = new_note_time      - _region->start(); 
        new_note_time = snap_to_frame(new_note_time_position_relative) + _region->start();
        
-       // we need to snap the duration too to be sample accurate
-       nframes64_t new_note_duration = nframes_t(duration);
-       new_note_duration = snap_to_frame(new_note_time_position_relative + new_note_duration) + _region->start() 
+       // we need to snap the length too to be sample accurate
+       nframes64_t new_note_length = nframes_t(length);
+       new_note_length = snap_to_frame(new_note_time_position_relative + new_note_length) + _region->start() 
                            - new_note_time;
 
        const boost::shared_ptr<Evoral::Note> new_note(new Evoral::Note(
-                       0, new_note_time, new_note_duration, (uint8_t)note, 0x40));
+                       0, new_note_time, new_note_length, (uint8_t)note, 0x40));
        view->update_bounds(new_note->note());
 
        MidiModel::DeltaCommand* cmd = _model->new_delta_command("add note");
@@ -508,7 +508,7 @@ MidiRegionView::redisplay_model()
                for (MidiModel::Notes::iterator i = notes.begin(); i != notes.end(); ++i) {
                        cerr << "NOTE  time: " << (*i)->time()
                                 << "  pitch: " << int((*i)->note()) 
-                            << "  duration: " << (*i)->duration() 
+                            << "  length: " << (*i)->length() 
                             << "  end-time: " << (*i)->end_time() 
                             << "  velocity: " << int((*i)->velocity()) 
                             << endl;
@@ -769,9 +769,9 @@ MidiRegionView::extend_active_notes()
 }
 
 
-/** Add a MIDI note to the view (with duration).
+/** Add a MIDI note to the view (with length).
  *
- * If in sustained mode, notes with duration 0 will be considered active
+ * If in sustained mode, notes with length 0 will be considered active
  * notes, and resolve_note should be called when the corresponding note off
  * event arrives, to properly display the note.
  */
@@ -804,13 +804,13 @@ MidiRegionView::add_note(const boost::shared_ptr<Evoral::Note> note)
                CanvasNote* ev_rect = new CanvasNote(*this, *group, note);
                ev_rect->property_x1() = x;
                ev_rect->property_y1() = y1;
-               if (note->duration() > 0)
+               if (note->length() > 0)
                        ev_rect->property_x2() = note_endpixel;
                else
                        ev_rect->property_x2() = trackview.editor.frame_to_pixel(_region->length());
                ev_rect->property_y2() = y1 + floor(midi_stream_view()->note_height());
 
-               if (note->duration() == 0) {
+               if (note->length() == 0) {
 
                        if (_active_notes) {
                                assert(note->note() < 128);
@@ -819,7 +819,7 @@ MidiRegionView::add_note(const boost::shared_ptr<Evoral::Note> note)
                                if (_active_notes[note->note()]) {
                                        CanvasNote* const old_rect = _active_notes[note->note()];
                                        boost::shared_ptr<Evoral::Note> old_note = old_rect->note();
-                                       cerr << "MidiModel: WARNING: Note has duration 0: chan " << old_note->channel()
+                                       cerr << "MidiModel: WARNING: Note has length 0: chan " << old_note->channel()
                                                << "note " << (int)old_note->note() << " @ " << old_note->time() << endl;
                                        /* FIXME: How large to make it?  Make it a diamond? */
                                        old_rect->property_x2() = old_rect->property_x1() + 2.0;
index 8d2986b6de672d1bd39d6f230a024a3aff17d20d..6c620128bcac10c6a7f5ceaee6e8aaf959a0c6c0 100644 (file)
@@ -555,7 +555,7 @@ MidiStreamView::update_rec_regions (boost::shared_ptr<MidiModel> data, nframes_t
 
                                                        const boost::shared_ptr<Evoral::Note> note = data->note_at(i);
                                                        
-                                                       if (note->duration() > 0 && note->end_time() + region->position() > start)
+                                                       if (note->length() > 0 && note->end_time() + region->position() > start)
                                                                mrv->resolve_note(note->note(), note->end_time());
 
                                                        if (note->time() + region->position() < start)
index c351510d1900935bdfb63daa6ca12549c9693d6d..352d1b26f60dd70e7d54182052b10d31ecb259ba 100644 (file)
@@ -32,18 +32,18 @@ ardour.Append(CPPPATH = '#libs/surfaces/control_protocol')
 ardour_files=Split("""
 amp.cc
 analyser.cc
-audioanalyser.cc
 audio_buffer.cc
 audio_diskstream.cc
-audioengine.cc
-audiofilesource.cc
-audiofile_tagger.cc
 audio_library.cc
 audio_playlist.cc
 audio_port.cc
+audio_track.cc
+audioanalyser.cc
+audioengine.cc
+audiofile_tagger.cc
+audiofilesource.cc
 audioregion.cc
 audiosource.cc
-audio_track.cc
 auditioner.cc
 auto_bundle.cc
 automatable.cc
@@ -65,13 +65,14 @@ default_click.cc
 directory_names.cc
 diskstream.cc
 enums.cc
+event_type_map.cc
 export_channel_configuration.cc
 export_file_io.cc
 export_filename.cc
 export_format_base.cc
 export_format_manager.cc
-export_formats.cc
 export_format_specification.cc
+export_formats.cc
 export_handler.cc
 export_preset.cc
 export_processor.cc
@@ -97,6 +98,7 @@ ladspa_plugin.cc
 location.cc
 meter.cc
 midi_buffer.cc
+midi_clock_slave.cc
 midi_diskstream.cc
 midi_model.cc
 midi_playlist.cc
@@ -107,7 +109,6 @@ midi_stretch.cc
 midi_track.cc
 mix.cc
 mtc_slave.cc
-midi_clock_slave.cc
 named_selection.cc
 onset_detector.cc
 panner.cc
@@ -131,8 +132,8 @@ reverse.cc
 route.cc
 route_group.cc
 send.cc
-session_butler.cc
 session.cc
+session_butler.cc
 session_click.cc
 session_command.cc
 session_directory.cc
@@ -150,8 +151,8 @@ silentfilesource.cc
 smf_reader.cc
 smf_source.cc
 sndfile_helpers.cc
-sndfilesource.cc
 sndfileimportable.cc
+sndfilesource.cc
 source.cc
 source_factory.cc
 svn_revision.cc
index 837bbbc61748e1f460074bf07eb5e387f87e4f77..dbce7de0bf4abcac023fc28dc6f8d5e0fe3c7a41 100644 (file)
@@ -27,6 +27,7 @@
 #include <ardour/automation_list.h>
 #include <ardour/automation_control.h>
 #include <ardour/parameter.h>
+#include <ardour/event_type_map.h>
 #include <evoral/ControlSet.hpp>
 #include <evoral/Sequence.hpp>
 
@@ -53,9 +54,6 @@ public:
        virtual void add_control(boost::shared_ptr<Evoral::Control>);
        
        virtual void automation_snapshot(nframes_t now, bool force);
-       bool should_snapshot (nframes_t now) {
-               return (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _automation_interval);
-       }
        virtual void transport_stopped(nframes_t now);
 
        virtual string describe_parameter(Parameter param);
@@ -73,6 +71,11 @@ public:
 
        void mark_automation_visible(Parameter, bool);
        
+       inline bool should_snapshot (nframes_t now) {
+               return (_last_automation_snapshot > now
+                               || (now - _last_automation_snapshot) > _automation_interval);
+       }
+       
        static void set_automation_interval (jack_nframes_t frames) {
                _automation_interval = frames;
        }
@@ -113,7 +116,7 @@ public:
        AutomatableSequence(Session& s, size_t size)
                : Evoral::ControlSet()
                , Automatable(s)
-               , Evoral::Sequence(size)
+               , Evoral::Sequence(EventTypeMap::instance())
        {}
 };
 
diff --git a/libs/ardour/ardour/event_type_map.h b/libs/ardour/ardour/event_type_map.h
new file mode 100644 (file)
index 0000000..6736fee
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+    Copyright (C) 2000-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_event_type_map_h__
+#define __ardour_event_type_map_h__
+
+#include <evoral/TypeMap.hpp>
+
+namespace ARDOUR {
+
+class EventTypeMap : public Evoral::TypeMap {
+public:
+       bool     type_is_midi(uint32_t type) const;
+       uint8_t  parameter_midi_type(const Evoral::Parameter& param) const;
+       uint32_t midi_event_type(uint8_t status) const;
+
+       static EventTypeMap& instance() { return event_type_map; }
+
+private:
+       static EventTypeMap event_type_map;
+};
+
+} // namespace ARDOUR
+
+#endif /* __ardour_event_type_map_h__ */
+
index 0c131998254bdf80363e5411130e80f1c2fcc242..606cbd0ec80db06956af2eb7dcff8b95231a577c 100644 (file)
@@ -39,7 +39,7 @@ public:
        
        void copy(const MidiBuffer& copy);
 
-       bool     push_back(const Evoral::Event& event);
+       bool     push_back(const Evoral::MIDIEvent& event);
        bool     push_back(const jack_midi_event_t& event);
        uint8_t* reserve(double time, size_t size);
 
@@ -50,7 +50,7 @@ public:
        struct iterator {
                iterator(MidiBuffer& b, size_t i) : buffer(b), index(i) {}
 
-               inline Evoral::Event& operator*() const { return buffer[index]; }
+               inline Evoral::MIDIEvent& 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 Evoral::Event& operator*() const { return buffer[index]; }
+               inline const Evoral::MIDIEvent& 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 Evoral::Event& operator[](size_t i) const { assert(i < _size); return _events[i]; }
-       Evoral::Event& operator[](size_t i) { assert(i < _size); return _events[i]; }
+       const Evoral::MIDIEvent& operator[](size_t i) const { assert(i < _size); return _events[i]; }
+       Evoral::MIDIEvent& operator[](size_t i) { assert(i < _size); return _events[i]; }
 
        // FIXME: Eliminate this
        static const size_t MAX_EVENT_SIZE = 4; // bytes
@@ -92,8 +92,8 @@ private:
 
        /* FIXME: this is utter crap.  rewrite as a flat/packed buffer like MidiRingBuffer */
 
-       Evoral::Event* _events; ///< Event structs that point to offsets in _data
-       uint8_t*       _data;   ///< MIDI, straight up.  No time stamps.
+       Evoral::MIDIEvent* _events; ///< Event structs that point to offsets in _data
+       uint8_t*           _data;   ///< MIDI, straight up.  No time stamps.
 };
 
 
index db0c3029a8aa1fd81bf1a0f268bb2a50bc2839b4..ae82dc14ab5f0ed7f44f55f52fa764aa403ccd49 100644 (file)
 #include <ardour/types.h>
 #include <ardour/buffer.h>
 #include <evoral/EventSink.hpp>
+#include <evoral/EventRingBuffer.hpp>
 
 namespace ARDOUR {
 
 
-/* FIXME: this is probably too much inlined code */
-
-
-/** A RingBuffer.
- * Read/Write realtime safe.
- * Single-reader Single-writer thread safe.
- *
- * This is Raul::RingBuffer, lifted for MIDIRingBuffer to inherit from as it works
- * a bit differently than PBD::Ringbuffer.  This could/should be replaced with
- * the PBD ringbuffer to decrease code size, but this code is tested and known to
- * work, so here it sits for now...
- *
- * Ignore this class, use MidiRingBuffer.
- */
-template <typename T>
-class MidiRingBufferBase {
-public:
-
-       /** @param size Size in bytes.
-        */
-       MidiRingBufferBase(size_t size)
-               : _size(size)
-               , _buf(new T[size])
-       {
-               reset();
-               assert(read_space() == 0);
-               assert(write_space() == size - 1);
-       }
-       
-       virtual ~MidiRingBufferBase() {
-               delete[] _buf;
-       }
-
-       /** Reset(empty) the ringbuffer.
-        * NOT thread safe.
-        */
-       void reset() {
-               g_atomic_int_set(&_write_ptr, 0);
-               g_atomic_int_set(&_read_ptr, 0);
-       }
-
-       size_t write_space() const {
-               
-               const size_t w = g_atomic_int_get(&_write_ptr);
-               const size_t r = g_atomic_int_get(&_read_ptr);
-               
-               if (w > r) {
-                       return ((r - w + _size) % _size) - 1;
-               } else if (w < r) {
-                       return (r - w) - 1;
-               } else {
-                       return _size - 1;
-               }
-       }
-       
-       size_t read_space() const {
-               
-               const size_t w = g_atomic_int_get(&_write_ptr);
-               const size_t r = g_atomic_int_get(&_read_ptr);
-               
-               if (w > r) {
-                       return w - r;
-               } else {
-                       return (w - r + _size) % _size;
-               }
-       }
-
-       size_t capacity() const { return _size; }
-
-       size_t peek(size_t size, T* dst);
-       bool   full_peek(size_t size, T* dst);
-
-       size_t read(size_t size, T* dst);
-       bool   full_read(size_t size, T* dst);
-
-       bool   skip(size_t size);
-       
-       void   write(size_t size, const T* src);
-
-protected:
-       mutable int _write_ptr;
-       mutable int _read_ptr;
-       
-       size_t _size; ///< Size (capacity) in bytes
-       T*     _buf;  ///< size, event, size, event...
-};
-
-
-/** Peek at the ringbuffer (read w/o advancing read pointer).
- *
- * Note that a full read may not be done if the data wraps around.
- * Caller must check return value and call again if necessary, or use the 
- * full_peek method which does this automatically.
- */
-template<typename T>
-size_t
-MidiRingBufferBase<T>::peek(size_t size, T* dst)
-{
-       const size_t priv_read_ptr = g_atomic_int_get(&_read_ptr);
-
-       const size_t read_size = (priv_read_ptr + size < _size)
-                       ? size
-                       : _size - priv_read_ptr;
-       
-       memcpy(dst, &_buf[priv_read_ptr], read_size);
-
-       return read_size;
-}
-
-
-template<typename T>
-bool
-MidiRingBufferBase<T>::full_peek(size_t size, T* dst)
-{
-       if (read_space() < size) {
-               return false;
-       }
-
-       const size_t read_size = peek(size, dst);
-       
-       if (read_size < size) {
-               peek(size - read_size, dst + read_size);
-       }
-
-       return true;
-}
-
-
-/** Read from the ringbuffer.
- *
- * Note that a full read may not be done if the data wraps around.
- * Caller must check return value and call again if necessary, or use the 
- * full_read method which does this automatically.
- */
-template<typename T>
-size_t
-MidiRingBufferBase<T>::read(size_t size, T* dst)
-{
-       const size_t priv_read_ptr = g_atomic_int_get(&_read_ptr);
-
-       const size_t read_size = (priv_read_ptr + size < _size)
-                       ? size
-                       : _size - priv_read_ptr;
-       
-       memcpy(dst, &_buf[priv_read_ptr], read_size);
-        
-       g_atomic_int_set(&_read_ptr, (priv_read_ptr + read_size) % _size);
-
-       return read_size;
-}
-
-
-template<typename T>
-bool
-MidiRingBufferBase<T>::full_read(size_t size, T* dst)
-{
-       if (read_space() < size) {
-               return false;
-       }
-
-       const size_t read_size = read(size, dst);
-       
-       if (read_size < size) {
-               read(size - read_size, dst + read_size);
-       }
-
-       return true;
-}
-
-
-template<typename T>
-bool
-MidiRingBufferBase<T>::skip(size_t size)
-{
-       if (read_space() < size) {
-               std::cerr << "WARNING: Attempt to skip past end of MIDI ring buffer" << std::endl;
-               return false;
-       }
-       
-       const size_t priv_read_ptr = g_atomic_int_get(&_read_ptr);
-       g_atomic_int_set(&_read_ptr, (priv_read_ptr + size) % _size);
-
-       return true;
-}
-
-
-template<typename T>
-inline void
-MidiRingBufferBase<T>::write(size_t size, const T* src)
-{
-       const size_t priv_write_ptr = g_atomic_int_get(&_write_ptr);
-       
-       if (priv_write_ptr + size <= _size) {
-               memcpy(&_buf[priv_write_ptr], src, size);
-               g_atomic_int_set(&_write_ptr, (priv_write_ptr + size) % _size);
-       } else {
-               const size_t this_size = _size - priv_write_ptr;
-               assert(this_size < size);
-               assert(priv_write_ptr + this_size <= _size);
-               memcpy(&_buf[priv_write_ptr], src, this_size);
-               memcpy(&_buf[0], src+this_size, size - this_size);
-               g_atomic_int_set(&_write_ptr, size - this_size);
-       }
-}
-
-
-/* ******************************************************************** */
-       
-
-/** A MIDI RingBuffer.
+/** A RingBuffer for (MIDI) events.
  *
- * This is timestamps and MIDI packed sequentially into a single buffer, similarly
- * to LV2 MIDI.  The buffer looks like this:
+ * This is simply a wrapper around a raw ringbuffer which writes/reads events
+ * as flat placked blobs.
+ * The buffer looks like this:
  *
- * [timestamp][size][size bytes of raw MIDI][timestamp][size][etc..]
+ * [timestamp][type][size][size bytes of raw MIDI][timestamp][type][size](etc...)
  */
-class MidiRingBuffer : public MidiRingBufferBase<uint8_t>, public Evoral::EventSink {
+class MidiRingBuffer : public Evoral::EventRingBuffer {
 public:
        /** @param size Size in bytes.
         */
        MidiRingBuffer(size_t size)
-               : MidiRingBufferBase<uint8_t>(size), _channel_mask(0x0000FFFF)
+               : Evoral::EventRingBuffer(size)
+               , _channel_mask(0x0000FFFF)
        {}
 
-       size_t write(double time, uint32_t size, const uint8_t* buf);
-       bool   read(double* time, uint32_t* size, uint8_t* buf);
-
-       bool   read_prefix(double* time, size_t* size);
-       bool   read_contents(size_t size, uint8_t* buf);
+       inline bool read_prefix(EventTime* time, EventType* type, uint32_t* size);
+       inline bool read_contents(uint32_t size, uint8_t* buf);
 
        size_t read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes_t offset=0);
        
@@ -292,32 +83,17 @@ private:
 };
 
 
-inline bool
-MidiRingBuffer::read(double* time, uint32_t* size, uint8_t* buf)
-{
-       bool success = MidiRingBufferBase<uint8_t>::full_read(sizeof(double), (uint8_t*)time);
-       
-       if (success) {
-               success = MidiRingBufferBase<uint8_t>::full_read(sizeof(size_t), (uint8_t*)size);
-       }
-       if (success) {
-               success = MidiRingBufferBase<uint8_t>::full_read(*size, buf);
-       }
-       
-       return success;
-}
-
-
 /** Read the time and size of an event.  This call MUST be immediately proceeded
  * by a call to read_contents (or the read pointer will be garabage).
  */
 inline bool
-MidiRingBuffer::read_prefix(double* time, size_t* size)
+MidiRingBuffer::read_prefix(EventTime* time, EventType* type, uint32_t* size)
 {
-       bool success = MidiRingBufferBase<uint8_t>::full_read(sizeof(double), (uint8_t*)time);
-       if (success) {
-               success = MidiRingBufferBase<uint8_t>::full_read(sizeof(size_t), (uint8_t*)size);
-       }
+       bool success = Evoral::EventRingBuffer::full_read(sizeof(EventTime), (uint8_t*)time);
+       if (success)
+               success = Evoral::EventRingBuffer::full_read(sizeof(EventType), (uint8_t*)type);
+       if (success)
+               success = Evoral::EventRingBuffer::full_read(sizeof(uint32_t), (uint8_t*)size);
 
        return success;
 }
@@ -327,51 +103,9 @@ MidiRingBuffer::read_prefix(double* time, size_t* size)
  * by a call to read_prefix (or the returned even will be garabage).
  */
 inline bool
-MidiRingBuffer::read_contents(size_t size, uint8_t* buf)
-{
-       return MidiRingBufferBase<uint8_t>::full_read(size, buf);
-}
-
-
-inline size_t
-MidiRingBuffer::write(double time, uint32_t size, const uint8_t* buf)
+MidiRingBuffer::read_contents(uint32_t size, uint8_t* buf)
 {
-       /*fprintf(stderr, "MRB %p write (t = %f) ", this, time);
-       for (size_t i = 0; i < size; ++i)
-               fprintf(stderr, "%X", (char)buf[i]);
-       fprintf(stderr, "\n");*/
-       
-       assert(size > 0);
-       
-       // Don't write event if it doesn't match channel filter
-       if (is_channel_event(buf[0]) && get_channel_mode() == FilterChannels) {
-               uint8_t channel = buf[0] & 0x0F;
-               if ( !(get_channel_mask() & (1L << channel)) ) {
-                       return 0;
-               }
-       }
-
-       if (write_space() < (sizeof(double) + sizeof(size_t) + size)) {
-               return 0;
-       } else {
-               MidiRingBufferBase<uint8_t>::write(sizeof(double), (uint8_t*)&time);
-               MidiRingBufferBase<uint8_t>::write(sizeof(size_t), (uint8_t*)&size);
-               if (is_channel_event(buf[0]) && get_channel_mode() == ForceChannel) {
-                       assert(size == 2 || size == 3);
-                       uint8_t tmp_buf[3];
-                       // Force event to channel
-                       tmp_buf[0] = (buf[0] & 0xF0) | (get_channel_mask() & 0x0F);
-                       tmp_buf[1] = buf[1];
-                       if (size == 3) {
-                               tmp_buf[2] = buf[2];
-                       }
-                       MidiRingBufferBase<uint8_t>::write(size, tmp_buf);
-               } else {
-                       MidiRingBufferBase<uint8_t>::write(size, buf);
-               }
-               return size;
-       }
-
+       return Evoral::EventRingBuffer::full_read(size, buf);
 }
 
 
@@ -383,31 +117,31 @@ MidiRingBuffer::write(double time, uint32_t size, const uint8_t* buf)
 inline size_t
 MidiRingBuffer::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes_t offset)
 {
-       if (read_space() == 0)
+       if (read_space() == 0) {
+               //std::cerr << "MRB: NO READ SPACE" << std::endl;
                return 0;
+       }
 
-       double   ev_time;
-       uint32_t ev_size;
+       EventTime ev_time;
+       EventType ev_type;
+       uint32_t  ev_size;
 
        size_t count = 0;
 
-       //printf("---- MRB read %u .. %u + %u\n", start, end, offset);
+       //std::cerr << "MRB read " << start << " .. " << end << " + " << offset << std::endl;
 
-       while (read_space() > sizeof(double) + sizeof(size_t)) {
+       while (read_space() > sizeof(EventTime) + sizeof(EventType) + sizeof(uint32_t)) {
        
-               full_peek(sizeof(double), (uint8_t*)&ev_time);
+               full_peek(sizeof(EventTime), (uint8_t*)&ev_time);
        
                if (ev_time > end) {
+                       //std::cerr << "MRB: PAST END (" << ev_time << " : " << end << ")" << std::endl;
                        break;
                }
                
-               bool success = MidiRingBufferBase<uint8_t>::full_read(sizeof(double), (uint8_t*)&ev_time);
-               if (success) {
-                       success = MidiRingBufferBase<uint8_t>::full_read(sizeof(size_t), (uint8_t*)&ev_size);
-               }
-
+               bool success = read_prefix(&ev_time, &ev_type, &ev_size);
                if (!success) {
-                       std::cerr << "MRB: READ ERROR (time/size)" << std::endl;
+                       //std::cerr << "MRB: READ ERROR (time/type/size)" << std::endl;
                        continue;
                }
                
@@ -419,6 +153,7 @@ MidiRingBuffer::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes_t
                if (is_channel_event(status) && get_channel_mode() == FilterChannels) {
                        const uint8_t channel = status & 0x0F;
                        if ( !(get_channel_mask() & (1L << channel)) ) {
+                               //std::cerr << "MRB skipping event due to channel mask" << std::endl;
                                skip(ev_size); // Advance read pointer to next event
                                continue;
                        }
@@ -426,36 +161,36 @@ MidiRingBuffer::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes_t
 
                if (ev_time >= start) {
 
-                       /*std::cerr << "MRB " << this << " - Reading event, time = "
-                               << ev_time << " - " << start << " => " << ev_time - start
-                               << ", size = " << ev_size << std::endl;*/
+                       //std::cerr << "MRB " << this << " - Reading event, time = "
+                       //      << ev_time << " - " << start << " => " << ev_time - start
+                       //      << ", size = " << ev_size << std::endl;
                        
                        ev_time -= start;
                        
                        uint8_t* write_loc = dst.reserve(ev_time, ev_size);
                        if (write_loc == NULL) {
-                               std::cerr << "MRB: Unable to reserve space in buffer, event skipped";
+                               //std::cerr << "MRB: Unable to reserve space in buffer, event skipped";
                                continue;
                        }
                        
-                       success = MidiRingBufferBase<uint8_t>::full_read(ev_size, write_loc);
+                       success = Evoral::EventRingBuffer::full_read(ev_size, write_loc);
                
                        if (success) {
                                if (is_channel_event(status) && get_channel_mode() == ForceChannel) {
                                        write_loc[0] = (write_loc[0] & 0xF0) | (get_channel_mask() & 0x0F);
                                }
                                ++count;
-                               //printf("MRB - read event at time %lf\n", ev_time);
+                               //std::cerr << "MRB - read event at time " << ev_time << std::endl;
                        } else {
-                               std::cerr << "MRB: READ ERROR (data)" << std::endl;
+                               //std::cerr << "MRB: READ ERROR (data)" << std::endl;
                        }
                        
                } else {
-                       printf("MRB (start %u) - Skipping event at (too early) time %f\n", start, ev_time);
+                       //std::cerr << "MRB (start " << start << ") - Skipping event at (too early) time " << ev_time << std::endl;
                }
        }
        
-       //printf("(R) read space: %zu\n", read_space());
+       //std::cerr << "MTB read space: " << read_space() << std::endl;
 
        return count;
 }
index 5c390c1039eae0e0f2cebd41ef5024ab828ea2cb..5ccbd4a6e3850d9d319d10eb3c4be99ba3fee74d 100644 (file)
@@ -50,20 +50,6 @@ public:
                init_metadata(type);
        }
        
-#if 0
-       Parameter(AutomationType type, double min, double max, double normal)
-               : Evoral::Parameter((uint32_t)type, 0, 0, min, max, normal)
-       {}
-       
-       Parameter(const Parameter& copy)
-               : Evoral::Parameter(copy)
-       {
-               _min = copy._min;
-               _max = copy._max;
-               _normal = copy._max;
-       }
-#endif
-
        Parameter(const Evoral::Parameter& copy)
                : Evoral::Parameter(copy)
        {
diff --git a/libs/ardour/event_type_map.cc b/libs/ardour/event_type_map.cc
new file mode 100644 (file)
index 0000000..cd78fd0
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+    Copyright (C) 2008 Paul Davis
+    Author: Dave Robillard
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <ardour/types.h>
+#include <ardour/event_type_map.h>
+#include <evoral/Parameter.hpp>
+#include <evoral/midi_events.h>
+
+namespace ARDOUR {
+
+EventTypeMap EventTypeMap::event_type_map;
+
+bool
+EventTypeMap::type_is_midi(uint32_t type) const
+{
+       return (type >= MidiCCAutomation) && (type <= MidiChannelPressureAutomation);
+}
+
+uint8_t
+EventTypeMap::parameter_midi_type(const Evoral::Parameter& param) const
+{
+       switch (param.type()) {
+       case MidiCCAutomation:              return MIDI_CMD_CONTROL; break; 
+       case MidiPgmChangeAutomation:       return MIDI_CMD_PGM_CHANGE; break; 
+       case MidiChannelPressureAutomation: return MIDI_CMD_CHANNEL_PRESSURE; break; 
+       case MidiPitchBenderAutomation:     return MIDI_CMD_BENDER; break; 
+       default: return 0;
+       }
+}
+
+uint32_t
+EventTypeMap::midi_event_type(uint8_t status) const
+{
+       switch (status & 0xF0) {
+       case MIDI_CMD_CONTROL:          return MidiCCAutomation; break;
+       case MIDI_CMD_PGM_CHANGE:       return MidiPgmChangeAutomation; break;
+       case MIDI_CMD_CHANNEL_PRESSURE: return MidiChannelPressureAutomation; break;
+       case MIDI_CMD_BENDER:           return MidiPitchBenderAutomation; break;
+       default: return 0;
+       }
+}
+
+} // namespace ARDOUR
+
index 199a2fd1a43e0f0a2d08e1cbfdf234a987bdf595..370991be5fa4066a7eef299bd8234d9ed5becb8d 100644 (file)
@@ -305,7 +305,7 @@ static void
 write_midi_data_to_new_files (SMFReader* source, Session::import_status& status,
                               vector<boost::shared_ptr<Source> >& newfiles)
 {
-       Evoral::Event ev(0.0, 4, NULL, true);
+       Evoral::Event ev(0, 0.0, 4, NULL, true);
 
        status.progress = 0.0f;
 
index 363cbe242f8b5c27e0d2d228d813b5a564cafb38..5dee1d98451d9089d80c44e1e34ccac3aecad3ce 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 Evoral::Event& ev = *i;
+                       const Evoral::MIDIEvent& 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 afd8481795f5937ad96f748967adda0534a0de04..f1f6b9b633450e8b8e8b84fc37aaf8326923b266 100644 (file)
@@ -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 Evoral::Event& ev = msrc[i];
+               const Evoral::MIDIEvent& ev = msrc[i];
                if (ev.time() >= offset && ev.time() < offset+nframes) {
                        //cout << "MidiBuffer::read_from got event, " << int(ev.type()) << " time: " << ev.time() << " buffer size: " << _size << 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 Evoral::Event& ev)
+MidiBuffer::push_back(const Evoral::MIDIEvent& ev)
 {
        if (_size == _capacity)
                return false;
@@ -262,8 +262,8 @@ MidiBuffer::merge(const MidiBuffer& a, const MidiBuffer& b)
                        push_back(b[b_index]);
                        ++b_index;
                } else {
-                       const Evoral::Event& a_ev = a[a_index];
-                       const Evoral::Event& b_ev = b[b_index];
+                       const Evoral::MIDIEvent& a_ev = a[a_index];
+                       const Evoral::MIDIEvent& b_ev = b[b_index];
 
                        if (a_ev.time() <= b_ev.time()) {
                                push_back(a_ev);
index b2991c1a7f11eb8d8ed96e18ee518bc2f01c3747..bb7f2931f4ee020df198fe0b40ad60f2965b8003 100644 (file)
@@ -520,9 +520,9 @@ 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 Evoral::Event& ev = *port_iter;
+                       const Evoral::MIDIEvent& ev = *port_iter;
                        assert(ev.buffer());
-                       _capture_buf->write(ev.time() + transport_frame, ev.size(), ev.buffer());
+                       _capture_buf->write(ev.time() + transport_frame, ev.type(), ev.size(), ev.buffer());
                        ++port_iter;
                }
        
index c22820c83c090bfeb572e8359b89d1f877b324e9..18b37689bd8b6092a241cd49ccdc5208ee36ac9a 100644 (file)
@@ -170,9 +170,9 @@ MidiModel::DeltaCommand::marshal_note(const boost::shared_ptr<Evoral::Note> note
        time_str << int(note->time());
        xml_note->add_property("time", time_str.str());
 
-       ostringstream duration_str(ios::ate);
-       duration_str <<(unsigned int) note->duration();
-       xml_note->add_property("duration", duration_str.str());
+       ostringstream length_str(ios::ate);
+       length_str <<(unsigned int) note->length();
+       xml_note->add_property("length", length_str.str());
 
        ostringstream velocity_str(ios::ate);
        velocity_str << (unsigned int) note->velocity();
@@ -195,15 +195,15 @@ boost::shared_ptr<Evoral::Note> MidiModel::DeltaCommand::unmarshal_note(XMLNode
        istringstream time_str(xml_note->property("time")->value());
        time_str >> time;
 
-       unsigned int duration;
-       istringstream duration_str(xml_note->property("duration")->value());
-       duration_str >> duration;
+       unsigned int length;
+       istringstream length_str(xml_note->property("length")->value());
+       length_str >> length;
 
        unsigned int velocity;
        istringstream velocity_str(xml_note->property("velocity")->value());
        velocity_str >> velocity;
 
-       boost::shared_ptr<Evoral::Note> note_ptr(new Evoral::Note(channel, time, duration, note, velocity));
+       boost::shared_ptr<Evoral::Note> note_ptr(new Evoral::Note(channel, time, length, note, velocity));
        return note_ptr;
 }
 
index 745e5bf1b75975206266a5bfc1e623edb0222567..d60aba8bbccc593d7eb692af8ef7e1770c6bbc82 100644 (file)
@@ -723,7 +723,8 @@ MidiTrack::write_immediate_event(size_t size, const uint8_t* buf)
                printf("%X ", buf[i]);
        }
        printf("\n");*/
-       return (_immediate_events.write(0, size, buf) == size);
+       const uint32_t type = EventTypeMap::instance().midi_event_type(buf[0]);
+       return (_immediate_events.write(0, type, size, buf) == size);
 }
 
 void
index ff8925edd95039d440f45a79d7398a1956c1e679..3b5a264a7b84ff77d62c9fca9ab199be9995a0fd 100644 (file)
@@ -72,12 +72,12 @@ Quantize::run (boost::shared_ptr<Region> r)
        for (Evoral::Sequence::Notes::iterator i = model->notes().begin();
                        i != model->notes().end(); ++i) {
                const double new_time = lrint((*i)->time() / q_frames) * q_frames;
-               double new_dur = lrint((*i)->duration() / q_frames) * q_frames;
+               double new_dur = lrint((*i)->length() / q_frames) * q_frames;
                if (new_dur == 0.0)
                        new_dur = q_frames;
                
                (*i)->set_time(new_time);
-               (*i)->set_duration(new_dur);
+               (*i)->set_length(new_dur);
        }
 
        model->set_edited(true);
index 2d5c0af0d599276f3fe6d4ca8d9f348c1d6819fb..03a8b98199343bce9289065704f375c8a4e6fa23 100644 (file)
@@ -39,6 +39,7 @@
 #include <ardour/tempo.h>
 #include <ardour/audioengine.h>
 #include <ardour/smf_reader.h>
+#include <ardour/event_type_map.h>
 
 #include "i18n.h"
 
@@ -385,6 +386,7 @@ SMFSource::read_unlocked (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, n
 
        // Output parameters for read_event (which will allocate scratch in buffer as needed)
        uint32_t ev_delta_t = 0;
+       uint32_t ev_type = 0;
        uint32_t ev_size = 0;
        uint8_t* ev_buffer = 0;
 
@@ -407,6 +409,8 @@ SMFSource::read_unlocked (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, n
                        break;
                }
                
+               ev_type = EventTypeMap::instance().midi_event_type(ev_buffer[0]);
+               
                time += ev_delta_t; // accumulate delta time
 
                if (ret == 0) { // meta-event (skipped, just accumulate time)
@@ -419,7 +423,7 @@ SMFSource::read_unlocked (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, n
                                        ((time / (double)_ppqn) * frames_per_beat)) + stamp_offset;
 
                        if (ev_frame_time <= start + cnt)
-                               dst.write(ev_frame_time - negative_stamp_offset, ev_size, ev_buffer);
+                               dst.write(ev_frame_time - negative_stamp_offset, ev_type, ev_size, ev_buffer);
                        else
                                break;
                }
@@ -441,8 +445,9 @@ SMFSource::write_unlocked (MidiRingBuffer& src, nframes_t cnt)
 {
        _write_data_count = 0;
                
-       double time;
-       size_t size;
+       EventTime time;
+       EventType type;
+       uint32_t  size;
 
        size_t buf_capacity = 4;
        uint8_t* buf = (uint8_t*)malloc(buf_capacity);
@@ -450,14 +455,14 @@ SMFSource::write_unlocked (MidiRingBuffer& src, nframes_t cnt)
        if (_model && ! _model->writing())
                _model->start_write();
 
-       Evoral::Event ev(0.0, 4, NULL, true);
+       Evoral::MIDIEvent ev(0, 0.0, 4, NULL, true);
 
        while (true) {
-               bool ret = src.full_peek(sizeof(double), (uint8_t*)&time);
+               bool ret = src.peek_time(&time);
                if (!ret || time - _timeline_position > _length + cnt)
                        break;
 
-               ret = src.read_prefix(&time, &size);
+               ret = src.read_prefix(&time, &type, &size);
                if (!ret)
                        break;
 
@@ -476,6 +481,7 @@ SMFSource::write_unlocked (MidiRingBuffer& src, nframes_t cnt)
                time -= _timeline_position;
                
                ev.set(buf, size, time);
+               ev.set_event_type(EventTypeMap::instance().midi_event_type(ev.buffer()[0]));
                if (! (ev.is_channel_event() || ev.is_smf_meta_event() || ev.is_sysex()) ) {
                        //cerr << "SMFSource: WARNING: caller tried to write non SMF-Event of type " << std::hex << int(ev.buffer()[0]) << endl;
                        continue;
index 6141f10e4f084a434c6d111746a316e8e281adb3..2b18d59107d95ed477145270a691708fc8b011f0 100644 (file)
@@ -21,16 +21,17 @@ if evoral['IS_OSX']:
 domain = 'evoral'
 
 evoral.Append(DOMAIN=domain, MAJOR=1, MINOR=0, MICRO=0)
-evoral.Append(CXXFLAGS="-DEVENT_WITH_XML")
+evoral.Append(CXXFLAGS="-DEVORAL_MIDI_XML")
 
 sources = Split("""
 src/Control.cpp
 src/ControlList.cpp
 src/ControlSet.cpp
+src/Curve.cpp
 src/Event.cpp
+src/MIDIEvent.cpp
 src/Note.cpp
 src/Sequence.cpp
-src/Curve.cpp
 """)
 
 libevoral = evoral.SharedLibrary('evoral', [ sources ])
index beffb01eb57f39bfa898fa1c03f4027042160639..1dd081a5b90575336e0b10e45f2abdd667405044 100644 (file)
 #include <cstring>
 #include <sstream>
 #include <assert.h>
-#include <evoral/midi_events.h>
-#ifdef EVENT_WITH_XML
-       #include <pbd/xml++.h>
-#endif
+#include <evoral/types.hpp>
+
 
 /** 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 EVENT_ALLOW_ALLOC 1
-
-//#define EVENT_WITH_XML
+#define EVORAL_EVENT_ALLOC 1
 
 namespace Evoral {
 
 
-/** Identical to jack_midi_event_t, but with double timestamp
+/** An event (much like a type generic jack_midi_event_t)
  *
  * 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 EVENT_ALLOW_ALLOC
-       Event(double t=0, uint32_t s=0, uint8_t* b=NULL, bool owns_buffer=false);
+#ifdef EVORAL_EVENT_ALLOC
+       Event(EventType type=0, EventTime t=0, uint32_t s=0, uint8_t* b=NULL, bool alloc=false);
        
        /** Copy \a copy.
         * 
-        * If \a owns_buffer is true, the buffer will be copied and this method
+        * If \a alloc 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);
-       
-#ifdef EVENT_WITH_XML
-       /** Event from XML ala http://www.midi.org/dtds/MIDIEvents10.dtd
-        */
-       Event(const XMLNode& event);
-       
-       /** Event to XML ala http://www.midi.org/dtds/MIDIEvents10.dtd
-        */
-       boost::shared_ptr<XMLNode> to_xml() const;
-#endif
+       Event(const Event& copy, bool alloc);
        
        ~Event();
 
        inline const Event& operator=(const Event& copy) {
+               _type = copy._type;
                _time = copy._time;
                if (_owns_buffer) {
                        if (copy._buffer) {
@@ -96,12 +83,13 @@ struct Event {
                        _owns_buffer = false;
                }
 
+               _type = copy._type;
                _time = copy._time;
                _size = copy._size;
                _buffer = copy._buffer;
        }
        
-       inline void set(uint8_t* buf, size_t size, double t) {
+       inline void set(uint8_t* buf, uint32_t size, EventTime t) {
                if (_owns_buffer) {
                        if (_size < size) {
                                _buffer = (uint8_t*) ::realloc(_buffer, size);
@@ -111,11 +99,14 @@ struct Event {
                        _buffer = buf;
                }
 
-               _size = size;
                _time = t;
+               _size = size;
        }
 
        inline bool operator==(const Event& other) const {
+               if (_type != other._type)
+                       return false;
+
                if (_time != other._time)
                        return false;
 
@@ -125,7 +116,7 @@ struct Event {
                if (_buffer == other._buffer)
                        return true;
 
-               for (size_t i=0; i < _size; ++i)
+               for (uint32_t i=0; i < _size; ++i)
                        if (_buffer[i] != other._buffer[i])
                                return false;
 
@@ -136,7 +127,7 @@ struct Event {
 
        inline bool owns_buffer() const { return _owns_buffer; }
        
-       inline void set_buffer(size_t size, uint8_t* buf, bool own) {
+       inline void set_buffer(uint32_t size, uint8_t* buf, bool own) {
                if (_owns_buffer) {
                        free(_buffer);
                        _buffer = NULL;
@@ -146,7 +137,7 @@ struct Event {
                _owns_buffer = own;
        }
 
-       inline void realloc(size_t size) {
+       inline void realloc(uint32_t size) {
                if (_owns_buffer) {
                        if (size > _size)
                                _buffer = (uint8_t*) ::realloc(_buffer, size);
@@ -157,57 +148,37 @@ struct Event {
 
                _size = size;
        }
-
+       
+       inline void clear() {
+               _type = 0;
+               _time = 0;
+               _size = 0;
+               _buffer = NULL;
+       }
 
 #else
 
        inline void set_buffer(uint8_t* buf) { _buffer = buf; }
 
-#endif // EVENT_ALLOW_ALLOC
+#endif // EVORAL_EVENT_ALLOC
 
-       inline double      time()                  const { return _time; }
-       inline double&     time()                        { return _time; }
+       inline EventType   event_type()            const { return _type; }
+       inline void        set_event_type(EventType t)   { _type = t; }
+       inline EventTime   time()                  const { return _time; }
+       inline EventTime&  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 void        set_type(uint8_t type)        { _buffer[0] =   (0x0F & _buffer[0])
-                                                                       | (0xF0 & type); }
-       inline uint8_t     channel()               const { return (_buffer[0] & 0x0F); }
-       inline void        set_channel(uint8_t channel)  { _buffer[0] =   (0xF0 & _buffer[0])
-                                                                       | (0x0F & channel); }
-       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_pitch_bender()       const { return (type() == MIDI_CMD_BENDER); }
-       inline bool        is_pgm_change()         const { return (type() == MIDI_CMD_PGM_CHANGE); }
-       inline bool        is_note()               const { return (is_note_on() || is_note_off()); }
-       inline bool        is_aftertouch()         const { return (type() == MIDI_CMD_NOTE_PRESSURE); }
-       inline bool        is_channel_aftertouch() const { return (type() == MIDI_CMD_CHANNEL_PRESSURE); }
-       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 uint8_t     pitch_bender_lsb()      const { return (_buffer[1]); }
-       inline uint8_t     pitch_bender_msb()      const { return (_buffer[2]); }
-       inline uint16_t    pitch_bender_value()    const { return ( ((0x7F & _buffer[2]) << 7)
-                                                                  | (0x7F & _buffer[1]) ); }
-       inline uint8_t     pgm_number()            const { return (_buffer[1]); }
-       inline void        set_pgm_number(uint8_t number){ _buffer[1] = number; }
-       inline uint8_t     aftertouch()            const { return (_buffer[1]); }
-       inline uint8_t     channel_aftertouch()    const { return (_buffer[1]); }
-       inline bool        is_channel_event()      const { return (0x80 <= type()) && (type() <= 0xE0); }
-       inline bool        is_smf_meta_event()     const { return _buffer[0] == 0xFF; }
-       inline bool        is_sysex()              const { return    _buffer[0] == 0xF0
-                                                                 || _buffer[0] == 0xF7; }
+
        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 */
+protected:
+       EventType _type;   /**< Type of event (application relative, NOT MIDI 'type') */
+       EventTime _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 EVENT_ALLOW_ALLOC
+#ifdef EVORAL_EVENT_ALLOC
        bool _owns_buffer; /**< Whether buffer is locally allocated */
 #endif
 };
diff --git a/libs/evoral/evoral/EventRingBuffer.hpp b/libs/evoral/evoral/EventRingBuffer.hpp
new file mode 100644 (file)
index 0000000..05ec921
--- /dev/null
@@ -0,0 +1,95 @@
+/* This file is part of Evoral.
+ * Copyright (C) 2008 Dave Robillard <http://drobilla.net>
+ * 
+ * Evoral 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.
+ * 
+ * Evoral 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 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef EVORAL_EVENT_RING_BUFFER_HPP
+#define EVORAL_EVENT_RING_BUFFER_HPP
+
+#include <glib.h>
+#include <evoral/RingBuffer.hpp>
+#include <evoral/EventSink.hpp>
+#include <evoral/types.hpp>
+
+#include <iostream>
+using namespace std;
+
+namespace Evoral {
+
+
+/** A RingBuffer of events (generic time-stamped binary "blobs").
+ *
+ * This packs a timestamp, size, and size bytes of data flat into the buffer.
+ * Useful for MIDI events, OSC messages, etc.
+ */
+class EventRingBuffer : public Evoral::RingBuffer<uint8_t>, public Evoral::EventSink {
+public:
+
+       /** @param capacity Ringbuffer capacity in bytes.
+        */
+       EventRingBuffer(size_t capacity) : RingBuffer<uint8_t>(capacity)
+       {}
+
+       size_t capacity() const { return _size; }
+       
+       bool peek_time(EventTime* time);
+
+       uint32_t write(EventTime  time, EventType  type, uint32_t  size, const uint8_t* buf);
+       bool     read (EventTime* time, EventType* type, uint32_t* size,       uint8_t* buf);
+};
+
+
+inline bool
+EventRingBuffer::peek_time(EventTime* time)
+{
+       bool success = RingBuffer<uint8_t>::full_peek(sizeof(EventTime), (uint8_t*)time);
+       return success;
+}
+
+
+inline bool
+EventRingBuffer::read(EventTime* time, EventType* type, uint32_t* size, uint8_t* buf)
+{
+       bool success = RingBuffer<uint8_t>::full_read(sizeof(EventTime), (uint8_t*)time);
+       if (success)
+               success = RingBuffer<uint8_t>::full_read(sizeof(EventType), (uint8_t*)type);
+       if (success)
+               success = RingBuffer<uint8_t>::full_read(sizeof(uint32_t), (uint8_t*)size);
+       if (success)
+               success = RingBuffer<uint8_t>::full_read(*size, buf);
+       
+       return success;
+}
+
+
+inline uint32_t
+EventRingBuffer::write(EventTime time, EventType type, uint32_t size, const uint8_t* buf)
+{
+       if (write_space() < (sizeof(EventTime) + sizeof(EventType) + sizeof(uint32_t) + size)) {
+               return 0;
+       } else {
+               RingBuffer<uint8_t>::write(sizeof(EventTime), (uint8_t*)&time);
+               RingBuffer<uint8_t>::write(sizeof(EventType), (uint8_t*)&type);
+               RingBuffer<uint8_t>::write(sizeof(uint32_t), (uint8_t*)&size);
+               RingBuffer<uint8_t>::write(size, buf);
+               return size;
+       }
+}
+
+
+} // namespace Evoral
+
+#endif // EVORAL_EVENT_RING_BUFFER_HPP
+
index 5f0610e15f354efed387fb18b8abf1a66bed1886..dfa746d870be08907d3b25010a048f02d93c0b47 100644 (file)
@@ -29,9 +29,7 @@ namespace Evoral {
 class EventSink {
 public:
        virtual ~EventSink() {}
-       virtual size_t write(timestamp_t    time,
-                            uint32_t       size,
-                            const uint8_t* buf) = 0;
+       virtual uint32_t write(EventTime time, EventType type, uint32_t size, const uint8_t* buf) = 0;
 };
 
 
diff --git a/libs/evoral/evoral/MIDIEvent.hpp b/libs/evoral/evoral/MIDIEvent.hpp
new file mode 100644 (file)
index 0000000..863103a
--- /dev/null
@@ -0,0 +1,89 @@
+/* This file is part of Evoral.
+ * Copyright (C) 2008 Dave Robillard <http://drobilla.net>
+ * Copyright (C) 2000-2008 Paul Davis
+ * 
+ * Evoral 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.
+ * 
+ * Evoral 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 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef EVORAL_MIDI_EVENT_HPP
+#define EVORAL_MIDI_EVENT_HPP
+
+#include <evoral/Event.hpp>
+#include <evoral/midi_events.h>
+#ifdef EVORAL_MIDI_XML
+       #include <pbd/xml++.h>
+#endif
+
+namespace Evoral {
+
+/** MIDI helper functions for an Event.
+ *
+ * This class contains no data, an event can be cast to a MIDIEvent
+ * but the application must make sure the event actually contains
+ * valid MIDI data for these functions to make sense.
+ */
+struct MIDIEvent : public Event {
+       MIDIEvent(EventType type=0, EventTime t=0, uint32_t s=0, uint8_t* b=NULL, bool alloc=false)
+               : Event(type, t, s, b, alloc)
+       {}
+       
+       MIDIEvent(const Event& copy, bool alloc)
+               : Event(copy, alloc)
+       {}
+
+#ifdef EVORAL_MIDI_XML
+       /** Event from XML ala http://www.midi.org/dtds/MIDIEvents10.dtd
+        */
+       MIDIEvent(const XMLNode& event);
+       
+       /** Event to XML ala http://www.midi.org/dtds/MIDIEvents10.dtd
+        */
+       boost::shared_ptr<XMLNode> to_xml() const;
+#endif
+
+       inline uint8_t  type()                  const { return (_buffer[0] & 0xF0); }
+       inline void     set_type(uint8_t type)        { _buffer[0] =   (0x0F & _buffer[0])
+                                                                    | (0xF0 & type); }
+       inline uint8_t  channel()               const { return (_buffer[0] & 0x0F); }
+       inline void     set_channel(uint8_t channel)  { _buffer[0] =   (0xF0 & _buffer[0])
+                                                                    | (0x0F & channel); }
+       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_pitch_bender()       const { return (type() == MIDI_CMD_BENDER); }
+       inline bool     is_pgm_change()         const { return (type() == MIDI_CMD_PGM_CHANGE); }
+       inline bool     is_note()               const { return (is_note_on() || is_note_off()); }
+       inline bool     is_aftertouch()         const { return (type() == MIDI_CMD_NOTE_PRESSURE); }
+       inline bool     is_channel_pressure()   const { return (type() == MIDI_CMD_CHANNEL_PRESSURE); }
+       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 uint8_t  pitch_bender_lsb()      const { return (_buffer[1]); }
+       inline uint8_t  pitch_bender_msb()      const { return (_buffer[2]); }
+       inline uint16_t pitch_bender_value()    const { return ( ((0x7F & _buffer[2]) << 7)
+                                                               | (0x7F & _buffer[1]) ); }
+       inline uint8_t  pgm_number()            const { return (_buffer[1]); }
+       inline void     set_pgm_number(uint8_t number){ _buffer[1] = number; }
+       inline uint8_t  aftertouch()            const { return (_buffer[1]); }
+       inline uint8_t  channel_pressure()      const { return (_buffer[1]); }
+       inline bool     is_channel_event()      const { return (0x80 <= type()) && (type() <= 0xE0);    }
+       inline bool     is_smf_meta_event()     const { return _buffer[0] == 0xFF; }
+       inline bool     is_sysex()              const { return    _buffer[0] == 0xF0
+                                                                 || _buffer[0] == 0xF7; }
+};
+
+} // namespace Evoral
+
+#endif // EVORAL_MIDI_EVENT_HPP
index e2bfdc3fb089ab3d574da6260da9592c003bcb39..744357f5b81889f15e5ed8a2066bec6e731c6f56 100644 (file)
@@ -31,8 +31,8 @@ struct ProgramChange : public Parameter {
        ProgramChange(uint32_t pc_type, uint8_t channel) : Parameter(pc_type, 0, channel) {}
 };
 
-struct ChannelAftertouch : public Parameter {
-       ChannelAftertouch(uint32_t ca_type, uint32_t channel) : Parameter(ca_type, 0, channel) {}
+struct ChannelPressure : public Parameter {
+       ChannelPressure(uint32_t ca_type, uint32_t channel) : Parameter(ca_type, 0, channel) {}
 };
 
 struct PitchBender : public Parameter {
index 76095e733c1d26bcad97c9f329361d9489ff376b..75a8046237d784d0ad3b949e3dad9c0aa3393109 100644 (file)
 #define EVORAL_NOTE_HPP
 
 #include <stdint.h>
-#include <evoral/Event.hpp>
+#include <evoral/MIDIEvent.hpp>
 
 namespace Evoral {
 
 
 /** An abstract (protocol agnostic) note.
  *
- * Currently a note is defined as (on event, duration, off event).
+ * Currently a note is defined as (on event, length, off event).
  */
 class Note {
 public:
-       Note(uint8_t chan=0, double time=0, double dur=0, uint8_t note=0, uint8_t vel=0x40);
+       Note(uint8_t chan=0, EventTime time=0, EventLength len=0, uint8_t note=0, uint8_t vel=0x40);
        Note(const Note& copy);
        ~Note();
 
@@ -40,26 +40,26 @@ public:
        inline bool operator==(const Note& other) {
                return time() == other.time() && 
                 note() == other.note() && 
-                duration() == other.duration() &&
+                length() == other.length() &&
                 velocity() == other.velocity() &&
                 channel()  == other.channel();
        }
 
-       inline double  time()     const { return _on_event.time(); }
-       inline double  end_time() const { return _off_event.time(); }
-       inline uint8_t note()     const { return _on_event.note(); }
-       inline uint8_t velocity() const { return _on_event.velocity(); }
-       inline double  duration() const { return _off_event.time() - _on_event.time(); }
-       inline uint8_t channel()  const { 
+       inline EventTime   time()     const { return _on_event.time(); }
+       inline EventTime   end_time() const { return _off_event.time(); }
+       inline uint8_t     note()     const { return _on_event.note(); }
+       inline uint8_t     velocity() const { return _on_event.velocity(); }
+       inline EventLength length()   const { return _off_event.time() - _on_event.time(); }
+       inline uint8_t     channel()  const {
                assert(_on_event.channel() == _off_event.channel()); 
            return _on_event.channel(); 
        }
 
-       inline void set_time(double t)      { _off_event.time() = t + duration(); _on_event.time() = t; }
-       inline void set_note(uint8_t n)     { _on_event.buffer()[1] = n; _off_event.buffer()[1] = n; }
-       inline void set_velocity(uint8_t n) { _on_event.buffer()[2] = n; }
-       inline void set_duration(double d)  { _off_event.time() = _on_event.time() + d; }
-       inline void set_channel(uint8_t c)  { _on_event.set_channel(c);  _off_event.set_channel(c); }
+       inline void set_time(EventTime t)     { _off_event.time() = t + length(); _on_event.time() = t; }
+       inline void set_note(uint8_t n)       { _on_event.buffer()[1] = n; _off_event.buffer()[1] = n; }
+       inline void set_velocity(uint8_t n)   { _on_event.buffer()[2] = n; }
+       inline void set_length(EventLength l) { _off_event.time() = _on_event.time() + l; }
+       inline void set_channel(uint8_t c)    { _on_event.set_channel(c);  _off_event.set_channel(c); }
 
        inline       Event& on_event()        { return _on_event; }
        inline const Event& on_event()  const { return _on_event; }
@@ -68,8 +68,8 @@ public:
 
 private:
        // Event buffers are self-contained
-       Event _on_event;
-       Event _off_event;
+       MIDIEvent _on_event;
+       MIDIEvent _off_event;
 };
 
 
diff --git a/libs/evoral/evoral/RingBuffer.hpp b/libs/evoral/evoral/RingBuffer.hpp
new file mode 100644 (file)
index 0000000..a27e97a
--- /dev/null
@@ -0,0 +1,226 @@
+/* This file is part of Evoral.
+ * Copyright (C) 2008 Dave Robillard <http://drobilla.net>
+ * 
+ * Evoral 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.
+ * 
+ * Evoral 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 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef EVORAL_RING_BUFFER_HPP
+#define EVORAL_RING_BUFFER_HPP
+
+#include <cassert>
+#include <iostream>
+#include <glib.h>
+
+namespace Evoral {
+
+
+/** A lock-free RingBuffer.
+ * Read/Write realtime safe.
+ * Single-reader Single-writer thread safe.
+ */
+template <typename T>
+class RingBuffer {
+public:
+
+       /** @param size Size in bytes.
+        */
+       RingBuffer(size_t size)
+               : _size(size)
+               , _buf(new T[size])
+       {
+               reset();
+               assert(read_space() == 0);
+               assert(write_space() == size - 1);
+       }
+       
+       virtual ~RingBuffer() {
+               delete[] _buf;
+       }
+
+       /** Reset(empty) the ringbuffer.
+        * NOT thread safe.
+        */
+       void reset() {
+               g_atomic_int_set(&_write_ptr, 0);
+               g_atomic_int_set(&_read_ptr, 0);
+       }
+
+       size_t write_space() const {
+               const size_t w = g_atomic_int_get(&_write_ptr);
+               const size_t r = g_atomic_int_get(&_read_ptr);
+               
+               if (w > r) {
+                       return ((r - w + _size) % _size) - 1;
+               } else if (w < r) {
+                       return (r - w) - 1;
+               } else {
+                       return _size - 1;
+               }
+       }
+       
+       size_t read_space() const {
+               const size_t w = g_atomic_int_get(&_write_ptr);
+               const size_t r = g_atomic_int_get(&_read_ptr);
+               
+               if (w > r) {
+                       return w - r;
+               } else {
+                       return (w - r + _size) % _size;
+               }
+       }
+
+       size_t capacity() const { return _size; }
+
+       size_t peek(size_t size, T* dst);
+       bool   full_peek(size_t size, T* dst);
+
+       size_t read(size_t size, T* dst);
+       bool   full_read(size_t size, T* dst);
+
+       bool   skip(size_t size);
+       
+       void   write(size_t size, const T* src);
+
+protected:
+       mutable int _write_ptr;
+       mutable int _read_ptr;
+       
+       size_t _size; ///< Size (capacity) in bytes
+       T*     _buf;  ///< size, event, size, event...
+};
+
+
+/** Peek at the ringbuffer (read w/o advancing read pointer).
+ *
+ * Note that a full read may not be done if the data wraps around.
+ * Caller must check return value and call again if necessary, or use the 
+ * full_peek method which does this automatically.
+ */
+template<typename T>
+size_t
+RingBuffer<T>::peek(size_t size, T* dst)
+{
+       const size_t priv_read_ptr = g_atomic_int_get(&_read_ptr);
+
+       const size_t read_size = (priv_read_ptr + size < _size)
+                       ? size
+                       : _size - priv_read_ptr;
+       
+       memcpy(dst, &_buf[priv_read_ptr], read_size);
+
+       return read_size;
+}
+
+
+template<typename T>
+bool
+RingBuffer<T>::full_peek(size_t size, T* dst)
+{
+       if (read_space() < size) {
+               return false;
+       }
+
+       const size_t read_size = peek(size, dst);
+       
+       if (read_size < size) {
+               peek(size - read_size, dst + read_size);
+       }
+
+       return true;
+}
+
+
+/** Read from the ringbuffer.
+ *
+ * Note that a full read may not be done if the data wraps around.
+ * Caller must check return value and call again if necessary, or use the 
+ * full_read method which does this automatically.
+ */
+template<typename T>
+size_t
+RingBuffer<T>::read(size_t size, T* dst)
+{
+       const size_t priv_read_ptr = g_atomic_int_get(&_read_ptr);
+
+       const size_t read_size = (priv_read_ptr + size < _size)
+                       ? size
+                       : _size - priv_read_ptr;
+       
+       memcpy(dst, &_buf[priv_read_ptr], read_size);
+        
+       g_atomic_int_set(&_read_ptr, (priv_read_ptr + read_size) % _size);
+
+       return read_size;
+}
+
+
+template<typename T>
+bool
+RingBuffer<T>::full_read(size_t size, T* dst)
+{
+       if (read_space() < size) {
+               return false;
+       }
+
+       const size_t read_size = read(size, dst);
+       
+       if (read_size < size) {
+               read(size - read_size, dst + read_size);
+       }
+
+       return true;
+}
+
+
+template<typename T>
+bool
+RingBuffer<T>::skip(size_t size)
+{
+       if (read_space() < size) {
+               std::cerr << "WARNING: Attempt to skip past end of MIDI ring buffer" << std::endl;
+               return false;
+       }
+       
+       const size_t priv_read_ptr = g_atomic_int_get(&_read_ptr);
+       g_atomic_int_set(&_read_ptr, (priv_read_ptr + size) % _size);
+
+       return true;
+}
+
+
+template<typename T>
+inline void
+RingBuffer<T>::write(size_t size, const T* src)
+{
+       const size_t priv_write_ptr = g_atomic_int_get(&_write_ptr);
+       
+       if (priv_write_ptr + size <= _size) {
+               memcpy(&_buf[priv_write_ptr], src, size);
+               g_atomic_int_set(&_write_ptr, (priv_write_ptr + size) % _size);
+       } else {
+               const size_t this_size = _size - priv_write_ptr;
+               assert(this_size < size);
+               assert(priv_write_ptr + this_size <= _size);
+               memcpy(&_buf[priv_write_ptr], src, this_size);
+               memcpy(&_buf[0], src+this_size, size - this_size);
+               g_atomic_int_set(&_write_ptr, size - this_size);
+       }
+}
+
+       
+} // namespace Evoral
+
+#endif // EVORAL_RING_BUFFER_HPP
+
+
index 73ddaca21b4c84cf7baad3c550ac3d1b6e808acc..b029e51f33da58eb53153137098a77deace952de 100644 (file)
 #include <evoral/Note.hpp>
 #include <evoral/Parameter.hpp>
 #include <evoral/ControlSet.hpp>
+#include <evoral/ControlList.hpp>
 
 namespace Evoral {
 
+class TypeMap;
 class EventSink;
 class Note;
 class Event;
-class ControlList;
 
-
-/** This class keeps track of the current x and y for a control
+/** An iterator over (the x axis of) a 2-d double coordinate space.
  */
 class ControlIterator {
 public:
+       ControlIterator(boost::shared_ptr<const ControlList> al, double ax, double ay)
+               : list(al)
+               , x(ax)
+               , y(ay)
+       {}
+
        boost::shared_ptr<const ControlList> list;
        double x;
        double y;
-       
-       ControlIterator(boost::shared_ptr<const ControlList> a_list,
-                       double a_x,
-                       double a_y)
-               : list(a_list)
-               , x(a_x)
-               , y(a_y)
-       {}
 };
 
 
@@ -62,7 +60,7 @@ public:
  * Controller data is represented as a list of time-stamped float values. */
 class Sequence : virtual public ControlSet {
 public:
-       Sequence(size_t size=0);
+       Sequence(const TypeMap& type_map, size_t size=0);
        
        bool read_locked() { return _read_iter.locked(); }
 
@@ -115,7 +113,7 @@ public:
        /** Read iterator */
        class const_iterator {
        public:
-               const_iterator(const Sequence& seq, double t);
+               const_iterator(const Sequence& seq, EventTime t);
                ~const_iterator();
 
                inline bool valid() const { return !_is_end && _event; }
@@ -144,18 +142,20 @@ public:
                
                mutable ActiveNotes _active_notes;
 
-               bool                                   _is_end;
-               bool                                   _locked;
-               Notes::const_iterator                  _note_iter;
-               std::vector<ControlIterator>           _control_iters;
-               std::vector<ControlIterator>::iterator _control_iter;
+               typedef std::vector<ControlIterator> ControlIterators;
+
+               bool                       _is_end;
+               bool                       _locked;
+               Notes::const_iterator      _note_iter;
+               ControlIterators           _control_iters;
+               ControlIterators::iterator _control_iter;
        };
        
-       const_iterator        begin(double t=0) const { return const_iterator(*this, t); }
-       const const_iterator& end()             const { return _end_iter; }
+       const_iterator        begin(EventTime t=0) const { return const_iterator(*this, t); }
+       const const_iterator& end()                const { return _end_iter; }
        
-       void   read_seek(double t) { _read_iter = begin(t); }
-       double read_time() const   { return _read_iter.valid() ? _read_iter->time() : 0.0; }
+       void      read_seek(EventTime t) { _read_iter = begin(t); }
+       EventTime read_time() const      { return _read_iter.valid() ? _read_iter->time() : 0.0; }
 
        bool control_to_midi_event(boost::shared_ptr<Event>& ev,
                                   const ControlIterator&    iter) const;
@@ -177,13 +177,15 @@ protected:
 private:
        friend class const_iterator;
        
-       void append_note_on_unlocked(uint8_t chan, double time, uint8_t note, uint8_t velocity);
-       void append_note_off_unlocked(uint8_t chan, double time, uint8_t note);
-       void append_control_unlocked(const Parameter& param, double time, double value);
+       void append_note_on_unlocked(uint8_t chan, EventTime time, uint8_t note, uint8_t velocity);
+       void append_note_off_unlocked(uint8_t chan, EventTime time, uint8_t note);
+       void append_control_unlocked(const Parameter& param, EventTime time, double value);
 
        mutable Glib::RWLock _lock;
 
-       Notes    _notes;
+       const TypeMap& _type_map;
+       
+       Notes _notes;
        
        typedef std::vector<size_t> WriteNotes;
        WriteNotes _write_notes[16];
@@ -196,14 +198,6 @@ private:
        mutable nframes_t      _next_read;
        bool                   _percussive;
 
-       /** FIXME: Make fully dynamic, map to URIs */
-       enum EventTypes {
-               midi_cc_type=0x20, // FIXME FIXME FIXME eeww
-               midi_pc_type,
-               midi_pb_type,
-               midi_ca_type
-       };
-
        typedef std::priority_queue<
                        boost::shared_ptr<Note>, std::deque< boost::shared_ptr<Note> >,
                        LaterNoteEndComparator>
diff --git a/libs/evoral/evoral/TypeMap.hpp b/libs/evoral/evoral/TypeMap.hpp
new file mode 100644 (file)
index 0000000..3d082fc
--- /dev/null
@@ -0,0 +1,50 @@
+/* This file is part of Evoral.
+ * Copyright (C) 2008 Dave Robillard <http://drobilla.net>
+ * Copyright (C) 2000-2008 Paul Davis
+ * 
+ * Evoral 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.
+ * 
+ * Evoral 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 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef EVORAL_TYPE_MAP_HPP
+#define EVORAL_TYPE_MAP_HPP
+
+#include <evoral/types.hpp>
+
+namespace Evoral {
+
+class Parameter;
+
+/** The applications passes one of these which provide the implementation
+ * with required information about event types in an opaque, type neutral way
+ */
+class TypeMap {
+public:
+       /** Return true iff the type is a MIDI event.
+        * The contents of the event will be used for specific ID
+        */
+       virtual bool type_is_midi(uint32_t type) const = 0;
+
+       /** Return the MIDI type (ie status byte with channel 0) for a
+        * parameter, or 0 if parameter can not be expressed as a MIDI event
+        */
+       virtual uint8_t parameter_midi_type(const Parameter& param) const = 0;
+       
+       /** The type ID for a MIDI event with the given status byte
+        */
+       virtual uint32_t midi_event_type(uint8_t status) const = 0;
+};
+
+} // namespace Evoral
+
+#endif // EVORAL_TYPE_MAP_HPP
index e078a69a03e6ddb5e6436e6ba9d94c358b5d0352..a72248418688002fe94b447303391fcdb5b965ea 100644 (file)
@@ -19,6 +19,8 @@
 #ifndef EVORAL_TYPES_HPP
 #define EVORAL_TYPES_HPP
 
+#include <stdint.h>
+
 /** Frame count (i.e. length of time in audio frames) */
 typedef uint32_t nframes_t;
 
@@ -28,4 +30,13 @@ typedef double timestamp_t;
 /** Duration of time in timestamp_t units */
 typedef timestamp_t timedur_t;
 
+/** Time stamp of an event */
+typedef double EventTime;
+
+/** Time stamp of an event */
+typedef double EventLength;
+
+/** Type of an event (opaque, mapped by application) */
+typedef uint32_t EventType;
+
 #endif // EVORAL_TYPES_HPP
index fd0a2e52bde08f57a1b94d9cc282ac44a054c3ea..63d96083d4e078fa34b2a150ad79f1ba611b64f1 100644 (file)
@@ -203,7 +203,7 @@ ControlList::reposition_for_rt_add (double when)
 void
 ControlList::rt_add (double when, double value)
 {
-       cerr << "RT: alist " << this << " add " << value << " @ " << when << endl;
+       //cerr << "RT: alist " << this << " add " << value << " @ " << when << endl;
 
        {
                Glib::Mutex::Lock lm (_lock);
@@ -1058,6 +1058,7 @@ ControlList::rt_safe_earliest_event_linear_unlocked (double start, double end, d
                         * (Optimize for immediate call this cycle within range) */
                        _search_cache.left = x;
                        //++_search_cache.range.first;
+                       assert(inclusive ? x >= start : x > start);
                        return true;
                }
                        
@@ -1069,6 +1070,7 @@ ControlList::rt_safe_earliest_event_linear_unlocked (double start, double end, d
                                 * (Optimize for immediate call this cycle within range) */
                                _search_cache.left = x;
                                //++_search_cache.range.first;
+                               assert(inclusive ? x >= start : x > start);
                                return true;
                        } else {
                                return false;
@@ -1098,9 +1100,9 @@ ControlList::rt_safe_earliest_event_linear_unlocked (double start, double end, d
                        x = first->when + (y - first->value) / (double)slope;
                }
 
-               /*cerr << first->value << " @ " << first->when << " ... "
+               cerr << first->value << " @ " << first->when << " ... "
                                << next->value << " @ " << next->when
-                               << " = " << y << " @ " << x << endl;*/
+                               << " = " << y << " @ " << x << endl;
 
                assert(    (y >= first->value && y <= next->value)
                                || (y <= first->value && y >= next->value) );
@@ -1111,9 +1113,8 @@ ControlList::rt_safe_earliest_event_linear_unlocked (double start, double end, d
                        /* Move left of cache to this point
                         * (Optimize for immediate call this cycle within range) */
                        _search_cache.left = x;
-
+                       assert(inclusive ? x >= start : x > start);
                        return true;
-
                } else {
                        return false;
                }
index 71d1808628aeea9a00b80087333ec3f5e23ac56c..99a94e0215e22def0b655e2f3478190e4451df3e 100644 (file)
 
 namespace Evoral {
 
-#ifdef EVENT_ALLOW_ALLOC
-Event::Event(double t, uint32_t s, uint8_t* b, bool owns_buffer)
-       : _time(t)
+#ifdef EVORAL_EVENT_ALLOC
+
+Event::Event(uint32_t tid, EventTime t, uint32_t s, uint8_t* b, bool owns_buffer)
+       : _type(tid)
+       , _time(t)
        , _size(s)
        , _buffer(b)
        , _owns_buffer(owns_buffer)
@@ -38,7 +40,8 @@ Event::Event(double t, uint32_t s, uint8_t* b, bool owns_buffer)
 }
 
 Event::Event(const Event& copy, bool owns_buffer)
-       : _time(copy._time)
+       : _type(copy._type)
+       , _time(copy._time)
        , _size(copy._size)
        , _buffer(copy._buffer)
        , _owns_buffer(owns_buffer)
@@ -59,49 +62,7 @@ Event::~Event() {
        }
 }
 
-#endif // EVENT_ALLOW_ALLOC
-
-#ifdef EVENT_WITH_XML
-
-Event::Event(const XMLNode& event)
-{
-       string name = event.name();
-       
-       if (name == "ControlChange") {
-               
-       } else if (name == "ProgramChange") {
-               
-       }
-}
-
-
-boost::shared_ptr<XMLNode> 
-Event::to_xml() const
-{
-       XMLNode *result = 0;
-       
-       switch (type()) {
-       case MIDI_CMD_CONTROL:
-               result = new XMLNode("ControlChange");
-               result->add_property("Channel", channel());
-               result->add_property("Control", cc_number());
-               result->add_property("Value",   cc_value());
-               break;
-                       
-       case MIDI_CMD_PGM_CHANGE:
-               result = new XMLNode("ProgramChange");
-               result->add_property("Channel", channel());
-               result->add_property("Number",  pgm_number());
-               break;
-               
-       default:
-               // The implementation is continued as needed
-               break;
-       }
-       
-       return boost::shared_ptr<XMLNode>(result);
-}
-#endif // EVENT_WITH_XML
+#endif // EVORAL_EVENT_ALLOC
 
 } // namespace MIDI
 
diff --git a/libs/evoral/src/MIDIEvent.cpp b/libs/evoral/src/MIDIEvent.cpp
new file mode 100644 (file)
index 0000000..3516151
--- /dev/null
@@ -0,0 +1,67 @@
+/* This file is part of Evoral.
+ * Copyright (C) 2008 Dave Robillard <http://drobilla.net>
+ * Copyright (C) 2000-2008 Paul Davis
+ * 
+ * Evoral 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.
+ * 
+ * Evoral 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 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <evoral/MIDIEvent.hpp>
+
+namespace Evoral {
+
+#ifdef EVORAL_MIDI_XML
+
+MIDIEvent::MIDIEvent(const XMLNode& event)
+{
+       string name = event.name();
+       
+       if (name == "ControlChange") {
+               
+       } else if (name == "ProgramChange") {
+               
+       }
+}
+
+
+boost::shared_ptr<XMLNode> 
+MIDIEvent::to_xml() const
+{
+       XMLNode *result = 0;
+       
+       switch (type()) {
+       case MIDI_CMD_CONTROL:
+               result = new XMLNode("ControlChange");
+               result->add_property("Channel", channel());
+               result->add_property("Control", cc_number());
+               result->add_property("Value",   cc_value());
+               break;
+                       
+       case MIDI_CMD_PGM_CHANGE:
+               result = new XMLNode("ProgramChange");
+               result->add_property("Channel", channel());
+               result->add_property("Number",  pgm_number());
+               break;
+               
+       default:
+               // The implementation is continued as needed
+               break;
+       }
+       
+       return boost::shared_ptr<XMLNode>(result);
+}
+
+#endif // EVORAL_MIDI_XML
+
+} // namespace MIDI
+
index 88be34fb36559c5a151c8ce804cba8afe6544040..894945c422a098dba5fc1764ddb4ec12a8eebea8 100644 (file)
 
 namespace Evoral {
 
-Note::Note(uint8_t chan, double t, double d, uint8_t n, uint8_t v)
-       : _on_event(t, 3, NULL, true)
-       , _off_event(t + d, 3, NULL, true)
+Note::Note(uint8_t chan, EventTime t, EventLength l, uint8_t n, uint8_t v)
+       // FIXME: types?
+       : _on_event(0xDE, t, 3, NULL, true)
+       , _off_event(0xAD, t + l, 3, NULL, true)
 {
        assert(chan < 16);
 
@@ -36,7 +37,7 @@ Note::Note(uint8_t chan, double t, double d, uint8_t n, uint8_t v)
        _off_event.buffer()[2] = 0x40;
        
        assert(time() == t);
-       assert(duration() == d);
+       assert(length() == l);
        assert(note() == n);
        assert(velocity() == v);
        assert(_on_event.channel() == _off_event.channel());
@@ -64,7 +65,7 @@ Note::Note(const Note& copy)
        assert(end_time() == copy.end_time());
        assert(note() == copy.note());
        assert(velocity() == copy.velocity());
-       assert(duration() == copy.duration());
+       assert(length() == copy.length());
        assert(_on_event.channel() == _off_event.channel());
        assert(channel() == copy.channel());
 }
@@ -80,20 +81,12 @@ Note::operator=(const Note& copy)
 {
        _on_event = copy._on_event;
        _off_event = copy._off_event;
-       /*_on_event.time = copy._on_event.time;
-       assert(copy._on_event.size == 3);
-       memcpy(_on_event_buffer, copy._on_event_buffer, 3);
-       
-       _off_event.time = copy._off_event.time;
-       assert(copy._off_event.size == 3);
-       memcpy(_off_event_buffer, copy._off_event_buffer, 3);
-       */
        
        assert(time() == copy.time());
        assert(end_time() == copy.end_time());
        assert(note() == copy.note());
        assert(velocity() == copy.velocity());
-       assert(duration() == copy.duration());
+       assert(length() == copy.length());
        assert(_on_event.channel() == _off_event.channel());
        assert(channel() == copy.channel());
        
index a41e191ebaf8ef1a8acf7fe1988cf1b004848d0a..07a06015506e3b0e8acbf6cd918f3a9aed816894 100644 (file)
@@ -29,6 +29,7 @@
 #include <evoral/ControlSet.hpp>
 #include <evoral/EventSink.hpp>
 #include <evoral/MIDIParameters.hpp>
+#include <evoral/TypeMap.hpp>
 
 using namespace std;
 
@@ -63,7 +64,7 @@ static ostream& errorout = cerr;
 
 // Read iterator (const_iterator)
 
-Sequence::const_iterator::const_iterator(const Sequence& seq, double t)
+Sequence::const_iterator::const_iterator(const Sequence& seq, EventTime t)
        : _seq(&seq)
        , _is_end( (t == DBL_MAX) || seq.empty() )
        , _locked( !_is_end )
@@ -76,8 +77,8 @@ Sequence::const_iterator::const_iterator(const Sequence& seq, double t)
 
        seq.read_lock();
 
-       _note_iter = seq.notes().end();
        // find first note which begins after t
+       _note_iter = seq.notes().end();
        for (Sequence::Notes::const_iterator i = seq.notes().begin(); i != seq.notes().end(); ++i) {
                if ((*i)->time() >= t) {
                        _note_iter = i;
@@ -124,26 +125,18 @@ Sequence::const_iterator::const_iterator(const Sequence& seq, double t)
                }
        }
 
-       if (_note_iter != seq.notes().end()) {
+       if (_note_iter != seq.notes().end()
+                       && (*_note_iter)->on_event().time() >= t
+                       && (!earliest_control.list
+                               || (*_note_iter)->on_event().time() < earliest_control.x)) {
+               debugout << "Reading note on event @ " << (*_note_iter)->on_event().time() << endl;
                _event = boost::shared_ptr<Event>(new Event((*_note_iter)->on_event(), true));
-       }
-
-       double time = DBL_MAX;
-       // in case we have no notes in the region, we still want to get controller messages
-       if (_event.get()) {
-               time = _event->time();
-               // if the note is going to make it this turn, advance _note_iter
-               if (earliest_control.x > time) {
-                       _active_notes.push(*_note_iter);
-                       ++_note_iter;
-               }
-       }
-       
-       // <=, because we probably would want to send control events first 
-       if (earliest_control.list.get() && earliest_control.x <= time) {
-               seq.control_to_midi_event(_event, earliest_control);
-       } else {
+               _active_notes.push(*_note_iter);
+               ++_note_iter;
                _control_iter = _control_iters.end();
+       } else if (earliest_control.list) {
+               debugout << "Reading control event @ " << earliest_control.x << endl;
+               seq.control_to_midi_event(_event, earliest_control);
        }
 
        if ( (! _event.get()) || _event->size() == 0) {
@@ -158,11 +151,12 @@ Sequence::const_iterator::const_iterator(const Sequence& seq, double t)
                        _locked = false;
                }
        } else {
-               debugout << "New Iterator = " << hex << _event->type();
+               debugout << "New Iterator = " << _event->event_type();
+               debugout << " : " << hex << (int)((MIDIEvent*)_event.get())->type();
                debugout << " @ " <<  _event->time() << endl;
        }
 
-       assert(_is_end || (_event->buffer() && _event->buffer()[0] != '\0'));
+       //assert(_is_end || (_event->buffer() && _event->buffer()[0] != '\0'));
 }
 
 Sequence::const_iterator::~const_iterator()
@@ -179,37 +173,42 @@ Sequence::const_iterator& Sequence::const_iterator::operator++()
                throw std::logic_error("Attempt to iterate past end of Sequence");
        }
        
-       assert(_event->buffer() && _event->buffer()[0] != '\0');
+       debugout << "Iterator ++" << endl;
+       assert(_event->buffer() && _event->size() > 0);
+       
+       const MIDIEvent& ev = *((MIDIEvent*)_event.get());
 
        //debugout << "const_iterator::operator++: " << _event->to_string() << endl;
 
-       if (! (_event->is_note() || _event->is_cc() || _event->is_pgm_change()
-                               || _event->is_pitch_bender() || _event->is_channel_aftertouch()) ) {
-               errorout << "Unknown event type: " << hex << int(_event->buffer()[0])
-                       << int(_event->buffer()[1]) << int(_event->buffer()[2]) << endl;
+       if (! (ev.is_note() || ev.is_cc() || ev.is_pgm_change()
+                               || ev.is_pitch_bender() || ev.is_channel_pressure()) ) {
+               errorout << "Unknown event type: " << hex << int(ev.buffer()[0])
+                       << int(ev.buffer()[1]) << int(ev.buffer()[2]) << endl;
        }
-       assert((_event->is_note() || _event->is_cc() || _event->is_pgm_change() || _event->is_pitch_bender() || _event->is_channel_aftertouch()));
+       assert((ev.is_note() || ev.is_cc() || ev.is_pgm_change() || ev.is_pitch_bender() || ev.is_channel_pressure()));
 
        // Increment past current control event
-       if (!_event->is_note() && _control_iter != _control_iters.end() && _control_iter->list.get()) {
+       if (!ev.is_note() && _control_iter != _control_iters.end() && _control_iter->list.get()) {
                double x = 0.0, y = 0.0;
                const bool ret = _control_iter->list->rt_safe_earliest_event_unlocked(
                                _control_iter->x, DBL_MAX, x, y, false);
 
+               assert(!ret || x > _control_iter->x);
+
                if (ret) {
                        _control_iter->x = x;
                        _control_iter->y = y;
                } else {
                        _control_iter->list.reset();
                        _control_iter->x = DBL_MAX;
+                       _control_iter->y = DBL_MAX;
                }
        }
 
        _control_iter = _control_iters.begin();
 
        // find the _control_iter with the earliest event time
-       for (std::vector<ControlIterator>::iterator i = _control_iters.begin();
-                       i != _control_iters.end(); ++i) {
+       for (ControlIterators::iterator i = _control_iters.begin(); i != _control_iters.end(); ++i) {
                if (i->x < _control_iter->x) {
                        _control_iter = i;
                }
@@ -218,7 +217,7 @@ Sequence::const_iterator& Sequence::const_iterator::operator++()
        enum Type {NIL, NOTE_ON, NOTE_OFF, CONTROL};
 
        Type type = NIL;
-       double t = 0;
+       EventTime t = 0;
 
        // Next earliest note on
        if (_note_iter != _seq->notes().end()) {
@@ -228,7 +227,7 @@ Sequence::const_iterator& Sequence::const_iterator::operator++()
 
        // Use the next earliest note off iff it's earlier than the note on
        if (!_seq->percussive() && (! _active_notes.empty())) {
-               if (type == NIL || _active_notes.top()->end_time() <= (*_note_iter)->time()) {
+               if (type == NIL || _active_notes.top()->end_time() <= t) {
                        type = NOTE_OFF;
                        t = _active_notes.top()->end_time();
                }
@@ -258,7 +257,7 @@ Sequence::const_iterator& Sequence::const_iterator::operator++()
                _is_end = true;
        }
 
-       assert(_is_end || _event->size() > 0);
+       assert(_is_end || (_event->size() > 0 && _event->buffer() && _event->buffer()[0] != '\0'));
 
        return *this;
 }
@@ -289,8 +288,16 @@ Sequence::const_iterator::operator=(const const_iterator& other)
        size_t index   = other._control_iter - other._control_iters.begin();
        _control_iter  = _control_iters.begin() + index;
        
-       if (!_is_end) {
-               _event =  boost::shared_ptr<Event>(new Event(*other._event, true));
+       if (!_is_end && other._event) {
+               if (_event) {
+                       *_event = *other._event.get();
+               } else {
+                       _event = boost::shared_ptr<Event>(new Event(*other._event, true));
+               }
+       } else {
+               if (_event) {
+                       _event->clear();
+               }
        }
 
        return *this;
@@ -298,9 +305,10 @@ Sequence::const_iterator::operator=(const const_iterator& other)
 
 // Sequence
 
-Sequence::Sequence(size_t size)
+Sequence::Sequence(const TypeMap& type_map, size_t size)
        : _read_iter(*this, DBL_MAX)
        , _edited(false)
+       , _type_map(type_map)
        , _notes(size)
        , _writing(false)
        , _end_iter(*this, DBL_MAX)
@@ -319,16 +327,15 @@ Sequence::Sequence(size_t size)
 size_t
 Sequence::read(EventSink& dst, timestamp_t start, timedur_t nframes, timestamp_t offset) const
 {
-       debugout << this << " read ev @ " << start << " * " << nframes << " + " << offset << endl;
+       debugout << this << " read @ " << start << " * " << nframes << " + " << offset << endl;
        debugout << this << " # notes: " << n_notes() << endl;
-       debugout << this << " controls: " << &_controls << endl;
        debugout << this << " # controls: " << _controls.size() << endl;
 
        size_t read_events = 0;
 
        if (start != _next_read) {
-               _read_iter = const_iterator(*this, (double)start);
                debugout << "Repositioning iterator from " << _next_read << " to " << start << endl;
+               _read_iter = const_iterator(*this, (double)start);
        } else {
                debugout << "Using cached iterator at " << _next_read << endl;
        }
@@ -339,14 +346,15 @@ Sequence::read(EventSink& dst, timestamp_t start, timedur_t nframes, timestamp_t
                assert(_read_iter->size() > 0);
                assert(_read_iter->buffer());
                dst.write(_read_iter->time() + offset,
+                         _read_iter->event_type(),
                          _read_iter->size(), 
                          _read_iter->buffer());
                
-                debugout << this << " read event @ " << _read_iter->time()  
-                                << " type: " << hex << int(_read_iter->type()) << dec 
-                                << " note: " << int(_read_iter->note()) 
-                                << " velocity: " << int(_read_iter->velocity()) 
-                                << endl;
+                debugout << this << " read event type " << _read_iter->event_type()
+                        << " @ " << _read_iter->time() << " : ";
+                for (size_t i = 0; i < _read_iter->size(); ++i)
+                        debugout << hex << (int)_read_iter->buffer()[i];
+                debugout << endl;
                
                ++_read_iter;
                ++read_events;
@@ -357,18 +365,22 @@ Sequence::read(EventSink& dst, timestamp_t start, timedur_t nframes, timestamp_t
 
 /** Write the controller event pointed to by \a iter to \a ev.
  * The buffer of \a ev will be allocated or resized as necessary.
+ * The event_type of \a ev should be set to the expected output type.
  * \return true on success
  */
 bool
 Sequence::control_to_midi_event(boost::shared_ptr<Event>& ev, const ControlIterator& iter) const
 {
        assert(iter.list.get());
+       const uint32_t event_type = iter.list->parameter().type();
        if (!ev) {
-               ev = boost::shared_ptr<Event>(new Event(0, 3, NULL, true));
+               ev = boost::shared_ptr<Event>(new Event(event_type, 0, 3, NULL, true));
        }
        
-       switch (iter.list->parameter().type()) {
-       case midi_cc_type:
+       uint8_t midi_type = _type_map.parameter_midi_type(iter.list->parameter());
+       ev->set_event_type(_type_map.midi_event_type(midi_type));
+       switch (midi_type) {
+       case MIDI_CMD_CONTROL:
                assert(iter.list.get());
                assert(iter.list->parameter().channel() < 16);
                assert(iter.list->parameter().id() <= INT8_MAX);
@@ -381,10 +393,9 @@ Sequence::control_to_midi_event(boost::shared_ptr<Event>& ev, const ControlItera
                ev->buffer()[2] = (uint8_t)iter.y;
                break;
 
-       case midi_pc_type:
+       case MIDI_CMD_PGM_CHANGE:
                assert(iter.list.get());
                assert(iter.list->parameter().channel() < 16);
-               assert(iter.list->parameter().id() == 0);
                assert(iter.y <= INT8_MAX);
                
                ev->time() = iter.x;
@@ -393,10 +404,9 @@ Sequence::control_to_midi_event(boost::shared_ptr<Event>& ev, const ControlItera
                ev->buffer()[1] = (uint8_t)iter.y;
                break;
 
-       case midi_pb_type:
+       case MIDI_CMD_BENDER:
                assert(iter.list.get());
                assert(iter.list->parameter().channel() < 16);
-               assert(iter.list->parameter().id() == 0);
                assert(iter.y < (1<<14));
                
                ev->time() = iter.x;
@@ -406,10 +416,9 @@ Sequence::control_to_midi_event(boost::shared_ptr<Event>& ev, const ControlItera
                ev->buffer()[2] = (uint16_t(iter.y) >> 7) & 0x7F; // MSB
                break;
 
-       case midi_ca_type:
+       case MIDI_CMD_CHANNEL_PRESSURE:
                assert(iter.list.get());
                assert(iter.list->parameter().channel() < 16);
-               assert(iter.list->parameter().id() == 0);
                assert(iter.y <= INT8_MAX);
 
                ev->time() = iter.x;
@@ -441,10 +450,10 @@ Sequence::clear()
 
 /** Begin a write of events to the model.
  *
- * If \a mode is Sustained, complete notes with duration are constructed as note
+ * If \a mode is Sustained, complete notes with length are constructed as note
  * on/off events are received.  Otherwise (Percussive), only note on events are
  * stored; note off events are discarded entirely and all contained notes will
- * have duration 0.
+ * have length 0.
  */
 void
 Sequence::start_write()
@@ -463,7 +472,7 @@ Sequence::start_write()
  *
  * If \a delete_stuck is true and the current mode is Sustained, note on events
  * that were never resolved with a corresonding note off will be deleted.
- * Otherwise they will remain as notes with duration 0.
+ * Otherwise they will remain as notes with length 0.
  */
 void
 Sequence::end_write(bool delete_stuck)
@@ -475,7 +484,7 @@ Sequence::end_write(bool delete_stuck)
 
        if (!_percussive && delete_stuck) {
                for (Notes::iterator n = _notes.begin(); n != _notes.end() ;) {
-                       if ((*n)->duration() == 0) {
+                       if ((*n)->length() == 0) {
                                errorout << "WARNING: Stuck note lost: " << (*n)->note() << endl;
                                n = _notes.erase(n);
                                // we have to break here because erase invalidates the iterator
@@ -509,10 +518,12 @@ Sequence::end_write(bool delete_stuck)
  * and MUST be >= the latest event currently in the model.
  */
 void
-Sequence::append(const Event& ev)
+Sequence::append(const Event& event)
 {
        write_lock();
        _edited = true;
+       
+       const MIDIEvent& ev = (const MIDIEvent&)event;
 
        assert(_notes.empty() || ev.time() >= _notes.back()->time());
        assert(_writing);
@@ -522,32 +533,34 @@ Sequence::append(const Event& ev)
                                ev.velocity());
        } else if (ev.is_note_off()) {
                append_note_off_unlocked(ev.channel(), ev.time(), ev.note());
+       } else if (!_type_map.type_is_midi(ev.event_type())) {
+               printf("WARNING: Sequence: Unknown event type %X\n", ev.event_type());
        } else if (ev.is_cc()) {
                append_control_unlocked(
-                               Evoral::MIDI::ContinuousController(midi_cc_type, ev.channel(), ev.cc_number()),
+                               Evoral::MIDI::ContinuousController(ev.event_type(), ev.channel(), ev.cc_number()),
                                ev.time(), ev.cc_value());
        } else if (ev.is_pgm_change()) {
                append_control_unlocked(
-                               Evoral::MIDI::ProgramChange(midi_pc_type, ev.channel()),
+                               Evoral::MIDI::ProgramChange(ev.event_type(), ev.channel()),
                                ev.time(), ev.pgm_number());
        } else if (ev.is_pitch_bender()) {
                append_control_unlocked(
-                               Evoral::MIDI::PitchBender(midi_pb_type, ev.channel()),
+                               Evoral::MIDI::PitchBender(ev.event_type(), ev.channel()),
                                ev.time(), double(  (0x7F & ev.pitch_bender_msb()) << 7
-                                                 | (0x7F & ev.pitch_bender_lsb()) ));
-       } else if (ev.is_channel_aftertouch()) {
+                                       | (0x7F & ev.pitch_bender_lsb()) ));
+       } else if (ev.is_channel_pressure()) {
                append_control_unlocked(
-                               Evoral::MIDI::ChannelAftertouch(midi_ca_type, ev.channel()),
-                               ev.time(), ev.channel_aftertouch());
+                               Evoral::MIDI::ChannelPressure(ev.event_type(), ev.channel()),
+                               ev.time(), ev.channel_pressure());
        } else {
-               printf("WARNING: Sequence: Unknown event type %X\n", ev.type());
+               printf("WARNING: Sequence: Unknown MIDI event type %X\n", ev.type());
        }
 
        write_unlock();
 }
 
 void
-Sequence::append_note_on_unlocked(uint8_t chan, double time, uint8_t note_num, uint8_t velocity)
+Sequence::append_note_on_unlocked(uint8_t chan, EventTime time, uint8_t note_num, uint8_t velocity)
 {
        debugout << this << " c" << (int)chan << " note " << (int)note_num << " off @ " << time << endl;
        assert(note_num <= 127);
@@ -566,7 +579,7 @@ Sequence::append_note_on_unlocked(uint8_t chan, double time, uint8_t note_num, u
 }
 
 void
-Sequence::append_note_off_unlocked(uint8_t chan, double time, uint8_t note_num)
+Sequence::append_note_off_unlocked(uint8_t chan, EventTime time, uint8_t note_num)
 {
        debugout << this << " c" << (int)chan << " note " << (int)note_num << " off @ " << time << endl;
        assert(note_num <= 127);
@@ -591,9 +604,9 @@ Sequence::append_note_off_unlocked(uint8_t chan, double time, uint8_t note_num)
                Note& note = *_notes[*n].get();
                if (note.note() == note_num) {
                        assert(time >= note.time());
-                       note.set_duration(time - note.time());
+                       note.set_length(time - note.time());
                        _write_notes[chan].erase(n);
-                       debugout << "resolved note, duration: " << note.duration() << endl;
+                       debugout << "resolved note, length: " << note.length() << endl;
                        resolved = true;
                        break;
                }
@@ -606,10 +619,9 @@ Sequence::append_note_off_unlocked(uint8_t chan, double time, uint8_t note_num)
 }
 
 void
-Sequence::append_control_unlocked(const Parameter& param, double time, double value)
+Sequence::append_control_unlocked(const Parameter& param, EventTime time, double value)
 {
-       debugout << this << " " << param.symbol() << " @ " << time << " = " << value
-                       << " controls: " << &_controls
+       debugout << this << " " << param.symbol() << " @ " << time << " \t= \t" << value
                        << " # controls: " << _controls.size() << endl;
        control(param, true)->list()->rt_add(time, value);
 }
@@ -637,8 +649,8 @@ Sequence::remove_note_unlocked(const boost::shared_ptr<const Note> note)
                // persisted undo does not work, because of rounding errors in the
                // event times after saving/restoring to/from MIDI files
                /*cerr << "======================================= " << endl;
-               cerr << int(_n.note()) << "@" << int(_n.time()) << "[" << int(_n.channel()) << "] --" << int(_n.duration()) << "-- #" << int(_n.velocity()) << endl;
-               cerr << int(_note.note()) << "@" << int(_note.time()) << "[" << int(_note.channel()) << "] --" << int(_note.duration()) << "-- #" << int(_note.velocity()) << endl;
+               cerr << int(_n.note()) << "@" << int(_n.time()) << "[" << int(_n.channel()) << "] --" << int(_n.length()) << "-- #" << int(_n.velocity()) << endl;
+               cerr << int(_note.note()) << "@" << int(_note.time()) << "[" << int(_note.channel()) << "] --" << int(_note.length()) << "-- #" << int(_note.velocity()) << endl;
                cerr << "Equal: " << bool(_n == _note) << endl;
                cerr << endl << endl;*/
                if (_n == _note) {
index 8973ef48bdecd423b2219e40109c6426e1a02530..24a8db37ee085ff133ec942d95942af3e056ee77 100644 (file)
  * but MidiEvent will never deep copy and (depending on the scenario)
  * may not be usable in STL containers, signals, etc. 
  */
-#define EVENT_ALLOW_ALLOC 1
+#define EVORAL_EVENT_ALLOC 1
 
 /** Support serialisation of MIDI events to/from XML */
-#define EVENT_WITH_XML 1
+#define EVORAL_MIDI_XML 1
 
 #include <evoral/Event.hpp>
+#include <evoral/MIDIEvent.hpp>
 
 #endif /* __libmidipp_midi_event_h__ */
index 3434db896acc8812748b46827454a7119e3ee794..d08911966b927d302eb0ddb94bf443c6991d7d37 100644 (file)
@@ -17,7 +17,7 @@ Patch::get_state (void)
        for (PatchMidiCommands::const_iterator event = _patch_midi_commands.begin();
            event != _patch_midi_commands.end();
            ++event) {
-               commands->add_child_copy(*(event->to_xml()));
+               commands->add_child_copy(*((((Evoral::MIDIEvent&)*event)).to_xml()));
        }
 
        return *node;
@@ -33,7 +33,7 @@ Patch::set_state (const XMLNode& node)
        assert(commands);
        const XMLNodeList events = commands->children();
        for (XMLNodeList::const_iterator i = events.begin(); i != events.end(); ++i) {
-               _patch_midi_commands.push_back(*(new Evoral::Event(*(*i))));
+               _patch_midi_commands.push_back(*(new Evoral::MIDIEvent(*(*i))));
        }
 
        return 0;