From 3893203399c1b67fb70729558e51f014b863b307 Mon Sep 17 00:00:00 2001
From: David Robillard <d@drobilla.net>
Date: Tue, 23 Feb 2010 03:46:44 +0000
Subject: Free plugin instances when decreasing polyphony.

git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@2482 a436a847-0d15-0410-975c-d299462d15a1
---
 src/engine/LADSPANode.cpp | 32 ++++++++++++++------------------
 src/engine/LADSPANode.hpp | 22 +++++++++++++++++++---
 src/engine/LV2Node.cpp    | 46 ++++++++++++++++++++++------------------------
 src/engine/LV2Node.hpp    | 10 +++++++---
 4 files changed, 62 insertions(+), 48 deletions(-)

(limited to 'src')

diff --git a/src/engine/LADSPANode.cpp b/src/engine/LADSPANode.cpp
index abc517fa..80e69162 100644
--- a/src/engine/LADSPANode.cpp
+++ b/src/engine/LADSPANode.cpp
@@ -60,10 +60,6 @@ LADSPANode::LADSPANode(PluginImpl*              plugin,
 
 LADSPANode::~LADSPANode()
 {
-	if (_instances)
-		for (uint32_t i = 0; i < _polyphony; ++i)
-			_descriptor->cleanup((*_instances)[i]);
-
 	delete _instances;
 }
 
@@ -76,15 +72,14 @@ LADSPANode::prepare_poly(BufferFactory& bufs, uint32_t poly)
 
 	NodeBase::prepare_poly(bufs, poly);
 
-	if ( (!_polyphonic)
-			|| (_prepared_instances && poly <= _prepared_instances->size()) ) {
+	if (_polyphony == poly)
 		return true;
-	}
 
-	_prepared_instances = new Raul::Array<LADSPA_Handle>(poly, *_instances, NULL);
+	_prepared_instances = new Instances(poly, *_instances, SharedPtr<Instance>());
 	for (uint32_t i = _polyphony; i < _prepared_instances->size(); ++i) {
-		_prepared_instances->at(i) = _descriptor->instantiate(_descriptor, _srate);
-		if (_prepared_instances->at(i) == NULL) {
+		_prepared_instances->at(i) = SharedPtr<Instance>(new Instance(_descriptor,
+				_descriptor->instantiate(_descriptor, _srate)));
+		if (!_prepared_instances->at(i)->handle) {
 			error << "Failed to instantiate plugin" << endl;
 			return false;
 		}
@@ -103,7 +98,7 @@ LADSPANode::prepare_poly(BufferFactory& bufs, uint32_t poly)
 		}
 
 		if (_activated && _descriptor->activate)
-			_descriptor->activate(_prepared_instances->at(i));
+			_descriptor->activate(_prepared_instances->at(i)->handle);
 	}
 
 	return true;
@@ -142,11 +137,12 @@ LADSPANode::instantiate(BufferFactory& bufs)
 	if (!_ports)
 		_ports = new Raul::Array<PortImpl*>(_descriptor->PortCount);
 
-	_instances = new Raul::Array<LADSPA_Handle>(_polyphony, NULL);
+	_instances = new Instances(_polyphony);
 
 	for (uint32_t i = 0; i < _polyphony; ++i) {
-		(*_instances)[i] = _descriptor->instantiate(_descriptor, _srate);
-		if ((*_instances)[i] == NULL) {
+		(*_instances)[i] = SharedPtr<Instance>(new Instance(
+				_descriptor, _descriptor->instantiate(_descriptor, _srate)));
+		if (!instance(i)) {
 			error << "Failed to instantiate plugin" << endl;
 			return false;
 		}
@@ -251,7 +247,7 @@ LADSPANode::activate(BufferFactory& bufs)
 
 	if (_descriptor->activate != NULL)
 		for (uint32_t i = 0; i < _polyphony; ++i)
-			_descriptor->activate((*_instances)[i]);
+			_descriptor->activate(instance(i));
 }
 
 
@@ -262,7 +258,7 @@ LADSPANode::deactivate()
 
 	for (uint32_t i = 0; i < _polyphony; ++i)
 		if (_descriptor->deactivate != NULL)
-			_descriptor->deactivate((*_instances)[i]);
+			_descriptor->deactivate(instance(i));
 }
 
 
@@ -272,7 +268,7 @@ LADSPANode::process(ProcessContext& context)
 	NodeBase::pre_process(context);
 
 	for (uint32_t i = 0; i < _polyphony; ++i)
-		_descriptor->run((*_instances)[i], context.nframes());
+		_descriptor->run(instance(i), context.nframes());
 
 	NodeBase::post_process(context);
 }
@@ -283,7 +279,7 @@ LADSPANode::set_port_buffer(uint32_t voice, uint32_t port_num, BufferFactory::Re
 {
 	NodeBase::set_port_buffer(voice, port_num, buf);
 
-	_descriptor->connect_port((*_instances)[voice], port_num,
+	_descriptor->connect_port(instance(voice), port_num,
 			buf ? (LADSPA_Data*)buf->port_data(_ports->at(port_num)->type()) : NULL);
 }
 
diff --git a/src/engine/LADSPANode.hpp b/src/engine/LADSPANode.hpp
index 91293699..927e6255 100644
--- a/src/engine/LADSPANode.hpp
+++ b/src/engine/LADSPANode.hpp
@@ -58,14 +58,30 @@ public:
 	void set_port_buffer(uint32_t voice, uint32_t port_num, IntrusivePtr<Buffer> buf);
 
 protected:
+	inline LADSPA_Handle instance(uint32_t voice) { return (*_instances)[voice]->handle; }
+
 	void get_port_limits(unsigned long            port_index,
 	                     boost::optional<Sample>& default_value,
 	                     boost::optional<Sample>& lower_bound,
 	                     boost::optional<Sample>& upper_bound);
 
-	const LADSPA_Descriptor*    _descriptor;
-	Raul::Array<LADSPA_Handle>* _instances;
-	Raul::Array<LADSPA_Handle>* _prepared_instances;
+	struct Instance {
+		Instance(const LADSPA_Descriptor* d=NULL, LADSPA_Handle h=NULL)
+			: descriptor(d), handle(h)
+		{}
+		~Instance() {
+			if (descriptor && handle)
+				descriptor->cleanup(handle);
+		}
+		const LADSPA_Descriptor* descriptor;
+		LADSPA_Handle            handle;
+	};
+
+	typedef Raul::Array< SharedPtr<Instance> > Instances;
+
+	const LADSPA_Descriptor* _descriptor;
+	Instances*               _instances;
+	Instances*               _prepared_instances;
 };
 
 
diff --git a/src/engine/LV2Node.cpp b/src/engine/LV2Node.cpp
index e995bec3..65da2c2c 100644
--- a/src/engine/LV2Node.cpp
+++ b/src/engine/LV2Node.cpp
@@ -21,6 +21,7 @@
 #include <cmath>
 #include "raul/log.hpp"
 #include "raul/Maid.hpp"
+#include "raul/Array.hpp"
 #include "AudioBuffer.hpp"
 #include "InputPort.hpp"
 #include "LV2Node.hpp"
@@ -60,10 +61,6 @@ LV2Node::LV2Node(LV2Plugin*    plugin,
 
 LV2Node::~LV2Node()
 {
-	if (_instances)
-		for (uint32_t i = 0; i < _polyphony; ++i)
-			slv2_instance_free((*_instances)[i]);
-
 	delete _instances;
 }
 
@@ -76,18 +73,18 @@ LV2Node::prepare_poly(BufferFactory& bufs, uint32_t poly)
 
 	NodeBase::prepare_poly(bufs, poly);
 
-	if ( (!_polyphonic)
-			|| (_prepared_instances && poly <= _prepared_instances->size()) ) {
+	if (_polyphony == poly)
 		return true;
-	}
 
 	SharedPtr<LV2Info> info = _lv2_plugin->lv2_info();
-	_prepared_instances = new Raul::Array<SLV2Instance>(poly, *_instances, NULL);
+	_prepared_instances = new Instances(poly, *_instances, SharedPtr<void>());
 	for (uint32_t i = _polyphony; i < _prepared_instances->size(); ++i) {
-		_prepared_instances->at(i) = slv2_plugin_instantiate(
-				_lv2_plugin->slv2_plugin(), _srate, _features->array());
+		_prepared_instances->at(i) = SharedPtr<void>(
+				slv2_plugin_instantiate(
+					_lv2_plugin->slv2_plugin(), _srate, _features->array()),
+				slv2_instance_free);
 
-		if (_prepared_instances->at(i) == NULL) {
+		if (!_prepared_instances->at(i)) {
 			error << "Failed to instantiate plugin" << endl;
 			return false;
 		}
@@ -106,7 +103,7 @@ LV2Node::prepare_poly(BufferFactory& bufs, uint32_t poly)
 		}
 
 		if (_activated)
-			slv2_instance_activate(_prepared_instances->at(i));
+			slv2_instance_activate((SLV2Instance)(*_prepared_instances)[i].get());
 	}
 
 	return true;
@@ -149,7 +146,7 @@ LV2Node::instantiate(BufferFactory& bufs)
 	assert(num_ports > 0);
 
 	_ports     = new Raul::Array<PortImpl*>(num_ports, NULL);
-	_instances = new Raul::Array<SLV2Instance>(_polyphony, NULL);
+	_instances = new Instances(_polyphony, SharedPtr<void>());
 
 	_features = info->world().lv2_features->lv2_features(this);
 
@@ -157,8 +154,11 @@ LV2Node::instantiate(BufferFactory& bufs)
 	SLV2Value ctx_ext_uri = slv2_value_new_uri(info->lv2_world(), LV2_CONTEXT_MESSAGE);
 
 	for (uint32_t i = 0; i < _polyphony; ++i) {
-		(*_instances)[i] = slv2_plugin_instantiate(plug, _srate, _features->array());
-		if ((*_instances)[i] == NULL) {
+		(*_instances)[i] = SharedPtr<void>(
+				slv2_plugin_instantiate(plug, _srate, _features->array()),
+				slv2_instance_free);
+
+		if (!instance(i)) {
 			error << "Failed to instantiate plugin" << endl;
 			return false;
 		}
@@ -167,7 +167,7 @@ LV2Node::instantiate(BufferFactory& bufs)
 			continue;
 
 		const void* ctx_ext = slv2_instance_get_extension_data(
-				(*_instances)[i], LV2_CONTEXT_MESSAGE);
+				instance(i), LV2_CONTEXT_MESSAGE);
 
 		if (i == 0 && ctx_ext) {
 			Raul::info << _lv2_plugin->uri() << " has message context" << endl;
@@ -324,9 +324,6 @@ LV2Node::instantiate(BufferFactory& bufs)
 	}
 
 	if (!ret) {
-		for (uint32_t i = 0; i < _polyphony; ++i) {
-			slv2_instance_deactivate((*_instances)[i]);
-		}
 		delete _ports;
 		_ports = NULL;
 		delete _instances;
@@ -351,7 +348,7 @@ LV2Node::activate(BufferFactory& bufs)
 	NodeBase::activate(bufs);
 
 	for (uint32_t i = 0; i < _polyphony; ++i)
-		slv2_instance_activate((*_instances)[i]);
+		slv2_instance_activate(instance(i));
 }
 
 
@@ -361,7 +358,7 @@ LV2Node::deactivate()
 	NodeBase::deactivate();
 
 	for (uint32_t i = 0; i < _polyphony; ++i)
-		slv2_instance_deactivate((*_instances)[i]);
+		slv2_instance_deactivate(instance(i));
 }
 
 
@@ -376,8 +373,9 @@ LV2Node::message_run(MessageContext& context)
 
 	if (!_valid_ports)
 		_valid_ports = calloc(num_ports() / 8, 1);
+
 	if (_message_funcs)
-		(*_message_funcs->message_run)((*_instances)[0]->lv2_handle, _valid_ports, _valid_ports);
+		(*_message_funcs->message_run)(instance(0)->lv2_handle, _valid_ports, _valid_ports);
 }
 
 
@@ -387,7 +385,7 @@ LV2Node::process(ProcessContext& context)
 	NodeBase::pre_process(context);
 
 	for (uint32_t i = 0; i < _polyphony; ++i)
-		slv2_instance_run((*_instances)[i], context.nframes());
+		slv2_instance_run(instance(i), context.nframes());
 
 	NodeBase::post_process(context);
 }
@@ -397,7 +395,7 @@ void
 LV2Node::set_port_buffer(uint32_t voice, uint32_t port_num, BufferFactory::Ref buf)
 {
 	NodeBase::set_port_buffer(voice, port_num, buf);
-	slv2_instance_connect_port((*_instances)[voice], port_num,
+	slv2_instance_connect_port(instance(voice), port_num,
 			buf ? buf->port_data(_ports->at(port_num)->type()) : NULL);
 }
 
diff --git a/src/engine/LV2Node.hpp b/src/engine/LV2Node.hpp
index 57ad7998..4d751f32 100644
--- a/src/engine/LV2Node.hpp
+++ b/src/engine/LV2Node.hpp
@@ -61,9 +61,13 @@ public:
 	void set_port_buffer(uint32_t voice, uint32_t port_num, IntrusivePtr<Buffer> buf);
 
 protected:
-	LV2Plugin*                 _lv2_plugin;
-	Raul::Array<SLV2Instance>* _instances;
-	Raul::Array<SLV2Instance>* _prepared_instances;
+	inline SLV2Instance instance(uint32_t voice) { return (SLV2Instance)(*_instances)[voice].get(); }
+
+	typedef Raul::Array< SharedPtr<void> > Instances;
+
+	LV2Plugin* _lv2_plugin;
+	Instances* _instances;
+	Instances* _prepared_instances;
 
 	LV2MessageContext* _message_funcs;
 
-- 
cgit v1.2.1