summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2008-09-22 16:28:02 +0000
committerDavid Robillard <d@drobilla.net>2008-09-22 16:28:02 +0000
commita2d2f738cb63dbf0fb89e0a00c424ce883fb7888 (patch)
tree8ff8b9067a8884566b023de2dabedc2b57b856ab
parentff2d51ddd8288ec967efab2cb8192f43c893909e (diff)
Move event specific ringbuffer stuff to evoral.
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
-rw-r--r--gtk2_ardour/canvas-program-change.cc2
-rw-r--r--gtk2_ardour/midi_region_view.cc24
-rw-r--r--gtk2_ardour/midi_streamview.cc2
-rw-r--r--libs/ardour/SConscript19
-rw-r--r--libs/ardour/ardour/automatable.h11
-rw-r--r--libs/ardour/ardour/event_type_map.h43
-rw-r--r--libs/ardour/ardour/midi_buffer.h14
-rw-r--r--libs/ardour/ardour/midi_ring_buffer.h347
-rw-r--r--libs/ardour/ardour/parameter.h14
-rw-r--r--libs/ardour/event_type_map.cc61
-rw-r--r--libs/ardour/import.cc2
-rw-r--r--libs/ardour/meter.cc2
-rw-r--r--libs/ardour/midi_buffer.cc8
-rw-r--r--libs/ardour/midi_diskstream.cc4
-rw-r--r--libs/ardour/midi_model.cc14
-rw-r--r--libs/ardour/midi_track.cc3
-rw-r--r--libs/ardour/quantize.cc4
-rw-r--r--libs/ardour/smf_source.cc18
-rw-r--r--libs/evoral/SConscript5
-rw-r--r--libs/evoral/evoral/Event.hpp103
-rw-r--r--libs/evoral/evoral/EventRingBuffer.hpp95
-rw-r--r--libs/evoral/evoral/EventSink.hpp4
-rw-r--r--libs/evoral/evoral/MIDIEvent.hpp89
-rw-r--r--libs/evoral/evoral/MIDIParameters.hpp4
-rw-r--r--libs/evoral/evoral/Note.hpp34
-rw-r--r--libs/evoral/evoral/RingBuffer.hpp226
-rw-r--r--libs/evoral/evoral/Sequence.hpp62
-rw-r--r--libs/evoral/evoral/TypeMap.hpp50
-rw-r--r--libs/evoral/evoral/types.hpp11
-rw-r--r--libs/evoral/src/ControlList.cpp11
-rw-r--r--libs/evoral/src/Event.cpp55
-rw-r--r--libs/evoral/src/MIDIEvent.cpp67
-rw-r--r--libs/evoral/src/Note.cpp21
-rw-r--r--libs/evoral/src/Sequence.cpp164
-rw-r--r--libs/midi++2/midi++/event.h5
-rw-r--r--libs/midi++2/midnam_patch.cc4
36 files changed, 954 insertions, 648 deletions
diff --git a/gtk2_ardour/canvas-program-change.cc b/gtk2_ardour/canvas-program-change.cc
index e5a7768f34..bd9c0e89db 100644
--- a/gtk2_ardour/canvas-program-change.cc
+++ b/gtk2_ardour/canvas-program-change.cc
@@ -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();
diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc
index bfd23f900e..c67d0a5c5e 100644
--- a/gtk2_ardour/midi_region_view.cc
+++ b/gtk2_ardour/midi_region_view.cc
@@ -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;
diff --git a/gtk2_ardour/midi_streamview.cc b/gtk2_ardour/midi_streamview.cc
index 8d2986b6de..6c620128bc 100644
--- a/gtk2_ardour/midi_streamview.cc
+++ b/gtk2_ardour/midi_streamview.cc
@@ -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)
diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript
index c351510d19..352d1b26f6 100644
--- a/libs/ardour/SConscript
+++ b/libs/ardour/SConscript
@@ -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
diff --git a/libs/ardour/ardour/automatable.h b/libs/ardour/ardour/automatable.h
index 837bbbc617..dbce7de0bf 100644
--- a/libs/ardour/ardour/automatable.h
+++ b/libs/ardour/ardour/automatable.h
@@ -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
index 0000000000..6736feeb86
--- /dev/null
+++ b/libs/ardour/ardour/event_type_map.h
@@ -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__ */
+
diff --git a/libs/ardour/ardour/midi_buffer.h b/libs/ardour/ardour/midi_buffer.h
index 0c13199825..606cbd0ec8 100644
--- a/libs/ardour/ardour/midi_buffer.h
+++ b/libs/ardour/ardour/midi_buffer.h
@@ -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.
};
diff --git a/libs/ardour/ardour/midi_ring_buffer.h b/libs/ardour/ardour/midi_ring_buffer.h
index db0c3029a8..ae82dc14ab 100644
--- a/libs/ardour/ardour/midi_ring_buffer.h
+++ b/libs/ardour/ardour/midi_ring_buffer.h
@@ -24,239 +24,30 @@
#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;
}
diff --git a/libs/ardour/ardour/parameter.h b/libs/ardour/ardour/parameter.h
index 5c390c1039..5ccbd4a6e3 100644
--- a/libs/ardour/ardour/parameter.h
+++ b/libs/ardour/ardour/parameter.h
@@ -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
index 0000000000..cd78fd02f7
--- /dev/null
+++ b/libs/ardour/event_type_map.cc
@@ -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
+
diff --git a/libs/ardour/import.cc b/libs/ardour/import.cc
index 199a2fd1a4..370991be5f 100644
--- a/libs/ardour/import.cc
+++ b/libs/ardour/import.cc
@@ -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;
diff --git a/libs/ardour/meter.cc b/libs/ardour/meter.cc
index 363cbe242f..5dee1d9845 100644
--- a/libs/ardour/meter.cc
+++ b/libs/ardour/meter.cc
@@ -47,7 +47,7 @@ PeakMeter::run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_f
// GUI needs a better MIDI meter, not much information can be
// expressed through peaks alone
for (MidiBuffer::iterator i = bufs.get_midi(n).begin(); i != bufs.get_midi(n).end(); ++i) {
- const 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);
diff --git a/libs/ardour/midi_buffer.cc b/libs/ardour/midi_buffer.cc
index afd8481795..f1f6b9b633 100644
--- a/libs/ardour/midi_buffer.cc
+++ b/libs/ardour/midi_buffer.cc
@@ -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);
diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc
index b2991c1a7f..bb7f2931f4 100644
--- a/libs/ardour/midi_diskstream.cc
+++ b/libs/ardour/midi_diskstream.cc
@@ -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;
}
diff --git a/libs/ardour/midi_model.cc b/libs/ardour/midi_model.cc
index c22820c83c..18b37689bd 100644
--- a/libs/ardour/midi_model.cc
+++ b/libs/ardour/midi_model.cc
@@ -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;
}
diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc
index 745e5bf1b7..d60aba8bbc 100644
--- a/libs/ardour/midi_track.cc
+++ b/libs/ardour/midi_track.cc
@@ -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
diff --git a/libs/ardour/quantize.cc b/libs/ardour/quantize.cc
index ff8925edd9..3b5a264a7b 100644
--- a/libs/ardour/quantize.cc
+++ b/libs/ardour/quantize.cc
@@ -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);
diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc
index 2d5c0af0d5..03a8b98199 100644
--- a/libs/ardour/smf_source.cc
+++ b/libs/ardour/smf_source.cc
@@ -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;
diff --git a/libs/evoral/SConscript b/libs/evoral/SConscript
index 6141f10e4f..2b18d59107 100644
--- a/libs/evoral/SConscript
+++ b/libs/evoral/SConscript
@@ -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 ])
diff --git a/libs/evoral/evoral/Event.hpp b/libs/evoral/evoral/Event.hpp
index beffb01eb5..1dd081a5b9 100644
--- a/libs/evoral/evoral/Event.hpp
+++ b/libs/evoral/evoral/Event.hpp
@@ -24,52 +24,39 @@
#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
index 0000000000..05ec9217b8
--- /dev/null
+++ b/libs/evoral/evoral/EventRingBuffer.hpp
@@ -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
+
diff --git a/libs/evoral/evoral/EventSink.hpp b/libs/evoral/evoral/EventSink.hpp
index 5f0610e15f..dfa746d870 100644
--- a/libs/evoral/evoral/EventSink.hpp
+++ b/libs/evoral/evoral/EventSink.hpp
@@ -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
index 0000000000..863103aa74
--- /dev/null
+++ b/libs/evoral/evoral/MIDIEvent.hpp
@@ -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
diff --git a/libs/evoral/evoral/MIDIParameters.hpp b/libs/evoral/evoral/MIDIParameters.hpp
index e2bfdc3fb0..744357f5b8 100644
--- a/libs/evoral/evoral/MIDIParameters.hpp
+++ b/libs/evoral/evoral/MIDIParameters.hpp
@@ -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 {
diff --git a/libs/evoral/evoral/Note.hpp b/libs/evoral/evoral/Note.hpp
index 76095e733c..75a8046237 100644
--- a/libs/evoral/evoral/Note.hpp
+++ b/libs/evoral/evoral/Note.hpp
@@ -20,18 +20,18 @@
#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
index 0000000000..a27e97adb2
--- /dev/null
+++ b/libs/evoral/evoral/RingBuffer.hpp
@@ -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
+
+
diff --git a/libs/evoral/evoral/Sequence.hpp b/libs/evoral/evoral/Sequence.hpp
index 73ddaca21b..b029e51f33 100644
--- a/libs/evoral/evoral/Sequence.hpp
+++ b/libs/evoral/evoral/Sequence.hpp
@@ -30,30 +30,28 @@
#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
index 0000000000..3d082fc4ef
--- /dev/null
+++ b/libs/evoral/evoral/TypeMap.hpp
@@ -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
diff --git a/libs/evoral/evoral/types.hpp b/libs/evoral/evoral/types.hpp
index e078a69a03..a722484186 100644
--- a/libs/evoral/evoral/types.hpp
+++ b/libs/evoral/evoral/types.hpp
@@ -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
diff --git a/libs/evoral/src/ControlList.cpp b/libs/evoral/src/ControlList.cpp
index fd0a2e52bd..63d96083d4 100644
--- a/libs/evoral/src/ControlList.cpp
+++ b/libs/evoral/src/ControlList.cpp
@@ -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;
}
diff --git a/libs/evoral/src/Event.cpp b/libs/evoral/src/Event.cpp
index 71d1808628..99a94e0215 100644
--- a/libs/evoral/src/Event.cpp
+++ b/libs/evoral/src/Event.cpp
@@ -20,9 +20,11 @@
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
index 0000000000..35161515d6
--- /dev/null
+++ b/libs/evoral/src/MIDIEvent.cpp
@@ -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
+
diff --git a/libs/evoral/src/Note.cpp b/libs/evoral/src/Note.cpp
index 88be34fb36..894945c422 100644
--- a/libs/evoral/src/Note.cpp
+++ b/libs/evoral/src/Note.cpp
@@ -21,9 +21,10 @@
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());
diff --git a/libs/evoral/src/Sequence.cpp b/libs/evoral/src/Sequence.cpp
index a41e191eba..07a0601550 100644
--- a/libs/evoral/src/Sequence.cpp
+++ b/libs/evoral/src/Sequence.cpp
@@ -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) {
diff --git a/libs/midi++2/midi++/event.h b/libs/midi++2/midi++/event.h
index 8973ef48bd..24a8db37ee 100644
--- a/libs/midi++2/midi++/event.h
+++ b/libs/midi++2/midi++/event.h
@@ -35,11 +35,12 @@
* 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__ */
diff --git a/libs/midi++2/midnam_patch.cc b/libs/midi++2/midnam_patch.cc
index 3434db896a..d08911966b 100644
--- a/libs/midi++2/midnam_patch.cc
+++ b/libs/midi++2/midnam_patch.cc
@@ -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;