ardour/libs/ardour/ardour/plugin_insert.h

402 lines
12 KiB
C++

/*
* Copyright (C) 2000-2017 Paul Davis <paul@linuxaudiosystems.com>
* Copyright (C) 2007-2014 David Robillard <d@drobilla.net>
* Copyright (C) 2008-2009 Sampo Savolainen <v2@iki.fi>
* Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
* Copyright (C) 2013-2019 Robin Gareus <robin@gareus.org>
* Copyright (C) 2018 Johannes Mueller <github@johannes-mueller.org>
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __ardour_plugin_insert_h__
#define __ardour_plugin_insert_h__
#include <atomic>
#include <memory>
#include <string>
#include <vector>
#include "pbd/stack_allocator.h"
#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/plug_insert_base.h"
#include "ardour/processor.h"
#include "ardour/readonly_control.h"
#include "ardour/sidechain.h"
class XMLNode;
namespace ARDOUR {
class Session;
class Route;
class Plugin;
/** Plugin inserts: send data through a plugin
*/
class LIBARDOUR_API PluginInsert : public Processor, public PlugInsertBase, public std::enable_shared_from_this <PluginInsert>
{
public:
PluginInsert (Session&, Temporal::TimeDomainProvider const & tdp, std::shared_ptr<Plugin> = std::shared_ptr<Plugin>());
~PluginInsert ();
void drop_references ();
std::weak_ptr<PluginInsert> weak_ptr () {
return shared_from_this();
}
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 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 (Evoral::EventType event_type, size_t size, const uint8_t* buf);
void automation_run (samplepos_t, pframes_t, bool only_active = false);
bool find_next_event (Temporal::timepos_t const &, Temporal::timepos_t const &, 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 ();
}
}
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; }
bool is_channelstrip () const;
UIElements ui_elements () const;
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 reset_sidechain_map ();
bool configured () const { return _configured; }
// these are ports visible on the outside
ChanCount output_streams() const;
ChanCount input_streams() const;
ChanCount internal_streams() const; // with side-chain
// 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;
// a single plugin's internal i/o
ChanCount natural_output_streams() const;
ChanCount natural_input_streams() const;
/** plugin ports marked as sidechain */
ChanCount sidechain_input_pins() const;
/** Plugin-Insert IO sidechain ports */
ChanCount sidechain_input_ports() const {
if (_sidechain) {
return _sidechain->input ()->n_ports ();
} else {
return ChanCount ();
}
}
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 ();
std::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_automatables () 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 (bool);
void monitoring_changed ();
bool load_preset (Plugin::PresetRecord);
bool provides_stats () const;
bool get_stats (PBD::microseconds_t& min, PBD::microseconds_t& max, double& avg, double& dev) const;
void clear_stats ();
struct PIControl : public PluginControl
{
PIControl (Session& s,
PlugInsertBase* p,
const Evoral::Parameter& param,
const ParameterDescriptor& desc,
std::shared_ptr<AutomationList> list = std::shared_ptr<AutomationList>())
: PluginControl (s, p, param, desc, list) {}
private:
void actually_set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
};
std::shared_ptr<Plugin> plugin(uint32_t num=0) const {
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;
}
std::shared_ptr<IO> sidechain_input () const {
if (_sidechain) {
return _sidechain->input ();
}
return std::shared_ptr<IO> ();
}
PluginType type () const;
std::shared_ptr<ReadOnlyControl> control_output (uint32_t) const;
std::string describe_parameter (Evoral::Parameter param);
samplecnt_t signal_latency () const;
std::shared_ptr<Plugin> get_impulse_analysis_plugin();
void collect_signal_for_analysis (samplecnt_t nframes);
bool strict_io_configured () const {
return _match.strict_io;
}
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;
protected:
XMLNode& state () const;
private:
/* disallow copy construction */
PluginInsert (const PluginInsert&);
void parameter_changed_externally (uint32_t, float);
void set_parameter (Evoral::Parameter param, float val, sampleoffset_t);
float default_parameter_value (const Evoral::Parameter& param);
typedef std::vector<std::shared_ptr<Plugin> > Plugins;
Plugins _plugins;
std::shared_ptr<SideChain> _sidechain;
uint32_t _sc_playback_latency;
uint32_t _sc_capture_latency;
uint32_t _plugin_signal_latency;
std::weak_ptr<Plugin> _impulseAnalysisPlugin;
samplecnt_t _signal_analysis_collect_nsamples;
samplecnt_t _signal_analysis_collect_nsamples_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;
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<>.
*/
#if defined(_MSC_VER) /* && (_MSC_VER < 1900)
* Regarding the note (below) it was initially
* thought that this got fixed in VS2015 - but
* in fact it's still faulty (JE - Feb 2021) */
/* Use the older (heap based) mapping for early versions of MSVC.
* In fact it might be safer to use this for all MSVC builds - as
* our StackAllocator class depends on 'boost::aligned_storage'
* which is known to be troublesome with Visual C++ :-
* https://www.boost.org/doc/libs/1_65_0/libs/type_traits/doc/html/boost_typetraits/reference/aligned_storage.html
*/
class PinMappings : public std::map <uint32_t, ARDOUR::ChanMapping>
#else
class PinMappings : public std::map <uint32_t, ARDOUR::ChanMapping, std::less<uint32_t>, PBD::StackAllocator<std::pair<const uint32_t, ARDOUR::ChanMapping>, 4> >
#endif
{
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 enable_changed ();
void bypassable_changed ();
bool sanitize_maps ();
bool check_inplace ();
void mapping_changed ();
void add_plugin (std::shared_ptr<Plugin>);
void plugin_removed (std::weak_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;
bool _inverted_bypass_enable;
typedef std::map<uint32_t, std::shared_ptr<ReadOnlyControl> >CtrlOutMap;
CtrlOutMap _control_outputs;
PBD::TimingStats _timing_stats;
std::atomic<int> _stat_reset;
std::atomic<int> _flush;
};
} // namespace ARDOUR
#endif /* __ardour_plugin_insert_h__ */