/*
- Copyright (C) 2000,2007 Paul Davis
+ Copyright (C) 2000,2007 Paul Davis
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
#include <vector>
#include <string>
-#include <exception>
-#include <sigc++/signal.h>
-#include <ardour/ardour.h>
-#include <ardour/plugin_state.h>
-#include <ardour/types.h>
-#include <ardour/insert.h>
+#include <boost/weak_ptr.hpp>
+
+#include "pbd/timing.h"
+
+#include "ardour/ardour.h"
+#include "ardour/libardour_visibility.h"
+#include "ardour/chan_mapping.h"
+#include "ardour/fixed_delay.h"
+#include "ardour/io.h"
+#include "ardour/types.h"
+#include "ardour/parameter_descriptor.h"
+#include "ardour/plugin.h"
+#include "ardour/processor.h"
+#include "ardour/readonly_control.h"
+#include "ardour/sidechain.h"
+#include "ardour/automation_control.h"
class XMLNode;
/** Plugin inserts: send data through a plugin
*/
-class PluginInsert : public Insert
+class LIBARDOUR_API PluginInsert : public Processor
{
- public:
- PluginInsert (Session&, boost::shared_ptr<Plugin>, Placement);
- PluginInsert (Session&, const XMLNode&);
- PluginInsert (const PluginInsert&);
+public:
+ PluginInsert (Session&, boost::shared_ptr<Plugin> = boost::shared_ptr<Plugin>());
~PluginInsert ();
- static const string port_automation_node_name;
-
- XMLNode& state(bool);
- XMLNode& get_state(void);
- int set_state(const XMLNode&);
+ static const std::string port_automation_node_name;
+
+ int set_state(const XMLNode&, int version);
+ void update_id (PBD::ID);
+ void set_owner (SessionObject*);
+ void set_state_dir (const std::string& d = "");
+
+ void run (BufferSet& in, samplepos_t start_sample, samplepos_t end_sample, double speed, pframes_t nframes, bool);
+ void silence (samplecnt_t nframes, samplepos_t start_sample);
- void run (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset);
- void silence (nframes_t nframes, nframes_t offset);
-
void activate ();
void deactivate ();
+ void flush ();
+
+ void enable (bool yn);
+ bool enabled () const;
+ bool bypassable () const;
+
+ bool reset_parameters_to_default ();
+ bool can_reset_all_parameters ();
+
+ bool write_immediate_event (size_t size, const uint8_t* buf);
+
+ void automation_run (samplepos_t, pframes_t, bool only_active = false);
+ bool find_next_event (double, double, Evoral::ControlEvent&, bool only_active = true) const;
+
+ int set_block_size (pframes_t nframes);
+
+ ChanMapping input_map (uint32_t num) const {
+ if (num < _in_map.size()) {
+ return _in_map.find (num)->second;
+ } else {
+ return ChanMapping ();
+ }
+ }
+
+ ChanMapping output_map (uint32_t num) const {
+ if (num < _out_map.size()) {
+ return _out_map.find (num)->second;
+ } else {
+ return ChanMapping ();
+ }
+ }
- void set_block_size (nframes_t nframes);
+ ChanMapping thru_map () const {
+ return _thru_map;
+ }
+ bool pre_seed (const ChanCount&, const ChanCount&, const ChanMapping&, const ChanMapping&, const ChanMapping&);
+
+ ChanMapping input_map () const; ///< combined (all instances) input map
+ ChanMapping no_sc_input_map () const; ///< combined (all instances) input map w/o sidechain sinks
+ ChanMapping output_map () const; ///< combined (all instances) output map
+ bool has_midi_bypass () const;
+ bool has_midi_thru () const;
+ bool inplace () const { return ! _no_inplace; }
+
+#ifdef MIXBUS
+ bool is_channelstrip () const;
+ bool is_nonbypassable () const;
+#else
+ bool is_channelstrip () const { return false; }
+ bool is_nonbypassable () const { return false; }
+#endif
+
+ void set_input_map (uint32_t, ChanMapping);
+ void set_output_map (uint32_t, ChanMapping);
+ void set_thru_map (ChanMapping);
+ bool reset_map (bool emit = true);
+ bool sanitize_maps ();
+ bool check_inplace ();
+ bool configured () const { return _configured; }
+
+ // these are ports visible on the outside
ChanCount output_streams() const;
ChanCount input_streams() const;
- ChanCount natural_output_streams() const;
- ChanCount natural_input_streams() const;
+ ChanCount internal_streams() const; // with side-chain
- bool set_count (uint32_t num);
- uint32_t get_count () const { return _plugins.size(); }
+ // actual ports of all plugins.
+ // n * natural_i/o or result of reconfigurable i/o
+ ChanCount internal_output_streams() const;
+ ChanCount internal_input_streams() const;
- virtual bool can_support_input_configuration (ChanCount in) const;
- virtual ChanCount output_for_input_configuration (ChanCount in) const;
- virtual bool configure_io (ChanCount in, ChanCount out);
-
- bool is_generator() const;
+ // a single plugin's internal i/o
+ ChanCount natural_output_streams() const;
+ ChanCount natural_input_streams() const;
- void set_parameter (uint32_t port, float val);
+ /** plugin ports marked as sidechain */
+ ChanCount sidechain_input_pins() const;
- AutoState get_port_automation_state (uint32_t port);
- void set_port_automation_state (uint32_t port, AutoState);
- void protect_automation ();
+ /** Plugin-Insert IO sidechain ports */
+ ChanCount sidechain_input_ports() const {
+ if (_sidechain) {
+ return _sidechain->input ()->n_ports ();
+ } else {
+ return ChanCount ();
+ }
+ }
- float default_parameter_value (uint32_t which);
+ const ChanCount& required_buffers () const { return _required_buffers; }
+ const ChanCount& preset_out () const { return _preset_out; }
+
+ // allow to override output_streams(), implies "Custom Mode"
+
+ // only the owning route may call these (with process lock held)
+ // route is not a friend class, it owns us
+ bool set_count (uint32_t num);
+ void set_sinks (const ChanCount&); // reconfigurable I/O ONLY
+ void set_outputs (const ChanCount&);
+ void set_strict_io (bool b);
+ void set_custom_cfg (bool b);
+ bool set_preset_out (const ChanCount&);
+ bool add_sidechain (uint32_t n_audio = 1, uint32_t n_midi = 0);
+ bool del_sidechain ();
+ void update_sidechain_name ();
+ boost::shared_ptr<SideChain> sidechain () const { return _sidechain; }
+ // end C++ class slavery!
+
+ uint32_t get_count () const { return _plugins.size(); }
+ bool strict_io () const { return _strict_io; }
+ bool custom_cfg () const { return _custom_cfg; }
+
+ bool can_support_io_configuration (const ChanCount& in, ChanCount& out);
+ bool configure_io (ChanCount in, ChanCount out);
+
+ bool has_no_inputs() const;
+ bool has_no_audio_inputs() const;
+
+ bool is_instrument () const;
+
+ bool has_output_presets (
+ ChanCount in = ChanCount (DataType::MIDI, 1),
+ ChanCount out = ChanCount (DataType::AUDIO, 2)
+ );
+
+ void realtime_handle_transport_stopped ();
+ void realtime_locate ();
+ void monitoring_changed ();
+
+ bool load_preset (Plugin::PresetRecord);
+
+ bool provides_stats () const;
+ bool get_stats (uint64_t& min, uint64_t& max, double& avg, double& dev) const;
+ void clear_stats ();
+
+ /** A control that manipulates a plugin parameter (control port). */
+ struct PluginControl : public AutomationControl
+ {
+ PluginControl (PluginInsert* p,
+ const Evoral::Parameter& param,
+ const ParameterDescriptor& desc,
+ boost::shared_ptr<AutomationList> list=boost::shared_ptr<AutomationList>());
+
+ double get_value (void) const;
+ void catch_up_with_external_value (double val);
+ XMLNode& get_state();
+
+ private:
+ PluginInsert* _plugin;
+ void actually_set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
+ };
+
+ /** A control that manipulates a plugin property (message). */
+ struct PluginPropertyControl : public AutomationControl
+ {
+ PluginPropertyControl (PluginInsert* p,
+ const Evoral::Parameter& param,
+ const ParameterDescriptor& desc,
+ boost::shared_ptr<AutomationList> list=boost::shared_ptr<AutomationList>());
+
+ double get_value (void) const;
+ XMLNode& get_state();
+ protected:
+ void actually_set_value (double value, PBD::Controllable::GroupControlDisposition);
+
+ private:
+ PluginInsert* _plugin;
+ Variant _value;
+ };
boost::shared_ptr<Plugin> plugin(uint32_t num=0) const {
- if (num < _plugins.size()) {
+ if (num < _plugins.size()) {
return _plugins[num];
} else {
return _plugins[0]; // we always have one
}
}
+ samplecnt_t plugin_latency () const;
+
+ bool has_sidechain () const {
+ return _sidechain ? true : false;
+ }
+
+ boost::shared_ptr<IO> sidechain_input () const {
+ if (_sidechain) {
+ return _sidechain->input ();
+ }
+ return boost::shared_ptr<IO> ();
+ }
+
PluginType type ();
- string describe_parameter (uint32_t);
+ boost::shared_ptr<ReadOnlyControl> control_output (uint32_t) const;
- nframes_t latency();
+ std::string describe_parameter (Evoral::Parameter param);
- void transport_stopped (nframes_t now);
- void automation_snapshot (nframes_t now);
+ samplecnt_t signal_latency () const;
- private:
+ boost::shared_ptr<Plugin> get_impulse_analysis_plugin();
- void parameter_changed (uint32_t, float);
-
- vector<boost::shared_ptr<Plugin> > _plugins;
-
- void automation_run (BufferSet& bufs, nframes_t nframes, nframes_t offset);
- void connect_and_run (BufferSet& bufs, nframes_t nframes, nframes_t offset, bool with_auto, nframes_t now = 0);
+ void collect_signal_for_analysis (samplecnt_t nframes);
- void init ();
- void set_automatable ();
- void auto_state_changed (uint32_t which);
- void automation_list_creation_callback (uint32_t, AutomationList&);
+ bool strict_io_configured () const {
+ return _match.strict_io;
+ }
- int32_t count_for_configuration (ChanCount in, ChanCount out) const;
+ bool splitting () const {
+ return _match.method == Split;
+ }
+
+ void configured_io (ChanCount &in, ChanCount &out) const {
+ in = _configured_in;
+ out = _configured_out;
+ }
+
+ PBD::Signal2<void,BufferSet*, BufferSet*> AnalysisDataGathered;
+ PBD::Signal0<void> PluginIoReConfigure;
+ PBD::Signal0<void> PluginMapChanged;
+ PBD::Signal0<void> PluginConfigChanged;
+
+ /** Enumeration of the ways in which we can match our insert's
+ * IO to that of the plugin(s).
+ */
+ enum MatchingMethod {
+ Impossible, ///< we can't
+ Delegate, ///< we are delegating to the plugin, and it can handle it
+ NoInputs, ///< plugin has no inputs, so anything goes
+ ExactMatch, ///< our insert's inputs are the same as the plugin's
+ Replicate, ///< we have multiple instances of the plugin
+ Split, ///< we copy one of our insert's inputs to multiple plugin inputs
+ Hide, ///< we `hide' some of the plugin's inputs by feeding them silence
+ };
+
+ /** Description of how we can match our plugin's IO to our own insert IO */
+ struct Match {
+ Match () : method (Impossible), plugins (0), strict_io (false), custom_cfg (false) {}
+ Match (MatchingMethod m, int32_t p,
+ bool strict = false, bool custom = false, ChanCount h = ChanCount ())
+ : method (m), plugins (p), hide (h), strict_io (strict), custom_cfg (custom) {}
+
+ MatchingMethod method; ///< method to employ
+ int32_t plugins; ///< number of copies of the plugin that we need
+ ChanCount hide; ///< number of channels to hide
+ bool strict_io; ///< force in == out
+ bool custom_cfg; ///< custom config (if not strict)
+ };
+
+protected:
+ XMLNode& state ();
+
+private:
+ /* disallow copy construction */
+ PluginInsert (const PluginInsert&);
+
+ void parameter_changed_externally (uint32_t, float);
+
+ void set_parameter (Evoral::Parameter param, float val);
+
+ float default_parameter_value (const Evoral::Parameter& param);
+
+ typedef std::vector<boost::shared_ptr<Plugin> > Plugins;
+ Plugins _plugins;
+
+ boost::shared_ptr<SideChain> _sidechain;
+ uint32_t _sc_playback_latency;
+ uint32_t _sc_capture_latency;
+ uint32_t _plugin_signal_latency;
+
+ boost::weak_ptr<Plugin> _impulseAnalysisPlugin;
+
+ samplecnt_t _signal_analysis_collected_nframes;
+ samplecnt_t _signal_analysis_collect_nframes_max;
+
+ BufferSet _signal_analysis_inputs;
+ BufferSet _signal_analysis_outputs;
+
+ FixedDelay _delaybuffers;
+
+ ChanCount _configured_in;
+ ChanCount _configured_internal; // with side-chain
+ ChanCount _configured_out;
+ ChanCount _custom_out;
+ ChanCount _custom_sinks;
+ ChanCount _preset_out;
+ ChanCount _cached_sidechain_pins;
+ ChanCount _required_buffers;
+
+ bool _configured;
+ bool _no_inplace;
+ bool _strict_io;
+ bool _custom_cfg;
+ bool _maps_from_state;
+ bool _mapping_changed;
+
+ Match private_can_support_io_configuration (ChanCount const &, ChanCount &) const;
+ Match internal_can_support_io_configuration (ChanCount const &, ChanCount &) const;
+ Match automatic_can_support_io_configuration (ChanCount const &, ChanCount &) const;
+
+ /** details of the match currently being used */
+ Match _match;
+
+ /* ordered map [plugin instance ID] => ARDOUR::ChanMapping
+ * TODO: consider replacing with boost::flat_map<> or std::vector<>.
+ */
+ class PinMappings : public std::map <uint32_t, ARDOUR::ChanMapping> {
+ public:
+ /* this emulates C++11's std::map::at()
+ * return mapping for given plugin instance */
+ inline ARDOUR::ChanMapping const& p (const uint32_t i) const {
+#ifndef NDEBUG
+ const_iterator x = find (i);
+ assert (x != end ());
+ return x->second;
+#else
+ return find(i)->second;
+#endif
+ }
+ };
+
+ PinMappings _in_map;
+ PinMappings _out_map;
+ ChanMapping _thru_map; // out-idx <= in-idx
+
+ void automate_and_run (BufferSet& bufs, samplepos_t start, samplepos_t end, double speed, pframes_t nframes);
+ void connect_and_run (BufferSet& bufs, samplepos_t start, samplecnt_t end, double speed, pframes_t nframes, samplecnt_t offset, bool with_auto);
+ void bypass (BufferSet& bufs, pframes_t nframes);
+ void inplace_silence_unconnected (BufferSet&, const PinMappings&, samplecnt_t nframes, samplecnt_t offset) const;
+
+ void create_automatable_parameters ();
+ void control_list_automation_state_changed (Evoral::Parameter, AutoState);
+ void set_parameter_state_2X (const XMLNode& node, int version);
+ void set_control_ids (const XMLNode&, int version);
+
+ void enable_changed ();
+ void bypassable_changed ();
boost::shared_ptr<Plugin> plugin_factory (boost::shared_ptr<Plugin>);
+ void add_plugin (boost::shared_ptr<Plugin>);
+
+ void add_sidechain_from_xml (const XMLNode& node, int version);
+
+ void start_touch (uint32_t param_id);
+ void end_touch (uint32_t param_id);
+
+ void latency_changed ();
+ bool _latency_changed;
+ uint32_t _bypass_port;
+
+ typedef std::map<uint32_t, boost::shared_ptr<ReadOnlyControl> >CtrlOutMap;
+ CtrlOutMap _control_outputs;
+
+ void preset_load_set_value (uint32_t, float);
+
+ PBD::TimingStats _timing_stats;
+ volatile gint _stat_reset;
};
} // namespace ARDOUR
+std::ostream& operator<<(std::ostream& o, const ARDOUR::PluginInsert::Match& m);
+
#endif /* __ardour_plugin_insert_h__ */