summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2009-05-04 15:50:51 +0000
committerDavid Robillard <d@drobilla.net>2009-05-04 15:50:51 +0000
commitca10cc82a4374a5b413c06ead6cc89c53f8881ee (patch)
tree3d44716ed02d80bd1256609631c77a730d04e169 /libs
parent9b06b1da0cec57a6848cf1f7920691ae022b30e7 (diff)
Preliminary MIDI plugin support.
git-svn-id: svn://localhost/ardour2/branches/3.0@5036 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs')
-rw-r--r--libs/ardour/ardour/audio_port.h2
-rw-r--r--libs/ardour/ardour/audio_unit.h5
-rw-r--r--libs/ardour/ardour/audioengine.h8
-rw-r--r--libs/ardour/ardour/buffer_set.h20
-rw-r--r--libs/ardour/ardour/chan_count.h10
-rw-r--r--libs/ardour/ardour/chan_mapping.h82
-rw-r--r--libs/ardour/ardour/io.h2
-rw-r--r--libs/ardour/ardour/ladspa_plugin.h5
-rw-r--r--libs/ardour/ardour/lv2_event_buffer.h81
-rw-r--r--libs/ardour/ardour/lv2_plugin.h13
-rw-r--r--libs/ardour/ardour/midi_buffer.h1
-rw-r--r--libs/ardour/ardour/midi_port.h2
-rw-r--r--libs/ardour/ardour/plugin.h5
-rw-r--r--libs/ardour/ardour/plugin_insert.h17
-rw-r--r--libs/ardour/ardour/port.h5
-rw-r--r--libs/ardour/ardour/processor.h3
-rw-r--r--libs/ardour/ardour/route.h6
-rw-r--r--libs/ardour/ardour/session.h2
-rw-r--r--libs/ardour/ardour/uri_map.h60
-rw-r--r--libs/ardour/ardour/vst_plugin.h6
-rw-r--r--libs/ardour/audio_port.cc6
-rw-r--r--libs/ardour/audioengine.cc26
-rw-r--r--libs/ardour/audioregion.cc2
-rw-r--r--libs/ardour/buffer_set.cc81
-rw-r--r--libs/ardour/ladspa_plugin.cc39
-rw-r--r--libs/ardour/lv2_event_buffer.cc191
-rw-r--r--libs/ardour/lv2_plugin.cc79
-rw-r--r--libs/ardour/lv2ext/lv2_event.h260
-rw-r--r--libs/ardour/lv2ext/lv2_event_helpers.h243
-rw-r--r--libs/ardour/lv2ext/lv2_uri_map.h88
-rw-r--r--libs/ardour/midi_buffer.cc32
-rw-r--r--libs/ardour/midi_port.cc13
-rw-r--r--libs/ardour/midi_track.cc1
-rw-r--r--libs/ardour/plugin_insert.cc64
-rw-r--r--libs/ardour/processor.cc8
-rw-r--r--libs/ardour/route.cc83
-rw-r--r--libs/ardour/session.cc25
-rw-r--r--libs/ardour/template_utils.cc2
-rw-r--r--libs/ardour/uri_map.cc74
-rw-r--r--libs/ardour/vst_plugin.cc4
-rw-r--r--libs/ardour/wscript6
41 files changed, 1459 insertions, 203 deletions
diff --git a/libs/ardour/ardour/audio_port.h b/libs/ardour/ardour/audio_port.h
index 85bac1f286..09bd8bdd1e 100644
--- a/libs/ardour/ardour/audio_port.h
+++ b/libs/ardour/ardour/audio_port.h
@@ -38,6 +38,8 @@ class AudioPort : public Port
void cycle_start (nframes_t);
void cycle_end (nframes_t);
void cycle_split ();
+
+ size_t raw_buffer_size(jack_nframes_t nframes) const;
Buffer& get_buffer (nframes_t nframes, nframes_t offset = 0) {
return get_audio_buffer (nframes, offset);
diff --git a/libs/ardour/ardour/audio_unit.h b/libs/ardour/ardour/audio_unit.h
index e023979ed8..83d85ec5d0 100644
--- a/libs/ardour/ardour/audio_unit.h
+++ b/libs/ardour/ardour/audio_unit.h
@@ -30,13 +30,14 @@
#include <vector>
#include <map>
-#include "ardour/plugin.h"
-
#include <AudioUnit/AudioUnit.h>
#include <appleutility/AUParamInfo.h>
#include <boost/shared_ptr.hpp>
+#include "ardour/plugin.h"
+#include "ardour/chan_mapping.h"
+
class CAComponent;
class CAAudioUnit;
class CAComponentDescription;
diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h
index 54154141f6..9dec7c8ec3 100644
--- a/libs/ardour/ardour/audioengine.h
+++ b/libs/ardour/ardour/audioengine.h
@@ -40,9 +40,10 @@
namespace ARDOUR {
-class Session;
-class Port;
class InternalPort;
+class MidiPort;
+class Port;
+class Session;
class AudioEngine : public sigc::trackable
{
@@ -74,6 +75,8 @@ class AudioEngine : public sigc::trackable
nframes_t frame_rate();
nframes_t frames_per_cycle();
+ size_t raw_buffer_size(DataType t);
+
int usecs_per_cycle () const { return _usecs_per_cycle; }
bool get_sync_offset (nframes_t& offset) const;
@@ -213,6 +216,7 @@ class AudioEngine : public sigc::trackable
bool _running;
bool _has_run;
nframes_t _buffer_size;
+ std::map<DataType,size_t> _raw_buffer_sizes;
nframes_t _frame_rate;
/// number of frames between each check for changes in monitor input
nframes_t monitor_check_interval;
diff --git a/libs/ardour/ardour/buffer_set.h b/libs/ardour/ardour/buffer_set.h
index f02470c3e8..72f45762c7 100644
--- a/libs/ardour/ardour/buffer_set.h
+++ b/libs/ardour/ardour/buffer_set.h
@@ -31,6 +31,7 @@ class Buffer;
class AudioBuffer;
class MidiBuffer;
class PortSet;
+class LV2EventBuffer;
/** A set of buffers of various types.
*
@@ -55,7 +56,6 @@ public:
void attach_buffers(PortSet& ports, nframes_t nframes, nframes_t offset = 0);
- void ensure_buffers(const ChanCount& count, size_t buffer_capacity);
void ensure_buffers(DataType type, size_t num_buffers, size_t buffer_capacity);
const ChanCount& available() const { return _available; }
@@ -68,10 +68,7 @@ public:
size_t buffer_capacity(DataType type) const;
- Buffer& get(DataType type, size_t i) {
- assert(i <= _count.get(type));
- return *_buffers[type][i];
- }
+ Buffer& get(DataType type, size_t i);
AudioBuffer& get_audio(size_t i) {
return (AudioBuffer&)get(DataType::AUDIO, i);
@@ -81,6 +78,14 @@ public:
return (MidiBuffer&)get(DataType::MIDI, i);
}
+ /** Get a MIDI buffer translated into an LV2 MIDI buffer for use with plugins.
+ * The index here corresponds directly to MIDI buffer numbers (i.e. the index
+ * passed to get_midi), translation back and forth will happen as needed */
+ LV2EventBuffer& get_lv2_midi(bool input, size_t i);
+
+ /** Flush modified LV2 event output buffers back to Ardour buffers */
+ void flush_lv2_midi(bool input, size_t i);
+
void read_from(BufferSet& in, nframes_t nframes);
// ITERATORS
@@ -137,6 +142,11 @@ private:
/// Vector of vectors, indexed by DataType
std::vector<BufferVec> _buffers;
+
+ /// LV2 MIDI buffers (for conversion to/from MIDI buffers)
+ //
+ typedef std::vector< std::pair<bool, LV2EventBuffer*> > LV2Buffers;
+ LV2Buffers _lv2_buffers;
/// Use counts (there may be more actual buffers than this)
ChanCount _count;
diff --git a/libs/ardour/ardour/chan_count.h b/libs/ardour/ardour/chan_count.h
index ff70be6bb6..fb4b1999ca 100644
--- a/libs/ardour/ardour/chan_count.h
+++ b/libs/ardour/ardour/chan_count.h
@@ -20,10 +20,10 @@
#ifndef __ardour_chan_count_h__
#define __ardour_chan_count_h__
+#include <cassert>
#include <ostream>
#include "ardour/data_type.h"
-#include <cassert>
namespace ARDOUR {
@@ -103,6 +103,14 @@ public:
bool operator>=(const ChanCount& other) const {
return ( (*this > other) || (*this == other) );
}
+
+ static ChanCount max(const ChanCount& a, const ChanCount& b) {
+ ChanCount ret;
+ for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+ ret.set(*t, std::max(a.get(*t), b.get(*t)));
+ }
+ return ret;
+ }
static const ChanCount INFINITE;
static const ChanCount ZERO;
diff --git a/libs/ardour/ardour/chan_mapping.h b/libs/ardour/ardour/chan_mapping.h
new file mode 100644
index 0000000000..1dae20e34a
--- /dev/null
+++ b/libs/ardour/ardour/chan_mapping.h
@@ -0,0 +1,82 @@
+/*
+ Copyright (C) 2009 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_chan_mapping_h__
+#define __ardour_chan_mapping_h__
+
+#include <map>
+#include <cassert>
+#include <ostream>
+#include <utility>
+
+#include "ardour/data_type.h"
+
+namespace ARDOUR {
+
+
+/** A mapping from one set of channels to another
+ * (e.g. how to 'connect' two BufferSets).
+ */
+class ChanMapping {
+public:
+ ChanMapping() {}
+ ChanMapping(ChanCount identity) {
+ for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+ for (size_t i = 0; i <= identity.get(*t); ++i)
+ set(*t, i, i);
+ }
+ }
+
+ uint32_t get(DataType t, uint32_t from) {
+ Mappings::iterator tm = _mappings.find(t);
+ assert(tm != _mappings.end());
+ TypeMapping::iterator m = tm->second.find(from);
+ assert(m != tm->second.end());
+ return m->second;
+ }
+
+ void set(DataType t, uint32_t from, uint32_t to) {
+ Mappings::iterator tm = _mappings.find(t);
+ if (tm == _mappings.end()) {
+ tm = _mappings.insert(std::make_pair(t, TypeMapping())).first;
+ }
+ tm->second.insert(std::make_pair(from, to));
+ }
+
+ /** Increase the 'to' field of every mapping for type @a t by @a delta */
+ void offset(DataType t, uint32_t delta) {
+ Mappings::iterator tm = _mappings.find(t);
+ if (tm != _mappings.end()) {
+ for (TypeMapping::iterator m = tm->second.begin(); m != tm->second.end(); ++m) {
+ m->second += delta;
+ }
+ }
+ }
+
+private:
+ typedef std::map<uint32_t, uint32_t> TypeMapping;
+ typedef std::map<DataType, TypeMapping> Mappings;
+
+ Mappings _mappings;
+};
+
+} // namespace ARDOUR
+
+#endif // __ardour_chan_mapping_h__
+
diff --git a/libs/ardour/ardour/io.h b/libs/ardour/ardour/io.h
index 6b309bf50c..8457668756 100644
--- a/libs/ardour/ardour/io.h
+++ b/libs/ardour/ardour/io.h
@@ -365,7 +365,7 @@ class IO : public SessionObject, public AutomatableControls, public Latent
int make_connections (const XMLNode&);
boost::shared_ptr<Bundle> find_possible_bundle (const string &desired_name, const string &default_name, const string &connection_type_name);
- void setup_peak_meters ();
+ virtual void setup_peak_meters ();
void meter ();
bool ensure_inputs_locked (ChanCount, bool clear, void *src);
diff --git a/libs/ardour/ardour/ladspa_plugin.h b/libs/ardour/ardour/ladspa_plugin.h
index 855aa7189b..847b582432 100644
--- a/libs/ardour/ardour/ladspa_plugin.h
+++ b/libs/ardour/ardour/ladspa_plugin.h
@@ -84,7 +84,10 @@ class LadspaPlugin : public ARDOUR::Plugin
void set_block_size (nframes_t nframes) {}
- int connect_and_run (BufferSet& bufs, uint32_t& in, uint32_t& out, nframes_t nframes, nframes_t offset);
+ int connect_and_run (BufferSet& bufs,
+ ChanMapping in, ChanMapping out,
+ nframes_t nframes, nframes_t offset);
+
std::string describe_parameter (Evoral::Parameter);
std::string state_node_name() const { return "ladspa"; }
void print_parameter (uint32_t, char*, uint32_t len) const;
diff --git a/libs/ardour/ardour/lv2_event_buffer.h b/libs/ardour/ardour/lv2_event_buffer.h
new file mode 100644
index 0000000000..9d35d36d55
--- /dev/null
+++ b/libs/ardour/ardour/lv2_event_buffer.h
@@ -0,0 +1,81 @@
+/*
+ Copyright (C) 2009 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_lv2_event_buffer_h__
+#define __ardour_lv2_event_buffer_h__
+
+#include "lv2ext/lv2_event.h"
+#include "lv2ext/lv2_event_helpers.h"
+
+namespace ARDOUR {
+
+
+class LV2EventBuffer {
+public:
+ LV2EventBuffer(size_t capacity);
+ ~LV2EventBuffer();
+
+ inline LV2_Event_Buffer* data() { return _data; }
+ inline const LV2_Event_Buffer* data() const { return _data; }
+
+ inline void rewind() const { lv2_event_begin(&_iter, _data); }
+
+ inline void reset() {
+ _latest_frames = 0;
+ _latest_subframes = 0;
+ _data->event_count = 0;
+ _data->size = 0;
+ rewind();
+ }
+
+ inline size_t event_count() const { return _data->event_count; }
+ inline uint32_t capacity() const { return _data->capacity; }
+ inline uint32_t size() const { return _data->size; }
+ inline uint32_t latest_frames() const { return _latest_frames; }
+ inline uint32_t latest_subframes() const { return _latest_subframes; }
+
+ bool increment() const;
+
+ bool is_valid() const;
+
+ bool get_event(uint32_t* frames,
+ uint32_t* subframes,
+ uint16_t* type,
+ uint16_t* size,
+ uint8_t** data) const;
+
+ bool append(uint32_t frames,
+ uint32_t subframes,
+ uint16_t type,
+ uint16_t size,
+ const uint8_t* data);
+
+ bool append(const LV2_Event_Buffer* buf);
+
+private:
+ LV2_Event_Buffer* _data; ///< Contents
+ mutable LV2_Event_Iterator _iter; ///< Iterator into _data
+ uint32_t _latest_frames; ///< Latest time of all events (frames)
+ uint32_t _latest_subframes; ///< Latest time of all events (subframes)
+};
+
+
+} // namespace ARDOUR
+
+#endif // __ardour_lv2_event_buffer_h__
diff --git a/libs/ardour/ardour/lv2_plugin.h b/libs/ardour/ardour/lv2_plugin.h
index f235a0b4c2..7daf4ed2b1 100644
--- a/libs/ardour/ardour/lv2_plugin.h
+++ b/libs/ardour/ardour/lv2_plugin.h
@@ -33,6 +33,7 @@
#include <jack/types.h>
#include <slv2/slv2.h>
#include "ardour/plugin.h"
+#include "ardour/uri_map.h"
namespace ARDOUR {
class AudioEngine;
@@ -95,9 +96,12 @@ class LV2Plugin : public ARDOUR::Plugin
void set_block_size (nframes_t nframes) {}
- int connect_and_run (BufferSet& bufs, uint32_t& in, uint32_t& out, nframes_t nframes, nframes_t offset);
+ int connect_and_run (BufferSet& bufs,
+ ChanMapping in, ChanMapping out,
+ nframes_t nframes, nframes_t offset);
+
std::string describe_parameter (Evoral::Parameter);
- std::string state_node_name() const { return "LV2"; }
+ std::string state_node_name() const { return "lv2"; }
void print_parameter (uint32_t, char*, uint32_t len) const;
bool parameter_is_audio(uint32_t) const;
@@ -107,6 +111,8 @@ class LV2Plugin : public ARDOUR::Plugin
bool parameter_is_output(uint32_t) const;
bool parameter_is_toggled(uint32_t) const;
+ static uint32_t midi_event_type() { return _midi_event_type; }
+
XMLNode& get_state();
int set_state(const XMLNode& node);
bool save_preset(std::string uri);
@@ -138,6 +144,9 @@ class LV2Plugin : public ARDOUR::Plugin
LV2_Feature _data_access_feature;
LV2_Feature _instance_access_feature;
+ static URIMap _uri_map;
+ static uint32_t _midi_event_type;
+
void init (LV2World& world, SLV2Plugin plugin, nframes_t rate);
void run (nframes_t nsamples);
void latency_compute_run ();
diff --git a/libs/ardour/ardour/midi_buffer.h b/libs/ardour/ardour/midi_buffer.h
index 70e2203df4..43626fd0e7 100644
--- a/libs/ardour/ardour/midi_buffer.h
+++ b/libs/ardour/ardour/midi_buffer.h
@@ -44,6 +44,7 @@ public:
bool push_back(const Evoral::MIDIEvent<TimeType>& event);
bool push_back(const jack_midi_event_t& event);
+ bool push_back(TimeType time, size_t size, const uint8_t* data);
uint8_t* reserve(TimeType time, size_t size);
void resize(size_t);
diff --git a/libs/ardour/ardour/midi_port.h b/libs/ardour/ardour/midi_port.h
index 2f3d8d1647..e4d6a41d05 100644
--- a/libs/ardour/ardour/midi_port.h
+++ b/libs/ardour/ardour/midi_port.h
@@ -40,6 +40,8 @@ class MidiPort : public Port {
void cycle_end (nframes_t nframes);
void cycle_split ();
void flush_buffers (nframes_t nframes, nframes_t offset = 0);
+
+ size_t raw_buffer_size(jack_nframes_t nframes) const;
Buffer& get_buffer (nframes_t nframes, nframes_t offset = 0) {
return get_midi_buffer (nframes, offset);
diff --git a/libs/ardour/ardour/plugin.h b/libs/ardour/ardour/plugin.h
index 0039a1f8ca..2cf3d3fc34 100644
--- a/libs/ardour/ardour/plugin.h
+++ b/libs/ardour/ardour/plugin.h
@@ -29,6 +29,7 @@
#include <jack/types.h>
#include "ardour/chan_count.h"
+#include "ardour/chan_mapping.h"
#include "ardour/cycles.h"
#include "ardour/latent.h"
#include "ardour/plugin_insert.h"
@@ -126,7 +127,9 @@ class Plugin : public PBD::StatefulDestructible, public Latent
virtual void deactivate () = 0;
virtual void set_block_size (nframes_t nframes) = 0;
- virtual int connect_and_run (BufferSet& bufs, uint32_t& in, uint32_t& out, nframes_t nframes, nframes_t offset) = 0;
+ virtual int connect_and_run (BufferSet& bufs,
+ ChanMapping in, ChanMapping out,
+ nframes_t nframes, nframes_t offset) = 0;
virtual std::set<Evoral::Parameter> automatable() const = 0;
virtual string describe_parameter (Evoral::Parameter) = 0;
diff --git a/libs/ardour/ardour/plugin_insert.h b/libs/ardour/ardour/plugin_insert.h
index 88a5ee357d..99bd492ab5 100644
--- a/libs/ardour/ardour/plugin_insert.h
+++ b/libs/ardour/ardour/plugin_insert.h
@@ -104,16 +104,10 @@ class PluginInsert : public Processor
nframes_t signal_latency() const;
boost::shared_ptr<Plugin> get_impulse_analysis_plugin();
+
+ void collect_signal_for_analysis(nframes_t nframes);
sigc::signal<void, BufferSet*, BufferSet*> AnalysisDataGathered;
- void collect_signal_for_analysis(nframes_t nframes) {
- // called from outside the audio thread, so this should be safe
- _signal_analysis_input_bufferset.ensure_buffers(input_streams(), nframes);
- _signal_analysis_output_bufferset.ensure_buffers(output_streams(), nframes);
-
- _signal_analysis_collected_nframes = 0;
- _signal_analysis_collect_nframes_max = nframes;
- }
private:
/* disallow copy construction */
@@ -126,15 +120,16 @@ class PluginInsert : public Processor
float default_parameter_value (const Evoral::Parameter& param);
- std::vector<boost::shared_ptr<Plugin> > _plugins;
+ typedef std::vector<boost::shared_ptr<Plugin> > Plugins;
+ Plugins _plugins;
boost::weak_ptr<Plugin> _impulseAnalysisPlugin;
nframes_t _signal_analysis_collected_nframes;
nframes_t _signal_analysis_collect_nframes_max;
- BufferSet _signal_analysis_input_bufferset;
- BufferSet _signal_analysis_output_bufferset;
+ BufferSet _signal_analysis_inputs;
+ BufferSet _signal_analysis_outputs;
void automation_run (BufferSet& bufs, nframes_t nframes);
void connect_and_run (BufferSet& bufs, nframes_t nframes, nframes_t offset, bool with_auto, nframes_t now = 0);
diff --git a/libs/ardour/ardour/port.h b/libs/ardour/ardour/port.h
index 0c77eb15dd..3f86fb8fd2 100644
--- a/libs/ardour/ardour/port.h
+++ b/libs/ardour/ardour/port.h
@@ -101,6 +101,9 @@ public:
void set_latency (nframes_t);
virtual void reset ();
+
+ /** @return the size of the raw buffer (bytes) for duration @a nframes (audio frames) */
+ virtual size_t raw_buffer_size(jack_nframes_t nframes) const = 0;
virtual DataType type () const = 0;
virtual void cycle_start (nframes_t) = 0;
@@ -108,7 +111,7 @@ public:
virtual void cycle_split () = 0;
virtual Buffer& get_buffer (nframes_t nframes, nframes_t offset = 0) = 0;
virtual void flush_buffers (nframes_t, nframes_t offset = 0) {}
-
+
static void set_engine (AudioEngine *);
sigc::signal<void, bool> MonitorInputChanged;
diff --git a/libs/ardour/ardour/processor.h b/libs/ardour/ardour/processor.h
index 24d3cd93c7..c2c23b8f67 100644
--- a/libs/ardour/ardour/processor.h
+++ b/libs/ardour/ardour/processor.h
@@ -95,8 +95,8 @@ class Processor : public SessionObject, public AutomatableControls, public Laten
virtual bool is_out_of_place () const { return false; }
virtual bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const = 0;
- virtual ChanCount output_streams() const { return _configured_input; }
virtual ChanCount input_streams () const { return _configured_input; }
+ virtual ChanCount output_streams() const { return _configured_output; }
virtual XMLNode& state (bool full);
virtual XMLNode& get_state (void);
@@ -116,6 +116,7 @@ protected:
bool _next_ab_is_active;
bool _configured;
ChanCount _configured_input;
+ ChanCount _configured_output;
Placement _placement;
uint32_t _sort_key;
void* _gui; /* generic, we don't know or care what this is */
diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h
index 183be9c4c8..6926dbd036 100644
--- a/libs/ardour/ardour/route.h
+++ b/libs/ardour/ardour/route.h
@@ -161,7 +161,7 @@ class Route : public IO
}
}
- ChanCount max_processor_outs () const { return processor_max_outs; }
+ ChanCount max_processor_streams () const { return processor_max_streams; }
ChanCount pre_fader_streams() const;
/** A record of the stream configuration at some point in the processor list.
@@ -333,11 +333,13 @@ class Route : public IO
sigc::connection input_signal_connection;
- ChanCount processor_max_outs;
+ ChanCount processor_max_streams;
uint32_t _remote_control_id;
uint32_t pans_required() const;
ChanCount n_process_buffers ();
+
+ void setup_peak_meters ();
virtual int _set_state (const XMLNode&, bool call_base);
virtual void _set_processor_states (const XMLNodeList&);
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index ce238fbc2e..bc8dcb81f1 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -944,6 +944,8 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
gain_t* gain_automation_buffer () const { return _gain_automation_buffer; }
pan_t** pan_automation_buffer () const { return _pan_automation_buffer; }
+
+ void ensure_buffer_set (BufferSet& buffers, const ChanCount& howmany);
/* VST support */
diff --git a/libs/ardour/ardour/uri_map.h b/libs/ardour/ardour/uri_map.h
new file mode 100644
index 0000000000..78e5393271
--- /dev/null
+++ b/libs/ardour/ardour/uri_map.h
@@ -0,0 +1,60 @@
+/*
+ Copyright (C) 2009 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_uri_map_h__
+#define __ardour_uri_map_h__
+
+#include <map>
+#include <string>
+#include <boost/utility.hpp>
+#include <slv2/slv2.h>
+#include "lv2ext/lv2_uri_map.h"
+
+namespace ARDOUR {
+
+
+/** Implementation of the LV2 URI Map extension
+ */
+class URIMap : public boost::noncopyable {
+public:
+ URIMap();
+
+ LV2_Feature* feature() { return &uri_map_feature; }
+
+ uint32_t uri_to_id(const char* map,
+ const char* uri);
+
+private:
+ typedef std::map<std::string, uint32_t> Map;
+
+ static uint32_t uri_map_uri_to_id(LV2_URI_Map_Callback_Data callback_data,
+ const char* map,
+ const char* uri);
+
+ LV2_Feature uri_map_feature;
+ LV2_URI_Map_Feature uri_map_feature_data;
+ Map uri_map;
+ uint32_t next_uri_id;
+};
+
+
+} // namespace ARDOUR
+
+#endif // __ardour_uri_map_h__
diff --git a/libs/ardour/ardour/vst_plugin.h b/libs/ardour/ardour/vst_plugin.h
index 7541740cf8..d4ca3b8b60 100644
--- a/libs/ardour/ardour/vst_plugin.h
+++ b/libs/ardour/ardour/vst_plugin.h
@@ -71,7 +71,11 @@ class VSTPlugin : public ARDOUR::Plugin
void activate ();
void deactivate ();
void set_block_size (nframes_t nframes);
- int connect_and_run (BufferSet&, uint32_t& in, uint32_t& out, nframes_t nframes, nframes_t offset);
+
+ int connect_and_run (BufferSet&,
+ ChanMapping in, ChanMapping out,
+ nframes_t nframes, nframes_t offset);
+
string describe_parameter (Evoral::Parameter);
string state_node_name() const { return "vst"; }
void print_parameter (uint32_t, char*, uint32_t len) const;
diff --git a/libs/ardour/audio_port.cc b/libs/ardour/audio_port.cc
index c62d31a6d0..f69d6685ff 100644
--- a/libs/ardour/audio_port.cc
+++ b/libs/ardour/audio_port.cc
@@ -97,3 +97,9 @@ AudioPort::get_audio_buffer (nframes_t nframes, nframes_t offset)
return *_buffer;
}
+size_t
+AudioPort::raw_buffer_size(nframes_t nframes) const
+{
+ return nframes * sizeof(float);
+}
+
diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc
index 8ca85c4fe8..51a6ae71fb 100644
--- a/libs/ardour/audioengine.cc
+++ b/libs/ardour/audioengine.cc
@@ -140,14 +140,14 @@ AudioEngine::start ()
if (!_running) {
+ nframes_t blocksize = jack_get_buffer_size (_jack);
+
if (session) {
- nframes_t blocksize = jack_get_buffer_size (_jack);
-
BootMessage (_("Connect session to engine"));
session->set_block_size (blocksize);
session->set_frame_rate (jack_get_sample_rate (_jack));
-
+
/* page in as much of the session process code as we
can before we really start running.
*/
@@ -188,6 +188,8 @@ AudioEngine::start ()
}
start_metering_thread();
+
+ _raw_buffer_sizes[DataType::AUDIO] = blocksize * sizeof(float);
}
return _running ? 0 : -1;
@@ -466,6 +468,7 @@ int
AudioEngine::jack_bufsize_callback (nframes_t nframes)
{
_buffer_size = nframes;
+ _raw_buffer_sizes[DataType::AUDIO] = nframes * sizeof(float);
_usecs_per_cycle = (int) floor ((((double) nframes / frame_rate())) * 1000000.0);
last_monitor_check = 0;
@@ -603,7 +606,11 @@ AudioEngine::register_port (DataType dtype, const string& portname, bool input)
} else {
throw unknown_type();
}
-
+
+ size_t& old_buffer_size = _raw_buffer_sizes[newport->type()];
+ size_t port_buffer_size = newport->raw_buffer_size(0);
+ if (port_buffer_size > old_buffer_size)
+ old_buffer_size = port_buffer_size;
RCUWriter<Ports> writer (ports);
boost::shared_ptr<Ports> ps = writer.get_copy ();
@@ -729,7 +736,7 @@ AudioEngine::disconnect (const string& source, const string& destination)
Port* src = get_port_by_name_locked (s);
Port* dst = get_port_by_name_locked (d);
- if (src) {
+ if (src) {
ret = src->disconnect (d);
} else if (dst) {
ret = dst->disconnect (s);
@@ -772,6 +779,13 @@ AudioEngine::frame_rate ()
}
}
+size_t
+AudioEngine::raw_buffer_size (DataType t)
+{
+ std::map<DataType,size_t>::const_iterator s = _raw_buffer_sizes.find(t);
+ return (s != _raw_buffer_sizes.end()) ? s->second : 0;
+}
+
ARDOUR::nframes_t
AudioEngine::frames_per_cycle ()
{
@@ -1184,7 +1198,6 @@ AudioEngine::disconnect_from_jack ()
return 0;
}
-
if (_running) {
stop_metering_thread ();
}
@@ -1197,6 +1210,7 @@ AudioEngine::disconnect_from_jack ()
_buffer_size = 0;
_frame_rate = 0;
+ _raw_buffer_sizes.clear();
if (_running) {
_running = false;
diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc
index b3fd239c59..f3fbbe6c1c 100644
--- a/libs/ardour/audioregion.cc
+++ b/libs/ardour/audioregion.cc
@@ -1463,8 +1463,6 @@ AudioRegion::find_silence (Sample threshold, nframes_t min_length) const
while (pos < end) {
- nframes_t const to_read = min (end - pos, block_size);
-
/* fill `loudest' with the loudest absolute sample at each instant, across all channels */
memset (loudest, 0, sizeof (Sample) * block_size);
for (uint32_t n = 0; n < n_channels(); ++n) {
diff --git a/libs/ardour/buffer_set.cc b/libs/ardour/buffer_set.cc
index dfc607ec03..c75a15c074 100644
--- a/libs/ardour/buffer_set.cc
+++ b/libs/ardour/buffer_set.cc
@@ -18,10 +18,14 @@
#include <iostream>
#include <algorithm>
-#include "ardour/buffer_set.h"
#include "ardour/buffer.h"
+#include "ardour/buffer_set.h"
+#include "ardour/lv2_event_buffer.h"
+#include "ardour/lv2_plugin.h"
+#include "ardour/midi_buffer.h"
#include "ardour/port.h"
#include "ardour/port_set.h"
+#include "ardour/audioengine.h"
namespace ARDOUR {
@@ -29,8 +33,9 @@ namespace ARDOUR {
BufferSet::BufferSet()
: _is_mirror(false)
{
- for (size_t i=0; i < DataType::num_types; ++i)
- _buffers.push_back( BufferVec() );
+ for (size_t i=0; i < DataType::num_types; ++i) {
+ _buffers.push_back(BufferVec());
+ }
_count.reset();
_available.reset();
@@ -81,15 +86,6 @@ BufferSet::attach_buffers(PortSet& ports, nframes_t nframes, nframes_t offset)
_is_mirror = true;
}
-void
-BufferSet::ensure_buffers(const ChanCount& count, size_t buffer_capacity)
-{
- for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
- ensure_buffers(*t, count.get(*t), buffer_capacity);
- }
-}
-
-
/** Ensure that there are @a num_buffers buffers of type @a type available,
* each of size at least @a buffer_size
*/
@@ -98,17 +94,10 @@ BufferSet::ensure_buffers(DataType type, size_t num_buffers, size_t buffer_capac
{
assert(type != DataType::NIL);
assert(type < _buffers.size());
- assert(buffer_capacity > 0);
if (num_buffers == 0)
return;
- // FIXME: Kludge to make MIDI buffers larger (size is bytes, not frames)
- // See MidiPort::MidiPort
- // We probably need a map<DataType, size_t> parameter for capacity
- if (type == DataType::MIDI)
- buffer_capacity *= 8;
-
// The vector of buffers of the type we care about
BufferVec& bufs = _buffers[type];
@@ -131,13 +120,21 @@ BufferSet::ensure_buffers(DataType type, size_t num_buffers, size_t buffer_capac
bufs.clear();
// Rebuild it
- for (size_t i=0; i < num_buffers; ++i) {
+ for (size_t i = 0; i < num_buffers; ++i) {
bufs.push_back(Buffer::create(type, buffer_capacity));
}
_available.set(type, num_buffers);
}
+ // Ensure enough low level MIDI format buffers are available for conversion
+ // in both directions (input & output, out-of-place)
+ if (type == DataType::MIDI && _lv2_buffers.size() < _buffers[type].size() * 2) {
+ while (_lv2_buffers.size() < _buffers[type].size() * 2) {
+ _lv2_buffers.push_back(std::make_pair(false, new LV2EventBuffer(buffer_capacity)));
+ }
+ }
+
// Post-conditions
assert(bufs[0]->type() == type);
assert(bufs.size() >= num_buffers);
@@ -156,6 +153,50 @@ BufferSet::buffer_capacity(DataType type) const
return _buffers[type][0]->capacity();
}
+Buffer&
+BufferSet::get(DataType type, size_t i)
+{
+ assert(i <= _count.get(type));
+ return *_buffers[type][i];
+}
+
+LV2EventBuffer&
+BufferSet::get_lv2_midi(bool input, size_t i)
+{
+ MidiBuffer& mbuf = get_midi(i);
+ LV2Buffers::value_type b = _lv2_buffers.at(i * 2 + (input ? 0 : 1));
+ LV2EventBuffer* ebuf = b.second;
+
+ ebuf->reset();
+ if (input) {
+ for (MidiBuffer::iterator e = mbuf.begin(); e != mbuf.end(); ++e) {
+ const Evoral::MIDIEvent<nframes_t> ev(*e, false);
+ uint32_t type = LV2Plugin::midi_event_type();
+ ebuf->append(ev.time(), 0, type, ev.size(), ev.buffer());
+ }
+ }
+ return *ebuf;
+}
+
+void
+BufferSet::flush_lv2_midi(bool input, size_t i)
+{
+ MidiBuffer& mbuf = get_midi(i);
+ LV2Buffers::value_type b = _lv2_buffers.at(i * 2 + (input ? 0 : 1));
+ LV2EventBuffer* ebuf = b.second;
+
+ mbuf.silence(0, 0);
+ for (ebuf->rewind(); ebuf->is_valid(); ebuf->increment()) {
+ uint32_t frames;
+ uint32_t subframes;
+ uint16_t type;
+ uint16_t size;
+ uint8_t* data;
+ ebuf->get_event(&frames, &subframes, &type, &size, &data);
+ mbuf.push_back(frames, size, data);
+ }
+}
+
// FIXME: make 'in' const
void
BufferSet::read_from (BufferSet& in, nframes_t nframes)
diff --git a/libs/ardour/ladspa_plugin.cc b/libs/ardour/ladspa_plugin.cc
index f287414fe5..348542ce1c 100644
--- a/libs/ardour/ladspa_plugin.cc
+++ b/libs/ardour/ladspa_plugin.cc
@@ -507,34 +507,23 @@ LadspaPlugin::automatable () const
}
int
-LadspaPlugin::connect_and_run (BufferSet& bufs, uint32_t& in_index, uint32_t& out_index, nframes_t nframes, nframes_t offset)
+LadspaPlugin::connect_and_run (BufferSet& bufs,
+ ChanMapping in_map, ChanMapping out_map,
+ nframes_t nframes, nframes_t offset)
{
- uint32_t port_index = 0;
- cycles_t then, now;
-
- then = get_cycles ();
-
- const uint32_t nbufs = bufs.count().n_audio();
-
- while (port_index < parameter_count()) {
- if (LADSPA_IS_PORT_AUDIO (port_descriptor(port_index))) {
- if (LADSPA_IS_PORT_INPUT (port_descriptor(port_index))) {
- const size_t index = min(in_index, nbufs - 1);
- connect_port (port_index, bufs.get_audio(index).data(offset));
- //cerr << this << ' ' << name() << " @ " << offset << " inport " << in_index << " = buf "
- // << min((uint32_t)in_index,nbufs) << " = " << &bufs[min((uint32_t)in_index,nbufs)][offset] << endl;
- in_index++;
-
-
- } else if (LADSPA_IS_PORT_OUTPUT (port_descriptor (port_index))) {
- const size_t index = min(out_index,nbufs - 1);
- connect_port (port_index, bufs.get_audio(index).data(offset));
- // cerr << this << ' ' << name() << " @ " << offset << " outport " << out_index << " = buf "
- // << min((uint32_t)out_index,nbufs) << " = " << &bufs[min((uint32_t)out_index,nbufs)][offset] << endl;
- out_index++;
+ cycles_t now;
+ cycles_t then = get_cycles ();
+
+ for (uint32_t port_index = 0; port_index < parameter_count(); ++port_index) {
+ if (LADSPA_IS_PORT_AUDIO(port_descriptor(port_index))) {
+ if (LADSPA_IS_PORT_INPUT(port_descriptor(port_index))) {
+ const uint32_t buf_index = in_map.get(DataType::AUDIO, port_index);
+ connect_port(port_index, bufs.get_audio(buf_index).data(offset));
+ } else if (LADSPA_IS_PORT_OUTPUT(port_descriptor(port_index))) {
+ const uint32_t buf_index = out_map.get(DataType::AUDIO, port_index);
+ connect_port(port_index, bufs.get_audio(buf_index).data(offset));
}
}
- port_index++;
}
run_in_place (nframes);
diff --git a/libs/ardour/lv2_event_buffer.cc b/libs/ardour/lv2_event_buffer.cc
new file mode 100644
index 0000000000..5405701da1
--- /dev/null
+++ b/libs/ardour/lv2_event_buffer.cc
@@ -0,0 +1,191 @@
+/*
+ Copyright (C) 2009 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.
+*/
+
+#define __STDC_LIMIT_MACROS 1
+#include <stdint.h>
+#include <iostream>
+#include "ardour/lv2_event_buffer.h"
+#include "lv2ext/lv2_event.h"
+#include "lv2ext/lv2_event_helpers.h"
+
+using namespace std;
+
+namespace ARDOUR {
+
+
+/** Allocate a new event buffer.
+ * \a capacity is in bytes (not number of events).
+ */
+LV2EventBuffer::LV2EventBuffer(size_t capacity)
+ : _latest_frames(0)
+ , _latest_subframes(0)
+{
+ if (capacity > UINT32_MAX) {
+ cerr << "Event buffer size " << capacity << " too large, aborting." << endl;
+ throw std::bad_alloc();
+ }
+
+#ifdef NO_POSIX_MEMALIGN
+ _data = (LV2_Event_Buffer*)malloc(sizeof(LV2_Event_Buffer) + capacity);
+ int ret = (_data != NULL) ? 0 : -1;
+#else
+ int ret = posix_memalign((void**)&_data, 16, sizeof(LV2_Event_Buffer) + capacity);
+#endif
+
+ if (ret != 0) {
+ cerr << "Failed to allocate event buffer. Aborting." << endl;
+ exit(EXIT_FAILURE);
+ }
+
+ _data->event_count = 0;
+ _data->capacity = (uint32_t)capacity;
+ _data->size = 0;
+ _data->data = reinterpret_cast<uint8_t*>(_data + 1);
+
+ reset();
+}
+
+
+LV2EventBuffer::~LV2EventBuffer()
+{
+ free(_data);
+}
+
+
+/** Increment the read position by one event.
+ *
+ * \return true if increment was successful, or false if end of buffer reached.
+ */
+bool
+LV2EventBuffer::increment() const
+{
+ if (lv2_event_is_valid(&_iter)) {
+ lv2_event_increment(&_iter);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+/** \return true iff the cursor is valid (ie get_event is safe)
+ */
+bool
+LV2EventBuffer::is_valid() const
+{
+ return lv2_event_is_valid(&_iter);
+}
+
+
+/** Read an event from the current position in the buffer
+ *
+ * \return true if read was successful, or false if end of buffer reached
+ */
+bool
+LV2EventBuffer::get_event(uint32_t* frames,
+ uint32_t* subframes,
+ uint16_t* type,
+ uint16_t* size,
+ uint8_t** data) const
+{
+ if (lv2_event_is_valid(&_iter)) {
+ LV2_Event* ev = lv2_event_get(&_iter, data);
+ *frames = ev->frames;
+ *subframes = ev->subframes;
+ *type = ev->type;
+ *size = ev->size;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+/** Append an event to the buffer.
+ *
+ * \a timestamp must be >= the latest event in the buffer.
+ *
+ * \return true on success
+ */
+bool
+LV2EventBuffer::append(uint32_t frames,
+ uint32_t subframes,
+ uint16_t type,
+ uint16_t size,
+ const uint8_t* data)
+{
+#ifndef NDEBUG
+ if (lv2_event_is_valid(&_iter)) {
+ LV2_Event* last_event = lv2_event_get(&_iter, NULL);
+ assert(last_event->frames < frames
+ || (last_event->frames == frames && last_event->subframes <= subframes));
+ }
+#endif
+
+ /*cout << "Appending event type " << type << ", size " << size
+ << " @ " << frames << "." << subframes << endl;*/
+
+ if (!lv2_event_write(&_iter, frames, subframes, type, size, data)) {
+ cerr << "ERROR: Failed to write event." << endl;
+ return false;
+ } else {
+ _latest_frames = frames;
+ _latest_subframes = subframes;
+ return true;
+ }
+}
+
+
+/** Append a buffer of events to the buffer.
+ *
+ * \a timestamp must be >= the latest event in the buffer.
+ *
+ * \return true on success
+ */
+bool
+LV2EventBuffer::append(const LV2_Event_Buffer* buf)
+{
+ uint8_t** data = NULL;
+ bool ret = true;
+
+ LV2_Event_Iterator iter;
+ for (lv2_event_begin(&iter, _data); lv2_event_is_valid(&iter); lv2_event_increment(&iter)) {
+ LV2_Event* ev = lv2_event_get(&iter, data);
+
+#ifndef NDEBUG
+ assert((ev->frames > _latest_frames)
+ || (ev->frames == _latest_frames
+ && ev->subframes >= _latest_subframes));
+#endif
+
+ if (!(ret = append(ev->frames, ev->subframes, ev->type, ev->size, *data))) {
+ cerr << "ERROR: Failed to write event." << endl;
+ break;
+ }
+
+ _latest_frames = ev->frames;
+ _latest_subframes = ev->subframes;
+ }
+
+ return ret;
+}
+
+
+} // namespace ARDOUR
+
diff --git a/libs/ardour/lv2_plugin.cc b/libs/ardour/lv2_plugin.cc
index c9098ae304..e7617671a0 100644
--- a/libs/ardour/lv2_plugin.cc
+++ b/libs/ardour/lv2_plugin.cc
@@ -34,6 +34,7 @@
#include "ardour/session.h"
#include "ardour/audioengine.h"
#include "ardour/audio_buffer.h"
+#include "ardour/lv2_event_buffer.h"
#include "ardour/lv2_plugin.h"
#include "pbd/stl_delete.h"
@@ -44,7 +45,12 @@
using namespace std;
using namespace ARDOUR;
using namespace PBD;
-
+
+URIMap LV2Plugin::_uri_map;
+uint32_t LV2Plugin::_midi_event_type = _uri_map.uri_to_id(
+ "http://lv2plug.in/ns/ext/event",
+ "http://lv2plug.in/ns/ext/midi#MidiEvent");
+
LV2Plugin::LV2Plugin (AudioEngine& e, Session& session, LV2World& world, SLV2Plugin plugin, nframes_t rate)
: Plugin (e, session)
, _world(world)
@@ -88,7 +94,8 @@ LV2Plugin::init (LV2World& world, SLV2Plugin plugin, nframes_t rate)
}
if (slv2_plugin_has_feature(plugin, world.in_place_broken)) {
- error << string_compose(_("LV2: \"%1\" cannot be used, since it cannot do inplace processing"),
+ error << string_compose(
+ _("LV2: \"%1\" cannot be used, since it cannot do inplace processing"),
slv2_value_as_string(_name));
slv2_value_free(_name);
slv2_value_free(_author);
@@ -102,10 +109,11 @@ LV2Plugin::init (LV2World& world, SLV2Plugin plugin, nframes_t rate)
_data_access_feature.URI = "http://lv2plug.in/ns/ext/data-access";
_data_access_feature.data = &_data_access_extension_data;
- _features = (LV2_Feature**)malloc(sizeof(LV2_Feature*) * 3);
+ _features = (LV2_Feature**)malloc(sizeof(LV2_Feature*) * 4);
_features[0] = &_instance_access_feature;
_features[1] = &_data_access_feature;
- _features[2] = NULL;
+ _features[2] = _uri_map.feature();
+ _features[3] = NULL;
_sample_rate = rate;
@@ -347,7 +355,7 @@ LV2Plugin::set_state(const XMLNode& node)
nodes = node.children ("Port");
- for(iter = nodes.begin(); iter != nodes.end(); ++iter){
+ for (iter = nodes.begin(); iter != nodes.end(); ++iter){
child = *iter;
@@ -450,52 +458,55 @@ LV2Plugin::automatable () const
}
int
-LV2Plugin::connect_and_run (BufferSet& bufs, uint32_t& in_index, uint32_t& out_index, nframes_t nframes, nframes_t offset)
+LV2Plugin::connect_and_run (BufferSet& bufs,
+ ChanMapping in_map, ChanMapping out_map,
+ nframes_t nframes, nframes_t offset)
{
- uint32_t port_index;
cycles_t then, now;
- port_index = 0;
-
then = get_cycles ();
-
- const uint32_t nbufs = bufs.count().n_audio();
- while (port_index < parameter_count()) {
+ uint32_t audio_in_index = 0;
+ uint32_t audio_out_index = 0;
+ uint32_t midi_in_index = 0;
+ uint32_t midi_out_index = 0;
+ for (uint32_t port_index = 0; port_index < parameter_count(); ++port_index) {
if (parameter_is_audio(port_index)) {
if (parameter_is_input(port_index)) {
- const size_t index = min(in_index, nbufs - 1);
+ const uint32_t buf_index = in_map.get(DataType::AUDIO, audio_in_index++);
slv2_instance_connect_port(_instance, port_index,
- bufs.get_audio(index).data(offset));
- in_index++;
+ bufs.get_audio(buf_index).data(offset));
} else if (parameter_is_output(port_index)) {
- const size_t index = min(out_index,nbufs - 1);
+ const uint32_t buf_index = out_map.get(DataType::AUDIO, audio_out_index++);
slv2_instance_connect_port(_instance, port_index,
- bufs.get_audio(index).data(offset));
- out_index++;
+ bufs.get_audio(buf_index).data(offset));
}
} else if (parameter_is_midi(port_index)) {
- // FIXME: Switch MIDI buffer format to LV2 event buffer
if (parameter_is_input(port_index)) {
- //const size_t index = min(in_index, nbufs - 1);
- //slv2_instance_connect_port(_instance, port_index,
- // bufs.get_midi(index).data(offset));
- // FIXME: hope it's connection optional...
- slv2_instance_connect_port(_instance, port_index, NULL);
- in_index++;
+ const uint32_t buf_index = in_map.get(DataType::MIDI, midi_in_index++);
+ slv2_instance_connect_port(_instance, port_index,
+ bufs.get_lv2_midi(true, buf_index).data());
} else if (parameter_is_output(port_index)) {
- //const size_t index = min(out_index,nbufs - 1);
- //slv2_instance_connect_port(_instance, port_index,
- // bufs.get_midi(index).data(offset));
- // FIXME: hope it's connection optional...
- slv2_instance_connect_port(_instance, port_index, NULL);
- out_index++;
+ const uint32_t buf_index = out_map.get(DataType::MIDI, midi_out_index++);
+ slv2_instance_connect_port(_instance, port_index,
+ bufs.get_lv2_midi(false, buf_index).data());
}
+ } else if (!parameter_is_control(port_index)) {
+ std::cerr << "WARNING: Unknown LV2 port type, ignored" << endl;
+ slv2_instance_connect_port(_instance, port_index, NULL);
}
- port_index++;
}
run (nframes);
+
+ midi_out_index = 0;
+ for (uint32_t port_index = 0; port_index < parameter_count(); ++port_index) {
+ if (parameter_is_midi(port_index) && parameter_is_output(port_index)) {
+ const uint32_t buf_index = out_map.get(DataType::MIDI, midi_out_index++);
+ bufs.flush_lv2_midi(true, buf_index);
+ }
+ }
+
now = get_cycles ();
set_cycles ((uint32_t) (now - then));
@@ -520,8 +531,8 @@ bool
LV2Plugin::parameter_is_midi (uint32_t param) const
{
SLV2Port port = slv2_plugin_get_port_by_index(_plugin, param);
- return slv2_port_is_a(_plugin, port, _world.event_class)
- && slv2_port_supports_event(_plugin, port, _world.midi_class);
+ return slv2_port_is_a(_plugin, port, _world.event_class);
+ // && slv2_port_supports_event(_plugin, port, _world.midi_class);
}
bool
diff --git a/libs/ardour/lv2ext/lv2_event.h b/libs/ardour/lv2ext/lv2_event.h
new file mode 100644
index 0000000000..6ea90c896d
--- /dev/null
+++ b/libs/ardour/lv2ext/lv2_event.h
@@ -0,0 +1,260 @@
+/* lv2_event.h - C header file for the LV2 events extension.
+ *
+ * Copyright (C) 2006-2007 Lars Luthman <lars.luthman@gmail.com>
+ * Copyright (C) 2008 Dave Robillard <dave@drobilla.net>
+ *
+ * This header is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This header is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this header; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 01222-1307 USA
+ */
+
+#ifndef LV2_EVENT_H
+#define LV2_EVENT_H
+
+#define LV2_EVENT_URI "http://lv2plug.in/ns/ext/event"
+#define LV2_EVENT_AUDIO_STAMP 0
+
+#include <stdint.h>
+
+/** @file
+ * This header defines the code portion of the LV2 events extension with URI
+ * <http://lv2plug.in/ns/ext/event> ('lv2ev').
+ *
+ * This extension is a generic transport mechanism for time stamped events
+ * of any type (e.g. MIDI, OSC, ramps, etc). Each port can transport mixed
+ * events of any type; the type of events and timestamps are defined by a URI
+ * which is mapped to an integer by the host for performance reasons.
+ *
+ * This extension requires the host to support the LV2 URI Map extension.
+ * Any host which supports this extension MUST guarantee that any call to
+ * the LV2 URI Map uri_to_id function with the URI of this extension as the
+ * 'map' argument returns a value within the range of uint16_t.
+ */
+
+
+/** The best Pulses Per Quarter Note for tempo-based uint32_t timestmaps.
+ * Equal to 2^12 * 5 * 7 * 9 * 11 * 13 * 17, which is evenly divisble
+ * by all integers from 1 through 18 inclusive, and powers of 2 up to 2^12.
+ */
+static const uint32_t LV2_EVENT_PPQN = 3136573440U;
+
+
+/** An LV2 event (header only).
+ *
+ * LV2 events are generic time-stamped containers for any type of event.
+ * The type field defines the format of a given event's contents.
+ *
+ * This struct defines the header of an LV2 event. An LV2 event is a single
+ * chunk of POD (plain old data), usually contained in a flat buffer
+ * (see LV2_EventBuffer below). Unless a required feature says otherwise,
+ * hosts may assume a deep copy of an LV2 event can be created safely
+ * using a simple:
+ *
+ * memcpy(ev_copy, ev, sizeof(LV2_Event) + ev->size); (or equivalent)
+ */
+typedef struct {
+
+ /** The frames portion of timestamp. The units used here can optionally be
+ * set for a port (with the lv2ev:timeUnits property), otherwise this
+ * is audio frames, corresponding to the sample_count parameter of the
+ * LV2 run method (e.g. frame 0 is the first frame for that call to run).
+ */
+ uint32_t frames;
+
+ /** The sub-frames portion of timestamp. The units used here can
+ * optionally be set for a port (with the lv2ev:timeUnits property),
+ * otherwise this is 1/(2^32) of an audio frame.
+ */
+ uint32_t subframes;
+
+ /** The type of this event, as a number which represents some URI
+ * defining an event type. This value MUST be some value previously
+ * returned from a call to the uri_to_id function defined in the LV2
+ * URI map extension (see lv2_uri_map.h).
+ * There are special rules which must be followed depending on the type
+ * of an event. If the plugin recognizes an event type, the definition
+ * of that event type will describe how to interpret the event, and
+ * any required behaviour. Otherwise, if the type is 0, this event is a
+ * non-POD event and lv2_event_unref MUST be called if the event is
+ * 'dropped' (see above). Even if the plugin does not understand an event,
+ * it may pass the event through to an output by simply copying (and NOT
+ * calling lv2_event_unref). These rules are designed to allow for generic
+ * event handling plugins and large non-POD events, but with minimal hassle
+ * on simple plugins that "don't care" about these more advanced features.
+ */
+ uint16_t type;
+
+ /** The size of the data portion of this event in bytes, which immediately
+ * follows. The header size (12 bytes) is not included in this value.
+ */
+ uint16_t size;
+
+ /* size bytes of data follow here */
+
+} LV2_Event;
+
+
+
+/** A buffer of LV2 events (header only).
+ *
+ * Like events (which this contains) an event buffer is a single chunk of POD:
+ * the entire buffer (including contents) can be copied with a single memcpy.
+ * The first contained event begins sizeof(LV2_EventBuffer) bytes after
+ * the start of this struct.
+ *
+ * After this header, the buffer contains an event header (defined by struct
+ * LV2_Event), followed by that event's contents (padded to 64 bits), followed by
+ * another header, etc:
+ *
+ * | | | | | | |
+ * | | | | | | | | | | | | | | | | | | | | | | | | |
+ * |FRAMES |SUBFRMS|TYP|LEN|DATA..DATA..PAD|FRAMES | ...
+ */
+typedef struct {
+
+ /** The contents of the event buffer. This may or may not reside in the
+ * same block of memory as this header, plugins must not assume either.
+ * The host guarantees this points to at least capacity bytes of allocated
+ * memory (though only size bytes of that are valid events).
+ */
+ uint8_t* data;
+
+ /** The size of this event header in bytes (including everything).
+ *
+ * This is to allow for extending this header in the future without
+ * breaking binary compatibility. Whenever this header is copied,
+ * it MUST be done using this field (and NOT the sizeof this struct).
+ */
+ uint16_t header_size;
+
+ /** The type of the time stamps for events in this buffer.
+ * As a special exception, '0' always means audio frames and subframes
+ * (1/UINT32_MAX'th of a frame) in the sample rate passed to instantiate.
+ * INPUTS: The host must set this field to the numeric ID of some URI
+ * defining the meaning of the frames/subframes fields of contained
+ * events (obtained by the LV2 URI Map uri_to_id function with the URI
+ * of this extension as the 'map' argument, see lv2_uri_map.h).
+ * The host must never pass a plugin a buffer which uses a stamp type
+ * the plugin does not 'understand'. The value of this field must
+ * never change, except when connect_port is called on the input
+ * port, at which time the host MUST have set the stamp_type field to
+ * the value that will be used for all subsequent run calls.
+ * OUTPUTS: The plugin may set this to any value that has been returned
+ * from uri_to_id with the URI of this extension for a 'map' argument.
+ * When connected to a buffer with connect_port, output ports MUST set
+ * this field to the type of time stamp they will be writing. On any
+ * call to connect_port on an event input port, the plugin may change
+ * this field on any output port, it is the responsibility of the host
+ * to check if any of these values have changed and act accordingly.
+ */
+ uint16_t stamp_type;
+
+ /** The number of events in this buffer.
+ * INPUTS: The host must set this field to the number of events
+ * contained in the data buffer before calling run().
+ * The plugin must not change this field.
+ * OUTPUTS: The plugin must set this field to the number of events it
+ * has written to the buffer before returning from run().
+ * Any initial value should be ignored by the plugin.
+ */
+ uint32_t event_count;
+
+ /** The size of the data buffer in bytes.
+ * This is set by the host and must not be changed by the plugin.
+ * The host is allowed to change this between run() calls.
+ */
+ uint32_t capacity;
+
+ /** The size of the initial portion of the data buffer containing data.
+ * INPUTS: The host must set this field to the number of bytes used
+ * by all events it has written to the buffer (including headers)
+ * before calling the plugin's run().
+ * The plugin must not change this field.
+ * OUTPUTS: The plugin must set this field to the number of bytes
+ * used by all events it has written to the buffer (including headers)
+ * before returning from run().
+ * Any initial value should be ignored by the plugin.
+ */
+ uint32_t size;
+
+} LV2_Event_Buffer;
+
+
+/** Opaque pointer to host data. */
+typedef void* LV2_Event_Callback_Data;
+
+
+/** The data field of the LV2_Feature for this extension.
+ *
+ * To support this feature the host must pass an LV2_Feature struct to the
+ * plugin's instantiate method with URI "http://lv2plug.in/ns/ext/event"
+ * and data pointed to an instance of this struct.
+ */
+typedef struct {
+
+ /** Opaque pointer to host data.
+ *
+ * The plugin MUST pass this to any call to functions in this struct.
+ * Otherwise, it must not be interpreted in any way.
+ */
+ LV2_Event_Callback_Data callback_data;
+
+ /** Take a reference to a non-POD event.
+ *
+ * If a plugin receives an event with type 0, it means the event is a
+ * pointer to some object in memory and not a flat sequence of bytes
+ * in the buffer. When receiving a non-POD event, the plugin already
+ * has an implicit reference to the event. If the event is stored AND
+ * passed to an output, lv2_event_ref MUST be called on that event.
+ * If the event is only stored OR passed through, this is not necessary
+ * (as the plugin already has 1 implicit reference).
+ *
+ * @param event An event received at an input that will not be copied to
+ * an output or stored in any way.
+ * @param context The calling context. (Like event types) this is a mapped
+ * URI, see lv2_context.h. Simple plugin with just a run()
+ * method should pass 0 here (the ID of the 'standard' LV2
+ * run context). The host guarantees that this function is
+ * realtime safe iff @a context is realtime safe.
+ *
+ * PLUGINS THAT VIOLATE THESE RULES MAY CAUSE CRASHES AND MEMORY LEAKS.
+ */
+ uint32_t (*lv2_event_ref)(LV2_Event_Callback_Data callback_data,
+ LV2_Event* event);
+
+ /** Drop a reference to a non-POD event.
+ *
+ * If a plugin receives an event with type 0, it means the event is a
+ * pointer to some object in memory and not a flat sequence of bytes
+ * in the buffer. If the plugin does not pass the event through to
+ * an output or store it internally somehow, it MUST call this function
+ * on the event (more information on using non-POD events below).
+ *
+ * @param event An event received at an input that will not be copied to
+ * an output or stored in any way.
+ * @param context The calling context. (Like event types) this is a mapped
+ * URI, see lv2_context.h. Simple plugin with just a run()
+ * method should pass 0 here (the ID of the 'standard' LV2
+ * run context). The host guarantees that this function is
+ * realtime safe iff @a context is realtime safe.
+ *
+ * PLUGINS THAT VIOLATE THESE RULES MAY CAUSE CRASHES AND MEMORY LEAKS.
+ */
+ uint32_t (*lv2_event_unref)(LV2_Event_Callback_Data callback_data,
+ LV2_Event* event);
+
+} LV2_Event_Feature;
+
+
+#endif // LV2_EVENT_H
+
diff --git a/libs/ardour/lv2ext/lv2_event_helpers.h b/libs/ardour/lv2ext/lv2_event_helpers.h
new file mode 100644
index 0000000000..8659b9bfae
--- /dev/null
+++ b/libs/ardour/lv2ext/lv2_event_helpers.h
@@ -0,0 +1,243 @@
+/* lv2_event_helpers.h - Helper functions for the LV2 events extension.
+ *
+ * Copyright (C) 2008 Dave Robillard <dave@drobilla.net>
+ *
+ * This header is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This header is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this header; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 01222-1307 USA
+ */
+
+#ifndef LV2_EVENT_HELPERS_H
+#define LV2_EVENT_HELPERS_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "lv2_event.h"
+
+/** @file
+ * This header defines some helper functions for the the LV2 events extension
+ * with URI <http://lv2plug.in/ns/ext/event> ('lv2ev').
+ *
+ * These functions are provided for convenience only, use of them is not
+ * required for supporting lv2ev (i.e. the events extension is defined by the
+ * raw buffer format described in lv2_event.h and NOT by this API).
+ *
+ * Note that these functions are all static inline which basically means:
+ * do not take the address of these functions. */
+
+
+/** Pad a size to 64 bits (for event sizes) */
+static inline uint16_t
+lv2_event_pad_size(uint16_t size)
+{
+ return (size + 7) & (~7);
+}
+
+
+/** Initialize (empty, reset..) an existing event buffer.
+ * The contents of buf are ignored entirely and overwritten, except capacity
+ * which is unmodified. */
+static inline void
+lv2_event_buffer_reset(LV2_Event_Buffer* buf, uint16_t stamp_type, uint8_t *data)
+{
+ buf->data = data;
+ buf->header_size = sizeof(LV2_Event_Buffer);
+ buf->stamp_type = stamp_type;
+ buf->event_count = 0;
+ buf->size = 0;
+}
+
+
+/** Allocate a new, empty event buffer. */
+static inline LV2_Event_Buffer*
+lv2_event_buffer_new(uint32_t capacity, uint16_t stamp_type)
+{
+ LV2_Event_Buffer* buf = (LV2_Event_Buffer*)malloc(sizeof(LV2_Event_Buffer) + capacity);
+ if (buf != NULL) {
+ buf->capacity = capacity;
+ lv2_event_buffer_reset(buf, stamp_type, (uint8_t *)(buf + 1));
+ return buf;
+ } else {
+ return NULL;
+ }
+}
+
+
+/** An iterator over an LV2_Event_Buffer.
+ *
+ * Multiple simultaneous read iterators over a single buffer is fine,
+ * but changing the buffer invalidates all iterators (e.g. RW Lock). */
+typedef struct {
+ LV2_Event_Buffer* buf;
+ uint32_t offset;
+} LV2_Event_Iterator;
+
+
+/** Reset an iterator to point to the start of @a buf.
+ * @return True if @a iter is valid, otherwise false (buffer is empty) */
+static inline bool
+lv2_event_begin(LV2_Event_Iterator* iter,
+ LV2_Event_Buffer* buf)
+{
+ iter->buf = buf;
+ iter->offset = 0;
+ return (buf->size > 0);
+}
+
+
+/** Check if @a iter is valid..
+ * @return True if @a iter is valid, otherwise false (past end of buffer) */
+static inline bool
+lv2_event_is_valid(LV2_Event_Iterator* iter)
+{
+ return (iter->offset < iter->buf->size);
+}
+
+
+/** Advance @a iter forward one event.
+ * @a iter must be valid.
+ * @return True if @a iter is valid, otherwise false (reached end of buffer) */
+static inline bool
+lv2_event_increment(LV2_Event_Iterator* iter)
+{
+ assert(lv2_event_is_valid(iter));
+
+ LV2_Event* const ev = (LV2_Event*)(
+ (uint8_t*)iter->buf->data + iter->offset);
+
+ iter->offset += lv2_event_pad_size(sizeof(LV2_Event) + ev->size);
+
+ return true;
+}
+
+
+/** Dereference an event iterator (get the event currently pointed at).
+ * @a iter must be valid.
+ * @a data if non-NULL, will be set to point to the contents of the event
+ * returned.
+ * @return A Pointer to the event @a iter is currently pointing at, or NULL
+ * if the end of the buffer is reached (in which case @a data is
+ * also set to NULL). */
+static inline LV2_Event*
+lv2_event_get(LV2_Event_Iterator* iter,
+ uint8_t** data)
+{
+ assert(lv2_event_is_valid(iter));
+
+ LV2_Event* const ev = (LV2_Event*)(
+ (uint8_t*)iter->buf->data + iter->offset);
+
+ if (data)
+ *data = (uint8_t*)ev + sizeof(LV2_Event);
+
+ return ev;
+}
+
+
+/** Write an event at @a iter.
+ * The event (if any) pointed to by @iter will be overwritten, and @a iter
+ * incremented to point to the following event (i.e. several calls to this
+ * function can be done in sequence without twiddling iter in-between).
+ * @return True if event was written, otherwise false (buffer is full). */
+static inline bool
+lv2_event_write(LV2_Event_Iterator* iter,
+ uint32_t frames,
+ uint32_t subframes,
+ uint16_t type,
+ uint16_t size,
+ const uint8_t* data)
+{
+ if (iter->buf->capacity - iter->buf->size < sizeof(LV2_Event) + size)
+ return false;
+
+ LV2_Event* const ev = (LV2_Event*)(
+ (uint8_t*)iter->buf->data + iter->offset);
+
+ ev->frames = frames;
+ ev->subframes = subframes;
+ ev->type = type;
+ ev->size = size;
+ memcpy((uint8_t*)ev + sizeof(LV2_Event), data, size);
+ ++iter->buf->event_count;
+
+ size = lv2_event_pad_size(sizeof(LV2_Event) + size);
+ iter->buf->size += size;
+ iter->offset += size;
+
+ return true;
+}
+
+
+/** Reserve space for an event in the buffer and return a pointer to
+ the memory where the caller can write the event data, or NULL if there
+ is not enough room in the buffer. */
+static inline uint8_t*
+lv2_event_reserve(LV2_Event_Iterator* iter,
+ uint32_t frames,
+ uint32_t subframes,
+ uint16_t type,
+ uint16_t size)
+{
+ size = lv2_event_pad_size(size);
+ if (iter->buf->capacity - iter->buf->size < sizeof(LV2_Event) + size)
+ return NULL;
+
+ LV2_Event* const ev = (LV2_Event*)((uint8_t*)iter->buf->data +
+ iter->offset);
+
+ ev->frames = frames;
+ ev->subframes = subframes;
+ ev->type = type;
+ ev->size = size;
+ ++iter->buf->event_count;
+
+ size = lv2_event_pad_size(sizeof(LV2_Event) + size);
+ iter->buf->size += size;
+ iter->offset += size;
+
+ return (uint8_t*)ev + sizeof(LV2_Event);
+}
+
+
+/** Write an event at @a iter.
+ * The event (if any) pointed to by @iter will be overwritten, and @a iter
+ * incremented to point to the following event (i.e. several calls to this
+ * function can be done in sequence without twiddling iter in-between).
+ * @return True if event was written, otherwise false (buffer is full). */
+static inline bool
+lv2_event_write_event(LV2_Event_Iterator* iter,
+ const LV2_Event* ev,
+ const uint8_t* data)
+{
+ if (iter->buf->capacity - iter->buf->size < sizeof(LV2_Event) + ev->size)
+ return false;
+
+ LV2_Event* const write_ev = (LV2_Event*)(
+ (uint8_t*)iter->buf->data + iter->offset);
+
+ *write_ev = *ev;
+ memcpy((uint8_t*)write_ev + sizeof(LV2_Event), data, ev->size);
+ ++iter->buf->event_count;
+
+ const uint16_t size = lv2_event_pad_size(sizeof(LV2_Event) + ev->size);
+ iter->buf->size += size;
+ iter->offset += size;
+
+ return true;
+}
+
+#endif // LV2_EVENT_HELPERS_H
+
diff --git a/libs/ardour/lv2ext/lv2_uri_map.h b/libs/ardour/lv2ext/lv2_uri_map.h
new file mode 100644
index 0000000000..1c2f5b0883
--- /dev/null
+++ b/libs/ardour/lv2ext/lv2_uri_map.h
@@ -0,0 +1,88 @@
+/* lv2_uri_map.h - C header file for the LV2 URI Map extension.
+ *
+ * Copyright (C) 2008 Dave Robillard <dave@drobilla.net>
+ *
+ * This header is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This header is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this header; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 01222-1307 USA
+ */
+
+#ifndef LV2_URI_MAP_H
+#define LV2_URI_MAP_H
+
+#define LV2_URI_MAP_URI "http://lv2plug.in/ns/ext/uri-map"
+
+#include <stdint.h>
+
+/** @file
+ * This header defines the LV2 URI Map extension with the URI
+ * <http://lv2plug.in/ns/ext/uri-map> (preferred prefix 'lv2urimap').
+ *
+ * This extension defines a simple mechanism for plugins to map URIs to
+ * integers, usually for performance reasons (e.g. processing events
+ * typed by URIs in real time). The expected use case is for plugins to
+ * map URIs to integers for things they 'understand' at instantiation time,
+ * and store those values for use in the audio thread without doing any string
+ * comparison. This allows the extensibility of RDF with the performance of
+ * integers (or centrally defined enumerations).
+ */
+
+
+/** Opaque pointer to host data. */
+typedef void* LV2_URI_Map_Callback_Data;
+
+
+/** The data field of the LV2_Feature for this extension.
+ *
+ * To support this feature the host must pass an LV2_Feature struct to the
+ * plugin's instantiate method with URI "http://lv2plug.in/ns/ext/uri-map"
+ * and data pointed to an instance of this struct.
+ */
+typedef struct {
+
+ /** Opaque pointer to host data.
+ *
+ * The plugin MUST pass this to any call to functions in this struct.
+ * Otherwise, it must not be interpreted in any way.
+ */
+ LV2_URI_Map_Callback_Data callback_data;
+
+ /** Get the numeric ID of a URI from the host.
+ *
+ * @param callback_data Must be the callback_data member of this struct.
+ * @param map The 'context' of this URI. Certain extensions may define a
+ * URI that must be passed here with certain restrictions on the
+ * return value (e.g. limited range). This value may be NULL if
+ * the plugin needs an ID for a URI in general.
+ * @param uri The URI to be mapped to an integer ID.
+ *
+ * This function is referentially transparent - any number of calls with
+ * the same arguments is guaranteed to return the same value over the life
+ * of a plugin instance (though the same URI may return different values
+ * with a different map parameter). However, this function is not
+ * necessarily very fast: plugins should cache any IDs they might need in
+ * performance critical situations.
+ * The return value 0 is reserved and means an ID for that URI could not
+ * be created for whatever reason. Extensions may define more precisely
+ * what this means, but in general plugins should gracefully handle 0
+ * and consider whatever they wanted the URI for "unsupported".
+ */
+ uint32_t (*uri_to_id)(LV2_URI_Map_Callback_Data callback_data,
+ const char* map,
+ const char* uri);
+
+} LV2_URI_Map_Feature;
+
+
+#endif // LV2_URI_MAP_H
+
diff --git a/libs/ardour/midi_buffer.cc b/libs/ardour/midi_buffer.cc
index 2a1426ab61..fd42c45fe7 100644
--- a/libs/ardour/midi_buffer.cc
+++ b/libs/ardour/midi_buffer.cc
@@ -124,11 +124,37 @@ MidiBuffer::push_back(const Evoral::MIDIEvent<TimeType>& ev)
return false;
}
+ push_back(ev.time(), ev.size(), ev.buffer());
+
+ return true;
+}
+
+
+/** Push an event into the buffer.
+ * @return false if operation failed (not enough room)
+ */
+bool
+MidiBuffer::push_back(TimeType time, size_t size, const uint8_t* data)
+{
+ const size_t stamp_size = sizeof(TimeType);
+ /*cerr << "MidiBuffer: pushing event @ " << ev.time()
+ << " size = " << ev.size() << endl;*/
+
+ if (_size + stamp_size + size >= _capacity) {
+ cerr << "MidiBuffer::push_back failed (buffer is full)" << endl;
+ return false;
+ }
+
+ if (!Evoral::midi_event_is_valid(data, size)) {
+ cerr << "WARNING: MidiBuffer ignoring illegal MIDI event" << endl;
+ return false;
+ }
+
uint8_t* const write_loc = _data + _size;
- *((TimeType*)write_loc) = ev.time();
- memcpy(write_loc + stamp_size, ev.buffer(), ev.size());
+ *((TimeType*)write_loc) = time;
+ memcpy(write_loc + stamp_size, data, size);
- _size += stamp_size + ev.size();
+ _size += stamp_size + size;
_silent = false;
return true;
diff --git a/libs/ardour/midi_port.cc b/libs/ardour/midi_port.cc
index f2f347a076..30084c6718 100644
--- a/libs/ardour/midi_port.cc
+++ b/libs/ardour/midi_port.cc
@@ -26,12 +26,10 @@ using namespace ARDOUR;
using namespace std;
MidiPort::MidiPort (const std::string& name, Flags flags)
- : Port (name, DataType::MIDI, flags)
+ : Port (name, DataType::MIDI, flags)
, _has_been_mixed_down (false)
{
- // FIXME: size kludge (see BufferSet::ensure_buffers)
- // Jack needs to tell us this
- _buffer = new MidiBuffer (1024 * 32);
+ _buffer = new MidiBuffer (raw_buffer_size(0));
}
MidiPort::~MidiPort()
@@ -39,7 +37,6 @@ MidiPort::~MidiPort()
delete _buffer;
}
-
void
MidiPort::cycle_start (nframes_t nframes)
{
@@ -133,3 +130,9 @@ MidiPort::flush_buffers (nframes_t nframes, nframes_t offset)
}
}
+size_t
+MidiPort::raw_buffer_size (nframes_t nframes) const
+{
+ return jack_midi_max_event_size(jack_port_get_buffer(_jack_port, nframes));
+}
+
diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc
index 3b16f25f9e..8451d538bf 100644
--- a/libs/ardour/midi_track.cc
+++ b/libs/ardour/midi_track.cc
@@ -579,6 +579,7 @@ MidiTrack::process_output_buffers (BufferSet& bufs,
Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK);
if (rm.locked()) {
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
+ bufs.set_count(ChanCount::max(bufs.count(), (*i)->output_streams()));
(*i)->run_in_place (bufs, start_frame, end_frame, nframes);
}
}
diff --git a/libs/ardour/plugin_insert.cc b/libs/ardour/plugin_insert.cc
index b4902bf7df..bf67e33493 100644
--- a/libs/ardour/plugin_insert.cc
+++ b/libs/ardour/plugin_insert.cc
@@ -234,7 +234,7 @@ PluginInsert::parameter_changed (Evoral::Parameter which, float val)
if (which.type() != PluginAutomation)
return;
- vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin();
+ Plugins::iterator i = _plugins.begin();
/* don't set the first plugin, just all the slaves */
@@ -249,7 +249,7 @@ PluginInsert::parameter_changed (Evoral::Parameter which, float val)
void
PluginInsert::set_block_size (nframes_t nframes)
{
- for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
+ for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
(*i)->set_block_size (nframes);
}
}
@@ -257,7 +257,7 @@ PluginInsert::set_block_size (nframes_t nframes)
void
PluginInsert::activate ()
{
- for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
+ for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
(*i)->activate ();
}
}
@@ -265,7 +265,7 @@ PluginInsert::activate ()
void
PluginInsert::deactivate ()
{
- for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
+ for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
(*i)->deactivate ();
}
}
@@ -280,8 +280,8 @@ PluginInsert::connect_and_run (BufferSet& bufs, nframes_t nframes, nframes_t off
collect_signal_nframes = nframes;
}
- uint32_t in_index = 0;
- uint32_t out_index = 0;
+ ChanMapping in_map(input_streams());
+ ChanMapping out_map(output_streams());
/* Note that we've already required that plugins
be able to handle in-place processing.
@@ -315,15 +315,19 @@ PluginInsert::connect_and_run (BufferSet& bufs, nframes_t nframes, nframes_t off
//std::cerr << " streams " << input_streams().n_audio() << std::endl;
//std::cerr << "filling buffer with " << collect_signal_nframes << " frames at " << _signal_analysis_collected_nframes << std::endl;
for (uint32_t i = 0; i < input_streams().n_audio(); ++i) {
- _signal_analysis_input_bufferset.get_audio(i).read_from(
+ _signal_analysis_inputs.get_audio(i).read_from(
bufs.get_audio(i),
collect_signal_nframes,
_signal_analysis_collected_nframes); // offset is for target buffer
}
}
- for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
- (*i)->connect_and_run (bufs, in_index, out_index, nframes, offset);
+ for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
+ (*i)->connect_and_run (bufs, in_map, out_map, nframes, offset);
+ for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+ in_map.offset(*t, input_streams().get(*t));
+ out_map.offset(*t, output_streams().get(*t));
+ }
}
if (collect_signal_nframes > 0) {
@@ -331,7 +335,7 @@ PluginInsert::connect_and_run (BufferSet& bufs, nframes_t nframes, nframes_t off
//std::cerr << " output, bufs " << bufs.count().n_audio() << " count, " << bufs.available().n_audio() << " available" << std::endl;
//std::cerr << " streams " << output_streams().n_audio() << std::endl;
for (uint32_t i = 0; i < output_streams().n_audio(); ++i) {
- _signal_analysis_output_bufferset.get_audio(i).read_from(
+ _signal_analysis_outputs.get_audio(i).read_from(
bufs.get_audio(i),
collect_signal_nframes,
_signal_analysis_collected_nframes); // offset is for target buffer
@@ -344,8 +348,8 @@ PluginInsert::connect_and_run (BufferSet& bufs, nframes_t nframes, nframes_t off
_signal_analysis_collect_nframes_max = 0;
_signal_analysis_collected_nframes = 0;
- AnalysisDataGathered(&_signal_analysis_input_bufferset,
- &_signal_analysis_output_bufferset);
+ AnalysisDataGathered(&_signal_analysis_inputs,
+ &_signal_analysis_outputs);
}
}
/* leave remaining channel buffers alone */
@@ -354,12 +358,12 @@ PluginInsert::connect_and_run (BufferSet& bufs, nframes_t nframes, nframes_t off
void
PluginInsert::silence (nframes_t nframes)
{
- uint32_t in_index = 0;
- uint32_t out_index = 0;
+ ChanMapping in_map(input_streams());
+ ChanMapping out_map(output_streams());
if (active()) {
- for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
- (*i)->connect_and_run (_session.get_silent_buffers ((*i)->get_info()->n_inputs), in_index, out_index, nframes, 0);
+ for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
+ (*i)->connect_and_run (_session.get_silent_buffers ((*i)->get_info()->n_inputs), in_map, out_map, nframes, 0);
}
}
}
@@ -546,12 +550,11 @@ PluginInsert::configure_io (ChanCount in, ChanCount out)
// current buffer size here. each request for data fills in these
// buffers and the analyser makes sure it gets enough data for the
// analysis window
- _signal_analysis_input_bufferset.ensure_buffers (in, session().engine().frames_per_cycle());
- _signal_analysis_input_bufferset.set_count(in);
-
- _signal_analysis_output_bufferset.ensure_buffers(out, session().engine().frames_per_cycle());
- _signal_analysis_output_bufferset.set_count(out);
-
+ session().ensure_buffer_set (_signal_analysis_inputs, in);
+ _signal_analysis_inputs.set_count (in);
+
+ session().ensure_buffer_set (_signal_analysis_outputs, out);
+ _signal_analysis_outputs.set_count (out);
return Processor::configure_io (in, out);
}
@@ -759,7 +762,7 @@ PluginInsert::set_state(const XMLNode& node)
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
if ((*niter)->name() == plugin->state_node_name()) {
- for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
+ for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
(*i)->set_state (**niter);
}
break;
@@ -939,7 +942,7 @@ PluginInsert::PluginControl::set_value (float val)
}
- for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugin->_plugins.begin();
+ for (Plugins::iterator i = _plugin->_plugins.begin();
i != _plugin->_plugins.end(); ++i) {
(*i)->set_parameter (_list->parameter().id(), val);
}
@@ -989,3 +992,16 @@ PluginInsert::get_impulse_analysis_plugin()
return ret;
}
+void
+PluginInsert::collect_signal_for_analysis(nframes_t nframes)
+{
+ // called from outside the audio thread, so this should be safe
+ for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+ _session.ensure_buffer_set(_signal_analysis_inputs, input_streams());
+ _session.ensure_buffer_set(_signal_analysis_outputs, output_streams());
+ }
+
+ _signal_analysis_collected_nframes = 0;
+ _signal_analysis_collect_nframes_max = nframes;
+}
+
diff --git a/libs/ardour/processor.cc b/libs/ardour/processor.cc
index e521e3702c..8ea45de406 100644
--- a/libs/ardour/processor.cc
+++ b/libs/ardour/processor.cc
@@ -248,12 +248,12 @@ Processor::set_state (const XMLNode& node)
bool
Processor::configure_io (ChanCount in, ChanCount out)
{
- /* this class assumes static output stream count.
- Derived classes must override, and must set "out"
- to reflect "in" before calling this.
- */
+ /* This class assumes 1:1 input:output.static output stream count.
+ Derived classes must override and set _configured_output appropriately
+ if this is not the case */
_configured_input = in;
+ _configured_output = out;
_configured = true;
return true;
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc
index 5a600cca7e..6179af5028 100644
--- a/libs/ardour/route.cc
+++ b/libs/ardour/route.cc
@@ -85,7 +85,7 @@ Route::Route (Session& sess, const XMLNode& node, DataType default_type)
void
Route::init ()
{
- processor_max_outs.reset();
+ processor_max_streams.reset();
_muted = false;
_soloed = false;
_solo_safe = false;
@@ -1049,7 +1049,15 @@ Route::process_output_buffers (BufferSet& bufs,
ChanCount
Route::n_process_buffers ()
{
- return max (n_inputs(), processor_max_outs);
+ return max (n_inputs(), processor_max_streams);
+}
+
+void
+Route::setup_peak_meters()
+{
+ ChanCount max_streams = std::max (_inputs.count(), _outputs.count());
+ max_streams = std::max (max_streams, processor_max_streams);
+ _meter->configure_io (max_streams, max_streams);
}
void
@@ -1169,9 +1177,9 @@ Route::set_mute (bool yn, void *src)
int
Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams* err)
{
- ChanCount old_pmo = processor_max_outs;
+ ChanCount old_pms = processor_max_streams;
- if (!_session.engine().connected()) {
+ if (!_session.engine().connected() || !processor) {
return 1;
}
@@ -1220,7 +1228,7 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams*
_user_latency = 0;
}
- if (processor_max_outs != old_pmo || old_pmo == ChanCount::ZERO) {
+ if (processor_max_streams != old_pms || old_pms == ChanCount::ZERO) {
reset_panner ();
}
@@ -1237,7 +1245,7 @@ Route::add_processors (const ProcessorList& others, ProcessorStreams* err)
differences between this and ::add_processor()
*/
- ChanCount old_pmo = processor_max_outs;
+ ChanCount old_pms = processor_max_streams;
if (!_session.engine().connected()) {
return 1;
@@ -1281,7 +1289,7 @@ Route::add_processors (const ProcessorList& others, ProcessorStreams* err)
_user_latency = 0;
}
- if (processor_max_outs != old_pmo || old_pmo == ChanCount::ZERO) {
+ if (processor_max_streams != old_pms || old_pms == ChanCount::ZERO) {
reset_panner ();
}
@@ -1428,7 +1436,7 @@ Route::pre_fader_streams() const
void
Route::clear_processors (Placement p)
{
- const ChanCount old_pmo = processor_max_outs;
+ const ChanCount old_pms = processor_max_streams;
if (!_session.engine().connected()) {
return;
@@ -1452,11 +1460,11 @@ Route::clear_processors (Placement p)
}
/* FIXME: can't see how this test can ever fire */
- if (processor_max_outs != old_pmo) {
+ if (processor_max_streams != old_pms) {
reset_panner ();
}
- processor_max_outs.reset();
+ processor_max_streams.reset();
_have_internal_generator = false;
processors_changed (); /* EMIT SIGNAL */
}
@@ -1464,13 +1472,13 @@ Route::clear_processors (Placement p)
int
Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStreams* err)
{
- ChanCount old_pmo = processor_max_outs;
+ ChanCount old_pms = processor_max_streams;
if (!_session.engine().connected()) {
return 1;
}
- processor_max_outs.reset();
+ processor_max_streams.reset();
{
Glib::RWLock::WriterLock lm (_processor_lock);
@@ -1538,7 +1546,7 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
}
}
- if (old_pmo != processor_max_outs) {
+ if (old_pms != processor_max_streams) {
reset_panner ();
}
@@ -1570,7 +1578,7 @@ Route::_reset_processor_counts (ProcessorStreams* err)
uint32_t max_audio = 0;
uint32_t max_midi = 0;
- processor_max_outs.reset ();
+ processor_max_streams.reset ();
/* Step 1: build a map that links each insert to an in/out channel count
@@ -1664,7 +1672,7 @@ Route::_reset_processor_counts (ProcessorStreams* err)
recompute:
- processor_max_outs.reset ();
+ processor_max_streams.reset ();
prev = _processors.end();
for (r = _processors.begin(); r != _processors.end(); prev = r, ++r) {
@@ -1684,14 +1692,16 @@ Route::_reset_processor_counts (ProcessorStreams* err)
} else {
+ max_audio = max ((*r)->input_streams ().n_audio(), max_audio);
+ max_midi = max ((*r)->input_streams ().n_midi(), max_midi);
max_audio = max ((*r)->output_streams ().n_audio(), max_audio);
max_midi = max ((*r)->output_streams ().n_midi(), max_midi);
}
}
- processor_max_outs.set (DataType::AUDIO, max_audio);
- processor_max_outs.set (DataType::MIDI, max_midi);
-
+ processor_max_streams.set (DataType::AUDIO, max_audio);
+ processor_max_streams.set (DataType::MIDI, max_midi);
+
/* we're done */
return 0;
@@ -1701,9 +1711,9 @@ Route::_reset_processor_counts (ProcessorStreams* err)
max_midi = max ((*r)->output_streams ().n_midi(), max_midi);
}
- processor_max_outs.set (DataType::AUDIO, max_audio);
- processor_max_outs.set (DataType::MIDI, max_midi);
-
+ processor_max_streams.set (DataType::AUDIO, max_audio);
+ processor_max_streams.set (DataType::MIDI, max_midi);
+
return ret;
}
@@ -1821,7 +1831,7 @@ Route::sort_processors (ProcessorStreams* err)
{
ProcessorSorter comparator;
Glib::RWLock::WriterLock lm (_processor_lock);
- ChanCount old_pmo = processor_max_outs;
+ ChanCount old_pms = processor_max_streams;
/* the sweet power of C++ ... */
@@ -1831,7 +1841,7 @@ Route::sort_processors (ProcessorStreams* err)
if (_reset_processor_counts (err)) {
_processors = as_it_was_before;
- processor_max_outs = old_pmo;
+ processor_max_streams = old_pms;
return -1;
}
}
@@ -2332,15 +2342,18 @@ Route::_set_processor_states(const XMLNodeList &nlist)
(*i)->id().print (buf, sizeof (buf));
-
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
// legacy sessions (IOProcessor as a child of Processor, both is-a IO)
- if (strncmp(buf,(*niter)->child(X_("IOProcessor"))->child(X_("IO"))->property(X_("id"))->value().c_str(), sizeof(buf)) == 0) {
+ XMLNode* ioproc_node = (*niter)->child(X_("IOProcessor"));
+ if (ioproc_node && strncmp(buf, ioproc_node->child(X_("IO"))->property(X_("id"))->value().c_str(), sizeof(buf)) == 0) {
processorInStateList = true;
break;
- } else if (strncmp(buf,(*niter)->property(X_("id"))->value().c_str(), sizeof(buf)) == 0) {
- processorInStateList = true;
+ } else {
+ XMLProperty* id_prop = (*niter)->property(X_("id"));
+ if (id_prop && strncmp(buf, id_prop->value().c_str(), sizeof(buf)) == 0) {
+ processorInStateList = true;
+ }
break;
}
}
@@ -2349,7 +2362,6 @@ Route::_set_processor_states(const XMLNodeList &nlist)
remove_processor (*i);
}
-
i = tmp;
}
@@ -2364,11 +2376,16 @@ Route::_set_processor_states(const XMLNodeList &nlist)
while (o != _processors.end()) {
(*o)->id().print (buf, sizeof (buf));
- if ( strncmp(buf, (*niter)->child(X_("IOProcessor"))->child(X_("IO"))->property(X_("id"))->value().c_str(), sizeof(buf)) == 0)
+ XMLNode* ioproc_node = (*niter)->child(X_("IOProcessor"));
+ if (ioproc_node && strncmp(buf, ioproc_node->child(X_("IO"))->property(X_("id"))->value().c_str(), sizeof(buf)) == 0) {
break;
- else if (strncmp(buf,(*niter)->property(X_("id"))->value().c_str(), sizeof(buf)) == 0)
- break;
-
+ } else {
+ XMLProperty* id_prop = (*niter)->property(X_("id"));
+ if (id_prop && strncmp(buf, id_prop->value().c_str(), sizeof(buf)) == 0) {
+ break;
+ }
+ }
+
++o;
}
@@ -2732,7 +2749,7 @@ Route::pans_required () const
return 0;
}
- return max (n_inputs ().n_audio(), processor_max_outs.n_audio());
+ return max (n_inputs ().n_audio(), processor_max_streams.n_audio());
}
int
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index c5904de869..0297aa76bb 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -3849,21 +3849,24 @@ Session::ensure_buffers (ChanCount howmany)
return; // too early? (is this ok?)
}
- // We need at least 2 MIDI scratch buffers to mix/merge
- if (howmany.n_midi() < 2) {
- howmany.set_midi(2);
+ for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+ size_t count = std::max(_scratch_buffers->available().get(*t), howmany.get(*t));
+ _scratch_buffers->ensure_buffers (*t, count, _engine.raw_buffer_size(*t));
+ _mix_buffers->ensure_buffers (*t, count, _engine.raw_buffer_size(*t));
+ _silent_buffers->ensure_buffers (*t, count, _engine.raw_buffer_size(*t));
}
- // FIXME: JACK needs to tell us maximum MIDI buffer size
- // Using nasty assumption (max # events == nframes) for now
-
- _scratch_buffers->ensure_buffers(howmany, current_block_size);
- _mix_buffers->ensure_buffers(howmany, current_block_size);
- _silent_buffers->ensure_buffers(howmany, current_block_size);
-
allocate_pan_automation_buffers (current_block_size, howmany.n_audio(), false);
}
+void
+Session::ensure_buffer_set(BufferSet& buffers, const ChanCount& count)
+{
+ for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+ buffers.ensure_buffers(*t, count.get(*t), _engine.raw_buffer_size(*t));
+ }
+}
+
uint32_t
Session::next_insert_id ()
{
@@ -4149,7 +4152,7 @@ Session::write_one_track (AudioTrack& track, nframes_t start, nframes_t end,
to_do = len;
/* create a set of reasonably-sized buffers */
- buffers.ensure_buffers(nchans, chunk_size);
+ buffers.ensure_buffers(DataType::AUDIO, nchans.n_audio(), chunk_size);
buffers.set_count(nchans);
for (vector<boost::shared_ptr<Source> >::iterator src=srcs.begin(); src != srcs.end(); ++src) {
diff --git a/libs/ardour/template_utils.cc b/libs/ardour/template_utils.cc
index 6dac270a50..22fc6f38df 100644
--- a/libs/ardour/template_utils.cc
+++ b/libs/ardour/template_utils.cc
@@ -94,8 +94,6 @@ find_session_templates (vector<TemplateInfo>& template_names)
continue;
}
- XMLNode* root = tree.root();
-
TemplateInfo rti;
rti.name = basename_nosuffix (fullpath);
diff --git a/libs/ardour/uri_map.cc b/libs/ardour/uri_map.cc
new file mode 100644
index 0000000000..fc82255ef8
--- /dev/null
+++ b/libs/ardour/uri_map.cc
@@ -0,0 +1,74 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2008 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen 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.
+ *
+ * Ingen 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
+ */
+
+#define __STDC_LIMIT_MACROS 1
+#include <cassert>
+#include <iostream>
+#include <stdint.h>
+#include "ardour/uri_map.h"
+
+using namespace std;
+
+namespace ARDOUR {
+
+
+URIMap::URIMap()
+ : next_uri_id(1)
+{
+ uri_map_feature_data.uri_to_id = &URIMap::uri_map_uri_to_id;
+ uri_map_feature_data.callback_data = this;
+ uri_map_feature.URI = LV2_URI_MAP_URI;
+ uri_map_feature.data = &uri_map_feature_data;
+}
+
+
+uint32_t
+URIMap::uri_to_id(const char* map,
+ const char* uri)
+{
+ return uri_map_uri_to_id(this, map, uri);
+}
+
+
+uint32_t
+URIMap::uri_map_uri_to_id(LV2_URI_Map_Callback_Data callback_data,
+ const char* map,
+ const char* uri)
+{
+ // TODO: map ignored, < UINT16_MAX assumed
+
+ URIMap* me = (URIMap*)callback_data;
+ uint32_t ret = 0;
+
+ Map::iterator i = me->uri_map.find(uri);
+ if (i != me->uri_map.end()) {
+ ret = i->second;
+ } else {
+ ret = me->next_uri_id++;
+ me->uri_map.insert(make_pair(string(uri), ret));
+ }
+
+ /*cout << "URI MAP (" << (map ? (void*)map : NULL)
+ << "): " << uri << " -> " << ret << endl;*/
+
+ assert(ret <= UINT16_MAX);
+ return ret;
+}
+
+
+} // namespace ARDOUR
+
diff --git a/libs/ardour/vst_plugin.cc b/libs/ardour/vst_plugin.cc
index 2566357f87..0aca137150 100644
--- a/libs/ardour/vst_plugin.cc
+++ b/libs/ardour/vst_plugin.cc
@@ -383,7 +383,9 @@ VSTPlugin::automatable () const
}
int
-VSTPlugin::connect_and_run (BufferSet& bufs, uint32_t& in_index, uint32_t& out_index, nframes_t nframes, nframes_t offset)
+VSTPlugin::connect_and_run (BufferSet& bufs,
+ ChanMapping in_map, ChanMapping out_map,
+ nframes_t nframes, nframes_t offset)
{
float *ins[_plugin->numInputs];
float *outs[_plugin->numOutputs];
diff --git a/libs/ardour/wscript b/libs/ardour/wscript
index 91a1bd0e50..2c612f7b9f 100644
--- a/libs/ardour/wscript
+++ b/libs/ardour/wscript
@@ -124,8 +124,8 @@ def build(bld):
export_status.cc
export_timespan.cc
export_utilities.cc
- filename_extensions.cc
file_source.cc
+ filename_extensions.cc
filesystem_paths.cc
filter.cc
find_session.cc
@@ -139,6 +139,7 @@ def build(bld):
ladspa_plugin.cc
location.cc
location_importer.cc
+ lv2_event_buffer.cc
meter.cc
midi_buffer.cc
midi_clock_slave.cc
@@ -198,7 +199,7 @@ def build(bld):
sndfilesource.cc
source.cc
source_factory.cc
- strip_silence.cc
+ strip_silence.cc
svn_revision.cc
tape_file_matcher.cc
template_utils.cc
@@ -209,6 +210,7 @@ def build(bld):
transient_detector.cc
user_bundle.cc
utils.cc
+ uri_map.cc
version.cc
'''
obj.export_incdirs = ['.']