summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2010-01-29 04:35:48 +0000
committerDavid Robillard <d@drobilla.net>2010-01-29 04:35:48 +0000
commit96613df7830699dbbfb5c2d9fe3ebdb0598e6aca (patch)
treebb7278466fc9ae92be6b53fb2f6399754d15f842 /src
parent1b964e850bbe3207fe9a65849520634955d141f0 (diff)
downloadingen-96613df7830699dbbfb5c2d9fe3ebdb0598e6aca.tar.gz
ingen-96613df7830699dbbfb5c2d9fe3ebdb0598e6aca.tar.bz2
ingen-96613df7830699dbbfb5c2d9fe3ebdb0598e6aca.zip
Remove references to deleted ports with control bindings (fix crash when applying binding to deleted port).
git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@2393 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src')
-rw-r--r--src/engine/ControlBindings.cpp34
-rw-r--r--src/engine/ControlBindings.hpp15
-rw-r--r--src/engine/events/Delete.cpp25
-rw-r--r--src/engine/events/Delete.hpp3
4 files changed, 58 insertions, 19 deletions
diff --git a/src/engine/ControlBindings.cpp b/src/engine/ControlBindings.cpp
index b74a3124..2c2a1888 100644
--- a/src/engine/ControlBindings.cpp
+++ b/src/engine/ControlBindings.cpp
@@ -60,7 +60,7 @@ ControlBindings::set_port_value(ProcessContext& context, PortImpl* port, int8_t
void
ControlBindings::bind(ProcessContext& context, int8_t cc_num)
{
- _bindings.insert(make_pair(cc_num, _learn_port));
+ _bindings->insert(make_pair(cc_num, _learn_port));
const Events::SendBinding ev(context.engine(), context.start(), _learn_port,
MessageType(MessageType::MIDI_CC, cc_num));
@@ -70,6 +70,30 @@ ControlBindings::bind(ProcessContext& context, int8_t cc_num)
}
+SharedPtr<ControlBindings::Bindings>
+ControlBindings::remove(const Raul::Path& path)
+{
+ ThreadManager::assert_thread(THREAD_PRE_PROCESS);
+
+ SharedPtr<Bindings> old_bindings = _bindings;
+
+ SharedPtr<Bindings> copy(new Bindings(*_bindings.get()));
+
+ for (Bindings::iterator i = copy->begin(); i != copy->end();) {
+ Bindings::iterator next = i;
+ ++next;
+
+ if (i->second->path() == path || i->second->path().is_child_of(path))
+ copy->erase(i);
+
+ i = next;
+ }
+
+ _bindings = copy;
+ return old_bindings;
+}
+
+
void
ControlBindings::process(ProcessContext& context, EventBuffer* buffer)
{
@@ -79,6 +103,8 @@ ControlBindings::process(ProcessContext& context, EventBuffer* buffer)
uint16_t size = 0;
uint8_t* buf = NULL;
+ SharedPtr<Bindings> bindings = _bindings;
+
if (_learn_port) {
buffer->rewind();
while (buffer->get_event(&frames, &subframes, &type, &size, &buf)) {
@@ -91,14 +117,14 @@ ControlBindings::process(ProcessContext& context, EventBuffer* buffer)
}
}
- if (!_bindings.empty()) {
+ if (!bindings->empty()) {
buffer->rewind();
while (buffer->get_event(&frames, &subframes, &type, &size, &buf)) {
if (type == _map->midi_event && (buf[0] & 0xF0) == MIDI_CMD_CONTROL) {
const int8_t controller = static_cast<const int8_t>(buf[1]);
const int8_t value = static_cast<const int8_t>(buf[2]);
- Bindings::const_iterator i = _bindings.find(controller);
- if (i != _bindings.end()) {
+ Bindings::const_iterator i = bindings->find(controller);
+ if (i != bindings->end()) {
set_port_value(context, i->second, value);
}
}
diff --git a/src/engine/ControlBindings.hpp b/src/engine/ControlBindings.hpp
index 8477a0fa..8823ecb1 100644
--- a/src/engine/ControlBindings.hpp
+++ b/src/engine/ControlBindings.hpp
@@ -15,12 +15,13 @@
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef CONTROL_BINDIGNS_HPP
+#ifndef CONTROL_BINDINGS_HPP
#define CONTROL_BINDINGS_HPP
#include <stdint.h>
#include <map>
#include "raul/SharedPtr.hpp"
+#include "raul/Path.hpp"
#include "shared/LV2URIMap.hpp"
namespace Ingen {
@@ -32,15 +33,24 @@ class PortImpl;
class ControlBindings {
public:
+ typedef std::map<int8_t, PortImpl*> Bindings;
+
ControlBindings(Engine& engine, SharedPtr<Shared::LV2URIMap> map)
: _engine(engine)
, _map(map)
, _learn_port(NULL)
+ , _bindings(new Bindings())
{}
void learn(PortImpl* port);
void process(ProcessContext& context, EventBuffer* buffer);
+ /** Remove all bindings for @a path or children of @a path.
+ * The caller must safely drop the returned reference in the
+ * post-processing thread after at least one process thread has run.
+ */
+ SharedPtr<Bindings> remove(const Raul::Path& path);
+
private:
Engine& _engine;
SharedPtr<Shared::LV2URIMap> _map;
@@ -49,8 +59,7 @@ private:
void set_port_value(ProcessContext& context, PortImpl* port, int8_t cc_value);
void bind(ProcessContext& context, int8_t cc_num);
- typedef std::map<int8_t, PortImpl*> Bindings;
- Bindings _bindings;
+ SharedPtr<Bindings> _bindings;
};
} // namespace Ingen
diff --git a/src/engine/events/Delete.cpp b/src/engine/events/Delete.cpp
index 956253d6..11d355a4 100644
--- a/src/engine/events/Delete.cpp
+++ b/src/engine/events/Delete.cpp
@@ -17,18 +17,19 @@
#include "raul/Maid.hpp"
#include "raul/Path.hpp"
+#include "ClientBroadcaster.hpp"
+#include "ControlBindings.hpp"
#include "Delete.hpp"
-#include "Responder.hpp"
-#include "Engine.hpp"
-#include "PatchImpl.hpp"
-#include "NodeBase.hpp"
-#include "PluginImpl.hpp"
-#include "Driver.hpp"
#include "DisconnectAll.hpp"
-#include "ClientBroadcaster.hpp"
+#include "Driver.hpp"
+#include "Engine.hpp"
#include "EngineStore.hpp"
#include "EventSource.hpp"
+#include "NodeBase.hpp"
+#include "PatchImpl.hpp"
+#include "PluginImpl.hpp"
#include "PortImpl.hpp"
+#include "Responder.hpp"
using namespace std;
@@ -62,6 +63,8 @@ Delete::~Delete()
void
Delete::pre_process()
{
+ _removed_bindings = _engine.control_bindings()->remove(_path);
+
_store_iterator = _engine.engine_store()->find(_path);
if (_store_iterator != _engine.engine_store()->end()) {
@@ -75,7 +78,7 @@ Delete::pre_process()
_removed_table = _engine.engine_store()->remove(_store_iterator);
}
- if (_node != NULL && !_path.is_root()) {
+ if (_node && !_path.is_root()) {
assert(_node->parent_patch());
_patch_node_listnode = _node->parent_patch()->remove_node(_path.name());
if (_patch_node_listnode) {
@@ -153,10 +156,6 @@ Delete::execute(ProcessContext& context)
if ( ! _port->parent_patch()->parent()) {
_driver_port = _engine.driver()->remove_port(_port->path());
-
- // Apparently this needs to be called in post_process??
- //if (_driver_port)
- // _driver_port->elem()->unregister();
}
}
@@ -168,6 +167,8 @@ Delete::execute(ProcessContext& context)
void
Delete::post_process()
{
+ _removed_bindings.reset();
+
if (!_node && !_port) {
if (_path.is_root()) {
_responder->respond_error("You can not destroy the root patch (/)");
diff --git a/src/engine/events/Delete.hpp b/src/engine/events/Delete.hpp
index ac46030f..e4cb6732 100644
--- a/src/engine/events/Delete.hpp
+++ b/src/engine/events/Delete.hpp
@@ -21,6 +21,7 @@
#include "QueuedEvent.hpp"
#include "EngineStore.hpp"
#include "PatchImpl.hpp"
+#include "ControlBindings.hpp"
namespace Raul {
template<typename T> class Array;
@@ -82,6 +83,8 @@ private:
CompiledPatch* _compiled_patch; ///< Patch's new process order
DisconnectAll* _disconnect_event;
+ SharedPtr<ControlBindings::Bindings> _removed_bindings;
+
SharedPtr< Raul::Table<Raul::Path, SharedPtr<Shared::GraphObject> > > _removed_table;
};