Preliminary MIDI plugin support.
git-svn-id: svn://localhost/ardour2/branches/3.0@5036 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
@@ -29,11 +29,12 @@ using namespace ARDOUR;
|
||||
using namespace PBD;
|
||||
|
||||
void
|
||||
LV2PluginUI::lv2_ui_write(LV2UI_Controller controller,
|
||||
uint32_t port_index,
|
||||
uint32_t buffer_size,
|
||||
uint32_t format,
|
||||
const void* buffer)
|
||||
LV2PluginUI::lv2_ui_write(
|
||||
LV2UI_Controller controller,
|
||||
uint32_t port_index,
|
||||
uint32_t buffer_size,
|
||||
uint32_t format,
|
||||
const void* buffer)
|
||||
{
|
||||
LV2PluginUI* me = (LV2PluginUI*)controller;
|
||||
if (*(float*)buffer != me->_values[port_index])
|
||||
|
||||
@@ -118,12 +118,6 @@ Panner2d::reset (uint32_t n_inputs)
|
||||
|
||||
case 2:
|
||||
pucks[0]->set_text ("R");
|
||||
assert(existing_pucks >= 0);
|
||||
// FIXME: Impossible (unsigned)
|
||||
if (existing_pucks < 0) {
|
||||
pucks[0]->x.set_value (0.5f);
|
||||
pucks[1]->y.set_value (0.25f);
|
||||
}
|
||||
pucks[0]->visible = true;
|
||||
pucks[1]->set_text ("L");
|
||||
if (existing_pucks < 2) {
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "gui_thread.h"
|
||||
#include "ardour/audio_buffer.h"
|
||||
#include "ardour/data_type.h"
|
||||
#include "ardour/chan_mapping.h"
|
||||
|
||||
#include <gtkmm/box.h>
|
||||
#include <gtkmm/button.h>
|
||||
@@ -310,18 +311,16 @@ PluginEqGui::run_impulse_analysis()
|
||||
|
||||
// Create the impulse, can't use silence() because consecutive calls won't work
|
||||
for (uint32_t i = 0; i < inputs; ++i) {
|
||||
ARDOUR::AudioBuffer &buf = _bufferset.get_audio(i);
|
||||
ARDOUR::Sample *d = buf.data();
|
||||
ARDOUR::AudioBuffer& buf = _bufferset.get_audio(i);
|
||||
ARDOUR::Sample* d = buf.data();
|
||||
memset(d, 0, sizeof(ARDOUR::Sample)*_buffer_size);
|
||||
*d = 1.0;
|
||||
}
|
||||
|
||||
uint32_t x,y;
|
||||
x=y=0;
|
||||
ARDOUR::ChanMapping in_map(_plugin->get_info()->n_inputs);
|
||||
ARDOUR::ChanMapping out_map(_plugin->get_info()->n_outputs);
|
||||
|
||||
|
||||
|
||||
_plugin->connect_and_run(_bufferset, x, y, _buffer_size, (nframes_t)0);
|
||||
_plugin->connect_and_run(_bufferset, in_map, out_map, _buffer_size, (nframes_t)0);
|
||||
nframes_t f = _plugin->signal_latency();
|
||||
// Adding user_latency() could be interesting
|
||||
|
||||
@@ -378,8 +377,9 @@ PluginEqGui::run_impulse_analysis()
|
||||
memset(d, 0, sizeof(ARDOUR::Sample)*_buffer_size);
|
||||
}
|
||||
|
||||
x=y=0;
|
||||
_plugin->connect_and_run(_bufferset, x, y, _buffer_size, (nframes_t)0);
|
||||
in_map = ARDOUR::ChanMapping(_plugin->get_info()->n_inputs);
|
||||
out_map = ARDOUR::ChanMapping(_plugin->get_info()->n_outputs);
|
||||
_plugin->connect_and_run(_bufferset, in_map, out_map, _buffer_size, (nframes_t)0);
|
||||
}
|
||||
} while ( frames_left > 0);
|
||||
|
||||
|
||||
@@ -303,25 +303,15 @@ PluginSelector::refiller (const PluginInfoList& plugs, const::std::string& filte
|
||||
|
||||
newrow[plugin_columns.creator] = creator;
|
||||
|
||||
if ((*i)->n_inputs.n_total() < 0) { // FIXME: Impossible (unsigned)
|
||||
newrow[plugin_columns.audio_ins] = "various";
|
||||
newrow[plugin_columns.midi_ins] = "various";
|
||||
} else {
|
||||
snprintf (buf, sizeof(buf), "%d", (*i)->n_inputs.n_audio());
|
||||
newrow[plugin_columns.audio_ins] = buf;
|
||||
snprintf (buf, sizeof(buf), "%d", (*i)->n_inputs.n_midi());
|
||||
newrow[plugin_columns.midi_ins] = buf;
|
||||
}
|
||||
|
||||
if ((*i)->n_outputs.n_total() < 0) { // FIXME: Impossible (unsigned)
|
||||
newrow[plugin_columns.audio_outs] = "various";
|
||||
newrow[plugin_columns.midi_outs] = "various";
|
||||
} else {
|
||||
snprintf (buf, sizeof(buf), "%d", (*i)->n_outputs.n_audio());
|
||||
newrow[plugin_columns.audio_outs] = buf;
|
||||
snprintf (buf, sizeof(buf), "%d", (*i)->n_outputs.n_midi());
|
||||
newrow[plugin_columns.midi_outs] = buf;
|
||||
}
|
||||
snprintf (buf, sizeof(buf), "%d", (*i)->n_inputs.n_audio());
|
||||
newrow[plugin_columns.audio_ins] = buf;
|
||||
snprintf (buf, sizeof(buf), "%d", (*i)->n_inputs.n_midi());
|
||||
newrow[plugin_columns.midi_ins] = buf;
|
||||
|
||||
snprintf (buf, sizeof(buf), "%d", (*i)->n_outputs.n_audio());
|
||||
newrow[plugin_columns.audio_outs] = buf;
|
||||
snprintf (buf, sizeof(buf), "%d", (*i)->n_outputs.n_midi());
|
||||
newrow[plugin_columns.midi_outs] = buf;
|
||||
|
||||
newrow[plugin_columns.plugin] = *i;
|
||||
}
|
||||
|
||||
@@ -434,51 +434,30 @@ ProcessorBox::weird_plugin_dialog (Plugin& p, Route::ProcessorStreams streams, b
|
||||
ArdourDialog dialog (_("ardour: weird plugin dialog"));
|
||||
Label label;
|
||||
|
||||
/* i hate this kind of code */
|
||||
string text = string_compose(_("You attempted to add the plugin \"%1\" at index %2.\n"),
|
||||
p.name(), streams.index);
|
||||
|
||||
if (streams.count > p.get_info()->n_inputs) {
|
||||
label.set_text (string_compose (_(
|
||||
"You attempted to add a plugin (%1).\n"
|
||||
"The plugin has %2 inputs\n"
|
||||
"but at the processorion point, there are\n"
|
||||
"%3 active signal streams.\n"
|
||||
"\n"
|
||||
"This makes no sense - you are throwing away\n"
|
||||
"part of the signal."),
|
||||
p.name(),
|
||||
p.get_info()->n_inputs.n_total(),
|
||||
streams.count.n_total()));
|
||||
} else if (streams.count < p.get_info()->n_inputs) {
|
||||
label.set_text (string_compose (_(
|
||||
"You attempted to add a plugin (%1).\n"
|
||||
"The plugin has %2 inputs\n"
|
||||
"but at the processorion point there are\n"
|
||||
"only %3 active signal streams.\n"
|
||||
"\n"
|
||||
"This makes no sense - unless the plugin supports\n"
|
||||
"side-chain inputs. A future version of Ardour will\n"
|
||||
"support this type of configuration."),
|
||||
p.name(),
|
||||
p.get_info()->n_inputs.n_total(),
|
||||
streams.count.n_total()));
|
||||
} else {
|
||||
label.set_text (string_compose (_(
|
||||
"You attempted to add a plugin (%1).\n"
|
||||
"\n"
|
||||
"The I/O configuration doesn't make sense:\n"
|
||||
"\n"
|
||||
"The plugin has %2 inputs and %3 outputs.\n"
|
||||
"The track/bus has %4 inputs and %5 outputs.\n"
|
||||
"The processorion point, has %6 active signals.\n"
|
||||
"\n"
|
||||
"Ardour does not understand what to do in such situations.\n"),
|
||||
p.name(),
|
||||
p.get_info()->n_inputs.n_total(),
|
||||
p.get_info()->n_outputs.n_total(),
|
||||
io->n_inputs().n_total(),
|
||||
io->n_outputs().n_total(),
|
||||
streams.count.n_total()));
|
||||
bool has_midi = streams.count.n_midi() > 0 || p.get_info()->n_inputs.n_midi() > 0;
|
||||
bool has_audio = streams.count.n_audio() > 0 || p.get_info()->n_inputs.n_audio() > 0;
|
||||
|
||||
text += _("\nThis plugin has:\n");
|
||||
if (has_midi) {
|
||||
text += string_compose("\t%1 ", p.get_info()->n_inputs.n_midi()) + _("MIDI input(s)\n");
|
||||
}
|
||||
if (has_audio) {
|
||||
text += string_compose("\t%1 ", p.get_info()->n_inputs.n_audio()) + _("audio input(s)\n");
|
||||
}
|
||||
|
||||
text += "\nBut at the insertion point, there are:\n";
|
||||
if (has_midi) {
|
||||
text += string_compose("\t%1 ", streams.count.n_midi()) + _("MIDI channel(s)\n");
|
||||
}
|
||||
if (has_audio) {
|
||||
text += string_compose("\t%1 ", streams.count.n_audio()) + _("audio channel(s)\n");
|
||||
}
|
||||
|
||||
text += "\nArdour is unable to insert this plugin here.\n";
|
||||
label.set_text(text);
|
||||
|
||||
dialog.get_vbox()->pack_start (label);
|
||||
dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
82
libs/ardour/ardour/chan_mapping.h
Normal file
82
libs/ardour/ardour/chan_mapping.h
Normal file
@@ -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__
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
81
libs/ardour/ardour/lv2_event_buffer.h
Normal file
81
libs/ardour/ardour/lv2_event_buffer.h
Normal file
@@ -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__
|
||||
@@ -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 ();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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&);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
60
libs/ardour/ardour/uri_map.h
Normal file
60
libs/ardour/ardour/uri_map.h
Normal file
@@ -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__
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
cycles_t now;
|
||||
cycles_t then = get_cycles ();
|
||||
|
||||
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++;
|
||||
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);
|
||||
|
||||
191
libs/ardour/lv2_event_buffer.cc
Normal file
191
libs/ardour/lv2_event_buffer.cc
Normal file
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
260
libs/ardour/lv2ext/lv2_event.h
Normal file
260
libs/ardour/lv2ext/lv2_event.h
Normal file
@@ -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
|
||||
|
||||
243
libs/ardour/lv2ext/lv2_event_helpers.h
Normal file
243
libs/ardour/lv2ext/lv2_event_helpers.h
Normal file
@@ -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
|
||||
|
||||
88
libs/ardour/lv2ext/lv2_uri_map.h
Normal file
88
libs/ardour/lv2ext/lv2_uri_map.h
Normal file
@@ -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
|
||||
|
||||
@@ -124,11 +124,37 @@ MidiBuffer::push_back(const Evoral::MIDIEvent<TimeType>& ev)
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t* const write_loc = _data + _size;
|
||||
*((TimeType*)write_loc) = ev.time();
|
||||
memcpy(write_loc + stamp_size, ev.buffer(), ev.size());
|
||||
push_back(ev.time(), ev.size(), ev.buffer());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_size += stamp_size + ev.size();
|
||||
|
||||
/** 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) = time;
|
||||
memcpy(write_loc + stamp_size, data, size);
|
||||
|
||||
_size += stamp_size + size;
|
||||
_silent = false;
|
||||
|
||||
return true;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -94,8 +94,6 @@ find_session_templates (vector<TemplateInfo>& template_names)
|
||||
continue;
|
||||
}
|
||||
|
||||
XMLNode* root = tree.root();
|
||||
|
||||
TemplateInfo rti;
|
||||
|
||||
rti.name = basename_nosuffix (fullpath);
|
||||
|
||||
74
libs/ardour/uri_map.cc
Normal file
74
libs/ardour/uri_map.cc
Normal file
@@ -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
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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 = ['.']
|
||||
|
||||
Reference in New Issue
Block a user