Added facilities into PluginInsert for the GUI to gather parts of the real signal...
[ardour.git] / libs / ardour / plugin_insert.cc
index b82ba28290c985de0e686a3f1837492bf3071465..7ed35dd1a7ff29e872f2d0e317f5dd17cf58e48d 100644 (file)
@@ -57,7 +57,9 @@ using namespace PBD;
 const string PluginInsert::port_automation_node_name = "PortAutomation";
 
 PluginInsert::PluginInsert (Session& s, boost::shared_ptr<Plugin> plug, Placement placement)
-       : Processor (s, plug->name(), placement)
+       : Processor (s, plug->name(), placement),
+          _signal_analysis_collected_nframes(0),
+          _signal_analysis_collect_nframes_max(0)
 {
        /* the first is the master */
 
@@ -74,13 +76,18 @@ PluginInsert::PluginInsert (Session& s, boost::shared_ptr<Plugin> plug, Placemen
 }
 
 PluginInsert::PluginInsert (Session& s, const XMLNode& node)
-       : Processor (s, "unnamed plugin insert", PreFader)
+       : Processor (s, "unnamed plugin insert", PreFader),
+          _signal_analysis_collected_nframes(0),
+          _signal_analysis_collect_nframes_max(0)
 {
        if (set_state (node)) {
                throw failed_constructor();
        }
 
-       // set_automatable ();
+       // XXX: This would dump all automation, which has already been loaded by
+       //      Processor. But this could also have been related to the Parameter change..
+       //      will look into this later.
+       //set_automatable ();
 
        {
                Glib::Mutex::Lock em (_session.engine().process_lock());
@@ -89,7 +96,9 @@ PluginInsert::PluginInsert (Session& s, const XMLNode& node)
 }
 
 PluginInsert::PluginInsert (const PluginInsert& other)
-       : Processor (other._session, other._name, other.placement())
+       : Processor (other._session, other._name, other.placement()),
+          _signal_analysis_collected_nframes(0),
+          _signal_analysis_collect_nframes_max(0)
 {
        uint32_t count = other._plugins.size();
 
@@ -147,13 +156,13 @@ PluginInsert::~PluginInsert ()
 }
 
 void
-PluginInsert::auto_state_changed (Parameter which)
+PluginInsert::auto_state_changed (Evoral::Parameter which)
 {
        if (which.type() != PluginAutomation)
                return;
 
        boost::shared_ptr<AutomationControl> c
-                       = boost::dynamic_pointer_cast<AutomationControl>(control (which));
+                       = boost::dynamic_pointer_cast<AutomationControl>(data().control (which));
 
        if (c && ((AutomationList*)c->list().get())->automation_state() != Off) {
                _plugins[0]->set_parameter (which.id(), c->list()->eval (_session.transport_frame()));
@@ -218,24 +227,24 @@ PluginInsert::is_generator() const
 void
 PluginInsert::set_automatable ()
 {
-       set<Parameter> a = _plugins.front()->automatable ();
+       set<Evoral::Parameter> a = _plugins.front()->automatable ();
 
        Plugin::ParameterDescriptor desc;
 
-       for (set<Parameter>::iterator i = a.begin(); i != a.end(); ++i) {
+       for (set<Evoral::Parameter>::iterator i = a.begin(); i != a.end(); ++i) {
                if (i->type() == PluginAutomation) {
                        can_automate (*i);
                        _plugins.front()->get_parameter_descriptor(i->id(), desc);
-                       Parameter param(*i);
+                       Evoral::Parameter param(*i);
                        param.set_range(desc.lower, desc.upper, _plugins.front()->default_value(i->id()));
                        boost::shared_ptr<AutomationList> list(new AutomationList(param));
-                       add_control(boost::shared_ptr<AutomationControl>(new PluginControl(*this, list)));
+                       add_control(boost::shared_ptr<AutomationControl>(new PluginControl(this, *i, list)));
                }
        }
 }
 
 void
-PluginInsert::parameter_changed (Parameter which, float val)
+PluginInsert::parameter_changed (Evoral::Parameter which, float val)
 {
        if (which.type() != PluginAutomation)
                return;
@@ -279,6 +288,13 @@ PluginInsert::deactivate ()
 void
 PluginInsert::connect_and_run (BufferSet& bufs, nframes_t nframes, nframes_t offset, bool with_auto, nframes_t now)
 {
+       // Calculate if, and how many frames we need to collect for analysis
+       nframes_t collect_signal_nframes = (_signal_analysis_collect_nframes_max -
+                                            _signal_analysis_collected_nframes);
+       if (nframes < collect_signal_nframes) { // we might not get all frames now
+               collect_signal_nframes = nframes;
+       }
+
        uint32_t in_index = 0;
        uint32_t out_index = 0;
 
@@ -290,7 +306,7 @@ PluginInsert::connect_and_run (BufferSet& bufs, nframes_t nframes, nframes_t off
 
                uint32_t n = 0;
                
-               for (Controls::iterator li = _controls.begin(); li != _controls.end(); ++li, ++n) {
+               for (Controls::iterator li = data().controls().begin(); li != data().controls().end(); ++li, ++n) {
                        
                        boost::shared_ptr<AutomationControl> c
                                = boost::dynamic_pointer_cast<AutomationControl>(li->second);
@@ -308,10 +324,45 @@ PluginInsert::connect_and_run (BufferSet& bufs, nframes_t nframes, nframes_t off
                }
        }
 
+       if (collect_signal_nframes > 0) {
+               // collect input
+               //std::cerr << "collect input, bufs " << bufs.count().n_audio() << " count,  " << bufs.available().n_audio() << " available" << std::endl;
+               //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(
+                               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);
        }
 
+       if (collect_signal_nframes > 0) {
+               // collect output
+               //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(
+                               bufs.get_audio(i), 
+                               collect_signal_nframes, 
+                               _signal_analysis_collected_nframes); // offset is for target buffer
+               }
+
+               _signal_analysis_collected_nframes += collect_signal_nframes;
+               assert(_signal_analysis_collected_nframes <= _signal_analysis_collect_nframes_max);
+
+               if (_signal_analysis_collected_nframes == _signal_analysis_collect_nframes_max) {
+                       _signal_analysis_collect_nframes_max = 0;
+                       _signal_analysis_collected_nframes   = 0;
+
+                       AnalysisDataGathered(&_signal_analysis_input_bufferset, 
+                                            &_signal_analysis_output_bufferset);
+               }
+       }
        /* leave remaining channel buffers alone */
 }
 
@@ -359,7 +410,7 @@ PluginInsert::run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t en
 }
 
 void
-PluginInsert::set_parameter (Parameter param, float val)
+PluginInsert::set_parameter (Evoral::Parameter param, float val)
 {
        if (param.type() != PluginAutomation)
                return;
@@ -368,15 +419,21 @@ PluginInsert::set_parameter (Parameter param, float val)
 
        _plugins[0]->set_parameter (param.id(), val);
        
-       boost::shared_ptr<Evoral::Control> c = control (param);
-       if (c)
-               c->set_value(val);
+       boost::shared_ptr<AutomationControl> ac
+                       = boost::dynamic_pointer_cast<AutomationControl>(data().control(param));
+       
+       if (ac) {
+               ac->set_value(val);
+       } else {
+               warning << "set_parameter called for nonexistant parameter "
+                       << EventTypeMap::instance().to_symbol(param) << endmsg;
+       }
 
        _session.set_dirty();
 }
 
 float
-PluginInsert::get_parameter (Parameter param)
+PluginInsert::get_parameter (Evoral::Parameter param)
 {
        if (param.type() != PluginAutomation)
                return 0.0;
@@ -388,18 +445,18 @@ PluginInsert::get_parameter (Parameter param)
 void
 PluginInsert::automation_run (BufferSet& bufs, nframes_t nframes, nframes_t offset)
 {
-       ControlEvent next_event (0, 0.0f);
+       Evoral::ControlEvent next_event (0, 0.0f);
        nframes_t now = _session.transport_frame ();
        nframes_t end = now + nframes;
 
-       Glib::Mutex::Lock lm (_control_lock, Glib::TRY_LOCK);
+       Glib::Mutex::Lock lm (data().control_lock(), Glib::TRY_LOCK);
 
        if (!lm.locked()) {
                connect_and_run (bufs, nframes, offset, false);
                return;
        }
        
-       if (!find_next_event (now, end, next_event)) {
+       if (!data().find_next_event (now, end, next_event)) {
                
                /* no events have a time within the relevant range */
                
@@ -417,7 +474,7 @@ PluginInsert::automation_run (BufferSet& bufs, nframes_t nframes, nframes_t offs
                offset += cnt;
                now += cnt;
 
-               if (!find_next_event (now, end, next_event)) {
+               if (!data().find_next_event (now, end, next_event)) {
                        break;
                }
        }
@@ -499,6 +556,17 @@ PluginInsert::configure_io (ChanCount in, ChanCount out)
                return false;
        }
 
+       // we don't know the analysis window size, so we must work with the
+       // 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);
+
+
        return Processor::configure_io (in, out);
 }
 
@@ -624,10 +692,10 @@ PluginInsert::state (bool full)
        node.add_child_nocopy (_plugins[0]->get_state());
 
        /* add port automation state */
-       XMLNode *autonode = new XMLNode(port_automation_node_name);
-       set<Parameter> automatable = _plugins[0]->automatable();
+       //XMLNode *autonode = new XMLNode(port_automation_node_name);
+       set<Evoral::Parameter> automatable = _plugins[0]->automatable();
        
-       for (set<Parameter>::iterator x = automatable.begin(); x != automatable.end(); ++x) {
+       for (set<Evoral::Parameter>::iterator x = automatable.begin(); x != automatable.end(); ++x) {
                
                /*XMLNode* child = new XMLNode("port");
                snprintf(buf, sizeof(buf), "%" PRIu32, *x);
@@ -636,10 +704,10 @@ PluginInsert::state (bool full)
                child->add_child_nocopy (automation_list (*x).state (full));
                autonode->add_child_nocopy (*child);
                */
-               autonode->add_child_nocopy (((AutomationList*)control(*x)->list().get())->state (full));
+               //autonode->add_child_nocopy (((AutomationList*)data().control(*x)->list().get())->state (full));
        }
 
-       node.add_child_nocopy (*autonode);
+       //node.add_child_nocopy (*autonode);
        
        return node;
 }
@@ -760,7 +828,7 @@ PluginInsert::set_state(const XMLNode& node)
                        }
 
                        boost::shared_ptr<AutomationControl> c = boost::dynamic_pointer_cast<AutomationControl>(
-                                       control(Parameter(PluginAutomation, port_id), true));
+                                       data().control(Evoral::Parameter(PluginAutomation, 0, port_id), true));
 
                        if (!child->children().empty()) {
                                c->alist()->set_state (*child->children().front());
@@ -799,7 +867,7 @@ PluginInsert::set_state(const XMLNode& node)
 }
 
 string
-PluginInsert::describe_parameter (Parameter param)
+PluginInsert::describe_parameter (Evoral::Parameter param)
 {
        if (param.type() != PluginAutomation)
                return Automatable::describe_parameter(param);
@@ -846,13 +914,12 @@ PluginInsert::type ()
        }
 }
 
-PluginInsert::PluginControl::PluginControl (PluginInsert& p, boost::shared_ptr<AutomationList> list)
-       : AutomationControl (p.session(), list, p.describe_parameter(list->parameter()))
+PluginInsert::PluginControl::PluginControl (PluginInsert* p, const Evoral::Parameter &param, boost::shared_ptr<AutomationList> list)
+       : AutomationControl (p->session(), param, list, p->describe_parameter(param))
        , _plugin (p)
-       , _list (list)
 {
        Plugin::ParameterDescriptor desc;
-       p.plugin(0)->get_parameter_descriptor (list->parameter().id(), desc);
+       p->plugin(0)->get_parameter_descriptor (param.id(), desc);
        _logarithmic = desc.logarithmic;
        _toggled = desc.toggled;
 }
@@ -886,11 +953,16 @@ PluginInsert::PluginControl::set_value (float val)
 
        }
 
-       for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugin._plugins.begin();
-                       i != _plugin._plugins.end(); ++i) {
+       for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugin->_plugins.begin();
+                       i != _plugin->_plugins.end(); ++i) {
                (*i)->set_parameter (_list->parameter().id(), val);
        }
 
+       boost::shared_ptr<Plugin> iasp = _plugin->_impulseAnalysisPlugin.lock();
+       if (iasp) {
+               iasp->set_parameter (_list->parameter().id(), val);
+       }
+
        AutomationControl::set_value(val);
 }
 
@@ -899,7 +971,7 @@ PluginInsert::PluginControl::get_value (void) const
 {
        /* FIXME: probably should be taking out some lock here.. */
        
-       float val = _plugin.get_parameter (_list->parameter());
+       float val = _plugin->get_parameter (_list->parameter());
 
        return val;
 
@@ -917,3 +989,17 @@ PluginInsert::PluginControl::get_value (void) const
        }*/
 }
 
+boost::shared_ptr<Plugin>
+PluginInsert::get_impulse_analysis_plugin()
+{
+       boost::shared_ptr<Plugin> ret;
+       if (_impulseAnalysisPlugin.expired()) {
+               ret = plugin_factory(_plugins[0]);
+               _impulseAnalysisPlugin = ret;
+       } else {
+               ret = _impulseAnalysisPlugin.lock();
+       }
+
+       return ret;
+}
+