From 48f87f1f1649fb7e169fdaac2cd38370e8a4a1fa Mon Sep 17 00:00:00 2001
From: David Robillard <d@drobilla.net>
Date: Fri, 8 Sep 2006 03:58:00 +0000
Subject: De-singleton-ified Engine Slight rework of
 Responder/ClientKey/ClientInterface for Requests

git-svn-id: http://svn.drobilla.net/lad/ingen@119 a436a847-0d15-0410-975c-d299462d15a1
---
 src/libs/engine/AlsaMidiDriver.cpp                 | 134 ++++++++--------
 src/libs/engine/AlsaMidiDriver.h                   |  34 ++--
 src/libs/engine/AudioDriver.h                      |   2 +-
 src/libs/engine/ClientBroadcaster.cpp              |  11 +-
 src/libs/engine/ClientBroadcaster.h                |   2 +-
 src/libs/engine/DSSINode.cpp                       |  16 +-
 src/libs/engine/DSSINode.h                         |   2 +-
 src/libs/engine/Engine.cpp                         |  29 ++--
 src/libs/engine/Engine.h                           |  20 +--
 src/libs/engine/Event.h                            |  20 ++-
 src/libs/engine/GraphObject.h                      |   5 +-
 src/libs/engine/InputPort.cpp                      |   8 +-
 src/libs/engine/InputPort.h                        |   2 +-
 src/libs/engine/InternalNode.h                     |   3 +-
 src/libs/engine/JackAudioDriver.cpp                | 175 ++++++++++-----------
 src/libs/engine/JackAudioDriver.h                  |  77 ++++-----
 src/libs/engine/LADSPANode.cpp                     |   4 +-
 src/libs/engine/LADSPANode.h                       |   2 +-
 src/libs/engine/LV2Node.cpp                        |   4 +-
 src/libs/engine/LV2Node.h                          |   2 +-
 src/libs/engine/MidiControlNode.cpp                |  12 +-
 src/libs/engine/MidiControlNode.h                  |   2 +-
 src/libs/engine/MidiNoteNode.cpp                   |  66 ++++----
 src/libs/engine/MidiNoteNode.h                     |  15 +-
 src/libs/engine/MidiTriggerNode.cpp                |  28 ++--
 src/libs/engine/MidiTriggerNode.h                  |   6 +-
 src/libs/engine/Node.h                             |   9 +-
 src/libs/engine/NodeBase.cpp                       |  39 +++--
 src/libs/engine/NodeBase.h                         |   8 +-
 src/libs/engine/NodeFactory.cpp                    |  10 --
 src/libs/engine/NodeFactory.h                      |   6 -
 src/libs/engine/OSCReceiver.cpp                    |   4 +-
 src/libs/engine/OSCReceiver.h                      |   2 +-
 src/libs/engine/OSCResponder.cpp                   |   8 -
 src/libs/engine/OSCResponder.h                     |   4 +-
 src/libs/engine/ObjectSender.cpp                   |  26 +--
 src/libs/engine/ObjectSender.h                     |   6 +-
 src/libs/engine/Patch.cpp                          |  35 ++---
 src/libs/engine/Patch.h                            |   9 +-
 src/libs/engine/Plugin.cpp                         |  44 ++++++
 src/libs/engine/Port.h                             |   6 +-
 src/libs/engine/PostProcessor.cpp                  |   8 +-
 src/libs/engine/PostProcessor.h                    |   6 +-
 src/libs/engine/QueuedEngineInterface.cpp          |  61 +++----
 src/libs/engine/QueuedEngineInterface.h            |   5 +-
 src/libs/engine/QueuedEvent.h                      |  22 ++-
 src/libs/engine/QueuedEventSource.cpp              |   2 +-
 src/libs/engine/QueuedEventSource.h                |   2 +-
 src/libs/engine/Responder.h                        |  11 +-
 src/libs/engine/TransportNode.cpp                  |   5 +-
 src/libs/engine/TransportNode.h                    |   2 +-
 src/libs/engine/TypedConnection.cpp                |   6 +-
 src/libs/engine/TypedConnection.h                  |   2 +-
 src/libs/engine/TypedPort.cpp                      |   2 +-
 src/libs/engine/TypedPort.h                        |   2 +-
 src/libs/engine/events/ActivateEvent.cpp           |   6 +-
 src/libs/engine/events/ActivateEvent.h             |   2 +-
 src/libs/engine/events/AddNodeEvent.cpp            |  26 +--
 src/libs/engine/events/AddNodeEvent.h              |   4 +-
 src/libs/engine/events/AddPortEvent.cpp            |  24 +--
 src/libs/engine/events/AddPortEvent.h              |   4 +-
 src/libs/engine/events/AllNotesOffEvent.cpp        |  12 +-
 src/libs/engine/events/AllNotesOffEvent.h          |   6 +-
 src/libs/engine/events/ClearPatchEvent.cpp         |  23 +--
 src/libs/engine/events/ClearPatchEvent.h           |   4 +-
 src/libs/engine/events/ConnectionEvent.cpp         |  32 ++--
 src/libs/engine/events/ConnectionEvent.h           |   8 +-
 src/libs/engine/events/CreatePatchEvent.cpp        |  26 +--
 src/libs/engine/events/CreatePatchEvent.h          |   4 +-
 src/libs/engine/events/DSSIConfigureEvent.cpp      |  10 +-
 src/libs/engine/events/DSSIConfigureEvent.h        |   4 +-
 src/libs/engine/events/DSSIControlEvent.cpp        |   8 +-
 src/libs/engine/events/DSSIControlEvent.h          |   4 +-
 src/libs/engine/events/DSSIProgramEvent.cpp        |  10 +-
 src/libs/engine/events/DSSIProgramEvent.h          |   4 +-
 src/libs/engine/events/DSSIUpdateEvent.cpp         |  10 +-
 src/libs/engine/events/DSSIUpdateEvent.h           |   4 +-
 src/libs/engine/events/DeactivateEvent.cpp         |  10 +-
 src/libs/engine/events/DeactivateEvent.h           |   4 +-
 src/libs/engine/events/DestroyEvent.cpp            |  32 ++--
 src/libs/engine/events/DestroyEvent.h              |   6 +-
 src/libs/engine/events/DisablePatchEvent.cpp       |  14 +-
 src/libs/engine/events/DisablePatchEvent.h         |   4 +-
 src/libs/engine/events/DisconnectNodeEvent.cpp     |  20 +--
 src/libs/engine/events/DisconnectNodeEvent.h       |   6 +-
 src/libs/engine/events/DisconnectPortEvent.cpp     |  22 +--
 src/libs/engine/events/DisconnectPortEvent.h       |   6 +-
 src/libs/engine/events/DisconnectionEvent.cpp      |  44 +++---
 src/libs/engine/events/DisconnectionEvent.h        |  10 +-
 src/libs/engine/events/EnablePatchEvent.cpp        |  14 +-
 src/libs/engine/events/EnablePatchEvent.h          |   4 +-
 src/libs/engine/events/LashRestoreDoneEvent.h      |   2 +-
 src/libs/engine/events/LoadPluginsEvent.cpp        |   6 +-
 src/libs/engine/events/LoadPluginsEvent.h          |   2 +-
 src/libs/engine/events/MidiLearnEvent.cpp          |  14 +-
 src/libs/engine/events/MidiLearnEvent.h            |   8 +-
 src/libs/engine/events/NoteOffEvent.cpp            |  18 ++-
 src/libs/engine/events/NoteOffEvent.h              |   6 +-
 src/libs/engine/events/NoteOnEvent.cpp             |  18 ++-
 src/libs/engine/events/NoteOnEvent.h               |   6 +-
 src/libs/engine/events/PingQueuedEvent.h           |   2 +-
 src/libs/engine/events/RegisterClientEvent.cpp     |   6 +-
 src/libs/engine/events/RegisterClientEvent.h       |   2 +-
 src/libs/engine/events/RenameEvent.cpp             |  14 +-
 src/libs/engine/events/RenameEvent.h               |   4 +-
 src/libs/engine/events/RequestAllObjectsEvent.cpp  |  17 +-
 src/libs/engine/events/RequestAllObjectsEvent.h    |   2 +-
 src/libs/engine/events/RequestMetadataEvent.cpp    |   8 +-
 src/libs/engine/events/RequestMetadataEvent.h      |   2 +-
 src/libs/engine/events/RequestPluginsEvent.cpp     |  15 +-
 src/libs/engine/events/RequestPluginsEvent.h       |   5 +-
 src/libs/engine/events/RequestPortValueEvent.cpp   |  18 ++-
 src/libs/engine/events/RequestPortValueEvent.h     |   4 +-
 src/libs/engine/events/SetMetadataEvent.cpp        |  12 +-
 src/libs/engine/events/SetMetadataEvent.h          |   4 +-
 src/libs/engine/events/SetPortValueEvent.cpp       |  22 +--
 src/libs/engine/events/SetPortValueEvent.h         |   6 +-
 src/libs/engine/events/SetPortValueQueuedEvent.cpp |  24 +--
 src/libs/engine/events/SetPortValueQueuedEvent.h   |   6 +-
 src/libs/engine/events/UnregisterClientEvent.cpp   |   6 +-
 src/libs/engine/events/UnregisterClientEvent.h     |   2 +-
 src/libs/engine/types.h                            |   1 +
 122 files changed, 891 insertions(+), 835 deletions(-)
 create mode 100644 src/libs/engine/Plugin.cpp

(limited to 'src/libs')

diff --git a/src/libs/engine/AlsaMidiDriver.cpp b/src/libs/engine/AlsaMidiDriver.cpp
index f609ac52..e516f1ac 100644
--- a/src/libs/engine/AlsaMidiDriver.cpp
+++ b/src/libs/engine/AlsaMidiDriver.cpp
@@ -18,9 +18,8 @@
 #include <iostream>
 #include <cstdlib>
 #include <pthread.h>
-#include "Engine.h"
 #include "types.h"
-#include "Engine.h"
+//#include "Engine.h"
 #include "Maid.h"
 #include "AudioDriver.h"
 #include "MidiMessage.h"
@@ -38,17 +37,17 @@ namespace Ingen {
 AlsaMidiPort::AlsaMidiPort(AlsaMidiDriver* driver, DuplexPort<MidiMessage>* port)
 : DriverPort(),
   ListNode<AlsaMidiPort*>(this),
-  m_driver(driver),
-  m_patch_port(port),
-  m_port_id(0),
-  m_midi_pool(new unsigned char*[port->buffer_size()]),
-  m_events(1024)
+  _driver(driver),
+  _patch_port(port),
+  _port_id(0),
+  _midi_pool(new unsigned char*[port->buffer_size()]),
+  _events(1024)
 {
 	assert(port->parent() != NULL);
 	assert(port->poly() == 1);
 
 	if (port->is_input()) {
-		if ((m_port_id = snd_seq_create_simple_port(driver->seq_handle(), port->path().c_str(),
+		if ((_port_id = snd_seq_create_simple_port(driver->seq_handle(), port->path().c_str(),
    	 		SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE,
 			SND_SEQ_PORT_TYPE_APPLICATION)) < 0)
 		{
@@ -56,7 +55,7 @@ AlsaMidiPort::AlsaMidiPort(AlsaMidiDriver* driver, DuplexPort<MidiMessage>* port
 			exit(EXIT_FAILURE);
 		}
 	} else {
-		if ((m_port_id = snd_seq_create_simple_port(driver->seq_handle(), port->path().c_str(),
+		if ((_port_id = snd_seq_create_simple_port(driver->seq_handle(), port->path().c_str(),
    	 		SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ,
 			SND_SEQ_PORT_TYPE_APPLICATION)) < 0)
 		{
@@ -70,7 +69,7 @@ AlsaMidiPort::AlsaMidiPort(AlsaMidiDriver* driver, DuplexPort<MidiMessage>* port
 	 * buffer will be set directly to an element in this pool, then next cycle they
 	 * will be overwritten (eliminating the need for any allocation/freeing). */
 	for (size_t i=0; i < port->buffer_size(); ++i)
-		m_midi_pool[i] = new unsigned char[MAX_MIDI_EVENT_SIZE];
+		_midi_pool[i] = new unsigned char[MAX_MIDI_EVENT_SIZE];
 
 	port->buffer(0)->clear();
 	port->fixed_buffers(true);
@@ -79,27 +78,27 @@ AlsaMidiPort::AlsaMidiPort(AlsaMidiDriver* driver, DuplexPort<MidiMessage>* port
 
 AlsaMidiPort::~AlsaMidiPort()
 {
-	snd_seq_delete_simple_port(m_driver->seq_handle(), m_port_id);
+	snd_seq_delete_simple_port(_driver->seq_handle(), _port_id);
 
 	// Free event pool
-	for (size_t i=0; i < m_patch_port->buffer_size(); ++i)
-		delete[] m_midi_pool[i];
+	for (size_t i=0; i < _patch_port->buffer_size(); ++i)
+		delete[] _midi_pool[i];
 	
-	delete[] m_midi_pool;
+	delete[] _midi_pool;
 }
 
 
 void
 AlsaMidiPort::add_to_driver()
 {
-	m_driver->add_port(this);
+	_driver->add_port(this);
 }
 
 
 void
 AlsaMidiPort::remove_from_driver()
 {
-	m_driver->remove_port(this);
+	_driver->remove_port(this);
 }
 
 
@@ -108,9 +107,9 @@ AlsaMidiPort::set_name(const string& name)
 {
 	snd_seq_port_info_t* info = NULL;
 	snd_seq_port_info_malloc(&info);
-	snd_seq_get_port_info(m_driver->seq_handle(), m_port_id, info);
+	snd_seq_get_port_info(_driver->seq_handle(), _port_id, info);
 	snd_seq_port_info_set_name(info, name.c_str());
-	snd_seq_set_port_info(m_driver->seq_handle(), m_port_id, info);
+	snd_seq_set_port_info(_driver->seq_handle(), _port_id, info);
 	snd_seq_port_info_free(info);
 }
 
@@ -119,13 +118,13 @@ void
 AlsaMidiPort::event(snd_seq_event_t* const ev)
 {
 	// Abuse the tick field to hold the timestamp
-	ev->time.tick = Engine::instance().audio_driver()->time_stamp();
+	ev->time.tick = _driver->clock()->time_stamp();
 	
 	// Fix noteons with velocity 0 (required for DSSI spec)
 	if (ev->type == SND_SEQ_EVENT_NOTEON && ev->data.note.velocity == 0)
 		ev->type = SND_SEQ_EVENT_NOTEOFF;
 
-	m_events.push(*ev);
+	_events.push(*ev);
 }
 
 
@@ -142,14 +141,14 @@ AlsaMidiPort::prepare_block(const SampleCount block_start, const SampleCount blo
 	
 	snd_seq_event_t* ev         = NULL;
 	MidiMessage*     message    = NULL;
-	size_t           num_events = 0;
+	size_t           nu_events = 0;
 	size_t           event_size = 0; // decoded length of Alsa event in bytes
 	int              timestamp  = 0;
 	
-	while (!m_events.is_empty() && m_events.front().time.tick < block_end) {
-		assert(num_events < m_patch_port->buffer_size());
-		ev = &m_events.front();
-		message = &m_patch_port->buffer(0)->data()[num_events];
+	while (!_events.is_empty() && _events.front().time.tick < block_end) {
+		assert(nu_events < _patch_port->buffer_size());
+		ev = &_events.front();
+		message = &_patch_port->buffer(0)->data()[nu_events];
 		
 		timestamp = ev->time.tick - block_start;
 		if (timestamp < 0) {
@@ -160,24 +159,24 @@ AlsaMidiPort::prepare_block(const SampleCount block_start, const SampleCount blo
 		assert(timestamp < (int)(block_end - block_start));
 		
 		// Reset decoder so we don't get running status
-		snd_midi_event_reset_decode(m_driver->event_coder());
+		snd_midi_event_reset_decode(_driver->event_coder());
 
 		// FIXME: is this realtime safe?
-		if ((event_size = snd_midi_event_decode(m_driver->event_coder(),
-				m_midi_pool[num_events], MAX_MIDI_EVENT_SIZE, ev)) > 0) {
+		if ((event_size = snd_midi_event_decode(_driver->event_coder(),
+				_midi_pool[nu_events], MAX_MIDI_EVENT_SIZE, ev)) > 0) {
 			message->size = event_size;
 			message->time = timestamp;
-			message->buffer = m_midi_pool[num_events];
-			++num_events;
+			message->buffer = _midi_pool[nu_events];
+			++nu_events;
 		} else {
 			cerr << "[AlsaMidiPort] Unable to decode MIDI event" << endl;
 		}
 		
-		m_events.pop();
+		_events.pop();
 	}
 
-	m_patch_port->buffer(0)->filled_size(num_events);
-	//m_patch_port->tied_port()->buffer(0)->filled_size(num_events);
+	_patch_port->buffer(0)->filled_size(nu_events);
+	//_patch_port->tied_port()->buffer(0)->filled_size(nu_events);
 }
 
 
@@ -185,38 +184,38 @@ AlsaMidiPort::prepare_block(const SampleCount block_start, const SampleCount blo
 //// AlsaMidiDriver ////
 
 
-bool AlsaMidiDriver::m_midi_thread_exit_flag = true;
+bool AlsaMidiDriver::_midi_thread_exit_flag = true;
 
 
 AlsaMidiDriver::AlsaMidiDriver()
-: m_seq_handle(NULL),
-  m_event_coder(NULL),
-  m_is_activated(false)
+: _seq_handle(NULL),
+  _event_coder(NULL),
+  _is_activated(false)
 {
-	if (snd_seq_open(&m_seq_handle, "hw", SND_SEQ_OPEN_INPUT, 0) < 0) {
+	if (snd_seq_open(&_seq_handle, "hw", SND_SEQ_OPEN_INPUT, 0) < 0) {
 		cerr << "[AlsaMidiDriver] Error opening ALSA sequencer." << endl;
 		exit(EXIT_FAILURE);
 	} else {
 		cout << "[AlsaMidiDriver] Successfully opened ALSA sequencer." << endl;
 	}
 
-	if (snd_midi_event_new(3, &m_event_coder)) {
+	if (snd_midi_event_new(3, &_event_coder)) {
 		cerr << "[AlsaMidiDriver] Failed to initialize ALSA MIDI event coder!";
 		exit(EXIT_FAILURE);
 	} else {
-		snd_midi_event_reset_encode(m_event_coder);
-		snd_midi_event_reset_decode(m_event_coder);
+		snd_midi_event_reset_encode(_event_coder);
+		snd_midi_event_reset_decode(_event_coder);
 	}
 
-	snd_seq_set_client_name(m_seq_handle, "Ingen");
+	snd_seq_set_client_name(_seq_handle, "Ingen");
 }
 
 
 AlsaMidiDriver::~AlsaMidiDriver()
 {
 	deactivate();
-	snd_midi_event_free(m_event_coder);
-	snd_seq_close(m_seq_handle);
+	snd_midi_event_free(_event_coder);
+	snd_seq_close(_seq_handle);
 }
 
 
@@ -226,11 +225,11 @@ void
 AlsaMidiDriver::activate() 
 {
 	// Just exit if already running
-	if (m_midi_thread_exit_flag == false)
+	if (_midi_thread_exit_flag == false)
 		return;
 	
 	bool success = false;
-	m_midi_thread_exit_flag = false;
+	_midi_thread_exit_flag = false;
 
 	//if (Engine::instance().audio_driver()->is_realtime()) {
 		pthread_attr_t attr;
@@ -250,7 +249,7 @@ AlsaMidiDriver::activate()
 			cout << "[AlsaMidiDriver] Unable to set SCHED_FIFO priority "
 				<< param.sched_priority << endl;
 	 
-		if (!pthread_create(&m_process_thread, &attr, process_midi_in, this)) {
+		if (!pthread_create(&_process_thread, &attr, process_midi_in, this)) {
 			cout << "[AlsaMidiDriver] Started realtime MIDI thread (SCHED_FIFO, priority "
 				<< param.sched_priority << ")" << endl;
 			success = true;
@@ -262,15 +261,16 @@ AlsaMidiDriver::activate()
 	
 	if (!success) {
 		// FIXME: check for success
-		pthread_create(&m_process_thread, NULL, process_midi_in, this);
+		pthread_create(&_process_thread, NULL, process_midi_in, this);
 		cout << "[AlsaMidiDriver] Started non-realtime MIDI thread." << endl;
 	}
 	
 #ifdef HAVE_LASH
-	Engine::instance().lash_driver()->set_alsa_client_id(snd_seq_client_id(m_seq_handle));
+	cerr << "FIXME: LASH + ALSA" << endl;
+	//Engine::instance().lash_driver()->set_alsa_client_id(snd_seq_client_id(_seq_handle));
 #endif
 
-	m_is_activated = true;
+	_is_activated = true;
 }
 
 
@@ -279,11 +279,11 @@ AlsaMidiDriver::activate()
 void
 AlsaMidiDriver::deactivate() 
 {
-	if (m_is_activated) {
-		m_midi_thread_exit_flag = true;
-		pthread_cancel(m_process_thread);
-		pthread_join(m_process_thread, NULL);
-		m_is_activated = false;
+	if (_is_activated) {
+		_midi_thread_exit_flag = true;
+		pthread_cancel(_process_thread);
+		pthread_join(_process_thread, NULL);
+		_is_activated = false;
 	}
 }
 
@@ -293,7 +293,7 @@ AlsaMidiDriver::deactivate()
 void
 AlsaMidiDriver::prepare_block(const SampleCount block_start, const SampleCount block_end)
 {
-	for (List<AlsaMidiPort*>::iterator i = m_in_ports.begin(); i != m_in_ports.end(); ++i)
+	for (List<AlsaMidiPort*>::iterator i = _in_ports.begin(); i != _in_ports.end(); ++i)
 		(*i)->prepare_block(block_start, block_end);
 }
 
@@ -309,9 +309,9 @@ void
 AlsaMidiDriver::add_port(AlsaMidiPort* port)
 {
 	if (port->patch_port()->is_input())
-		m_in_ports.push_back(port);
+		_in_ports.push_back(port);
 	else
-		m_out_ports.push_back(port);
+		_out_ports.push_back(port);
 }
 
 
@@ -327,13 +327,13 @@ AlsaMidiPort*
 AlsaMidiDriver::remove_port(AlsaMidiPort* port)
 {
 	if (port->patch_port()->is_input()) {
-		for (List<AlsaMidiPort*>::iterator i = m_in_ports.begin(); i != m_in_ports.end(); ++i)
+		for (List<AlsaMidiPort*>::iterator i = _in_ports.begin(); i != _in_ports.end(); ++i)
 			if ((*i) == (AlsaMidiPort*)port)
-				return m_in_ports.remove(i)->elem();
+				return _in_ports.remove(i)->elem();
 	} else {
-		for (List<AlsaMidiPort*>::iterator i = m_out_ports.begin(); i != m_out_ports.end(); ++i)
+		for (List<AlsaMidiPort*>::iterator i = _out_ports.begin(); i != _out_ports.end(); ++i)
 			if ((*i) == port)
-				return m_out_ports.remove(i)->elem();
+				return _out_ports.remove(i)->elem();
 	}
 	
 	cerr << "[AlsaMidiDriver::remove_input] WARNING: Failed to find Jack port to remove!" << endl;
@@ -350,14 +350,14 @@ AlsaMidiDriver::process_midi_in(void* alsa_driver)
 
 	snd_seq_event_t* ev;
 
-	int npfd = snd_seq_poll_descriptors_count(ad->m_seq_handle, POLLIN);
+	int npfd = snd_seq_poll_descriptors_count(ad->_seq_handle, POLLIN);
 	struct pollfd pfd;
-	snd_seq_poll_descriptors(ad->m_seq_handle, &pfd, npfd, POLLIN);
+	snd_seq_poll_descriptors(ad->_seq_handle, &pfd, npfd, POLLIN);
 	
-	while ( ! m_midi_thread_exit_flag)
+	while ( ! _midi_thread_exit_flag)
 		if (poll(&pfd, npfd, 100000) > 0)
-			while (snd_seq_event_input(ad->m_seq_handle, &ev) > 0)
-				for (List<AlsaMidiPort*>::iterator i = ad->m_in_ports.begin(); i != ad->m_in_ports.end(); ++i)
+			while (snd_seq_event_input(ad->_seq_handle, &ev) > 0)
+				for (List<AlsaMidiPort*>::iterator i = ad->_in_ports.begin(); i != ad->_in_ports.end(); ++i)
 					if ((*i)->port_id() == ev->dest.port)
 						(*i)->event(ev);
 	
diff --git a/src/libs/engine/AlsaMidiDriver.h b/src/libs/engine/AlsaMidiDriver.h
index c1941c42..ad40ed17 100644
--- a/src/libs/engine/AlsaMidiDriver.h
+++ b/src/libs/engine/AlsaMidiDriver.h
@@ -50,19 +50,19 @@ public:
 	void remove_from_driver();
 	void set_name(const string& name);
 	
-	int                      port_id()    const { return m_port_id; }
-	DuplexPort<MidiMessage>* patch_port() const { return m_patch_port; }
+	int                      port_id()    const { return _port_id; }
+	DuplexPort<MidiMessage>* patch_port() const { return _patch_port; }
 
 private:
 	// Prevent copies (undefined)
 	AlsaMidiPort(const AlsaMidiPort&);
 	AlsaMidiPort& operator=(const AlsaMidiPort&);
  
-	AlsaMidiDriver*          m_driver;
-	DuplexPort<MidiMessage>* m_patch_port;
-	int                      m_port_id;
-	unsigned char**          m_midi_pool; ///< Pool of raw MIDI events for MidiMessage::buffer
-	Queue<snd_seq_event_t>   m_events;
+	AlsaMidiDriver*          _driver;
+	DuplexPort<MidiMessage>* _patch_port;
+	int                      _port_id;
+	unsigned char**          _midi_pool; ///< Pool of raw MIDI events for MidiMessage::buffer
+	Queue<snd_seq_event_t>   _events;
 };
 
 
@@ -82,15 +82,15 @@ public:
 	void activate();
 	void deactivate();
 	
-	bool is_activated() const { return m_is_activated; }
+	bool is_activated() const { return _is_activated; }
 	
 	void prepare_block(const SampleCount block_start, const SampleCount block_end);
 
 	DriverPort* create_port(DuplexPort<MidiMessage>* patch_port)
 	{ return new AlsaMidiPort(this, patch_port); }
 
-	snd_seq_t*        seq_handle()  const { return m_seq_handle; }
-	snd_midi_event_t* event_coder() const { return m_event_coder; }
+	snd_seq_t*        seq_handle()  const { return _seq_handle; }
+	snd_midi_event_t* event_coder() const { return _event_coder; }
 
 private:
 
@@ -98,8 +98,8 @@ private:
 	AlsaMidiDriver(const AlsaMidiDriver&);
 	AlsaMidiDriver& operator=(const AlsaMidiDriver&);
 	
-	List<AlsaMidiPort*> m_in_ports;
-	List<AlsaMidiPort*> m_out_ports;
+	List<AlsaMidiPort*> _in_ports;
+	List<AlsaMidiPort*> _out_ports;
 	
 	friend class AlsaMidiPort;
 	
@@ -113,11 +113,11 @@ private:
 	// MIDI thread
 	static void* process_midi_in(void* me);
 
-	snd_seq_t*        m_seq_handle;
-	snd_midi_event_t* m_event_coder;
-	pthread_t         m_process_thread;
-	bool              m_is_activated;
-	static bool       m_midi_thread_exit_flag;
+	snd_seq_t*        _seq_handle;
+	snd_midi_event_t* _event_coder;
+	pthread_t         _process_thread;
+	bool              _is_activated;
+	static bool       _midi_thread_exit_flag;
 };
 
 
diff --git a/src/libs/engine/AudioDriver.h b/src/libs/engine/AudioDriver.h
index f46d4689..f72c43ea 100644
--- a/src/libs/engine/AudioDriver.h
+++ b/src/libs/engine/AudioDriver.h
@@ -41,7 +41,7 @@ public:
 	
 	virtual SampleCount buffer_size()  const = 0;
 	virtual SampleCount sample_rate()  const = 0;
-	virtual SampleCount time_stamp()   const = 0;
+	virtual SampleCount frame_time()   const = 0;
 };
 
 
diff --git a/src/libs/engine/ClientBroadcaster.cpp b/src/libs/engine/ClientBroadcaster.cpp
index 4dc992db..1fa64d9a 100644
--- a/src/libs/engine/ClientBroadcaster.cpp
+++ b/src/libs/engine/ClientBroadcaster.cpp
@@ -18,7 +18,6 @@
 #include <cassert>
 #include <iostream>
 #include <unistd.h>
-#include "Engine.h"
 #include "ObjectStore.h"
 #include "NodeFactory.h"
 #include "util.h"
@@ -131,11 +130,11 @@ ClientBroadcaster::send_error(const string& msg)
 /* FIXME: Make a copy method for list and just make a copy and pass it here
  * instead of this global+locking mess */
 void
-ClientBroadcaster::send_plugins_to(ClientInterface* client)
+ClientBroadcaster::send_plugins_to(ClientInterface* client, const list<Plugin*>& plugin_list)
 {
-	Engine::instance().node_factory()->lock_plugin_list();
-	
-	const list<Plugin*>& plugs = Engine::instance().node_factory()->plugins();
+	// FIXME: This probably isn't actually thread safe
+	const list<Plugin*> plugs = plugin_list; // make a copy
+
 	const Plugin* plugin;
 
 	lo_timetag tt;
@@ -174,8 +173,6 @@ ClientBroadcaster::send_plugins_to(ClientInterface* client)
 	}
 	for (list<lo_bundle>::const_iterator i = msgs.begin(); i != msgs.end(); ++i)
 		lo_message_free(*i);
-
-	Engine::instance().node_factory()->unlock_plugin_list();
 }
 
 
diff --git a/src/libs/engine/ClientBroadcaster.h b/src/libs/engine/ClientBroadcaster.h
index 2c9890a6..adc0e7e9 100644
--- a/src/libs/engine/ClientBroadcaster.h
+++ b/src/libs/engine/ClientBroadcaster.h
@@ -66,7 +66,7 @@ public:
 	// Error that isn't the direct result of a request
 	void send_error(const string& msg);
 
-	void send_plugins_to(ClientInterface* client);
+	void send_plugins_to(ClientInterface* client, const list<Plugin*>& plugin_list);
 	
 	//void send_node_creation_messages(const Node* const node);
 	
diff --git a/src/libs/engine/DSSINode.cpp b/src/libs/engine/DSSINode.cpp
index 122c13b4..11fda753 100644
--- a/src/libs/engine/DSSINode.cpp
+++ b/src/libs/engine/DSSINode.cpp
@@ -17,7 +17,6 @@
 #include "DSSINode.h"
 #include <map>
 #include <set>
-#include "Engine.h"
 #include "ClientBroadcaster.h"
 #include "interface/ClientInterface.h"
 #include "InputPort.h"
@@ -160,9 +159,9 @@ DSSINode::has_midi_input() const
 
 
 void
-DSSINode::process(SampleCount nframes)
+DSSINode::process(SampleCount nframes, FrameTime start, FrameTime end)
 {
-	NodeBase::process(nframes);
+	NodeBase::process(nframes, start, end);
 
 	if (_dssi_descriptor->run_synth) {
 		convert_events();
@@ -176,7 +175,7 @@ DSSINode::process(SampleCount nframes)
 		_dssi_descriptor->run_multiple_synths(1, _instances, nframes,
 			events, events_sizes);
 	} else {
-		LADSPANode::process(nframes);
+		LADSPANode::process(nframes, start, end);
 	}
 }
 
@@ -252,6 +251,7 @@ DSSINode::send_update()
 bool
 DSSINode::update_programs(bool send_events)
 {
+#if 0
 	// remember all old banks and programs
 	set<pair<int, int> > to_be_deleted;
 	map<int, Bank>::const_iterator iter;
@@ -276,7 +276,7 @@ DSSINode::update_programs(bool send_events)
 			    iter->second.find(descriptor->Program)->second != descriptor->Name) {
 				_banks[descriptor->Bank][descriptor->Program] = descriptor->Name;
 				if (send_events) {
-					Engine::instance().client_broadcaster()->send_program_add(path(), descriptor->Bank,
+					_engine.client_broadcaster()->send_program_add(path(), descriptor->Bank,
 									   descriptor->Program, 
 									   descriptor->Name);
 				}
@@ -291,11 +291,13 @@ DSSINode::update_programs(bool send_events)
 	     set_iter != to_be_deleted.end(); ++set_iter) {
 		_banks[set_iter->first].erase(set_iter->second);
 		if (send_events)
-			Engine::instance().client_broadcaster()->send_program_remove(path(), set_iter->first, set_iter->second);
+			_engine.client_broadcaster()->send_program_remove(path(), set_iter->first, set_iter->second);
 		if (_banks[set_iter->first].size() == 0)
 			_banks.erase(set_iter->first);
 	}
-	
+#endif
+	cerr << "FIXME: DSSI programs broken!" << endl;
+
 	return true;
 }
 
diff --git a/src/libs/engine/DSSINode.h b/src/libs/engine/DSSINode.h
index 625d325c..3c8dc841 100644
--- a/src/libs/engine/DSSINode.h
+++ b/src/libs/engine/DSSINode.h
@@ -53,7 +53,7 @@ public:
 	void configure(const string& key, const string& val);
 	void program(int bank, int program);
 
-	void process(SampleCount nframes);
+	void process(SampleCount nframes, FrameTime start, FrameTime end);
 
 	bool update_programs(bool send_events);
 	void set_default_program();
diff --git a/src/libs/engine/Engine.cpp b/src/libs/engine/Engine.cpp
index 75c544ac..a98f4fbf 100644
--- a/src/libs/engine/Engine.cpp
+++ b/src/libs/engine/Engine.cpp
@@ -49,20 +49,9 @@ using std::cout; using std::cerr; using std::endl;
 namespace Ingen {
 
 
-Engine* Engine::m_instance = NULL;
-
-
-void
-Engine::instantiate(const char* port, AudioDriver* audio_driver)
-{
-	assert(!m_instance);
-	m_instance = new Engine(port, audio_driver);
-}
-
-
-Engine::Engine(const char* port, AudioDriver* audio_driver)
-: m_audio_driver( (audio_driver) ? audio_driver : new JackAudioDriver() ),
-  m_osc_receiver(new OSCReceiver(pre_processor_queue_size, port)),
+Engine::Engine(const char* listen_port, AudioDriver* audio_driver)
+: m_audio_driver( (audio_driver) ? audio_driver : new JackAudioDriver(*this) ),
+  m_osc_receiver(new OSCReceiver(*this, pre_processor_queue_size, listen_port)),
 #ifdef HAVE_JACK_MIDI
   m_midi_driver(new JackMidiDriver(((JackAudioDriver*)m_audio_driver)->jack_client())),
 #elif HAVE_ALSA_MIDI
@@ -70,8 +59,8 @@ Engine::Engine(const char* port, AudioDriver* audio_driver)
 #else
   m_midi_driver(new DummyMidiDriver()),
 #endif
-  m_post_processor(new PostProcessor(post_processor_queue_size)),
   m_maid(new Maid(maid_queue_size)),
+  m_post_processor(new PostProcessor(*m_maid, post_processor_queue_size)),
   m_client_broadcaster(new ClientBroadcaster()),
   m_object_store(new ObjectStore()),
   m_node_factory(new NodeFactory()),
@@ -155,13 +144,13 @@ Engine::activate()
 		return;
 	
 	// Create root patch
-	CreatePatchEvent create_ev(CountedPtr<Responder>(new Responder()), 0, "/", 1);
+	CreatePatchEvent create_ev(*this, CountedPtr<Responder>(new Responder()), 0, "/", 1);
 	create_ev.pre_process();
-	create_ev.execute(0);
+	create_ev.execute(1, 0, 1);
 	create_ev.post_process();
-	EnablePatchEvent enable_ev(CountedPtr<Responder>(new Responder()), 0, "/");
+	EnablePatchEvent enable_ev(*this, CountedPtr<Responder>(new Responder()), 0, "/");
 	enable_ev.pre_process();
-	enable_ev.execute(0);
+	enable_ev.execute(1, 0, 1);
 	enable_ev.post_process();
 
 	assert(m_audio_driver->root_patch() != NULL);
@@ -183,7 +172,7 @@ Engine::deactivate()
 	if (!m_activated)
 		return;
 	
-	m_audio_driver->root_patch()->process(false);
+	m_audio_driver->root_patch()->disable();
 	m_audio_driver->root_patch()->deactivate();
 
 	/*for (Tree<GraphObject*>::iterator i = m_object_store->objects().begin();
diff --git a/src/libs/engine/Engine.h b/src/libs/engine/Engine.h
index f6cfe9e9..fbad649f 100644
--- a/src/libs/engine/Engine.h
+++ b/src/libs/engine/Engine.h
@@ -39,21 +39,21 @@ class LashDriver;
 template <typename T> class Driver;
 
 
-/** The main class for Ingen, the whole engine basically lives in here
+/** The main class for the Engine.
  *
- * A singleton, but shouldn't be (FIXME).  Explicitly instantiated singleton
- * to be exact - call instantiate before instance or suffer horrible death.
+ * With access to this you can find any object that's a part of the engine.
+ * Access to this should be limited as possible, it basically exists so
+ * there's something to pass Event constructors so they can access what
+ * they need to perform their function.
  *
  * \ingroup engine
  */
 class Engine
 {
 public:
+	Engine(const char* listen_port, AudioDriver* audio_driver = 0);
 	~Engine();
 
-	static void   instantiate(const char* port, AudioDriver* audio_driver = 0);
-	static Engine& instance() { assert(m_instance); return *m_instance; }
-	
 	int main();
 	
 	/** Set the quit flag that should kill all threads and exit cleanly.
@@ -66,8 +66,8 @@ public:
 	AudioDriver*       audio_driver()       const { return m_audio_driver; }
 	OSCReceiver*       osc_receiver()       const { return m_osc_receiver; }
 	MidiDriver*        midi_driver()        const { return m_midi_driver; }
-	PostProcessor*     post_processor()     const { return m_post_processor; }
 	Maid*              maid()               const { return m_maid; }
+	PostProcessor*     post_processor()     const { return m_post_processor; }
 	ClientBroadcaster* client_broadcaster() const { return m_client_broadcaster; }
 	ObjectStore*       object_store()       const { return m_object_store; }
 	NodeFactory*       node_factory()       const { return m_node_factory; }
@@ -77,19 +77,15 @@ public:
 	template<typename T> Driver<T>* driver();
 	
 private:
-	Engine(const char* port, AudioDriver* audio_driver = 0);
-
 	// Prevent copies (undefined)
 	Engine(const Engine&);
 	Engine& operator=(const Engine&);
 
-	static Engine*      m_instance;
-
 	AudioDriver*       m_audio_driver;
 	OSCReceiver*       m_osc_receiver;
 	MidiDriver*        m_midi_driver;
-	PostProcessor*     m_post_processor;
 	Maid*              m_maid;
+	PostProcessor*     m_post_processor;
 	ClientBroadcaster* m_client_broadcaster;
 	ObjectStore*       m_object_store;
 	NodeFactory*       m_node_factory;
diff --git a/src/libs/engine/Event.h b/src/libs/engine/Event.h
index 6532655c..3ea72555 100644
--- a/src/libs/engine/Event.h
+++ b/src/libs/engine/Event.h
@@ -25,6 +25,7 @@
 
 namespace Ingen {	
 
+class Engine;
 
 
 /** Base class for all events (both realtime and QueuedEvent).
@@ -44,27 +45,34 @@ public:
 	virtual ~Event() {}
 
 	/** Execute this event in the audio thread (MUST be realtime safe). */
-	virtual void execute(SampleCount offset) { assert(!_executed); _executed = true; }
+	virtual void execute(SampleCount nframes, FrameTime start, FrameTime end)
+	{
+		assert(!_executed);
+		assert(_time >= start && _time <= end);
+		_executed = true;
+	}
 	
 	/** Perform any actions after execution (ie send replies to commands)
 	 * (no realtime requirements). */
 	virtual void post_process() {}
 	
-	inline SampleCount time_stamp() { return _time_stamp; }
+	inline SampleCount time() { return _time; }
 		
 protected:
 	// Prevent copies
 	Event(const Event&);
 	Event& operator=(const Event&);
 
-	Event(CountedPtr<Responder> responder, SampleCount timestamp)
-	: _responder(responder)
-	, _time_stamp(timestamp)
+	Event(Engine& engine, CountedPtr<Responder> responder, FrameTime time)
+	: _engine(engine)
+	, _responder(responder)
+	, _time(time)
 	, _executed(false)
 	{}
 	
+	Engine&                _engine;
 	CountedPtr<Responder>  _responder;
-	SampleCount            _time_stamp;
+	FrameTime              _time;
 	bool                   _executed;
 };
 
diff --git a/src/libs/engine/GraphObject.h b/src/libs/engine/GraphObject.h
index 1c4fae49..3b0c27b1 100644
--- a/src/libs/engine/GraphObject.h
+++ b/src/libs/engine/GraphObject.h
@@ -31,6 +31,7 @@ namespace Ingen {
 class Patch;
 class Node;
 class Port;
+class ObjectStore;
 
 
 /** An object on the audio graph - Patch, Node, Port, etc.
@@ -57,7 +58,7 @@ public:
 	inline GraphObject*  parent() const { return _parent; }
 	inline const string& name()   const { return _name; }
 	
-	virtual void process(SampleCount nframes) = 0;
+	virtual void process(SampleCount nframes, FrameTime start, FrameTime end) = 0;
 
 	/** Rename */
 	virtual void set_path(const Path& new_path) {
@@ -79,7 +80,7 @@ public:
 
 
 	/** Patch and Node override this to recursively add their children. */
-	virtual void add_to_store() = 0;
+	virtual void add_to_store(ObjectStore* store) = 0;
 	
 	/** Patch and Node override this to recursively remove their children. */
 	virtual void remove_from_store() = 0;
diff --git a/src/libs/engine/InputPort.cpp b/src/libs/engine/InputPort.cpp
index 29270bd1..830b370c 100644
--- a/src/libs/engine/InputPort.cpp
+++ b/src/libs/engine/InputPort.cpp
@@ -209,7 +209,7 @@ template void InputPort<MidiMessage>::tie(OutputPort<MidiMessage>* const port);
  */
 template<>
 void
-InputPort<Sample>::process(SampleCount nframes)
+InputPort<Sample>::process(SampleCount nframes, FrameTime start, FrameTime end)
 {
 	//assert(!m_is_tied || m_tied_port != NULL);
 
@@ -219,7 +219,7 @@ InputPort<Sample>::process(SampleCount nframes)
 	if (m_connections.size() == 0) return;
 
 	for (TypedConnectionListIterator c = m_connections.begin(); c != m_connections.end(); ++c)
-		(*c)->process(nframes);
+		(*c)->process(nframes, start, end);
 
 	// If only one connection, buffer is (maybe) used directly (no copying)
 	if (m_connections.size() == 1) {
@@ -272,7 +272,7 @@ InputPort<Sample>::process(SampleCount nframes)
  */
 template <>
 void
-InputPort<MidiMessage>::process(SampleCount nframes)
+InputPort<MidiMessage>::process(SampleCount nframes, FrameTime start, FrameTime end)
 {	
 	//assert(!m_is_tied || m_tied_port != NULL);
 	
@@ -285,7 +285,7 @@ InputPort<MidiMessage>::process(SampleCount nframes)
 	assert(_poly == 1);
 	
 	for (TypedConnectionListIterator c = m_connections.begin(); c != m_connections.end(); ++c)
-		(*c)->process(nframes);
+		(*c)->process(nframes, start, end);
 	
 
 	// If only one connection, buffer is used directly (no copying)
diff --git a/src/libs/engine/InputPort.h b/src/libs/engine/InputPort.h
index 39632cee..8360fd3e 100644
--- a/src/libs/engine/InputPort.h
+++ b/src/libs/engine/InputPort.h
@@ -55,7 +55,7 @@ public:
 
 	const List<TypedConnection<T>*>& connections() { return m_connections; }
 
-	void process(SampleCount nframes);
+	void process(SampleCount nframes, FrameTime start, FrameTime end);
 	
 	bool is_connected() const { return (m_connections.size() > 0); }
 	bool is_connected_to(const OutputPort<T>* const port) const;
diff --git a/src/libs/engine/InternalNode.h b/src/libs/engine/InternalNode.h
index 2cbbcff8..9c95aacb 100644
--- a/src/libs/engine/InternalNode.h
+++ b/src/libs/engine/InternalNode.h
@@ -44,7 +44,8 @@ public:
 
 	virtual void deactivate() { if (_is_added) remove_from_patch(); NodeBase::deactivate(); }
 	
-	virtual void process(SampleCount nframes) { NodeBase::process(nframes); }
+	virtual void process(SampleCount nframes, FrameTime start, FrameTime end)
+		{ NodeBase::process(nframes, start, end); }
 
 	virtual void add_to_patch()      { assert(!_is_added); _is_added = true; }
 	virtual void remove_from_patch() { assert(_is_added); _is_added = false; }
diff --git a/src/libs/engine/JackAudioDriver.cpp b/src/libs/engine/JackAudioDriver.cpp
index 8f5c788a..2c0d4a70 100644
--- a/src/libs/engine/JackAudioDriver.cpp
+++ b/src/libs/engine/JackAudioDriver.cpp
@@ -48,15 +48,15 @@ namespace Ingen {
 JackAudioPort::JackAudioPort(JackAudioDriver* driver, DuplexPort<Sample>* patch_port)
 : DriverPort(),
   ListNode<JackAudioPort*>(this),
-  m_driver(driver),
-  m_jack_port(NULL),
-  m_jack_buffer(NULL),
-  m_patch_port(patch_port)
+  _driver(driver),
+  _jack_port(NULL),
+  _jack_buffer(NULL),
+  _patch_port(patch_port)
 {
 	//assert(patch_port->tied_port() != NULL);
 	assert(patch_port->poly() == 1);
 
-	m_jack_port = jack_port_register(m_driver->jack_client(),
+	_jack_port = jack_port_register(_driver->jack_client(),
 		patch_port->path().c_str(), JACK_DEFAULT_AUDIO_TYPE,
 		(patch_port->is_input()) ? JackPortIsInput : JackPortIsOutput,
 		0);
@@ -67,21 +67,21 @@ JackAudioPort::JackAudioPort(JackAudioDriver* driver, DuplexPort<Sample>* patch_
 
 JackAudioPort::~JackAudioPort()
 {
-	jack_port_unregister(m_driver->jack_client(), m_jack_port);
+	jack_port_unregister(_driver->jack_client(), _jack_port);
 }
 
 
 void
 JackAudioPort::add_to_driver()
 {
-	m_driver->add_port(this);
+	_driver->add_port(this);
 }
 
 
 void
 JackAudioPort::remove_from_driver()
 {
-	m_driver->remove_port(this);
+	_driver->remove_port(this);
 }
 
 void
@@ -93,12 +93,12 @@ JackAudioPort::prepare_buffer(jack_nframes_t nframes)
 	
 	m_patch_port->buffer(0)->join(m_jack_buffer);
 */
-	jack_sample_t* jack_buf = (jack_sample_t*)jack_port_get_buffer(m_jack_port, nframes);
+	jack_sample_t* jack_buf = (jack_sample_t*)jack_port_get_buffer(_jack_port, nframes);
 
-	if (jack_buf != m_jack_buffer) {
+	if (jack_buf != _jack_buffer) {
 		//cerr << "Jack buffer: " << jack_buf << endl;
-		m_patch_port->buffer(0)->set_data(jack_buf);
-		m_jack_buffer = jack_buf;
+		_patch_port->buffer(0)->set_data(jack_buf);
+		_jack_buffer = jack_buf;
 	}
 
 	//assert(m_patch_port->tied_port() != NULL);
@@ -111,47 +111,36 @@ JackAudioPort::prepare_buffer(jack_nframes_t nframes)
 
 	//m_patch_port->fixed_buffers(true);
 	
-	//assert(m_patch_port->buffer(0)->data() == m_patch_port->tied_port()->buffer(0)->data());
-	assert(m_patch_port->buffer(0)->data() == jack_buf);
+	//assert(m_patch_port->buffer(0)->data() == _patch_port->tied_port()->buffer(0)->data());
+	assert(_patch_port->buffer(0)->data() == jack_buf);
 }
 
 	
 //// JackAudioDriver ////
 
-JackAudioDriver::JackAudioDriver()
-: m_client(NULL),
-  m_buffer_size(0),
-  m_sample_rate(0),
-  m_is_activated(false),
-  m_local_client(true),
-  m_root_patch(NULL)
+JackAudioDriver::JackAudioDriver(Engine& engine, jack_client_t* jack_client)
+: _engine(engine),
+  _client(jack_client),
+  _buffer_size(jack_client ? jack_get_buffer_size(jack_client) : 0),
+  _sample_rate(jack_client ? jack_get_sample_rate(jack_client) : 0),
+  _is_activated(false),
+  _local_client(false),
+  _root_patch(NULL)
 {
-	m_client = jack_client_new("Ingen");
-	if (m_client == NULL) {
-		cerr << "[JackAudioDriver] Unable to connect to Jack.  Exiting." << endl;
-		exit(EXIT_FAILURE);
+	if (!_client) {
+		_client = jack_client_new("Ingen");
+		if (_client == NULL) {
+			cerr << "[JackAudioDriver] Unable to connect to Jack.  Exiting." << endl;
+			exit(EXIT_FAILURE);
+		}
+		_buffer_size = jack_get_buffer_size(_client);
+		_sample_rate = jack_get_sample_rate(_client);
 	}
 
-	jack_on_shutdown(m_client, shutdown_cb, this);
-
-	m_buffer_size = jack_get_buffer_size(m_client);
-	m_sample_rate = jack_get_sample_rate(m_client);
+	jack_on_shutdown(_client, shutdown_cb, this);
 
-	jack_set_sample_rate_callback(m_client, sample_rate_cb, this);
-	jack_set_buffer_size_callback(m_client, buffer_size_cb, this);
-}
-
-JackAudioDriver::JackAudioDriver(jack_client_t* jack_client)
-: m_client(jack_client),
-  m_buffer_size(jack_get_buffer_size(jack_client)),
-  m_sample_rate(jack_get_sample_rate(jack_client)),
-  m_is_activated(false),
-  m_local_client(false)
-{
-	jack_on_shutdown(m_client, shutdown_cb, this);
-
-	jack_set_sample_rate_callback(m_client, sample_rate_cb, this);
-	jack_set_buffer_size_callback(m_client, buffer_size_cb, this);
+	jack_set_sample_rate_callback(_client, sample_rate_cb, this);
+	jack_set_buffer_size_callback(_client, buffer_size_cb, this);
 }
 
 
@@ -159,30 +148,30 @@ JackAudioDriver::~JackAudioDriver()
 {
 	deactivate();
 	
-	if (m_local_client)
-		jack_client_close(m_client);
+	if (_local_client)
+		jack_client_close(_client);
 }
 
 
 void
 JackAudioDriver::activate()
 {	
-	if (m_is_activated) {
+	if (_is_activated) {
 		cerr << "[JackAudioDriver] Jack driver already activated." << endl;
 		return;
 	}
 
-	jack_set_process_callback(m_client, process_cb, this);
+	jack_set_process_callback(_client, process_cb, this);
 
-	m_is_activated = true;
+	_is_activated = true;
 
-	if (jack_activate(m_client)) {
+	if (jack_activate(_client)) {
 		cerr << "[JackAudioDriver] Could not activate Jack client, aborting." << endl;
 		exit(EXIT_FAILURE);
 	} else {
 		cout << "[JackAudioDriver] Activated Jack client." << endl;
 #ifdef HAVE_LASH
-	Engine::instance().lash_driver()->set_jack_client_name(jack_client_get_name(m_client));
+	_engine.lash_driver()->set_jack_client_name(jack_client_get_name(_client));
 #endif
 	}
 }
@@ -191,20 +180,20 @@ JackAudioDriver::activate()
 void
 JackAudioDriver::deactivate()
 {
-	if (m_is_activated) {
-		Engine::instance().osc_receiver()->deactivate();
+	if (_is_activated) {
+		_engine.osc_receiver()->deactivate();
 	
-		jack_deactivate(m_client);
-		m_is_activated = false;
+		jack_deactivate(_client);
+		_is_activated = false;
 	
-		for (List<JackAudioPort*>::iterator i = m_ports.begin(); i != m_ports.end(); ++i)
-			jack_port_unregister(m_client, (*i)->jack_port());
+		for (List<JackAudioPort*>::iterator i = _ports.begin(); i != _ports.end(); ++i)
+			jack_port_unregister(_client, (*i)->jack_port());
 	
-		m_ports.clear();
+		_ports.clear();
 	
 		cout << "[JackAudioDriver] Deactivated Jack client." << endl;
 		
-		Engine::instance().post_processor()->stop();
+		_engine.post_processor()->stop();
 	}
 }
 
@@ -219,7 +208,7 @@ JackAudioDriver::deactivate()
 void
 JackAudioDriver::add_port(JackAudioPort* port)
 {
-	m_ports.push_back(port);
+	_ports.push_back(port);
 }
 
 
@@ -234,9 +223,9 @@ JackAudioDriver::add_port(JackAudioPort* port)
 JackAudioPort*
 JackAudioDriver::remove_port(JackAudioPort* port)
 {
-	for (List<JackAudioPort*>::iterator i = m_ports.begin(); i != m_ports.end(); ++i)
+	for (List<JackAudioPort*>::iterator i = _ports.begin(); i != _ports.end(); ++i)
 		if ((*i) == port)
-			return m_ports.remove(i)->elem();
+			return _ports.remove(i)->elem();
 	
 	cerr << "[JackAudioDriver::remove_port] WARNING: Failed to find Jack port to remove!" << endl;
 	return NULL;
@@ -246,7 +235,7 @@ JackAudioDriver::remove_port(JackAudioPort* port)
 DriverPort*
 JackAudioDriver::create_port(DuplexPort<Sample>* patch_port)
 {
-	if (patch_port->buffer_size() == m_buffer_size)
+	if (patch_port->buffer_size() == _buffer_size)
 		return new JackAudioPort(this, patch_port);
 	else
 		return NULL;
@@ -258,7 +247,7 @@ JackAudioDriver::create_port(DuplexPort<Sample>* patch_port)
  * Called from the realtime thread once every process cycle.
  */
 void
-JackAudioDriver::process_events(jack_nframes_t block_start, jack_nframes_t block_end)
+JackAudioDriver::process_events(SampleCount nframes, FrameTime cycle_start, FrameTime cycle_end)
 {
 	Event* ev = NULL;
 
@@ -266,10 +255,9 @@ JackAudioDriver::process_events(jack_nframes_t block_start, jack_nframes_t block
 	 * makes the process callback (more) realtime-safe by preventing being
 	 * choked by events coming in faster than they can be processed.
 	 * FIXME: run the math on this and figure out a good value */
-	const unsigned int MAX_QUEUED_EVENTS = m_buffer_size / 100;
+	const unsigned int MAX_QUEUED_EVENTS = _buffer_size / 100;
 
 	unsigned int num_events_processed = 0;
-	unsigned int offset = 0;
 	
 	// Process the "slow" events first, because it's possible some of the
 	// RT events depend on them
@@ -277,26 +265,21 @@ JackAudioDriver::process_events(jack_nframes_t block_start, jack_nframes_t block
 	/* FIXME: Merge these next two loops into one */
 
 	// FIXME
-	while ((ev = Engine::instance().osc_receiver()->pop_earliest_queued_before(block_end))) {
-		ev->execute(0);  // QueuedEvents are not sample accurate
-		Engine::instance().post_processor()->push(ev);
+	while ((ev = _engine.osc_receiver()->pop_earliest_queued_before(cycle_end))) {
+		ev->execute(nframes, cycle_start, cycle_end);
+		_engine.post_processor()->push(ev);
 		if (++num_events_processed > MAX_QUEUED_EVENTS)
 			break;
 	}
 	
-	while ((ev = Engine::instance().osc_receiver()->pop_earliest_stamped_before(block_end))) {
-		if (ev->time_stamp() >= block_start)
-			offset = ev->time_stamp() - block_start;
-		else
-			offset = 0;
-
-		ev->execute(offset);
-		Engine::instance().post_processor()->push(ev);
+	while ((ev = _engine.osc_receiver()->pop_earliest_stamped_before(cycle_end))) {
+		ev->execute(nframes, cycle_start, cycle_end);
+		_engine.post_processor()->push(ev);
 		++num_events_processed;
 	}
 	
 	if (num_events_processed > 0)
-		Engine::instance().post_processor()->whip();
+		_engine.post_processor()->whip();
 }
 
 
@@ -310,68 +293,70 @@ JackAudioDriver::process_events(jack_nframes_t block_start, jack_nframes_t block
  * \callgraph
  */
 int
-JackAudioDriver::m_process_cb(jack_nframes_t nframes) 
+JackAudioDriver::_process_cb(jack_nframes_t nframes) 
 {
+	// FIXME: all of this time stuff is screwy
+	
 	static jack_nframes_t start_of_current_cycle = 0;
 	static jack_nframes_t start_of_last_cycle    = 0;
 
 	// FIXME: support nframes != buffer_size, even though that never damn well happens
-	assert(nframes == m_buffer_size);
+	assert(nframes == _buffer_size);
 
 	// Jack can elect to not call this function for a cycle, if overloaded
 	// FIXME: this doesn't make sense, and the start time isn't used anyway
-	start_of_current_cycle = jack_last_frame_time(m_client);
+	start_of_current_cycle = jack_last_frame_time(_client);
 	start_of_last_cycle = start_of_current_cycle - nframes;
 
 	// FIXME: ditto
 	assert(start_of_current_cycle - start_of_last_cycle == nframes);
 
-	m_transport_state = jack_transport_query(m_client, &m_position);
+	_transport_state = jack_transport_query(_client, &_position);
 	
-	process_events(start_of_last_cycle, start_of_current_cycle);
-	Engine::instance().midi_driver()->prepare_block(start_of_last_cycle, start_of_current_cycle);
+	process_events(nframes, start_of_last_cycle, start_of_current_cycle);
+	_engine.midi_driver()->prepare_block(start_of_last_cycle, start_of_current_cycle);
 	
 	// Set buffers of patch ports to Jack port buffers (zero-copy processing)
-	for (List<JackAudioPort*>::iterator i = m_ports.begin(); i != m_ports.end(); ++i)
+	for (List<JackAudioPort*>::iterator i = _ports.begin(); i != _ports.end(); ++i)
 		(*i)->prepare_buffer(nframes);
 	
 	// Run root patch
-	assert(m_root_patch != NULL);
-	m_root_patch->process(nframes);
+	assert(_root_patch != NULL);
+	_root_patch->process(nframes, start_of_current_cycle, start_of_current_cycle + nframes);
 	
 	return 0;
 }
 
 
 void 
-JackAudioDriver::m_shutdown_cb() 
+JackAudioDriver::_shutdown_cb() 
 {
 	cout << "[JackAudioDriver] Jack shutdown.  Exiting." << endl;
-	Engine::instance().quit();
+	_engine.quit();
 }
 
 
 int
-JackAudioDriver::m_sample_rate_cb(jack_nframes_t nframes) 
+JackAudioDriver::_sample_rate_cb(jack_nframes_t nframes) 
 {
-	if (m_is_activated) {
+	if (_is_activated) {
 		cerr << "[JackAudioDriver] On-the-fly sample rate changing not supported (yet).  Aborting." << endl;
 		exit(EXIT_FAILURE);
 	} else {
-		m_sample_rate = nframes;
+		_sample_rate = nframes;
 	}
 	return 0;
 }
 
 
 int
-JackAudioDriver::m_buffer_size_cb(jack_nframes_t nframes) 
+JackAudioDriver::_buffer_size_cb(jack_nframes_t nframes) 
 {
-	if (m_is_activated) {
+	if (_is_activated) {
 		cerr << "[JackAudioDriver] On-the-fly buffer size changing not supported (yet).  Aborting." << endl;
 		exit(EXIT_FAILURE);
 	} else {
-		m_buffer_size = nframes;
+		_buffer_size = nframes;
 	}
 	return 0;
 }
diff --git a/src/libs/engine/JackAudioDriver.h b/src/libs/engine/JackAudioDriver.h
index 73b80a78..aa0cebbc 100644
--- a/src/libs/engine/JackAudioDriver.h
+++ b/src/libs/engine/JackAudioDriver.h
@@ -25,6 +25,7 @@
 
 namespace Ingen {
 
+class Engine;
 class Patch;
 class Port;
 template <typename T> class DuplexPort;
@@ -44,22 +45,22 @@ public:
 	
 	void add_to_driver();
 	void remove_from_driver();
-	void set_name(const string& name) { jack_port_set_name(m_jack_port, name.c_str()); };
+	void set_name(const string& name) { jack_port_set_name(_jack_port, name.c_str()); };
 	
 	void prepare_buffer(jack_nframes_t nframes);
 
-	jack_port_t*          jack_port() const             { return m_jack_port; }
-	DuplexPort<Sample>*   patch_port() const            { return m_patch_port; }
+	jack_port_t*          jack_port() const  { return _jack_port; }
+	DuplexPort<Sample>*   patch_port() const { return _patch_port; }
 
 private:
 	// Prevent copies (undefined)
 	JackAudioPort(const JackAudioPort&);
 	JackAudioPort& operator=(const JackAudioPort&);
 	
-	JackAudioDriver*      m_driver;
-	jack_port_t*          m_jack_port;
-	jack_sample_t*        m_jack_buffer; ///< Cached for output ports
-	DuplexPort<Sample>*   m_patch_port;
+	JackAudioDriver*      _driver;
+	jack_port_t*          _jack_port;
+	jack_sample_t*        _jack_buffer; ///< Cached for output ports
+	DuplexPort<Sample>*   _patch_port;
 };
 
 
@@ -75,8 +76,7 @@ private:
 class JackAudioDriver : public AudioDriver
 {
 public:	
-	JackAudioDriver();
-	JackAudioDriver(jack_client_t *jack_client);
+	JackAudioDriver(Engine& engine, jack_client_t *jack_client = 0);
 	~JackAudioDriver();
 
 	void activate();
@@ -84,26 +84,26 @@ public:
 	void enable();
 	void disable();
 
-	void process_events(jack_nframes_t block_start, jack_nframes_t block_end);
+	void process_events(SampleCount nframes, FrameTime cycle_start, FrameTime cycle_end);
 	
 	DriverPort* create_port(DuplexPort<Sample>* patch_port);
 	
-	Patch* root_patch()                 { return m_root_patch; }
-	void   set_root_patch(Patch* patch) { m_root_patch = patch; }
+	Patch* root_patch()                 { return _root_patch; }
+	void   set_root_patch(Patch* patch) { _root_patch = patch; }
 	
 	/** Transport state for this frame.
 	 * Intended to only be called from the audio thread. */
-	inline const jack_position_t* position() { return &m_position; }
-	inline const jack_transport_state_t transport_state() { return m_transport_state; }
+	inline const jack_position_t* position() { return &_position; }
+	inline const jack_transport_state_t transport_state() { return _transport_state; }
 	
-	bool is_realtime() { return jack_is_realtime(m_client); }
+	bool is_realtime() { return jack_is_realtime(_client); }
 	
-	jack_client_t* jack_client() const  { return m_client; }
-	SampleCount    buffer_size() const  { return m_buffer_size; }
-	SampleCount    sample_rate() const  { return m_sample_rate; }
-	bool           is_activated() const { return m_is_activated; }
+	jack_client_t* jack_client() const  { return _client; }
+	SampleCount    buffer_size() const  { return _buffer_size; }
+	SampleCount    sample_rate() const  { return _sample_rate; }
+	bool           is_activated() const { return _is_activated; }
 	
-	SampleCount time_stamp() const { return jack_frame_time(m_client); }
+	inline SampleCount frame_time() const { return jack_frame_time(_client); }
 
 private:
 	// Prevent copies (undefined)
@@ -124,45 +124,46 @@ private:
 	inline static int  sample_rate_cb(jack_nframes_t nframes, void* const jack_driver);
 
 	// Non static callbacks
-	int  m_process_cb(jack_nframes_t nframes);
-	void m_shutdown_cb();
-	int  m_buffer_size_cb(jack_nframes_t nframes);
-	int  m_sample_rate_cb(jack_nframes_t nframes);
-
-	jack_client_t*         m_client;
-	jack_nframes_t         m_buffer_size;
-	jack_nframes_t         m_sample_rate;
-	bool                   m_is_activated;
-	bool                   m_local_client; ///< Whether m_client should be closed on destruction
-	jack_position_t        m_position;
-	jack_transport_state_t m_transport_state;
+	int  _process_cb(jack_nframes_t nframes);
+	void _shutdown_cb();
+	int  _buffer_size_cb(jack_nframes_t nframes);
+	int  _sample_rate_cb(jack_nframes_t nframes);
+
+	Engine&                _engine;
+	jack_client_t*         _client;
+	jack_nframes_t         _buffer_size;
+	jack_nframes_t         _sample_rate;
+	bool                   _is_activated;
+	bool                   _local_client; ///< Whether _client should be closed on destruction
+	jack_position_t        _position;
+	jack_transport_state_t _transport_state;
 	
-	List<JackAudioPort*> m_ports;
+	List<JackAudioPort*> _ports;
 
-	Patch* m_root_patch;
+	Patch* _root_patch;
 };
 
 
 inline int JackAudioDriver::process_cb(jack_nframes_t nframes, void* jack_driver)
 {
-	return ((JackAudioDriver*)jack_driver)->m_process_cb(nframes);
+	return ((JackAudioDriver*)jack_driver)->_process_cb(nframes);
 }
 
 inline void JackAudioDriver::shutdown_cb(void* jack_driver)
 {
-	return ((JackAudioDriver*)jack_driver)->m_shutdown_cb();
+	return ((JackAudioDriver*)jack_driver)->_shutdown_cb();
 }
 
 
 inline int JackAudioDriver::buffer_size_cb(jack_nframes_t nframes, void* jack_driver)
 {
-	return ((JackAudioDriver*)jack_driver)->m_buffer_size_cb(nframes);
+	return ((JackAudioDriver*)jack_driver)->_buffer_size_cb(nframes);
 }
 
 
 inline int JackAudioDriver::sample_rate_cb(jack_nframes_t nframes, void* jack_driver)
 {
-	return ((JackAudioDriver*)jack_driver)->m_sample_rate_cb(nframes);
+	return ((JackAudioDriver*)jack_driver)->_sample_rate_cb(nframes);
 }
 	
 
diff --git a/src/libs/engine/LADSPANode.cpp b/src/libs/engine/LADSPANode.cpp
index 96be6771..b01f8900 100644
--- a/src/libs/engine/LADSPANode.cpp
+++ b/src/libs/engine/LADSPANode.cpp
@@ -168,9 +168,9 @@ LADSPANode::deactivate()
 
 
 void
-LADSPANode::process(SampleCount nframes)
+LADSPANode::process(SampleCount nframes, FrameTime start, FrameTime end)
 {
-	NodeBase::process(nframes); // mixes down input ports
+	NodeBase::process(nframes, start, end); // mixes down input ports
 	for (size_t i=0; i < _poly; ++i) 
 		_descriptor->run(_instances[i], nframes);
 }
diff --git a/src/libs/engine/LADSPANode.h b/src/libs/engine/LADSPANode.h
index 677145fe..7fc78fb6 100644
--- a/src/libs/engine/LADSPANode.h
+++ b/src/libs/engine/LADSPANode.h
@@ -41,7 +41,7 @@ public:
 	void activate();
 	void deactivate();
 	
-	void process(SampleCount nframes);
+	void process(SampleCount nframes, FrameTime start, FrameTime end);
 	
 	void set_port_buffer(size_t voice, size_t port_num, void* buf);
 
diff --git a/src/libs/engine/LV2Node.cpp b/src/libs/engine/LV2Node.cpp
index d56778c1..40270409 100644
--- a/src/libs/engine/LV2Node.cpp
+++ b/src/libs/engine/LV2Node.cpp
@@ -164,9 +164,9 @@ LV2Node::deactivate()
 
 
 void
-LV2Node::process(SampleCount nframes)
+LV2Node::process(SampleCount nframes, FrameTime start, FrameTime end)
 {
-	NodeBase::process(nframes); // mixes down input ports
+	NodeBase::process(nframes, start, end); // mixes down input ports
 	for (size_t i=0; i < _poly; ++i) 
 		slv2_instance_run(_instances[i], nframes);
 }
diff --git a/src/libs/engine/LV2Node.h b/src/libs/engine/LV2Node.h
index 1c2c8416..224024a3 100644
--- a/src/libs/engine/LV2Node.h
+++ b/src/libs/engine/LV2Node.h
@@ -47,7 +47,7 @@ public:
 	void activate();
 	void deactivate();
 	
-	void process(SampleCount nframes);
+	void process(SampleCount nframes, FrameTime start, FrameTime end);
 	
 	void set_port_buffer(size_t voice, size_t port_num, void* buf);
 
diff --git a/src/libs/engine/MidiControlNode.cpp b/src/libs/engine/MidiControlNode.cpp
index 32f14dc2..b469f590 100644
--- a/src/libs/engine/MidiControlNode.cpp
+++ b/src/libs/engine/MidiControlNode.cpp
@@ -16,7 +16,6 @@
 
 #include "MidiControlNode.h"
 #include <math.h>
-#include "Engine.h"
 #include "PostProcessor.h"
 #include "MidiLearnEvent.h"
 #include "InputPort.h"
@@ -63,9 +62,9 @@ MidiControlNode::MidiControlNode(const string& path, size_t poly, Patch* parent,
 
 
 void
-MidiControlNode::process(SampleCount nframes)
+MidiControlNode::process(SampleCount nframes, FrameTime start, FrameTime end)
 {
-	InternalNode::process(nframes);
+	InternalNode::process(nframes, start, end);
 
 	MidiMessage ev;
 	
@@ -88,15 +87,18 @@ MidiControlNode::control(uchar control_num, uchar val, SampleCount offset)
 	const Sample nval = (val / 127.0f); // normalized [0, 1]
 	
 	if (_learning) {
+		assert(false); // FIXME FIXME FIXME
+#if 0
 		assert(_learn_event != NULL);
 		_param_port->set_value(control_num, offset);
 		assert(_param_port->buffer(0)->value_at(0) == control_num);
 		_learn_event->set_value(control_num);
 		_learn_event->execute(offset);
-		Engine::instance().post_processor()->push(_learn_event);
-		Engine::instance().post_processor()->whip();
+		//Engine::instance().post_processor()->push(_learn_event);
+		//Engine::instance().post_processor()->whip();
 		_learning = false;
 		_learn_event = NULL;
+#endif
 	}
 
 	if (_log_port->buffer(0)->value_at(0) > 0.0f) {
diff --git a/src/libs/engine/MidiControlNode.h b/src/libs/engine/MidiControlNode.h
index 952aa0c4..b291fe9c 100644
--- a/src/libs/engine/MidiControlNode.h
+++ b/src/libs/engine/MidiControlNode.h
@@ -42,7 +42,7 @@ class MidiControlNode : public InternalNode
 public:
 	MidiControlNode(const string& path, size_t poly, Patch* parent, SampleRate srate, size_t buffer_size);
 	
-	void process(SampleCount nframes);
+	void process(SampleCount nframes, FrameTime start, FrameTime end);
 	
 	void control(uchar control_num, uchar val, SampleCount offset);
 
diff --git a/src/libs/engine/MidiNoteNode.cpp b/src/libs/engine/MidiNoteNode.cpp
index 5d08c495..956c1494 100644
--- a/src/libs/engine/MidiNoteNode.cpp
+++ b/src/libs/engine/MidiNoteNode.cpp
@@ -17,7 +17,6 @@
 #include "MidiNoteNode.h"
 #include <cmath>
 #include <iostream>
-#include "Engine.h"
 #include "MidiMessage.h"
 #include "InputPort.h"
 #include "OutputPort.h"
@@ -72,9 +71,9 @@ MidiNoteNode::~MidiNoteNode()
 
 
 void
-MidiNoteNode::process(SampleCount nframes)
+MidiNoteNode::process(SampleCount nframes, FrameTime start, FrameTime end)
 {
-	InternalNode::process(nframes);
+	InternalNode::process(nframes, start, end);
 	
 	MidiMessage ev;
 	
@@ -84,24 +83,24 @@ MidiNoteNode::process(SampleCount nframes)
 		switch (ev.buffer[0] & 0xF0) {
 		case MIDI_CMD_NOTE_ON:
 			if (ev.buffer[2] == 0)
-				note_off(ev.buffer[1], ev.time);
+				note_off(ev.buffer[1], ev.time, nframes, start, end);
 			else
-				note_on(ev.buffer[1], ev.buffer[2], ev.time);
+				note_on(ev.buffer[1], ev.buffer[2], ev.time, nframes, start, end);
 			break;
 		case MIDI_CMD_NOTE_OFF:
-			note_off(ev.buffer[1], ev.time);
+			note_off(ev.buffer[1], ev.time, nframes, start, end);
 			break;
 		case MIDI_CMD_CONTROL:
 			switch (ev.buffer[1]) {
 			case MIDI_CTL_ALL_NOTES_OFF:
 			case MIDI_CTL_ALL_SOUNDS_OFF:
-				all_notes_off(ev.time);
+				all_notes_off(ev.time, nframes, start, end);
 				break;
 			case MIDI_CTL_SUSTAIN:
 				if (ev.buffer[2] > 63)
-					sustain_on();
+					sustain_on(ev.time, nframes, start, end);
 				else
-					sustain_off(ev.time);
+					sustain_off(ev.time, nframes, start, end);
 				break;
 			case MIDI_CMD_BENDER:
 
@@ -115,12 +114,10 @@ MidiNoteNode::process(SampleCount nframes)
 
 
 void
-MidiNoteNode::note_on(uchar note_num, uchar velocity, SampleCount offset)
+MidiNoteNode::note_on(uchar note_num, uchar velocity, SampleCount nframes, FrameTime time, FrameTime start, FrameTime end)
 {
-	// FIXME: this is stupid..
-	const jack_nframes_t time_stamp = Engine::instance().audio_driver()->time_stamp();
-
-	assert(offset < _buffer_size);
+	assert(time >= start && time <= end);
+	assert(time - start < _buffer_size);
 	assert(note_num <= 127);
 
 	Key*   key        = &_keys[note_num];
@@ -165,16 +162,20 @@ MidiNoteNode::note_on(uchar note_num, uchar velocity, SampleCount offset)
 	// Store key information for later reallocation on note off
 	key->state = Key::Key::ON_ASSIGNED;
 	key->voice = voice_num;
-	key->time  = time_stamp;
+	key->time  = time;
 
 	// Trigger voice
 	voice->state = Voice::Voice::ACTIVE;
 	voice->note  = note_num;
-	voice->time  = time_stamp;
+	voice->time  = time;
 	
 	assert(_keys[voice->note].state == Key::Key::ON_ASSIGNED);
 	assert(_keys[voice->note].voice == voice_num);
 	
+	// FIXME FIXME FIXME
+	
+	SampleCount offset = time - start;
+
 	// one-sample jitter hack to avoid having to deal with trigger sample "next time"
 	if (offset == (SampleCount)(_buffer_size-1))
 		--offset;
@@ -195,9 +196,10 @@ MidiNoteNode::note_on(uchar note_num, uchar velocity, SampleCount offset)
 
 
 void
-MidiNoteNode::note_off(uchar note_num, SampleCount offset)
+MidiNoteNode::note_off(uchar note_num, FrameTime time, SampleCount nframes, FrameTime start, FrameTime end)
 {
-	assert(offset < _buffer_size);
+	assert(time >= start && time <= end);
+	assert(time - start < _buffer_size);
 
 	Key* key = &_keys[note_num];
 
@@ -208,7 +210,7 @@ MidiNoteNode::note_off(uchar note_num, SampleCount offset)
 		key->state = Key::OFF;
 
 		if ( ! _sustain)
-			free_voice(key->voice, offset);
+			free_voice(key->voice, time - start, nframes, start, end);
 		else
 			_voices[key->voice].state = Voice::HOLDING;
 	}
@@ -218,8 +220,11 @@ MidiNoteNode::note_off(uchar note_num, SampleCount offset)
 
 	
 void
-MidiNoteNode::free_voice(size_t voice, SampleCount offset)
+MidiNoteNode::free_voice(size_t voice, FrameTime time, SampleCount nframes, FrameTime start, FrameTime end)
 {
+	assert(time >= start && time <= end);
+	assert(time - start < _buffer_size);
+
 	// Find a key to reassign to the freed voice (the newest, if there is one)
 	Key*  replace_key     = NULL;
 	uchar replace_key_num = 0;
@@ -238,7 +243,7 @@ MidiNoteNode::free_voice(size_t voice, SampleCount offset)
 		assert(replace_key->state == Key::ON_UNASSIGNED);
 		
 		// Change the freq but leave the gate high and don't retrigger
-		_freq_port->buffer(voice)->set(note_to_freq(replace_key_num), offset);
+		_freq_port->buffer(voice)->set(note_to_freq(replace_key_num), time - start);
 
 		replace_key->state = Key::ON_ASSIGNED;
 		replace_key->voice = voice;
@@ -248,22 +253,24 @@ MidiNoteNode::free_voice(size_t voice, SampleCount offset)
 	} else {
 		// No new note for voice, deactivate (set gate low)
 		//cerr << "[MidiNoteNode] Note off. Key " << (int)note_num << ", Voice " << voice << " Killed" << endl;
-		_gate_port->buffer(voice)->set(0.0f, offset);
+		_gate_port->buffer(voice)->set(0.0f, time - start);
 		_voices[voice].state = Voice::FREE;
 	}
 }
 
 
 void
-MidiNoteNode::all_notes_off(SampleCount offset)
+MidiNoteNode::all_notes_off(SampleCount nframes, FrameTime time, FrameTime start, FrameTime end)
 {
+	assert(time >= start && time <= end);
+	assert(time - start < _buffer_size);
+
 	//cerr << "Note off starting at sample " << offset << endl;
-	assert(offset < _buffer_size);
 
 	// FIXME: set all keys to Key::OFF?
 	
 	for (size_t i=0; i < _poly; ++i) {
-		_gate_port->buffer(i)->set(0.0f, offset);
+		_gate_port->buffer(i)->set(0.0f, time - start);
 		_voices[i].state = Voice::FREE;
 	}
 }
@@ -280,20 +287,23 @@ MidiNoteNode::note_to_freq(int num)
 
 
 void
-MidiNoteNode::sustain_on()
+MidiNoteNode::sustain_on(FrameTime time, SampleCount nframes, FrameTime start, FrameTime end)
 {
 	_sustain = true;
 }
 
 
 void
-MidiNoteNode::sustain_off(SampleCount offset)
+MidiNoteNode::sustain_off(FrameTime time, SampleCount nframes, FrameTime start, FrameTime end)
 {
+	assert(time >= start && time <= end);
+	assert(time - start < _buffer_size);
+
 	_sustain = false;
 	
 	for (size_t i=0; i < _poly; ++i)
 		if (_voices[i].state == Voice::HOLDING)
-			free_voice(i, offset);
+			free_voice(i, time, nframes, start, end);
 }
 
 
diff --git a/src/libs/engine/MidiNoteNode.h b/src/libs/engine/MidiNoteNode.h
index 1f727b98..ba86455d 100644
--- a/src/libs/engine/MidiNoteNode.h
+++ b/src/libs/engine/MidiNoteNode.h
@@ -42,17 +42,16 @@ public:
 	MidiNoteNode(const string& path, size_t poly, Patch* parent, SampleRate srate, size_t buffer_size);
 	~MidiNoteNode();
 
-	void process(SampleCount nframes);
+	void process(SampleCount nframes, FrameTime start, FrameTime end);
 	
-	void note_on(uchar note_num, uchar velocity, SampleCount offset);
-	void note_off(uchar note_num, SampleCount offset);
-	void all_notes_off(SampleCount offset);
+	void note_on(uchar note_num, uchar velocity, SampleCount nframes, FrameTime time, FrameTime start, FrameTime end);
+	void note_off(uchar note_num, FrameTime time, SampleCount nframes, FrameTime start, FrameTime end);
+	void all_notes_off(SampleCount nframes, FrameTime time, FrameTime start, FrameTime end);
 
-	void sustain_on();
-	void sustain_off(SampleCount offset);
+	void sustain_on(FrameTime time, SampleCount nframes, FrameTime start, FrameTime end);
+	void sustain_off(FrameTime time, SampleCount nframes, FrameTime start, FrameTime end);
 
 private:
-	
 	/** Key, one for each key on the keyboard */
 	struct Key {
 		enum State { OFF, ON_ASSIGNED, ON_UNASSIGNED };
@@ -68,7 +67,7 @@ private:
 	};
 
 	float note_to_freq(int num);
-	void free_voice(size_t voice, SampleCount offset);
+	void free_voice(size_t voice, FrameTime time, SampleCount nframes, FrameTime start, FrameTime end);
 
 	Voice* _voices;
 	Key    _keys[128];
diff --git a/src/libs/engine/MidiTriggerNode.cpp b/src/libs/engine/MidiTriggerNode.cpp
index c117a70c..b4b5cd8b 100644
--- a/src/libs/engine/MidiTriggerNode.cpp
+++ b/src/libs/engine/MidiTriggerNode.cpp
@@ -56,9 +56,9 @@ MidiTriggerNode::MidiTriggerNode(const string& path, size_t poly, Patch* parent,
 
 
 void
-MidiTriggerNode::process(SampleCount nframes)
+MidiTriggerNode::process(SampleCount nframes, FrameTime start, FrameTime end)
 {
-	InternalNode::process(nframes);
+	InternalNode::process(nframes, start, end);
 	
 	MidiMessage ev;
 	
@@ -68,12 +68,12 @@ MidiTriggerNode::process(SampleCount nframes)
 		switch (ev.buffer[0] & 0xF0) {
 		case MIDI_CMD_NOTE_ON:
 			if (ev.buffer[2] == 0)
-				note_off(ev.buffer[1], ev.time);
+				note_off(ev.buffer[1], ev.time, nframes, start, end);
 			else
-				note_on(ev.buffer[1], ev.buffer[2], ev.time);
+				note_on(ev.buffer[1], ev.buffer[2], ev.time, nframes, start, end);
 			break;
 		case MIDI_CMD_NOTE_OFF:
-			note_off(ev.buffer[1], ev.time);
+			note_off(ev.buffer[1], ev.time, nframes, start, end);
 			break;
 		case MIDI_CMD_CONTROL:
 			if (ev.buffer[1] == MIDI_CTL_ALL_NOTES_OFF
@@ -87,14 +87,19 @@ MidiTriggerNode::process(SampleCount nframes)
 
 
 void
-MidiTriggerNode::note_on(uchar note_num, uchar velocity, SampleCount offset)
+MidiTriggerNode::note_on(uchar note_num, uchar velocity, FrameTime time, SampleCount nframes, FrameTime start, FrameTime end)
 {
+	assert(time >= start && time <= end);
+	assert(time - start < _buffer_size);
+
 	//std::cerr << "Note on starting at sample " << offset << std::endl;
-	assert(offset < _buffer_size);
 
 	const Sample filter_note = _note_port->buffer(0)->value_at(0);
 	if (filter_note >= 0.0 && filter_note < 127.0 && (note_num == (uchar)filter_note)){
-				
+			
+		// FIXME FIXME FIXME
+		SampleCount offset = time - start;
+
 		// See comments in MidiNoteNode::note_on (FIXME)
 		if (offset == (SampleCount)(_buffer_size-1))
 			--offset;
@@ -108,12 +113,13 @@ MidiTriggerNode::note_on(uchar note_num, uchar velocity, SampleCount offset)
 
 
 void
-MidiTriggerNode::note_off(uchar note_num, SampleCount offset)
+MidiTriggerNode::note_off(uchar note_num, FrameTime time, SampleCount nframes, FrameTime start, FrameTime end)
 {
-	assert(offset < _buffer_size);
+	assert(time >= start && time <= end);
+	assert(time - start < _buffer_size);
 
 	if (note_num == lrintf(_note_port->buffer(0)->value_at(0)))
-		_gate_port->buffer(0)->set(0.0f, offset);
+		_gate_port->buffer(0)->set(0.0f, time - start);
 }
 
 
diff --git a/src/libs/engine/MidiTriggerNode.h b/src/libs/engine/MidiTriggerNode.h
index bf11f0b8..e45e6d9e 100644
--- a/src/libs/engine/MidiTriggerNode.h
+++ b/src/libs/engine/MidiTriggerNode.h
@@ -45,10 +45,10 @@ class MidiTriggerNode : public InternalNode
 public:
 	MidiTriggerNode(const string& path, size_t poly, Patch* parent, SampleRate srate, size_t buffer_size);
 
-	void process(SampleCount nframes);
+	void process(SampleCount nframes, FrameTime start, FrameTime end);
 	
-	void note_on(uchar note_num, uchar velocity, SampleCount offset);
-	void note_off(uchar note_num, SampleCount offset);
+	void note_on(uchar note_num, uchar velocity, FrameTime time, SampleCount nframes, FrameTime start, FrameTime end);
+	void note_off(uchar note_num, FrameTime time, SampleCount nframes, FrameTime start, FrameTime end);
 
 private:
 	InputPort<MidiMessage>* _midi_in_port;
diff --git a/src/libs/engine/Node.h b/src/libs/engine/Node.h
index 6d1158b0..beabb7da 100644
--- a/src/libs/engine/Node.h
+++ b/src/libs/engine/Node.h
@@ -63,6 +63,13 @@ public:
 	virtual void activate()   = 0;
 	virtual void deactivate() = 0;
 	virtual bool activated()  = 0;
+	
+	/** Run the node for @a nframes input/output.
+	 *
+	 * @a start and @a end are transport times: end is not redundant in the case
+	 * of varispeed, where end-start != nframes.
+	 */
+	virtual void process(SampleCount nframes, FrameTime start, FrameTime end) = 0;
 
 	virtual void set_port_buffer(size_t voice, size_t port_num, void* buf) = 0;
 
@@ -91,7 +98,7 @@ public:
 	/** The Patch this Node belongs to. */
 	virtual Patch* parent_patch() const = 0;
 
-	/** Information about what 'plugin' this Node is an instance of.
+	/** Information about the Plugin this Node is an instance of.
 	 * Not the best name - not all nodes come from plugins (ie Patch)
 	 */
 	virtual const Plugin* plugin() const = 0;
diff --git a/src/libs/engine/NodeBase.cpp b/src/libs/engine/NodeBase.cpp
index 80ceb6ef..2532064e 100644
--- a/src/libs/engine/NodeBase.cpp
+++ b/src/libs/engine/NodeBase.cpp
@@ -19,7 +19,6 @@
 #include <iostream>
 #include <stdint.h>
 #include "util.h"
-#include "Engine.h"
 #include "Array.h"
 #include "Plugin.h"
 #include "ClientBroadcaster.h"
@@ -35,6 +34,7 @@ namespace Ingen {
 
 NodeBase::NodeBase(const Plugin* plugin, const string& name, size_t poly, Patch* parent, SampleRate srate, size_t buffer_size)
 : Node(parent, name),
+  _store(NULL),
   _plugin(plugin),
   _poly(poly),
   _srate(srate),
@@ -84,16 +84,21 @@ void
 NodeBase::send_creation_messages(ClientInterface* client) const
 {
 	cerr << "FIXME: send_creation\n";
-	//Engine::instance().client_broadcaster()->send_node_to(client, this);
+	//_engine.client_broadcaster()->send_node_to(client, this);
 }
 */
 
 void
-NodeBase::add_to_store()
+NodeBase::add_to_store(ObjectStore* store)
 {
-	Engine::instance().object_store()->add(this);
+	assert(!_store);
+
+	store->add(this);
+	
 	for (size_t i=0; i < num_ports(); ++i)
-		Engine::instance().object_store()->add(_ports->at(i));
+		store->add(_ports->at(i));
+
+	_store = store;
 }
 
 
@@ -101,32 +106,34 @@ void
 NodeBase::remove_from_store()
 {
 	// Remove self
-	TreeNode<GraphObject*>* node = Engine::instance().object_store()->remove(path());
+	TreeNode<GraphObject*>* node = _store->remove(path());
 	if (node != NULL) {
-		assert(Engine::instance().object_store()->find(path()) == NULL);
+		assert(_store->find(path()) == NULL);
 		delete node;
 	}
 	
 	// Remove ports
 	for (size_t i=0; i < num_ports(); ++i) {
-		node = Engine::instance().object_store()->remove(_ports->at(i)->path());
+		node = _store->remove(_ports->at(i)->path());
 		if (node != NULL) {
-			assert(Engine::instance().object_store()->find(_ports->at(i)->path()) == NULL);
+			assert(_store->find(_ports->at(i)->path()) == NULL);
 			delete node;
 		}
 	}
+
+	_store = NULL;
 }
 
 
 /** Runs the Node for the specified number of frames (block size)
  */
 void
-NodeBase::process(SampleCount nframes)
+NodeBase::process(SampleCount nframes, FrameTime start, FrameTime end)
 {
 	assert(_activated);
 	// Mix down any ports with multiple inputs
 	for (size_t i=0; i < _ports->size(); ++i)
-		_ports->at(i)->process(nframes);
+		_ports->at(i)->process(nframes, start, end);
 }
 
 
@@ -145,23 +152,23 @@ NodeBase::set_path(const Path& new_path)
 	
 	// Reinsert ports
 	for (size_t i=0; i < num_ports(); ++i) {
-		treenode = Engine::instance().object_store()->remove(old_path +"/"+ _ports->at(i)->name());
+		treenode = _store->remove(old_path +"/"+ _ports->at(i)->name());
 		assert(treenode != NULL);
 		assert(treenode->node() == _ports->at(i));
 		treenode->key(new_path +"/" + _ports->at(i)->name());
-		Engine::instance().object_store()->add(treenode);
+		_store->add(treenode);
 	}
 	
 	// Rename and reinsert self
-	treenode = Engine::instance().object_store()->remove(old_path);
+	treenode = _store->remove(old_path);
 	assert(treenode != NULL);
 	assert(treenode->node() == this);
 	GraphObject::set_path(new_path);
 	treenode->key(new_path);
-	Engine::instance().object_store()->add(treenode);
+	_store->add(treenode);
 	
 
-	assert(Engine::instance().object_store()->find(new_path) == this);
+	assert(_store->find(new_path) == this);
 }
 
 
diff --git a/src/libs/engine/NodeBase.h b/src/libs/engine/NodeBase.h
index df9c6e7c..78a8cab5 100644
--- a/src/libs/engine/NodeBase.h
+++ b/src/libs/engine/NodeBase.h
@@ -28,6 +28,8 @@ namespace Ingen {
 
 class Plugin;
 class Patch;
+class ObjectStore;
+
 namespace Shared {
 	class ClientInterface;
 } using Shared::ClientInterface;
@@ -50,14 +52,14 @@ public:
 	virtual void deactivate();
 	bool activated() { return _activated; }
 
-	virtual void process(SampleCount nframes);
+	virtual void process(SampleCount nframes, FrameTime start, FrameTime end);
 		
 	virtual void set_port_buffer(size_t voice, size_t port_num, void* buf) {}
 	
 	virtual void add_to_patch() {}
 	virtual void remove_from_patch() {}
 	
-	void add_to_store();
+	void add_to_store(ObjectStore* store);
 	void remove_from_store();
 	
 	//void send_creation_messages(ClientInterface* client) const;
@@ -89,6 +91,8 @@ protected:
 	NodeBase(const NodeBase&);
 	NodeBase& operator=(const NodeBase&);
 	
+	ObjectStore* _store;
+
 	const Plugin* _plugin;
 
 	size_t      _poly;
diff --git a/src/libs/engine/NodeFactory.cpp b/src/libs/engine/NodeFactory.cpp
index 65829d97..7bac3bd8 100644
--- a/src/libs/engine/NodeFactory.cpp
+++ b/src/libs/engine/NodeFactory.cpp
@@ -56,8 +56,6 @@ namespace Ingen {
 NodeFactory::NodeFactory()
 : _has_loaded(false)
 {
-	pthread_mutex_init(&_plugin_list_mutex, NULL);
-	
 	// Add builtin plugin types to _internal_plugins list
 	// FIXME: ewwww, definitely a better way to do this!
 
@@ -101,8 +99,6 @@ NodeFactory::load_plugins()
 	// this (expensive!) stuff to happen.  Not the best solution - would be nice
 	// if clients could refresh plugins list for whatever reason :/
 	if (!_has_loaded) {
-		pthread_mutex_lock(&_plugin_list_mutex);
-		
 		_plugins.clear();
 		_plugins = _internal_plugins;
 	
@@ -117,8 +113,6 @@ NodeFactory::load_plugins()
 #endif
 		
 		_has_loaded = true;
-		
-		pthread_mutex_unlock(&_plugin_list_mutex);
 	}
 }
 
@@ -137,8 +131,6 @@ NodeFactory::load_plugin(const Plugin* a_plugin,
 	assert(poly == 1 || poly == parent->internal_poly());
 	assert(a_plugin);
 
-	pthread_mutex_lock(&_plugin_list_mutex);
-	
 	Node* r = NULL;
 	Plugin* plugin = NULL;
 
@@ -201,8 +193,6 @@ NodeFactory::load_plugin(const Plugin* a_plugin,
 		cerr << "[NodeFactory] WARNING: Unknown plugin type." << endl;
 	}
 
-	pthread_mutex_unlock(&_plugin_list_mutex);
-
 	return r;
 }
 
diff --git a/src/libs/engine/NodeFactory.h b/src/libs/engine/NodeFactory.h
index cf2fb0d0..25408b2d 100644
--- a/src/libs/engine/NodeFactory.h
+++ b/src/libs/engine/NodeFactory.h
@@ -56,9 +56,6 @@ public:
 	
 	const list<Plugin*>& plugins() { return _plugins; }
 	
-	void lock_plugin_list()   { pthread_mutex_lock(&_plugin_list_mutex); }
-	void unlock_plugin_list() { pthread_mutex_unlock(&_plugin_list_mutex); }
-	
 private:
 #ifdef HAVE_LADSPA
 	void load_ladspa_plugins();
@@ -81,9 +78,6 @@ private:
 	list<Plugin*>        _internal_plugins;
 	list<Plugin*>        _plugins;
 
-	/** Used to protect the list while load_plugins is building it. */
-	pthread_mutex_t _plugin_list_mutex;
-
 	bool _has_loaded;
 };
 
diff --git a/src/libs/engine/OSCReceiver.cpp b/src/libs/engine/OSCReceiver.cpp
index 3b2e0be6..5c08c17a 100644
--- a/src/libs/engine/OSCReceiver.cpp
+++ b/src/libs/engine/OSCReceiver.cpp
@@ -47,8 +47,8 @@ using Shared::ClientKey;
  */
 
 
-OSCReceiver::OSCReceiver(size_t queue_size, const char* const port)
-: QueuedEngineInterface(queue_size, queue_size), // FIXME
+OSCReceiver::OSCReceiver(Engine& engine, size_t queue_size, const char* const port)
+: QueuedEngineInterface(engine, queue_size, queue_size), // FIXME
   _port(port),
   _server(NULL),
   _osc_responder(NULL)
diff --git a/src/libs/engine/OSCReceiver.h b/src/libs/engine/OSCReceiver.h
index d217319a..671944fd 100644
--- a/src/libs/engine/OSCReceiver.h
+++ b/src/libs/engine/OSCReceiver.h
@@ -59,7 +59,7 @@ inline static int name##_cb(LO_HANDLER_ARGS, void* osc_receiver)\
 class OSCReceiver : public QueuedEngineInterface
 {
 public:
-	OSCReceiver(size_t queue_size, const char* const port);
+	OSCReceiver(Engine& engine, size_t queue_size, const char* const port);
 	~OSCReceiver();
 
 	void activate();
diff --git a/src/libs/engine/OSCResponder.cpp b/src/libs/engine/OSCResponder.cpp
index 2fd68540..d67342d6 100644
--- a/src/libs/engine/OSCResponder.cpp
+++ b/src/libs/engine/OSCResponder.cpp
@@ -15,7 +15,6 @@
  */
 
 #include "OSCResponder.h"
-#include "Engine.h"
 #include "ClientBroadcaster.h"
 #include "interface/ClientKey.h"
 #include <cstdlib>
@@ -51,13 +50,6 @@ OSCResponder::~OSCResponder()
 }
 
 
-CountedPtr<Shared::ClientInterface>
-OSCResponder::find_client()
-{
-	return Engine::instance().client_broadcaster()->client(ClientKey(ClientKey::OSC_URL, _url));
-}
-
-
 void
 OSCResponder::respond_ok()
 {
diff --git a/src/libs/engine/OSCResponder.h b/src/libs/engine/OSCResponder.h
index 57e61886..78b40894 100644
--- a/src/libs/engine/OSCResponder.h
+++ b/src/libs/engine/OSCResponder.h
@@ -41,13 +41,13 @@ public:
 	OSCResponder(int32_t id, char* url);
 	~OSCResponder();
 	
-	CountedPtr<Shared::ClientInterface> find_client();
-	
 	void respond_ok();
 	void respond_error(const string& msg);
 
 	const char* url() const { return _url; }
 
+	ClientKey client_key() { return ClientKey(ClientKey::OSC_URL, _url); }
+
 private:
 	int32_t     _id;
 	char* const _url;
diff --git a/src/libs/engine/ObjectSender.cpp b/src/libs/engine/ObjectSender.cpp
index 3055217c..063a2d1d 100644
--- a/src/libs/engine/ObjectSender.cpp
+++ b/src/libs/engine/ObjectSender.cpp
@@ -16,7 +16,6 @@
 
 #include "ObjectSender.h"
 #include "interface/ClientInterface.h"
-#include "Engine.h"
 #include "ObjectStore.h"
 #include "Patch.h"
 #include "Node.h"
@@ -27,22 +26,6 @@
 
 namespace Ingen {
 
-/** Send all currently existing objects to client.
- */
-void
-ObjectSender::send_all(ClientInterface* client)
-{
-	Patch* root = Engine::instance().object_store()->find_patch("/");
-	assert(root);
-	send_patch(client, root);
-	/*for (Tree<GraphObject*>::iterator i = Engine::instance().object_store()->objects().begin();
-			i != Engine::instance().object_store()->objects().end(); ++i)
-		if ((*i)->as_patch() != NULL && (*i)->parent() == NULL)
-			send_patch(client, (*i)->as_patch());*/
-			//(*i)->as_node()->send_creation_messages(client);
-
-}
-
 
 void
 ObjectSender::send_patch(ClientInterface* client, const Patch* patch)
@@ -85,7 +68,7 @@ ObjectSender::send_patch(ClientInterface* client, const Patch* patch)
 	for (map<string, string>::const_iterator j = data.begin(); j != data.end(); ++j)
 		client->metadata_update(patch->path(), (*j).first, (*j).second);
 	
-	if (patch->process())
+	if (patch->enabled())
 		client->patch_enabled(patch->path());
 }
 
@@ -173,12 +156,8 @@ ObjectSender::send_port(ClientInterface* client, const Port* port)
 
 
 void
-ObjectSender::send_plugins(ClientInterface* client)
+ObjectSender::send_plugins(ClientInterface* client, const list<Plugin*>& plugs)
 {
-	Engine::instance().node_factory()->lock_plugin_list();
-	
-	const list<Plugin*>& plugs = Engine::instance().node_factory()->plugins();
-
 /*
 	lo_timetag tt;
 	lo_timetag_now(&tt);
@@ -221,7 +200,6 @@ ObjectSender::send_plugins(ClientInterface* client)
 	for (list<lo_bundle>::const_iterator i = msgs.begin(); i != msgs.end(); ++i)
 		lo_message_free(*i);
 */
-	Engine::instance().node_factory()->unlock_plugin_list();
 }
 
 
diff --git a/src/libs/engine/ObjectSender.h b/src/libs/engine/ObjectSender.h
index 93cdf2b9..38b1577f 100644
--- a/src/libs/engine/ObjectSender.h
+++ b/src/libs/engine/ObjectSender.h
@@ -17,6 +17,8 @@
 #ifndef OBJECTSENDER_H
 #define OBJECTSENDER_H
 
+#include <list>
+
 namespace Ingen {
 
 namespace Shared {
@@ -26,6 +28,7 @@ namespace Shared {
 class Patch;
 class Node;
 class Port;
+class Plugin;
 
 
 /** Utility class for sending GraphObjects to clients through ClientInterface.
@@ -42,11 +45,10 @@ public:
 	
 	// FIXME: Make all object parameters const
 	
-	static void send_all(ClientInterface* client);
 	static void send_patch(ClientInterface* client, const Patch* patch);
 	static void send_node(ClientInterface* client, const Node* node);
 	static void send_port(ClientInterface* client, const Port* port);
-	static void send_plugins(ClientInterface* client);
+	static void send_plugins(ClientInterface* client, const std::list<Plugin*>& plugs);
 };
 
 } // namespace Ingen
diff --git a/src/libs/engine/Patch.cpp b/src/libs/engine/Patch.cpp
index c8c3dd3a..257deb59 100644
--- a/src/libs/engine/Patch.cpp
+++ b/src/libs/engine/Patch.cpp
@@ -94,18 +94,17 @@ Patch::deactivate()
 
 
 void
-Patch::process(bool p)
+Patch::disable()
 {
-	if (!p) {
-		// Write output buffers to 0
-		/*for (List<InternalNode*>::iterator i = _bridge_nodes.begin(); i != _bridge_nodes.end(); ++i) {
-			assert((*i)->as_port() != NULL);
-			if ((*i)->as_port()->port_info()->is_output())
-				(*i)->as_port()->clear_buffers();*/
-		for (List<Port*>::iterator i = _output_ports.begin(); i != _output_ports.end(); ++i)
-			(*i)->clear_buffers();
-	}
-	_process = p;
+	// Write output buffers to 0
+	/*for (List<InternalNode*>::iterator i = _bridge_nodes.begin(); i != _bridge_nodes.end(); ++i) {
+	  assert((*i)->as_port() != NULL);
+	  if ((*i)->as_port()->port_info()->is_output())
+	  (*i)->as_port()->clear_buffers();*/
+	for (List<Port*>::iterator i = _output_ports.begin(); i != _output_ports.end(); ++i)
+		(*i)->clear_buffers();
+
+	_process = false;
 }
 
 
@@ -114,7 +113,7 @@ Patch::process(bool p)
  * Calls all Nodes in the order _process_order specifies.
  */
 void
-Patch::process(SampleCount nframes)
+Patch::process(SampleCount nframes, FrameTime start, FrameTime end)
 {
 	if (_process_order == NULL || !_process)
 		return;
@@ -123,31 +122,31 @@ Patch::process(SampleCount nframes)
 	
 	// Prepare input ports for nodes to consume
 	for (List<Port*>::iterator i = _input_ports.begin(); i != _input_ports.end(); ++i)
-		(*i)->process(nframes);
+		(*i)->process(nframes, start, end);
 
 	// Run all nodes (consume input ports)
 	for (size_t i=0; i < _process_order->size(); ++i) {
 		// Could be a gap due to a node removal event (see RemoveNodeEvent.cpp)
 		// Yes, this is ugly
 		if (_process_order->at(i) != NULL)
-			_process_order->at(i)->process(nframes);
+			_process_order->at(i)->process(nframes, start, end);
 	}
 	
 	// Prepare output ports (for caller to consume)
 	for (List<Port*>::iterator i = _output_ports.begin(); i != _output_ports.end(); ++i)
-		(*i)->process(nframes);
+		(*i)->process(nframes, start, end);
 }
 
 
 void
-Patch::add_to_store()
+Patch::add_to_store(ObjectStore* store)
 {
 	// Add self and ports
-	NodeBase::add_to_store();
+	NodeBase::add_to_store(store);
 
 	// Add nodes
 	for (List<Node*>::iterator j = _nodes.begin(); j != _nodes.end(); ++j)
-		(*j)->add_to_store();
+		(*j)->add_to_store(store);
 }
 
 
diff --git a/src/libs/engine/Patch.h b/src/libs/engine/Patch.h
index 4a37d2d0..b6b709c4 100644
--- a/src/libs/engine/Patch.h
+++ b/src/libs/engine/Patch.h
@@ -54,11 +54,11 @@ public:
 	void activate();
 	void deactivate();
 
-	void process(SampleCount nframes);
+	void process(SampleCount nframes, FrameTime start, FrameTime end);
 	
 	//void send_creation_messages(ClientInterface* client) const;
 	
-	void add_to_store();
+	void add_to_store(ObjectStore* store);
 	void remove_from_store();
 	
 	void set_path(const Path& new_path);
@@ -91,8 +91,9 @@ public:
 	Array<Node*>* build_process_order() const;
 	
 	/** Whether to run this patch's DSP bits in the audio thread */
-	bool process() const { return _process; }
-	void process(bool p);
+	bool enabled() const { return _process; }
+	void enable()        { _process = true; }
+	void disable();
 
 	size_t internal_poly() const { return _internal_poly; }
 
diff --git a/src/libs/engine/Plugin.cpp b/src/libs/engine/Plugin.cpp
new file mode 100644
index 00000000..338e532b
--- /dev/null
+++ b/src/libs/engine/Plugin.cpp
@@ -0,0 +1,44 @@
+/* This file is part of Ingen.  Copyright (C) 2006 Dave Robillard.
+ * 
+ * Ingen 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.
+ * 
+ * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "Plugin.h"
+#include "MidiNoteNode.h"
+#include "MidiTriggerNode.h"
+#include "MidiControlNode.h"
+#include "TransportNode.h"
+
+namespace Ingen {
+
+Node*
+Plugin::instantiate(const string& name, size_t poly, Ingen::Patch* parent, SampleRate srate, size_t buffer_size)
+{
+	assert(_type == Internal);
+
+	if (_uri == "ingen:note_node") {
+		return new MidiNoteNode(name, poly, parent, srate, buffer_size);
+	} else if (_uri == "ingen:trigger_node") {
+		return new MidiTriggerNode(name, poly, parent, srate, buffer_size);
+	} else if (_uri == "ingen:control_node") {
+		return new MidiControlNode(name, poly, parent, srate, buffer_size);
+	} else if (_uri == "ingen:transport_node") {
+		return new TransportNode(name, poly, parent, srate, buffer_size);
+	} else {
+		return NULL;
+	}
+}
+
+
+} // namespace Ingen
diff --git a/src/libs/engine/Port.h b/src/libs/engine/Port.h
index 918681e5..e538248b 100644
--- a/src/libs/engine/Port.h
+++ b/src/libs/engine/Port.h
@@ -43,14 +43,14 @@ class Port : public GraphObject
 public:
 	virtual ~Port() {}
 
-	void add_to_store()      { assert(false); }
-	void remove_from_store() { assert(false); }
+	void add_to_store(ObjectStore* store) { assert(false); }
+	void remove_from_store()        { assert(false); }
 	
 	/** A port's parent is always a node, so static cast should be safe */
 	Node* parent_node() const { return (Node*)_parent; }
 
 	/** Called once per process cycle */
-	virtual void process(SampleCount nframes) = 0;
+	virtual void process(SampleCount nframes, FrameTime start, FrameTime end) = 0;
 	
 	/** Empty buffer contents completely (ie silence) */
 	virtual void clear_buffers() = 0;
diff --git a/src/libs/engine/PostProcessor.cpp b/src/libs/engine/PostProcessor.cpp
index 47a48f21..5fd1218a 100644
--- a/src/libs/engine/PostProcessor.cpp
+++ b/src/libs/engine/PostProcessor.cpp
@@ -18,7 +18,6 @@
 #include <cassert>
 #include <iostream>
 #include <pthread.h>
-#include "Engine.h"
 #include "Event.h"
 #include "util/Queue.h"
 #include "Maid.h"
@@ -29,8 +28,9 @@ using std::cerr; using std::cout; using std::endl;
 namespace Ingen {
 
 
-PostProcessor::PostProcessor(size_t queue_size)
-: _events(queue_size)
+PostProcessor::PostProcessor(Maid& maid, size_t queue_size)
+: _maid(maid),
+  _events(queue_size)
 {
 	set_name("PostProcessor");
 }
@@ -47,7 +47,7 @@ PostProcessor::_whipped()
 		Event* const ev = _events.pop();
 		assert(ev);
 		ev->post_process();
-		Engine::instance().maid()->push(ev);
+		_maid.push(ev);
 	}
 }
 
diff --git a/src/libs/engine/PostProcessor.h b/src/libs/engine/PostProcessor.h
index 2ae8f28b..e29175ee 100644
--- a/src/libs/engine/PostProcessor.h
+++ b/src/libs/engine/PostProcessor.h
@@ -20,9 +20,10 @@
 #include <pthread.h>
 #include "types.h"
 #include "util/Queue.h"
-#include "util/Semaphore.h"
 #include "Slave.h"
 
+class Maid;
+
 namespace Ingen {
 
 class Event;
@@ -39,7 +40,7 @@ class Event;
 class PostProcessor : public Slave
 {
 public:
-	PostProcessor(size_t queue_size);
+	PostProcessor(Maid& maid, size_t queue_size);
 
 	/** Push an event on to the process queue, realtime-safe, not thread-safe. */
 	inline void push(Event* const ev) { _events.push(ev); }
@@ -49,6 +50,7 @@ private:
 	PostProcessor(const PostProcessor&);
 	PostProcessor& operator=(const PostProcessor&);
 
+	Maid&         _maid;
 	Queue<Event*> _events;
 	virtual void  _whipped();
 };
diff --git a/src/libs/engine/QueuedEngineInterface.cpp b/src/libs/engine/QueuedEngineInterface.cpp
index f9ad8a00..4d38f91c 100644
--- a/src/libs/engine/QueuedEngineInterface.cpp
+++ b/src/libs/engine/QueuedEngineInterface.cpp
@@ -23,9 +23,10 @@
 
 namespace Ingen {
 
-QueuedEngineInterface::QueuedEngineInterface(size_t queued_size, size_t stamped_size)
+QueuedEngineInterface::QueuedEngineInterface(Engine& engine, size_t queued_size, size_t stamped_size)
 : QueuedEventSource(queued_size, stamped_size)
 , _responder(CountedPtr<Responder>(new Responder())) // NULL responder
+, _engine(engine)
 {
 }
 
@@ -33,7 +34,7 @@ QueuedEngineInterface::QueuedEngineInterface(size_t queued_size, size_t stamped_
 SampleCount
 QueuedEngineInterface::now() const
 {
-	return Engine::instance().audio_driver()->time_stamp();
+	return _engine.audio_driver()->frame_time();
 }
 
 /** Set the Responder to send responses to commands with, once the commands
@@ -63,14 +64,14 @@ QueuedEngineInterface::disable_responses()
 void
 QueuedEngineInterface::register_client(ClientKey key, CountedPtr<ClientInterface> client)
 {
-	push_queued(new RegisterClientEvent(_responder, now(), key, client));
+	push_queued(new RegisterClientEvent(_engine, _responder, now(), key, client));
 }
 
 
 void
 QueuedEngineInterface::unregister_client(ClientKey key)
 {
-	push_queued(new UnregisterClientEvent(_responder, now(), key));
+	push_queued(new UnregisterClientEvent(_engine, _responder, now(), key));
 }
 
 
@@ -79,7 +80,7 @@ QueuedEngineInterface::unregister_client(ClientKey key)
 void
 QueuedEngineInterface::load_plugins()
 {
-	push_queued(new LoadPluginsEvent(_responder, now()));
+	push_queued(new LoadPluginsEvent(_engine, _responder, now()));
 
 }
 
@@ -87,14 +88,14 @@ QueuedEngineInterface::load_plugins()
 void
 QueuedEngineInterface::activate()    
 {
-	push_queued(new ActivateEvent(_responder, now()));
+	push_queued(new ActivateEvent(_engine, _responder, now()));
 }
 
 
 void
 QueuedEngineInterface::deactivate()  
 {
-	push_queued(new DeactivateEvent(_responder, now()));
+	push_queued(new DeactivateEvent(_engine, _responder, now()));
 }
 
 
@@ -102,7 +103,7 @@ void
 QueuedEngineInterface::quit()        
 {
 	_responder->respond_ok();
-	Engine::instance().quit();
+	_engine.quit();
 }
 
 
@@ -113,7 +114,7 @@ void
 QueuedEngineInterface::create_patch(const string& path,
                                     uint32_t      poly)
 {
-	push_queued(new CreatePatchEvent(_responder, now(), path, poly));
+	push_queued(new CreatePatchEvent(_engine, _responder, now(), path, poly));
 
 }
 
@@ -122,7 +123,7 @@ void QueuedEngineInterface::create_port(const string& path,
                                         const string& data_type,
                                         bool          direction)
 {
-	push_queued(new AddPortEvent(_responder, now(), path, data_type, direction));
+	push_queued(new AddPortEvent(_engine, _responder, now(), path, data_type, direction));
 }
 
 
@@ -138,7 +139,7 @@ QueuedEngineInterface::create_node(const string& path,
 	plugin->set_type(plugin_type);
 	plugin->uri(plugin_uri);
 
-	push_queued(new AddNodeEvent(_responder, now(), path, plugin, polyphonic));
+	push_queued(new AddNodeEvent(_engine, _responder, now(), path, plugin, polyphonic));
 }
 
 
@@ -156,42 +157,42 @@ QueuedEngineInterface::create_node(const string& path,
 	plugin->lib_name(plugin_lib);
 	plugin->plug_label(plugin_label);
 
-	push_queued(new AddNodeEvent(_responder, now(), path, plugin, polyphonic));
+	push_queued(new AddNodeEvent(_engine, _responder, now(), path, plugin, polyphonic));
 }
 
 void
 QueuedEngineInterface::rename(const string& old_path,
                               const string& new_name)
 {
-	push_queued(new RenameEvent(_responder, now(), old_path, new_name));
+	push_queued(new RenameEvent(_engine, _responder, now(), old_path, new_name));
 }
 
 
 void
 QueuedEngineInterface::destroy(const string& path)
 {
-	push_queued(new DestroyEvent(_responder, now(), this, path));
+	push_queued(new DestroyEvent(_engine, _responder, now(), this, path));
 }
 
 
 void
 QueuedEngineInterface::clear_patch(const string& patch_path)
 {
-	push_queued(new ClearPatchEvent(_responder, now(), patch_path));
+	push_queued(new ClearPatchEvent(_engine, _responder, now(), patch_path));
 }
 
 
 void
 QueuedEngineInterface::enable_patch(const string& patch_path)
 {
-	push_queued(new EnablePatchEvent(_responder, now(), patch_path));
+	push_queued(new EnablePatchEvent(_engine, _responder, now(), patch_path));
 }
 
 
 void
 QueuedEngineInterface::disable_patch(const string& patch_path)
 {
-	push_queued(new DisablePatchEvent(_responder, now(), patch_path));
+	push_queued(new DisablePatchEvent(_engine, _responder, now(), patch_path));
 }
 
 
@@ -199,7 +200,7 @@ void
 QueuedEngineInterface::connect(const string& src_port_path,
                                const string& dst_port_path)
 {
-	push_queued(new ConnectionEvent(_responder, now(), src_port_path, dst_port_path));
+	push_queued(new ConnectionEvent(_engine, _responder, now(), src_port_path, dst_port_path));
 
 }
 
@@ -208,14 +209,14 @@ void
 QueuedEngineInterface::disconnect(const string& src_port_path,
                                   const string& dst_port_path)
 {
-	push_queued(new DisconnectionEvent(_responder, now(), src_port_path, dst_port_path));
+	push_queued(new DisconnectionEvent(_engine, _responder, now(), src_port_path, dst_port_path));
 }
 
 
 void
 QueuedEngineInterface::disconnect_all(const string& node_path)
 {
-	push_queued(new DisconnectNodeEvent(_responder, now(), node_path));
+	push_queued(new DisconnectNodeEvent(_engine, _responder, now(), node_path));
 }
 
 
@@ -223,7 +224,7 @@ void
 QueuedEngineInterface::set_port_value(const string& port_path,
                                       float         value)
 {
-	push_stamped(new SetPortValueEvent(_responder, now(), port_path, value));
+	push_stamped(new SetPortValueEvent(_engine, _responder, now(), port_path, value));
 }
 
 
@@ -232,7 +233,7 @@ QueuedEngineInterface::set_port_value(const string& port_path,
                                       uint32_t      voice,
                                       float         value)
 {
-	push_stamped(new SetPortValueEvent(_responder, now(), voice, port_path, value));
+	push_stamped(new SetPortValueEvent(_engine, _responder, now(), voice, port_path, value));
 }
 
 
@@ -240,7 +241,7 @@ void
 QueuedEngineInterface::set_port_value_queued(const string& port_path,
                                              float         value)
 {
-	push_queued(new SetPortValueQueuedEvent(_responder, now(), port_path, value));
+	push_queued(new SetPortValueQueuedEvent(_engine, _responder, now(), port_path, value));
 }
 
 
@@ -249,14 +250,14 @@ QueuedEngineInterface::set_program(const string& node_path,
                                    uint32_t      bank,
                                    uint32_t      program)
 {
-	push_queued(new DSSIProgramEvent(_responder, now(), node_path, bank, program));
+	push_queued(new DSSIProgramEvent(_engine, _responder, now(), node_path, bank, program));
 }
 
 
 void
 QueuedEngineInterface::midi_learn(const string& node_path)
 {
-	push_queued(new MidiLearnEvent(_responder, now(), node_path));
+	push_queued(new MidiLearnEvent(_engine, _responder, now(), node_path));
 }
 
 
@@ -265,7 +266,7 @@ QueuedEngineInterface::set_metadata(const string& path,
                                     const string& predicate,
                                     const string& value)
 {
-	push_queued(new SetMetadataEvent(_responder, now(), path, predicate, value));
+	push_queued(new SetMetadataEvent(_engine, _responder, now(), path, predicate, value));
 }
 
 
@@ -274,28 +275,28 @@ QueuedEngineInterface::set_metadata(const string& path,
 void
 QueuedEngineInterface::ping()
 {
-	push_queued(new PingQueuedEvent(_responder, now()));
+	push_queued(new PingQueuedEvent(_engine, _responder, now()));
 }
 
 
 void
 QueuedEngineInterface::request_port_value(const string& port_path)
 {
-	push_queued(new RequestPortValueEvent(_responder, now(), port_path));
+	push_queued(new RequestPortValueEvent(_engine, _responder, now(), port_path));
 }
 
 
 void
 QueuedEngineInterface::request_plugins()
 {
-	push_queued(new RequestPluginsEvent(_responder, now()));
+	push_queued(new RequestPluginsEvent(_engine, _responder, now()));
 }
 
 
 void
 QueuedEngineInterface::request_all_objects()
 {
-	push_queued(new RequestAllObjectsEvent(_responder, now()));
+	push_queued(new RequestAllObjectsEvent(_engine, _responder, now()));
 }
 
 
diff --git a/src/libs/engine/QueuedEngineInterface.h b/src/libs/engine/QueuedEngineInterface.h
index cd5ef1b7..c5904a2e 100644
--- a/src/libs/engine/QueuedEngineInterface.h
+++ b/src/libs/engine/QueuedEngineInterface.h
@@ -33,6 +33,7 @@ namespace Ingen {
 using Shared::ClientKey;
 using Shared::ClientInterface;
 using Shared::EngineInterface;
+class Engine;
 
 
 /** A queued (preprocessed) event source / interface.
@@ -58,7 +59,7 @@ using Shared::EngineInterface;
 class QueuedEngineInterface : public QueuedEventSource, public EngineInterface
 {
 public:
-	QueuedEngineInterface(size_t queued_size, size_t stamped_size);
+	QueuedEngineInterface(Engine& engine, size_t queued_size, size_t stamped_size);
 	virtual ~QueuedEngineInterface() {}
 	
 	virtual void set_responder(CountedPtr<Responder> responder);
@@ -152,6 +153,8 @@ protected:
 
 private:
 	SampleCount now() const;
+
+	Engine& _engine;
 };
 
 
diff --git a/src/libs/engine/QueuedEvent.h b/src/libs/engine/QueuedEvent.h
index d88a247c..388630e7 100644
--- a/src/libs/engine/QueuedEvent.h
+++ b/src/libs/engine/QueuedEvent.h
@@ -49,9 +49,16 @@ public:
 		_pre_processed = true;
 	}
 
-	virtual void execute(SampleCount offset) {
+	virtual void execute(SampleCount nframes, FrameTime start, FrameTime end) {
 		assert(_pre_processed);
-		Event::execute(offset);
+		assert(_time <= end);
+
+		// Didn't prepare in time.  QueuedEvents aren't (necessarily) sample accurate
+		// so just run at the beginning of this cycle
+		if (_time <= start)
+			_time = start;
+			
+		Event::execute(nframes, start, end);
 	}
 
 	virtual void post_process() {}
@@ -66,17 +73,18 @@ protected:
 	QueuedEvent(const QueuedEvent& copy);
 	QueuedEvent& operator=(const QueuedEvent&);
 	
-	QueuedEvent(CountedPtr<Responder> responder,
-	            SampleCount           timestamp, 
+	QueuedEvent(Engine&               engine,
+	            CountedPtr<Responder> responder,
+	            FrameTime             time, 
 	            bool                  blocking = false,
 	            QueuedEventSource*    source = NULL)
-	: Event(responder, timestamp)
+	: Event(engine, responder, time)
 	, _pre_processed(false), _blocking(blocking), _source(source)
 	{}
 	
 	// NULL event base (for internal events only!)
-	QueuedEvent()
-	: Event(NULL, 0)
+	QueuedEvent(Engine& engine)
+	: Event(engine, NULL, 0)
 	, _pre_processed(false), _blocking(false), _source(NULL)
 	{}
 
diff --git a/src/libs/engine/QueuedEventSource.cpp b/src/libs/engine/QueuedEventSource.cpp
index 33ac130a..0ef11ac1 100644
--- a/src/libs/engine/QueuedEventSource.cpp
+++ b/src/libs/engine/QueuedEventSource.cpp
@@ -87,7 +87,7 @@ QueuedEventSource::pop_earliest_queued_before(const SampleCount time)
 	QueuedEvent* const front_event = _events[_front];
 	
 	// Pop
-	if (front_event && front_event->is_prepared() && front_event->time_stamp() < time) {
+	if (front_event && front_event->is_prepared() && front_event->time() < time) {
 		_events[_front] = NULL;
 		_front = (_front + 1) % _size;
 		return front_event;
diff --git a/src/libs/engine/QueuedEventSource.h b/src/libs/engine/QueuedEventSource.h
index 5dcc9200..abdea293 100644
--- a/src/libs/engine/QueuedEventSource.h
+++ b/src/libs/engine/QueuedEventSource.h
@@ -94,7 +94,7 @@ private:
 inline Event*
 QueuedEventSource::pop_earliest_stamped_before(const SampleCount time)
 {
-	if (!_stamped_queue.is_empty() && _stamped_queue.front()->time_stamp() < time)
+	if (!_stamped_queue.is_empty() && _stamped_queue.front()->time() < time)
 		return _stamped_queue.pop();
 	return NULL;
 }
diff --git a/src/libs/engine/Responder.h b/src/libs/engine/Responder.h
index 14c857bc..162af23f 100644
--- a/src/libs/engine/Responder.h
+++ b/src/libs/engine/Responder.h
@@ -20,12 +20,12 @@
 #include <inttypes.h>
 #include <string>
 #include "util/CountedPtr.h"
-#include "interface/ClientInterface.h"
+#include "interface/ClientKey.h"
 using std::string;
 
 namespace Ingen {
 
-using Shared::ClientInterface;
+using Shared::ClientKey;
 
 
 /** Class to handle responding to clients.
@@ -36,8 +36,8 @@ using Shared::ClientInterface;
  * Note that this class only handles sending responses to commands from
  * clients, (ie OK or an error), <b>not</b> notifications (ie new node,
  * disconnection) - that's what ClientInterface is for.  If a command is
- * a request, \ref find_client can find the corresponding ClientInterface
- * for this client to send the reply to.
+ * a request, the ClientKey of the Responder can be used to find the
+ * ClientInterface which should receive the response.
  *
  * ClientInterface and Responder are seperate because responding might not
  * actually get exposed to the client interface (eg in simulated blocking
@@ -49,8 +49,7 @@ public:
 	Responder() {}
 	virtual ~Responder() {}
 
-	virtual CountedPtr<Shared::ClientInterface> find_client()
-	{ return CountedPtr<Shared::ClientInterface>(NULL); }
+	virtual ClientKey client_key() { return ClientKey(); }
 
 	virtual void respond_ok() {}
 	virtual void respond_error(const string& msg) {}
diff --git a/src/libs/engine/TransportNode.cpp b/src/libs/engine/TransportNode.cpp
index 49ab20b8..caab50d2 100644
--- a/src/libs/engine/TransportNode.cpp
+++ b/src/libs/engine/TransportNode.cpp
@@ -14,7 +14,6 @@
  * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-
 #include "TransportNode.h"
 #include <jack/transport.h>
 #include "OutputPort.h"
@@ -81,9 +80,9 @@ TransportNode::TransportNode(const string& path, size_t poly, Patch* parent, Sam
 
 
 void
-TransportNode::run(size_t nframes)
+TransportNode::process(SampleCount nframes, FrameTime start, FrameTime end)
 {
-	NodeBase::process(nframes);
+	NodeBase::process(nframes, start, end);
 #if 0
 
 	// FIXME: this will die horribly with any driver other than jack (in theory)
diff --git a/src/libs/engine/TransportNode.h b/src/libs/engine/TransportNode.h
index b4547fdc..1f40e844 100644
--- a/src/libs/engine/TransportNode.h
+++ b/src/libs/engine/TransportNode.h
@@ -39,7 +39,7 @@ class TransportNode : public InternalNode
 public:
 	TransportNode(const string& path, size_t poly, Patch* parent, SampleRate srate, size_t buffer_size);
 
-	void run(size_t nframes);
+	virtual void process(SampleCount nframes, FrameTime start, FrameTime end);
 };
 
 
diff --git a/src/libs/engine/TypedConnection.cpp b/src/libs/engine/TypedConnection.cpp
index daee10d9..a0cd01e6 100644
--- a/src/libs/engine/TypedConnection.cpp
+++ b/src/libs/engine/TypedConnection.cpp
@@ -63,7 +63,7 @@ template TypedConnection<MidiMessage>::~TypedConnection();
 
 template <typename Sample>
 void
-TypedConnection<Sample>::process(SampleCount nframes)
+TypedConnection<Sample>::process(SampleCount nframes, FrameTime start, FrameTime end)
 {
 	// FIXME: nframes parameter not used
 	assert(m_buffer_size == 1 || m_buffer_size == nframes);
@@ -91,13 +91,13 @@ TypedConnection<Sample>::process(SampleCount nframes)
 			m_local_buffer->scale(1.0f/(float)src_port()->poly(), 0, m_buffer_size-1);
 	}
 }
-template void TypedConnection<Sample>::process(SampleCount nframes);
+template void TypedConnection<Sample>::process(SampleCount nframes, FrameTime start, FrameTime end);
 
 
 // FIXME: MIDI mixing not implemented
 template <>
 void
-TypedConnection<MidiMessage>::process(SampleCount nframes)
+TypedConnection<MidiMessage>::process(SampleCount nframes, FrameTime start, FrameTime end)
 {
 }
 
diff --git a/src/libs/engine/TypedConnection.h b/src/libs/engine/TypedConnection.h
index 1289e158..8fb16676 100644
--- a/src/libs/engine/TypedConnection.h
+++ b/src/libs/engine/TypedConnection.h
@@ -39,7 +39,7 @@ public:
 	TypedConnection(OutputPort<T>* const src_port, InputPort<T>* const dst_port);
 	virtual ~TypedConnection();
 
-	void process(SampleCount nframes);
+	void process(SampleCount nframes, FrameTime start, FrameTime end);
 
 	inline OutputPort<T>* src_port() const { return dynamic_cast<OutputPort<T>*>(m_src_port); }
 	inline InputPort<T>*  dst_port() const { return dynamic_cast<InputPort<T>*>(m_dst_port); }
diff --git a/src/libs/engine/TypedPort.cpp b/src/libs/engine/TypedPort.cpp
index 176c658c..484dcaf7 100644
--- a/src/libs/engine/TypedPort.cpp
+++ b/src/libs/engine/TypedPort.cpp
@@ -102,7 +102,7 @@ template void TypedPort<MidiMessage>::allocate_buffers();
 
 template <typename T>
 void
-TypedPort<T>::process(SampleCount nframes)
+TypedPort<T>::process(SampleCount nframes, FrameTime start, FrameTime end)
 {
 	for (size_t i=0; i < _poly; ++i)
 		m_buffers.at(i)->prepare(nframes);
diff --git a/src/libs/engine/TypedPort.h b/src/libs/engine/TypedPort.h
index 4958269b..cf4c36a2 100644
--- a/src/libs/engine/TypedPort.h
+++ b/src/libs/engine/TypedPort.h
@@ -49,7 +49,7 @@ public:
 	
 	Buffer<T>* buffer(size_t voice) const { return m_buffers.at(voice); }
 	
-	virtual void process(SampleCount nframes);
+	virtual void process(SampleCount nframes, FrameTime start, FrameTime end);
 	virtual void clear_buffers();
 	
 	/** Used by drivers to prevent port from changing buffers */
diff --git a/src/libs/engine/events/ActivateEvent.cpp b/src/libs/engine/events/ActivateEvent.cpp
index 31a218ad..9d8162ec 100644
--- a/src/libs/engine/events/ActivateEvent.cpp
+++ b/src/libs/engine/events/ActivateEvent.cpp
@@ -21,8 +21,8 @@
 namespace Ingen {
 
 
-ActivateEvent::ActivateEvent(CountedPtr<Responder> responder, SampleCount timestamp)
-: QueuedEvent(responder, timestamp)
+ActivateEvent::ActivateEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp)
+: QueuedEvent(engine, responder, timestamp)
 {
 }
 
@@ -32,7 +32,7 @@ ActivateEvent::pre_process()
 {
 	QueuedEvent::pre_process();
 
-	Engine::instance().activate();
+	_engine.activate();
 }
 
 
diff --git a/src/libs/engine/events/ActivateEvent.h b/src/libs/engine/events/ActivateEvent.h
index de47ddf3..26ee5b84 100644
--- a/src/libs/engine/events/ActivateEvent.h
+++ b/src/libs/engine/events/ActivateEvent.h
@@ -29,7 +29,7 @@ namespace Ingen {
 class ActivateEvent : public QueuedEvent
 {
 public:
-	ActivateEvent(CountedPtr<Responder> responder, SampleCount timestamp);
+	ActivateEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp);
 	
 	void pre_process();
 	void post_process();
diff --git a/src/libs/engine/events/AddNodeEvent.cpp b/src/libs/engine/events/AddNodeEvent.cpp
index a5dc7538..5287c7cd 100644
--- a/src/libs/engine/events/AddNodeEvent.cpp
+++ b/src/libs/engine/events/AddNodeEvent.cpp
@@ -33,8 +33,8 @@
 namespace Ingen {
 
 
-AddNodeEvent::AddNodeEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& path, Plugin* plugin, bool poly)
-: QueuedEvent(responder, timestamp),
+AddNodeEvent::AddNodeEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& path, Plugin* plugin, bool poly)
+: QueuedEvent(engine, responder, timestamp),
   m_path(path),
   m_plugin(plugin),
   m_poly(poly),
@@ -55,19 +55,19 @@ AddNodeEvent::~AddNodeEvent()
 void
 AddNodeEvent::pre_process()
 {
-	if (Engine::instance().object_store()->find(m_path) != NULL) {
+	if (_engine.object_store()->find(m_path) != NULL) {
 		m_node_already_exists = true;
 		QueuedEvent::pre_process();
 		return;
 	}
 
-	m_patch = Engine::instance().object_store()->find_patch(m_path.parent());
+	m_patch = _engine.object_store()->find_patch(m_path.parent());
 
 	if (m_patch != NULL) {
 		if (m_poly)
-			m_node = Engine::instance().node_factory()->load_plugin(m_plugin, m_path.name(), m_patch->internal_poly(), m_patch);
+			m_node = _engine.node_factory()->load_plugin(m_plugin, m_path.name(), m_patch->internal_poly(), m_patch);
 		else
-			m_node = Engine::instance().node_factory()->load_plugin(m_plugin, m_path.name(), 1, m_patch);
+			m_node = _engine.node_factory()->load_plugin(m_plugin, m_path.name(), 1, m_patch);
 		
 		if (m_node != NULL) {
 			m_node->activate();
@@ -75,9 +75,9 @@ AddNodeEvent::pre_process()
 			// This can be done here because the audio thread doesn't touch the
 			// node tree - just the process order array
 			m_patch->add_node(new ListNode<Node*>(m_node));
-			m_node->add_to_store();
+			m_node->add_to_store(_engine.object_store());
 			
-			if (m_patch->process())
+			if (m_patch->enabled())
 				m_process_order = m_patch->build_process_order();
 		}
 	}
@@ -86,15 +86,15 @@ AddNodeEvent::pre_process()
 
 
 void
-AddNodeEvent::execute(SampleCount offset)
+AddNodeEvent::execute(SampleCount nframes, FrameTime start, FrameTime end)
 {
-	QueuedEvent::execute(offset);
+	QueuedEvent::execute(nframes, start, end);
 
 	if (m_node != NULL) {
 		m_node->add_to_patch();
 		
 		if (m_patch->process_order() != NULL)
-			Engine::instance().maid()->push(m_patch->process_order());
+			_engine.maid()->push(m_patch->process_order());
 		m_patch->process_order(m_process_order);
 	}
 }
@@ -117,8 +117,8 @@ AddNodeEvent::post_process()
 		_responder->respond_error(msg);
 	} else {
 		_responder->respond_ok();
-		//Engine::instance().client_broadcaster()->send_node_creation_messages(m_node);
-		Engine::instance().client_broadcaster()->send_node(m_node);
+		//_engine.client_broadcaster()->send_node_creation_messages(m_node);
+		_engine.client_broadcaster()->send_node(m_node);
 	}
 }
 
diff --git a/src/libs/engine/events/AddNodeEvent.h b/src/libs/engine/events/AddNodeEvent.h
index c2ec043a..c7616c2b 100644
--- a/src/libs/engine/events/AddNodeEvent.h
+++ b/src/libs/engine/events/AddNodeEvent.h
@@ -39,11 +39,11 @@ class Plugin;
 class AddNodeEvent : public QueuedEvent
 {
 public:
-	AddNodeEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& path, Plugin* plugin, bool poly);
+	AddNodeEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& path, Plugin* plugin, bool poly);
 	~AddNodeEvent();
 
 	void pre_process();
-	void execute(SampleCount offset);
+	void execute(SampleCount nframes, FrameTime start, FrameTime end);
 	void post_process();
 
 private:
diff --git a/src/libs/engine/events/AddPortEvent.cpp b/src/libs/engine/events/AddPortEvent.cpp
index cf40b45f..7b034f43 100644
--- a/src/libs/engine/events/AddPortEvent.cpp
+++ b/src/libs/engine/events/AddPortEvent.cpp
@@ -36,8 +36,8 @@
 namespace Ingen {
 
 
-AddPortEvent::AddPortEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& path, const string& type, bool is_output)
-: QueuedEvent(responder, timestamp),
+AddPortEvent::AddPortEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& path, const string& type, bool is_output)
+: QueuedEvent(engine, responder, timestamp),
   _path(path),
   _type(type),
   _is_output(is_output),
@@ -57,21 +57,21 @@ AddPortEvent::AddPortEvent(CountedPtr<Responder> responder, SampleCount timestam
 void
 AddPortEvent::pre_process()
 {
-	if (Engine::instance().object_store()->find(_path) != NULL) {
+	if (_engine.object_store()->find(_path) != NULL) {
 		QueuedEvent::pre_process();
 		return;
 	}
 
 	// FIXME: this is just a mess :/
 	
-	_patch = Engine::instance().object_store()->find_patch(_path.parent());
+	_patch = _engine.object_store()->find_patch(_path.parent());
 
 	if (_patch != NULL) {
 		assert(_patch->path() == _path.parent());
 		
 		size_t buffer_size = 1;
 		if (_type == "AUDIO" || _type == "MIDI")
-			buffer_size = Engine::instance().audio_driver()->buffer_size();
+			buffer_size = _engine.audio_driver()->buffer_size();
 	
 		_patch_port = _patch->create_port(_path.name(), _data_type, buffer_size, _is_output);
 		if (_patch_port) {
@@ -86,14 +86,14 @@ AddPortEvent::pre_process()
 				_ports_array = new Array<Port*>(_patch->num_ports() + 1, NULL);
 
 			_ports_array->at(_patch->num_ports()) = _patch_port;
-			Engine::instance().object_store()->add(_patch_port);
+			_engine.object_store()->add(_patch_port);
 
 			if (!_patch->parent()) {
 				if (_type == "AUDIO")
-					_driver_port = Engine::instance().audio_driver()->create_port(
+					_driver_port = _engine.audio_driver()->create_port(
 						dynamic_cast<DuplexPort<Sample>*>(_patch_port));
 				else if (_type == "MIDI")
-					_driver_port = Engine::instance().midi_driver()->create_port(
+					_driver_port = _engine.midi_driver()->create_port(
 						dynamic_cast<DuplexPort<MidiMessage>*>(_patch_port));
 			}
 		}
@@ -103,12 +103,12 @@ AddPortEvent::pre_process()
 
 
 void
-AddPortEvent::execute(SampleCount offset)
+AddPortEvent::execute(SampleCount nframes, FrameTime start, FrameTime end)
 {
-	QueuedEvent::execute(offset);
+	QueuedEvent::execute(nframes, start, end);
 
 	if (_patch_port) {
-		Engine::instance().maid()->push(_patch->external_ports());
+		_engine.maid()->push(_patch->external_ports());
 		//_patch->add_port(_port);
 		_patch->external_ports(_ports_array);
 	}
@@ -126,7 +126,7 @@ AddPortEvent::post_process()
 		_responder->respond_error(msg);
 	} else {
 		_responder->respond_ok();
-		Engine::instance().client_broadcaster()->send_port(_patch_port);
+		_engine.client_broadcaster()->send_port(_patch_port);
 	}
 }
 
diff --git a/src/libs/engine/events/AddPortEvent.h b/src/libs/engine/events/AddPortEvent.h
index 9643bd13..070d07df 100644
--- a/src/libs/engine/events/AddPortEvent.h
+++ b/src/libs/engine/events/AddPortEvent.h
@@ -41,10 +41,10 @@ class DriverPort;
 class AddPortEvent : public QueuedEvent
 {
 public:
-	AddPortEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& path, const string& type, bool is_output);
+	AddPortEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& path, const string& type, bool is_output);
 
 	void pre_process();
-	void execute(SampleCount offset);
+	void execute(SampleCount nframes, FrameTime start, FrameTime end);
 	void post_process();
 
 private:
diff --git a/src/libs/engine/events/AllNotesOffEvent.cpp b/src/libs/engine/events/AllNotesOffEvent.cpp
index 349c6cd5..b26f1315 100644
--- a/src/libs/engine/events/AllNotesOffEvent.cpp
+++ b/src/libs/engine/events/AllNotesOffEvent.cpp
@@ -24,8 +24,8 @@ namespace Ingen {
 
 /** Note off with patch explicitly passed - triggered by MIDI.
  */
-AllNotesOffEvent::AllNotesOffEvent(CountedPtr<Responder> responder, SampleCount timestamp, Patch* patch)
-: Event(responder, timestamp),
+AllNotesOffEvent::AllNotesOffEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, Patch* patch)
+: Event(engine, responder, timestamp),
   m_patch(patch)
 {
 }
@@ -33,8 +33,8 @@ AllNotesOffEvent::AllNotesOffEvent(CountedPtr<Responder> responder, SampleCount
 
 /** Note off event with lookup - triggered by OSC.
  */
-AllNotesOffEvent::AllNotesOffEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& patch_path)
-: Event(responder, timestamp),
+AllNotesOffEvent::AllNotesOffEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& patch_path)
+: Event(engine, responder, timestamp),
   m_patch(NULL),
   m_patch_path(patch_path)
 {
@@ -42,10 +42,10 @@ AllNotesOffEvent::AllNotesOffEvent(CountedPtr<Responder> responder, SampleCount
 
 
 void
-AllNotesOffEvent::execute(SampleCount offset)
+AllNotesOffEvent::execute(SampleCount nframes, FrameTime start, FrameTime end)
 {	
 	if (m_patch == NULL && m_patch_path != "")
-		m_patch = Engine::instance().object_store()->find_patch(m_patch_path);
+		m_patch = _engine.object_store()->find_patch(m_patch_path);
 		
 	//if (m_patch != NULL)
 	//	for (List<MidiInNode*>::iterator j = m_patch->midi_in_nodes().begin(); j != m_patch->midi_in_nodes().end(); ++j)
diff --git a/src/libs/engine/events/AllNotesOffEvent.h b/src/libs/engine/events/AllNotesOffEvent.h
index 56d52a25..5c8f46f0 100644
--- a/src/libs/engine/events/AllNotesOffEvent.h
+++ b/src/libs/engine/events/AllNotesOffEvent.h
@@ -33,10 +33,10 @@ class Patch;
 class AllNotesOffEvent : public Event
 {
 public:
-	AllNotesOffEvent(CountedPtr<Responder> responder, SampleCount timestamp, Patch* patch);
-	AllNotesOffEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& patch_path);
+	AllNotesOffEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, Patch* patch);
+	AllNotesOffEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& patch_path);
 	
-	void execute(SampleCount offset);
+	void execute(SampleCount nframes, FrameTime start, FrameTime end);
 	void post_process();
 
 private:
diff --git a/src/libs/engine/events/ClearPatchEvent.cpp b/src/libs/engine/events/ClearPatchEvent.cpp
index 3cd8faab..e73fd376 100644
--- a/src/libs/engine/events/ClearPatchEvent.cpp
+++ b/src/libs/engine/events/ClearPatchEvent.cpp
@@ -30,8 +30,8 @@
 namespace Ingen {
 
 
-ClearPatchEvent::ClearPatchEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& patch_path)
-: QueuedEvent(responder, true),
+ClearPatchEvent::ClearPatchEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& patch_path)
+: QueuedEvent(engine, responder, true),
   m_patch_path(patch_path),
   m_patch(NULL),
   m_process(false)
@@ -42,11 +42,11 @@ ClearPatchEvent::ClearPatchEvent(CountedPtr<Responder> responder, SampleCount ti
 void
 ClearPatchEvent::pre_process()
 {
-	m_patch = Engine::instance().object_store()->find_patch(m_patch_path);
+	m_patch = _engine.object_store()->find_patch(m_patch_path);
 	
 	if (m_patch != NULL) {
 	
-		m_process = m_patch->process();
+		m_process = m_patch->enabled();
 
 		for (List<Node*>::const_iterator i = m_patch->nodes().begin(); i != m_patch->nodes().end(); ++i)
 			(*i)->remove_from_store();
@@ -57,21 +57,21 @@ ClearPatchEvent::pre_process()
 
 
 void
-ClearPatchEvent::execute(SampleCount offset)
+ClearPatchEvent::execute(SampleCount nframes, FrameTime start, FrameTime end)
 {
 	if (m_patch != NULL) {
-		m_patch->process(false);
+		m_patch->disable();
 		
 		for (List<Node*>::const_iterator i = m_patch->nodes().begin(); i != m_patch->nodes().end(); ++i)
 			(*i)->remove_from_patch();
 
 		if (m_patch->process_order() != NULL) {
-			Engine::instance().maid()->push(m_patch->process_order());
+			_engine.maid()->push(m_patch->process_order());
 			m_patch->process_order(NULL);
 		}
 	}
 	
-	QueuedEvent::execute(offset);
+	QueuedEvent::execute(nframes, start, end);
 }
 
 
@@ -92,7 +92,10 @@ ClearPatchEvent::post_process()
 		m_patch->connections().clear();
 		
 		// Restore patch's run state
-		m_patch->process(m_process);
+		if (m_process)
+			m_patch->enable();
+		else
+			m_patch->disable();
 
 		// Make sure everything's sane
 		assert(m_patch->nodes().size() == 0);
@@ -100,7 +103,7 @@ ClearPatchEvent::post_process()
 		
 		// Reply
 		_responder->respond_ok();
-		Engine::instance().client_broadcaster()->send_patch_cleared(m_patch_path);
+		_engine.client_broadcaster()->send_patch_cleared(m_patch_path);
 	} else {
 		_responder->respond_error(string("Patch ") + m_patch_path + " not found");
 	}
diff --git a/src/libs/engine/events/ClearPatchEvent.h b/src/libs/engine/events/ClearPatchEvent.h
index bef90477..0eb9b495 100644
--- a/src/libs/engine/events/ClearPatchEvent.h
+++ b/src/libs/engine/events/ClearPatchEvent.h
@@ -35,10 +35,10 @@ class Patch;
 class ClearPatchEvent : public QueuedEvent
 {
 public:
-	ClearPatchEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& patch_path);
+	ClearPatchEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& patch_path);
 	
 	void pre_process();
-	void execute(SampleCount offset);
+	void execute(SampleCount nframes, FrameTime start, FrameTime end);
 	void post_process();
 
 private:
diff --git a/src/libs/engine/events/ConnectionEvent.cpp b/src/libs/engine/events/ConnectionEvent.cpp
index bf64df0a..b873bccb 100644
--- a/src/libs/engine/events/ConnectionEvent.cpp
+++ b/src/libs/engine/events/ConnectionEvent.cpp
@@ -36,8 +36,8 @@ namespace Ingen {
 //// ConnectionEvent ////
 
 
-ConnectionEvent::ConnectionEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& src_port_path, const string& dst_port_path)
-: QueuedEvent(responder, timestamp),
+ConnectionEvent::ConnectionEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& src_port_path, const string& dst_port_path)
+: QueuedEvent(engine, responder, timestamp),
   m_src_port_path(src_port_path),
   m_dst_port_path(dst_port_path),
   m_patch(NULL),
@@ -66,7 +66,7 @@ ConnectionEvent::pre_process()
 		return;
 	}
 	
-	/*m_patch = Engine::instance().object_store()->find_patch(m_src_port_path.parent().parent());
+	/*m_patch = _engine.object_store()->find_patch(m_src_port_path.parent().parent());
 
 	if (m_patch == NULL) {
 		m_error = PORT_NOT_FOUND;
@@ -74,8 +74,8 @@ ConnectionEvent::pre_process()
 		return;
 	}*/
 	
-	m_src_port = Engine::instance().object_store()->find_port(m_src_port_path);
-	m_dst_port = Engine::instance().object_store()->find_port(m_dst_port_path);
+	m_src_port = _engine.object_store()->find_port(m_src_port_path);
+	m_dst_port = _engine.object_store()->find_port(m_dst_port_path);
 	
 	if (m_src_port == NULL || m_dst_port == NULL) {
 		m_error = PORT_NOT_FOUND;
@@ -104,10 +104,10 @@ ConnectionEvent::pre_process()
 	// Create the typed event to actually do the work
 	const DataType type = m_src_port->type();
 	if (type == DataType::FLOAT) {
-		m_typed_event = new TypedConnectionEvent<Sample>(_responder, _time_stamp,
+		m_typed_event = new TypedConnectionEvent<Sample>(_engine, _responder, _time,
 			dynamic_cast<OutputPort<Sample>*>(m_src_port), dynamic_cast<InputPort<Sample>*>(m_dst_port));
 	} else if (type == DataType::MIDI) {
-		m_typed_event = new TypedConnectionEvent<MidiMessage>(_responder, _time_stamp,
+		m_typed_event = new TypedConnectionEvent<MidiMessage>(_engine, _responder, _time,
 			dynamic_cast<OutputPort<MidiMessage>*>(m_src_port), dynamic_cast<InputPort<MidiMessage>*>(m_dst_port));
 	} else {
 		m_error = TYPE_MISMATCH;
@@ -122,12 +122,12 @@ ConnectionEvent::pre_process()
 
 
 void
-ConnectionEvent::execute(SampleCount offset)
+ConnectionEvent::execute(SampleCount nframes, FrameTime start, FrameTime end)
 {
-	QueuedEvent::execute(offset);
+	QueuedEvent::execute(nframes, start, end);
 
 	if (m_error == NO_ERROR)
-		m_typed_event->execute(offset);
+		m_typed_event->execute(nframes, start, end);
 }
 
 
@@ -150,8 +150,8 @@ ConnectionEvent::post_process()
 
 
 template <typename T>
-TypedConnectionEvent<T>::TypedConnectionEvent(CountedPtr<Responder> responder, SampleCount timestamp, OutputPort<T>* src_port, InputPort<T>* dst_port)
-: QueuedEvent(responder, timestamp),
+TypedConnectionEvent<T>::TypedConnectionEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, OutputPort<T>* src_port, InputPort<T>* dst_port)
+: QueuedEvent(engine, responder, timestamp),
   m_src_port(src_port),
   m_dst_port(dst_port),
   m_patch(NULL),
@@ -221,21 +221,21 @@ TypedConnectionEvent<T>::pre_process()
 		src_node->dependants()->push_back(new ListNode<Node*>(dst_node));
 	}
 
-	if (m_patch->process())
+	if (m_patch->enabled())
 		m_process_order = m_patch->build_process_order();
 }
 
 
 template <typename T>
 void
-TypedConnectionEvent<T>::execute(SampleCount offset)
+TypedConnectionEvent<T>::execute(SampleCount nframes, FrameTime start, FrameTime end)
 {
 	if (m_succeeded) {
 		// These must be inserted here, since they're actually used by the audio thread
 		m_dst_port->add_connection(m_port_listnode);
 		m_patch->add_connection(m_patch_listnode);
 		if (m_patch->process_order() != NULL)
-			Engine::instance().maid()->push(m_patch->process_order());
+			_engine.maid()->push(m_patch->process_order());
 		m_patch->process_order(m_process_order);
 	}
 }
@@ -250,7 +250,7 @@ TypedConnectionEvent<T>::post_process()
 	
 		_responder->respond_ok();
 	
-		Engine::instance().client_broadcaster()->send_connection(m_connection);
+		_engine.client_broadcaster()->send_connection(m_connection);
 	} else {
 		_responder->respond_error("Unable to make connection.");
 	}
diff --git a/src/libs/engine/events/ConnectionEvent.h b/src/libs/engine/events/ConnectionEvent.h
index d5a580a5..2f65eb3a 100644
--- a/src/libs/engine/events/ConnectionEvent.h
+++ b/src/libs/engine/events/ConnectionEvent.h
@@ -46,11 +46,11 @@ template <typename T> class TypedConnectionEvent; // helper, defined below
 class ConnectionEvent : public QueuedEvent
 {
 public:
-	ConnectionEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& src_port_path, const string& dst_port_path);
+	ConnectionEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& src_port_path, const string& dst_port_path);
 	~ConnectionEvent();
 
 	void pre_process();
-	void execute(SampleCount offset);
+	void execute(SampleCount nframes, FrameTime start, FrameTime end);
 	void post_process();
 
 private:
@@ -80,10 +80,10 @@ template <typename T>
 class TypedConnectionEvent : public QueuedEvent
 {
 public:
-	TypedConnectionEvent(CountedPtr<Responder> responder, SampleCount timestamp, OutputPort<T>* src_port, InputPort<T>* dst_port);
+	TypedConnectionEvent(Engine& engine, CountedPtr<Responder> responder, FrameTime time, OutputPort<T>* src_port, InputPort<T>* dst_port);
 	
 	void pre_process();
-	void execute(SampleCount offset);
+	void execute(SampleCount nframes, FrameTime start, FrameTime end);
 	void post_process();
 
 private:
diff --git a/src/libs/engine/events/CreatePatchEvent.cpp b/src/libs/engine/events/CreatePatchEvent.cpp
index 65e2106d..d66a3ff9 100644
--- a/src/libs/engine/events/CreatePatchEvent.cpp
+++ b/src/libs/engine/events/CreatePatchEvent.cpp
@@ -30,8 +30,8 @@
 namespace Ingen {
 
 
-CreatePatchEvent::CreatePatchEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& path, int poly)
-: QueuedEvent(responder, timestamp),
+CreatePatchEvent::CreatePatchEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& path, int poly)
+: QueuedEvent(engine, responder, timestamp),
   m_path(path),
   m_patch(NULL),
   m_parent(NULL),
@@ -45,7 +45,7 @@ CreatePatchEvent::CreatePatchEvent(CountedPtr<Responder> responder, SampleCount
 void
 CreatePatchEvent::pre_process()
 {
-	if (Engine::instance().object_store()->find(m_path) != NULL) {
+	if (_engine.object_store()->find(m_path) != NULL) {
 		m_error = OBJECT_EXISTS;
 		QueuedEvent::pre_process();
 		return;
@@ -58,7 +58,7 @@ CreatePatchEvent::pre_process()
 	}
 	
 	if (m_path != "/") {
-		m_parent = Engine::instance().object_store()->find_patch(m_path.parent());
+		m_parent = _engine.object_store()->find_patch(m_path.parent());
 		if (m_parent == NULL) {
 			m_error = PARENT_NOT_FOUND;
 			QueuedEvent::pre_process();
@@ -70,34 +70,34 @@ CreatePatchEvent::pre_process()
 	if (m_parent != NULL && m_poly > 1 && m_poly == static_cast<int>(m_parent->internal_poly()))
 		poly = m_poly;
 	
-	m_patch = new Patch(m_path.name(), poly, m_parent, Engine::instance().audio_driver()->sample_rate(), Engine::instance().audio_driver()->buffer_size(), m_poly);
+	m_patch = new Patch(m_path.name(), poly, m_parent, _engine.audio_driver()->sample_rate(), _engine.audio_driver()->buffer_size(), m_poly);
 		
 	if (m_parent != NULL) {
 		m_parent->add_node(new ListNode<Node*>(m_patch));
 
-		if (m_parent->process())
+		if (m_parent->enabled())
 			m_process_order = m_parent->build_process_order();
 	}
 	
 	m_patch->activate();
 	
 	// Insert into ObjectStore
-	m_patch->add_to_store();
+	m_patch->add_to_store(_engine.object_store());
 	
 	QueuedEvent::pre_process();
 }
 
 
 void
-CreatePatchEvent::execute(SampleCount offset)
+CreatePatchEvent::execute(SampleCount nframes, FrameTime start, FrameTime end)
 {
-	QueuedEvent::execute(offset);
+	QueuedEvent::execute(nframes, start, end);
 
 	if (m_patch != NULL) {
 		if (m_parent == NULL) {
 			assert(m_path == "/");
 			assert(m_patch->parent_patch() == NULL);
-			Engine::instance().audio_driver()->set_root_patch(m_patch);
+			_engine.audio_driver()->set_root_patch(m_patch);
 		} else {
 			assert(m_parent != NULL);
 			assert(m_path != "/");
@@ -105,7 +105,7 @@ CreatePatchEvent::execute(SampleCount offset)
 			m_patch->add_to_patch();
 			
 			if (m_parent->process_order() != NULL)
-				Engine::instance().maid()->push(m_parent->process_order());
+				_engine.maid()->push(m_parent->process_order());
 			m_parent->process_order(m_process_order);
 		}
 	}
@@ -121,10 +121,10 @@ CreatePatchEvent::post_process()
 			_responder->respond_ok();
 			
 			// Don't want to send nodes that have been added since prepare()
-			//Engine::instance().client_broadcaster()->send_node_creation_messages(m_patch);
+			//_engine.client_broadcaster()->send_node_creation_messages(m_patch);
 
 			// Patches are always empty on creation, so this is fine
-			Engine::instance().client_broadcaster()->send_patch(m_patch);
+			_engine.client_broadcaster()->send_patch(m_patch);
 			
 		} else if (m_error == OBJECT_EXISTS) {
 			string msg = "Unable to create patch: ";
diff --git a/src/libs/engine/events/CreatePatchEvent.h b/src/libs/engine/events/CreatePatchEvent.h
index 581bb381..63a33271 100644
--- a/src/libs/engine/events/CreatePatchEvent.h
+++ b/src/libs/engine/events/CreatePatchEvent.h
@@ -39,10 +39,10 @@ class Plugin;
 class CreatePatchEvent : public QueuedEvent
 {
 public:
-	CreatePatchEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& path, int poly);
+	CreatePatchEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& path, int poly);
 
 	void pre_process();
-	void execute(SampleCount offset);
+	void execute(SampleCount nframes, FrameTime start, FrameTime end);
 	void post_process();
 
 private:
diff --git a/src/libs/engine/events/DSSIConfigureEvent.cpp b/src/libs/engine/events/DSSIConfigureEvent.cpp
index 59a7401c..de79a083 100644
--- a/src/libs/engine/events/DSSIConfigureEvent.cpp
+++ b/src/libs/engine/events/DSSIConfigureEvent.cpp
@@ -24,8 +24,8 @@
 namespace Ingen {
 
 
-DSSIConfigureEvent::DSSIConfigureEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path, const string& key, const string& val)
-: QueuedEvent(responder, timestamp),
+DSSIConfigureEvent::DSSIConfigureEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path, const string& key, const string& val)
+: QueuedEvent(engine, responder, timestamp),
   m_node_path(node_path),
   m_key(key),
   m_val(val),
@@ -37,7 +37,7 @@ DSSIConfigureEvent::DSSIConfigureEvent(CountedPtr<Responder> responder, SampleCo
 void
 DSSIConfigureEvent::pre_process()
 {
-	Node* node = Engine::instance().object_store()->find_node(m_node_path);
+	Node* node = _engine.object_store()->find_node(m_node_path);
 
 	if (node != NULL && node->plugin()->type() == Plugin::DSSI) {
 		m_node = (DSSINode*)node;
@@ -49,7 +49,7 @@ DSSIConfigureEvent::pre_process()
 
 	
 void
-DSSIConfigureEvent::execute(SampleCount offset)
+DSSIConfigureEvent::execute(SampleCount nframes, FrameTime start, FrameTime end)
 {
 	// Nothing.
 }
@@ -63,7 +63,7 @@ DSSIConfigureEvent::post_process()
 	} else {
 		string key = "dssi-configure--";
 		key += m_key;
-		Engine::instance().client_broadcaster()->send_metadata_update(m_node_path, key, m_val);
+		_engine.client_broadcaster()->send_metadata_update(m_node_path, key, m_val);
 	}
 }
 
diff --git a/src/libs/engine/events/DSSIConfigureEvent.h b/src/libs/engine/events/DSSIConfigureEvent.h
index 80769929..bef3fbb7 100644
--- a/src/libs/engine/events/DSSIConfigureEvent.h
+++ b/src/libs/engine/events/DSSIConfigureEvent.h
@@ -30,10 +30,10 @@ namespace Ingen {
 class DSSIConfigureEvent : public QueuedEvent
 {
 public:
-	DSSIConfigureEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path, const string& key, const string& val);
+	DSSIConfigureEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path, const string& key, const string& val);
 
 	void pre_process();
-	void execute(SampleCount offset);
+	void execute(SampleCount nframes, FrameTime start, FrameTime end);
 	void post_process();
 
 private:
diff --git a/src/libs/engine/events/DSSIControlEvent.cpp b/src/libs/engine/events/DSSIControlEvent.cpp
index 5ba8a87e..9ae4274b 100644
--- a/src/libs/engine/events/DSSIControlEvent.cpp
+++ b/src/libs/engine/events/DSSIControlEvent.cpp
@@ -23,8 +23,8 @@
 namespace Ingen {
 
 
-DSSIControlEvent::DSSIControlEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path, int port_num, Sample val)
-: QueuedEvent(responder, timestamp),
+DSSIControlEvent::DSSIControlEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path, int port_num, Sample val)
+: QueuedEvent(engine, responder, timestamp),
   m_node_path(node_path),
   m_port_num(port_num),
   m_val(val),
@@ -36,7 +36,7 @@ DSSIControlEvent::DSSIControlEvent(CountedPtr<Responder> responder, SampleCount
 void
 DSSIControlEvent::pre_process()
 {
-	Node* node = Engine::instance().object_store()->find_node(m_node_path);
+	Node* node = _engine.object_store()->find_node(m_node_path);
 
 	if (node->plugin()->type() != Plugin::DSSI)
 		m_node = NULL;
@@ -48,7 +48,7 @@ DSSIControlEvent::pre_process()
 
 	
 void
-DSSIControlEvent::execute(SampleCount offset)
+DSSIControlEvent::execute(SampleCount nframes, FrameTime start, FrameTime end)
 {
 	if (m_node != NULL)
 		m_node->set_control(m_port_num, m_val);
diff --git a/src/libs/engine/events/DSSIControlEvent.h b/src/libs/engine/events/DSSIControlEvent.h
index e7c8605d..9eeeb136 100644
--- a/src/libs/engine/events/DSSIControlEvent.h
+++ b/src/libs/engine/events/DSSIControlEvent.h
@@ -32,10 +32,10 @@ namespace Ingen {
 class DSSIControlEvent : public QueuedEvent
 {
 public:
-	DSSIControlEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path, int port_num, Sample val);
+	DSSIControlEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path, int port_num, Sample val);
 
 	void pre_process();
-	void execute(SampleCount offset);
+	void execute(SampleCount nframes, FrameTime start, FrameTime end);
 	void post_process();
 
 private:
diff --git a/src/libs/engine/events/DSSIProgramEvent.cpp b/src/libs/engine/events/DSSIProgramEvent.cpp
index 3d62e5b8..4545268a 100644
--- a/src/libs/engine/events/DSSIProgramEvent.cpp
+++ b/src/libs/engine/events/DSSIProgramEvent.cpp
@@ -28,8 +28,8 @@ using std::cout; using std::cerr; using std::endl;
 namespace Ingen {
 
 
-DSSIProgramEvent::DSSIProgramEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path, int bank, int program)
-: QueuedEvent(responder, timestamp),
+DSSIProgramEvent::DSSIProgramEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path, int bank, int program)
+: QueuedEvent(engine, responder, timestamp),
   m_node_path(node_path),
   m_bank(bank),
   m_program(program),
@@ -41,7 +41,7 @@ DSSIProgramEvent::DSSIProgramEvent(CountedPtr<Responder> responder, SampleCount
 void
 DSSIProgramEvent::pre_process()
 {
-	Node* node = Engine::instance().object_store()->find_node(m_node_path);
+	Node* node = _engine.object_store()->find_node(m_node_path);
 
 	if (node != NULL && node->plugin()->type() == Plugin::DSSI)
 		m_node = (DSSINode*)node;
@@ -51,7 +51,7 @@ DSSIProgramEvent::pre_process()
 
 	
 void
-DSSIProgramEvent::execute(SampleCount offset)
+DSSIProgramEvent::execute(SampleCount nframes, FrameTime start, FrameTime end)
 {
 	if (m_node != NULL)
 		m_node->program(m_bank, m_program);
@@ -67,7 +67,7 @@ DSSIProgramEvent::post_process()
 		// sends program as metadata in the form bank/program
 		char* temp_buf = new char[16];
 		snprintf(temp_buf, 16, "%d/%d", m_bank, m_program);
-		Engine::instance().client_broadcaster()->send_metadata_update(m_node_path, "dssi-program", temp_buf);
+		_engine.client_broadcaster()->send_metadata_update(m_node_path, "dssi-program", temp_buf);
 	}
 }
 
diff --git a/src/libs/engine/events/DSSIProgramEvent.h b/src/libs/engine/events/DSSIProgramEvent.h
index 864110f4..51967cf0 100644
--- a/src/libs/engine/events/DSSIProgramEvent.h
+++ b/src/libs/engine/events/DSSIProgramEvent.h
@@ -30,10 +30,10 @@ namespace Ingen {
 class DSSIProgramEvent : public QueuedEvent
 {
 public:
-	DSSIProgramEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path, int bank, int program);
+	DSSIProgramEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path, int bank, int program);
 
 	void pre_process();
-	void execute(SampleCount offset);
+	void execute(SampleCount nframes, FrameTime start, FrameTime end);
 	void post_process();
 
 private:
diff --git a/src/libs/engine/events/DSSIUpdateEvent.cpp b/src/libs/engine/events/DSSIUpdateEvent.cpp
index 48590917..d2953a9b 100644
--- a/src/libs/engine/events/DSSIUpdateEvent.cpp
+++ b/src/libs/engine/events/DSSIUpdateEvent.cpp
@@ -27,8 +27,8 @@ using std::cerr; using std::endl;
 namespace Ingen {
 
 
-DSSIUpdateEvent::DSSIUpdateEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& path, const string& url)
-: QueuedEvent(responder, timestamp),
+DSSIUpdateEvent::DSSIUpdateEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& path, const string& url)
+: QueuedEvent(engine, responder, timestamp),
   m_path(path),
   m_url(url),
   m_node(NULL)
@@ -39,7 +39,7 @@ DSSIUpdateEvent::DSSIUpdateEvent(CountedPtr<Responder> responder, SampleCount ti
 void
 DSSIUpdateEvent::pre_process()
 {
-	Node* node = Engine::instance().object_store()->find_node(m_path);
+	Node* node = _engine.object_store()->find_node(m_path);
 
 	if (node == NULL || node->plugin()->type() != Plugin::DSSI) {
 		m_node = NULL;
@@ -54,13 +54,13 @@ DSSIUpdateEvent::pre_process()
 
 
 void
-DSSIUpdateEvent::execute(SampleCount offset)
+DSSIUpdateEvent::execute(SampleCount nframes, FrameTime start, FrameTime end)
 {
 	if (m_node != NULL) {
 		m_node->set_ui_url(m_url);
 	}
 	
-	QueuedEvent::execute(offset);
+	QueuedEvent::execute(nframes, start, end);
 }
 
 
diff --git a/src/libs/engine/events/DSSIUpdateEvent.h b/src/libs/engine/events/DSSIUpdateEvent.h
index bddbc21d..91163efe 100644
--- a/src/libs/engine/events/DSSIUpdateEvent.h
+++ b/src/libs/engine/events/DSSIUpdateEvent.h
@@ -36,10 +36,10 @@ class DSSINode;
 class DSSIUpdateEvent : public QueuedEvent
 {
 public:
-	DSSIUpdateEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& path, const string& url);
+	DSSIUpdateEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& path, const string& url);
 	
 	void pre_process();
-	void execute(SampleCount offset);
+	void execute(SampleCount nframes, FrameTime start, FrameTime end);
 	void post_process();
 
 private:
diff --git a/src/libs/engine/events/DeactivateEvent.cpp b/src/libs/engine/events/DeactivateEvent.cpp
index e1c0541e..ff1740dc 100644
--- a/src/libs/engine/events/DeactivateEvent.cpp
+++ b/src/libs/engine/events/DeactivateEvent.cpp
@@ -21,8 +21,8 @@
 namespace Ingen {
 
 
-DeactivateEvent::DeactivateEvent(CountedPtr<Responder> responder, SampleCount timestamp)
-: QueuedEvent(responder, timestamp)
+DeactivateEvent::DeactivateEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp)
+: QueuedEvent(engine, responder, timestamp)
 {
 }
 
@@ -35,9 +35,9 @@ DeactivateEvent::pre_process()
 
 
 void
-DeactivateEvent::execute(SampleCount offset)
+DeactivateEvent::execute(SampleCount nframes, FrameTime start, FrameTime end)
 {
-	QueuedEvent::execute(offset);
+	QueuedEvent::execute(nframes, start, end);
 }
 
 
@@ -45,7 +45,7 @@ void
 DeactivateEvent::post_process()
 {
 	_responder->respond_ok();
-	Engine::instance().deactivate();
+	_engine.deactivate();
 }
 
 
diff --git a/src/libs/engine/events/DeactivateEvent.h b/src/libs/engine/events/DeactivateEvent.h
index 0fd79d32..ddeb75f5 100644
--- a/src/libs/engine/events/DeactivateEvent.h
+++ b/src/libs/engine/events/DeactivateEvent.h
@@ -29,10 +29,10 @@ namespace Ingen {
 class DeactivateEvent : public QueuedEvent
 {
 public:
-	DeactivateEvent(CountedPtr<Responder> responder, SampleCount timestamp);
+	DeactivateEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp);
 	
 	void pre_process();
-	void execute(SampleCount offset);
+	void execute(SampleCount nframes, FrameTime start, FrameTime end);
 	void post_process();
 };
 
diff --git a/src/libs/engine/events/DestroyEvent.cpp b/src/libs/engine/events/DestroyEvent.cpp
index d55a2935..dd172e7f 100644
--- a/src/libs/engine/events/DestroyEvent.cpp
+++ b/src/libs/engine/events/DestroyEvent.cpp
@@ -34,8 +34,8 @@
 namespace Ingen {
 
 
-DestroyEvent::DestroyEvent(CountedPtr<Responder> responder, SampleCount timestamp, QueuedEventSource* source, const string& path, bool lock_mutex)
-: QueuedEvent(responder, true, source),
+DestroyEvent::DestroyEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, QueuedEventSource* source, const string& path, bool lock_mutex)
+: QueuedEvent(engine, responder, true, source),
   m_path(path),
   m_node(NULL),
   m_patch_listnode(NULL),
@@ -47,8 +47,8 @@ DestroyEvent::DestroyEvent(CountedPtr<Responder> responder, SampleCount timestam
 }
 
 
-DestroyEvent::DestroyEvent(CountedPtr<Responder> responder, SampleCount timestamp, Node* node, bool lock_mutex)
-: QueuedEvent(responder, true),
+DestroyEvent::DestroyEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, Node* node, bool lock_mutex)
+: QueuedEvent(engine, responder, true),
   m_path(node->path()),
   m_node(node),
   m_patch_listnode(NULL),
@@ -71,7 +71,7 @@ void
 DestroyEvent::pre_process()
 {
 	if (m_node == NULL)
-		m_node = Engine::instance().object_store()->find_node(m_path);
+		m_node = _engine.object_store()->find_node(m_path);
 
 	if (m_node != NULL && m_path != "/") {
 		assert(m_node->parent_patch() != NULL);
@@ -82,7 +82,7 @@ DestroyEvent::pre_process()
 			m_node->remove_from_store();
 
 			if (m_node->providers()->size() != 0 || m_node->dependants()->size() != 0) {
-				m_disconnect_event = new DisconnectNodeEvent(m_node);
+				m_disconnect_event = new DisconnectNodeEvent(_engine, m_node);
 				m_disconnect_event->pre_process();
 			}
 			
@@ -90,11 +90,11 @@ DestroyEvent::pre_process()
 			cerr << "FIXME: Destroy bridge\n";
 			/*Port* parent_port = m_patch_listnode->elem()->as_port();
 			if (parent_port != NULL) {  // Bridge node
-				m_parent_disconnect_event = new DisconnectPortEvent(parent_port);
+				m_parent_disconnect_event = new DisconnectPortEvent(Engine& engine, parent_port);
 				m_parent_disconnect_event->pre_process();
 			}*/
 				
-			if (m_node->parent_patch()->process()) {
+			if (m_node->parent_patch()->enabled()) {
 				m_process_order = m_node->parent_patch()->build_process_order();
 				// Remove node to be removed from the process order so it isn't executed by
 				// Patch::run and can safely be destroyed
@@ -116,20 +116,20 @@ DestroyEvent::pre_process()
 
 
 void
-DestroyEvent::execute(SampleCount offset)
+DestroyEvent::execute(SampleCount nframes, FrameTime start, FrameTime end)
 {
-	QueuedEvent::execute(offset);
+	QueuedEvent::execute(nframes, start, end);
 
 	if (m_patch_listnode != NULL) {
 		m_node->remove_from_patch();
 		
 		if (m_disconnect_event != NULL)
-			m_disconnect_event->execute(offset);
+			m_disconnect_event->execute(nframes, start, end);
 		if (m_parent_disconnect_event != NULL)
-			m_parent_disconnect_event->execute(offset);
+			m_parent_disconnect_event->execute(nframes, start, end);
 		
 		if (m_node->parent_patch()->process_order() != NULL)
-			Engine::instance().maid()->push(m_node->parent_patch()->process_order());
+			_engine.maid()->push(m_node->parent_patch()->process_order());
 		m_node->parent_patch()->process_order(m_process_order);
 	}
 }
@@ -153,9 +153,9 @@ DestroyEvent::post_process()
 			m_disconnect_event->post_process();
 		if (m_parent_disconnect_event != NULL)
 			m_parent_disconnect_event->post_process();
-		Engine::instance().client_broadcaster()->send_destroyed(m_path);
-		Engine::instance().maid()->push(m_patch_listnode);
-		Engine::instance().maid()->push(m_node);
+		_engine.client_broadcaster()->send_destroyed(m_path);
+		_engine.maid()->push(m_patch_listnode);
+		_engine.maid()->push(m_node);
 	} else {
 		_responder->respond_error("Unable to destroy object");
 	}
diff --git a/src/libs/engine/events/DestroyEvent.h b/src/libs/engine/events/DestroyEvent.h
index de4686c1..6eda8006 100644
--- a/src/libs/engine/events/DestroyEvent.h
+++ b/src/libs/engine/events/DestroyEvent.h
@@ -44,12 +44,12 @@ class DisconnectPortEvent;
 class DestroyEvent : public QueuedEvent
 {
 public:
-	DestroyEvent(CountedPtr<Responder> responder, SampleCount timestamp, QueuedEventSource* source, const string& path, bool lock_mutex = true);
-	DestroyEvent(CountedPtr<Responder> responder, SampleCount timestamp, Node* node, bool lock_mutex = true);
+	DestroyEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, QueuedEventSource* source, const string& path, bool lock_mutex = true);
+	DestroyEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, Node* node, bool lock_mutex = true);
 	~DestroyEvent();
 
 	void pre_process();
-	void execute(SampleCount offset);
+	void execute(SampleCount nframes, FrameTime start, FrameTime end);
 	void post_process();
 
 private:
diff --git a/src/libs/engine/events/DisablePatchEvent.cpp b/src/libs/engine/events/DisablePatchEvent.cpp
index 45b19f54..299e4fdc 100644
--- a/src/libs/engine/events/DisablePatchEvent.cpp
+++ b/src/libs/engine/events/DisablePatchEvent.cpp
@@ -26,8 +26,8 @@
 namespace Ingen {
 
 
-DisablePatchEvent::DisablePatchEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& patch_path)
-: QueuedEvent(responder, timestamp),
+DisablePatchEvent::DisablePatchEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& patch_path)
+: QueuedEvent(engine, responder, timestamp),
   m_patch_path(patch_path),
   m_patch(NULL)
 {
@@ -37,19 +37,19 @@ DisablePatchEvent::DisablePatchEvent(CountedPtr<Responder> responder, SampleCoun
 void
 DisablePatchEvent::pre_process()
 {
-	m_patch = Engine::instance().object_store()->find_patch(m_patch_path);
+	m_patch = _engine.object_store()->find_patch(m_patch_path);
 	
 	QueuedEvent::pre_process();
 }
 
 
 void
-DisablePatchEvent::execute(SampleCount offset)
+DisablePatchEvent::execute(SampleCount nframes, FrameTime start, FrameTime end)
 {
 	if (m_patch != NULL)
-		m_patch->process(false);
+		m_patch->disable();
 
-	QueuedEvent::execute(offset);
+	QueuedEvent::execute(nframes, start, end);
 }
 
 
@@ -58,7 +58,7 @@ DisablePatchEvent::post_process()
 {	
 	if (m_patch != NULL) {
 		_responder->respond_ok();
-		Engine::instance().client_broadcaster()->send_patch_disable(m_patch_path);
+		_engine.client_broadcaster()->send_patch_disable(m_patch_path);
 	} else {
 		_responder->respond_error(string("Patch ") + m_patch_path + " not found");
 	}
diff --git a/src/libs/engine/events/DisablePatchEvent.h b/src/libs/engine/events/DisablePatchEvent.h
index 10721825..09347b08 100644
--- a/src/libs/engine/events/DisablePatchEvent.h
+++ b/src/libs/engine/events/DisablePatchEvent.h
@@ -34,10 +34,10 @@ class Patch;
 class DisablePatchEvent : public QueuedEvent
 {
 public:
-	DisablePatchEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& patch_path);
+	DisablePatchEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& patch_path);
 	
 	void pre_process();
-	void execute(SampleCount offset);
+	void execute(SampleCount nframes, FrameTime start, FrameTime end);
 	void post_process();
 
 private:
diff --git a/src/libs/engine/events/DisconnectNodeEvent.cpp b/src/libs/engine/events/DisconnectNodeEvent.cpp
index 7955f602..c1a965ad 100644
--- a/src/libs/engine/events/DisconnectNodeEvent.cpp
+++ b/src/libs/engine/events/DisconnectNodeEvent.cpp
@@ -38,8 +38,8 @@ using std::cerr; using std::endl;
 namespace Ingen {
 
 
-DisconnectNodeEvent::DisconnectNodeEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path)
-: QueuedEvent(responder, timestamp),
+DisconnectNodeEvent::DisconnectNodeEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path)
+: QueuedEvent(engine, responder, timestamp),
   m_node_path(node_path),
   m_patch(NULL),
   m_node(NULL),
@@ -51,8 +51,8 @@ DisconnectNodeEvent::DisconnectNodeEvent(CountedPtr<Responder> responder, Sample
 
 /** Internal version, disconnects parent port as well (in the case of InputNode, etc).
  */
-DisconnectNodeEvent::DisconnectNodeEvent(Node* node)
-: QueuedEvent(),
+DisconnectNodeEvent::DisconnectNodeEvent(Engine& engine, Node* node)
+: QueuedEvent(engine),
   m_node_path(""),
   m_patch(node->parent_patch()),
   m_node(node),
@@ -77,7 +77,7 @@ DisconnectNodeEvent::pre_process()
 	// cerr << "Preparing disconnection event...\n";
 	
 	if (m_lookup) {
-		m_patch = Engine::instance().object_store()->find_patch(m_node_path.parent());
+		m_patch = _engine.object_store()->find_patch(m_node_path.parent());
 	
 		if (m_patch == NULL) {
 			m_succeeded = false;
@@ -85,7 +85,7 @@ DisconnectNodeEvent::pre_process()
 			return;
 		}
 		
-		m_node = Engine::instance().object_store()->find_node(m_node_path);
+		m_node = _engine.object_store()->find_node(m_node_path);
 		
 		if (m_node == NULL) {
 			m_succeeded = false;
@@ -98,7 +98,7 @@ DisconnectNodeEvent::pre_process()
 	for (ConnectionListIterator i = m_patch->connections().begin(); i != m_patch->connections().end(); ++i) {
 		c = (*i);
 		if ((c->src_port()->parent_node() == m_node || c->dst_port()->parent_node() == m_node) && !c->pending_disconnection()) {
-			DisconnectionEvent* ev = new DisconnectionEvent(CountedPtr<Responder>(new Responder()), _time_stamp,
+			DisconnectionEvent* ev = new DisconnectionEvent(_engine, CountedPtr<Responder>(new Responder()), _time,
 				c->src_port(), c->dst_port());
 			ev->pre_process();
 			m_disconnection_events.push_back(new ListNode<DisconnectionEvent*>(ev));
@@ -112,14 +112,14 @@ DisconnectNodeEvent::pre_process()
 
 
 void
-DisconnectNodeEvent::execute(SampleCount offset)
+DisconnectNodeEvent::execute(SampleCount nframes, FrameTime start, FrameTime end)
 {
 	if (m_succeeded) {
 		for (List<DisconnectionEvent*>::iterator i = m_disconnection_events.begin(); i != m_disconnection_events.end(); ++i)
-			(*i)->execute(offset);
+			(*i)->execute(nframes, start, end);
 	}
 	
-	QueuedEvent::execute(offset);
+	QueuedEvent::execute(nframes, start, end);
 }
 
 
diff --git a/src/libs/engine/events/DisconnectNodeEvent.h b/src/libs/engine/events/DisconnectNodeEvent.h
index d45fff39..90aeabed 100644
--- a/src/libs/engine/events/DisconnectNodeEvent.h
+++ b/src/libs/engine/events/DisconnectNodeEvent.h
@@ -42,12 +42,12 @@ template <typename T> class OutputPort;
 class DisconnectNodeEvent : public QueuedEvent
 {
 public:
-	DisconnectNodeEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path);
-	DisconnectNodeEvent(Node* node);
+	DisconnectNodeEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path);
+	DisconnectNodeEvent(Engine& engine, Node* node);
 	~DisconnectNodeEvent();
 
 	void pre_process();
-	void execute(SampleCount offset);
+	void execute(SampleCount nframes, FrameTime start, FrameTime end);
 	void post_process();
 
 private:
diff --git a/src/libs/engine/events/DisconnectPortEvent.cpp b/src/libs/engine/events/DisconnectPortEvent.cpp
index 2126dffd..41ceff8b 100644
--- a/src/libs/engine/events/DisconnectPortEvent.cpp
+++ b/src/libs/engine/events/DisconnectPortEvent.cpp
@@ -38,8 +38,8 @@ using std::cerr; using std::endl;
 namespace Ingen {
 
 
-DisconnectPortEvent::DisconnectPortEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& port_path)
-: QueuedEvent(responder, timestamp),
+DisconnectPortEvent::DisconnectPortEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& port_path)
+: QueuedEvent(engine, responder, timestamp),
   m_port_path(port_path),
   m_patch(NULL),
   m_port(NULL),
@@ -50,8 +50,8 @@ DisconnectPortEvent::DisconnectPortEvent(CountedPtr<Responder> responder, Sample
 }
 
 
-DisconnectPortEvent::DisconnectPortEvent(Port* port)
-: QueuedEvent(),
+DisconnectPortEvent::DisconnectPortEvent(Engine& engine, Port* port)
+: QueuedEvent(engine),
   m_port_path(""),
   m_patch((port->parent_node() == NULL) ? NULL : port->parent_node()->parent_patch()),
   m_port(port),
@@ -59,7 +59,7 @@ DisconnectPortEvent::DisconnectPortEvent(Port* port)
   m_succeeded(true),
   m_lookup(false)
 {
-	//cerr << "DisconnectPortEvent()\n";
+	//cerr << "DisconnectPortEvent(Engine& engine, )\n";
 }
 
 
@@ -76,7 +76,7 @@ DisconnectPortEvent::pre_process()
 	// cerr << "Preparing disconnection event...\n";
 	
 	if (m_lookup) {
-		m_patch = Engine::instance().object_store()->find_patch(m_port_path.parent().parent());
+		m_patch = _engine.object_store()->find_patch(m_port_path.parent().parent());
 	
 		if (m_patch == NULL) {
 			m_succeeded = false;
@@ -84,7 +84,7 @@ DisconnectPortEvent::pre_process()
 			return;
 		}
 		
-		m_port = Engine::instance().object_store()->find_port(m_port_path);
+		m_port = _engine.object_store()->find_port(m_port_path);
 		
 		if (m_port == NULL) {
 			m_succeeded = false;
@@ -103,7 +103,7 @@ DisconnectPortEvent::pre_process()
 	for (List<Connection*>::const_iterator i = m_patch->connections().begin(); i != m_patch->connections().end(); ++i) {
 		c = (*i);
 		if ((c->src_port() == m_port || c->dst_port() == m_port) && !c->pending_disconnection()) {
-			DisconnectionEvent* ev = new DisconnectionEvent(CountedPtr<Responder>(new Responder()), _time_stamp,
+			DisconnectionEvent* ev = new DisconnectionEvent(_engine, CountedPtr<Responder>(new Responder()), _time,
 					c->src_port(), c->dst_port());
 			ev->pre_process();
 			m_disconnection_events.push_back(new ListNode<DisconnectionEvent*>(ev));
@@ -117,14 +117,14 @@ DisconnectPortEvent::pre_process()
 
 
 void
-DisconnectPortEvent::execute(SampleCount offset)
+DisconnectPortEvent::execute(SampleCount nframes, FrameTime start, FrameTime end)
 {
 	if (m_succeeded) {
 		for (List<DisconnectionEvent*>::iterator i = m_disconnection_events.begin(); i != m_disconnection_events.end(); ++i)
-			(*i)->execute(offset);
+			(*i)->execute(nframes, start, end);
 	}
 	
-	QueuedEvent::execute(offset);
+	QueuedEvent::execute(nframes, start, end);
 }
 
 
diff --git a/src/libs/engine/events/DisconnectPortEvent.h b/src/libs/engine/events/DisconnectPortEvent.h
index 639de102..0c185317 100644
--- a/src/libs/engine/events/DisconnectPortEvent.h
+++ b/src/libs/engine/events/DisconnectPortEvent.h
@@ -43,12 +43,12 @@ using std::string;
 class DisconnectPortEvent : public QueuedEvent
 {
 public:
-	DisconnectPortEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& port_path);
-	DisconnectPortEvent(Port* port);
+	DisconnectPortEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& port_path);
+	DisconnectPortEvent(Engine& engine, Port* port);
 	~DisconnectPortEvent();
 
 	void pre_process();
-	void execute(SampleCount offset);
+	void execute(SampleCount nframes, FrameTime start, FrameTime end);
 	void post_process();
 
 private:
diff --git a/src/libs/engine/events/DisconnectionEvent.cpp b/src/libs/engine/events/DisconnectionEvent.cpp
index 431061a2..c246e9dc 100644
--- a/src/libs/engine/events/DisconnectionEvent.cpp
+++ b/src/libs/engine/events/DisconnectionEvent.cpp
@@ -35,8 +35,8 @@ namespace Ingen {
 //// DisconnectionEvent ////
 
 
-DisconnectionEvent::DisconnectionEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& src_port_path, const string& dst_port_path)
-: QueuedEvent(responder, timestamp),
+DisconnectionEvent::DisconnectionEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& src_port_path, const string& dst_port_path)
+: QueuedEvent(engine, responder, timestamp),
   m_src_port_path(src_port_path),
   m_dst_port_path(dst_port_path),
   m_patch(NULL),
@@ -49,8 +49,8 @@ DisconnectionEvent::DisconnectionEvent(CountedPtr<Responder> responder, SampleCo
 }
 
 
-DisconnectionEvent::DisconnectionEvent(CountedPtr<Responder> responder, SampleCount timestamp, Port* const src_port, Port* const dst_port)
-: QueuedEvent(responder, timestamp),
+DisconnectionEvent::DisconnectionEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, Port* const src_port, Port* const dst_port)
+: QueuedEvent(engine, responder, timestamp),
   m_src_port_path(src_port->path()),
   m_dst_port_path(dst_port->path()),
   m_patch(src_port->parent_node()->parent_patch()),
@@ -85,7 +85,7 @@ DisconnectionEvent::pre_process()
 			return;
 		}
 
-		/*m_patch = Engine::instance().object_store()->find_patch(m_src_port_path.parent().parent());
+		/*m_patch = _engine.object_store()->find_patch(m_src_port_path.parent().parent());
 
 		  if (m_patch == NULL) {
 		  m_error = PORT_NOT_FOUND;
@@ -93,8 +93,8 @@ DisconnectionEvent::pre_process()
 		  return;
 		  }*/
 
-		m_src_port = Engine::instance().object_store()->find_port(m_src_port_path);
-		m_dst_port = Engine::instance().object_store()->find_port(m_dst_port_path);
+		m_src_port = _engine.object_store()->find_port(m_src_port_path);
+		m_dst_port = _engine.object_store()->find_port(m_dst_port_path);
 	}
 	
 	if (m_src_port == NULL || m_dst_port == NULL) {
@@ -112,10 +112,10 @@ DisconnectionEvent::pre_process()
 	// Create the typed event to actually do the work
 	const DataType type = m_src_port->type();
 	if (type == DataType::FLOAT) {
-		m_typed_event = new TypedDisconnectionEvent<Sample>(_responder, _time_stamp,
+		m_typed_event = new TypedDisconnectionEvent<Sample>(_engine, _responder, _time,
 				dynamic_cast<OutputPort<Sample>*>(m_src_port), dynamic_cast<InputPort<Sample>*>(m_dst_port));
 	} else if (type == DataType::MIDI) {
-		m_typed_event = new TypedDisconnectionEvent<MidiMessage>(_responder, _time_stamp,
+		m_typed_event = new TypedDisconnectionEvent<MidiMessage>(_engine, _responder, _time,
 				dynamic_cast<OutputPort<MidiMessage>*>(m_src_port), dynamic_cast<InputPort<MidiMessage>*>(m_dst_port));
 	} else {
 		m_error = TYPE_MISMATCH;
@@ -131,12 +131,12 @@ DisconnectionEvent::pre_process()
 
 
 void
-DisconnectionEvent::execute(SampleCount offset)
+DisconnectionEvent::execute(SampleCount nframes, FrameTime start, FrameTime end)
 {
-	QueuedEvent::execute(offset);
+	QueuedEvent::execute(nframes, start, end);
 
 	if (m_error == NO_ERROR)
-		m_typed_event->execute(offset);
+		m_typed_event->execute(nframes, start, end);
 }
 
 
@@ -159,8 +159,8 @@ DisconnectionEvent::post_process()
 
 
 template <typename T>
-TypedDisconnectionEvent<T>::TypedDisconnectionEvent(CountedPtr<Responder> responder, SampleCount timestamp, OutputPort<T>* src_port, InputPort<T>* dst_port)
-: QueuedEvent(responder, timestamp),
+TypedDisconnectionEvent<T>::TypedDisconnectionEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, OutputPort<T>* src_port, InputPort<T>* dst_port)
+: QueuedEvent(engine, responder, timestamp),
   m_src_port(src_port),
   m_dst_port(dst_port),
   m_patch(NULL),
@@ -223,7 +223,7 @@ TypedDisconnectionEvent<T>::pre_process()
 			break;
 		}
 	
-	if (m_patch->process())
+	if (m_patch->enabled())
 		m_process_order = m_patch->build_process_order();
 	
 	m_succeeded = true;
@@ -233,7 +233,7 @@ TypedDisconnectionEvent<T>::pre_process()
 
 template <typename T>
 void
-TypedDisconnectionEvent<T>::execute(SampleCount offset)
+TypedDisconnectionEvent<T>::execute(SampleCount nframes, FrameTime start, FrameTime end)
 {
 	if (m_succeeded) {
 
@@ -248,18 +248,18 @@ TypedDisconnectionEvent<T>::execute(SampleCount offset)
 			assert((Connection*)port_connection->elem() == patch_connection->elem());
 			
 			// Clean up both the list node and the connection itself...
-			Engine::instance().maid()->push(port_connection);
-			Engine::instance().maid()->push(patch_connection);
-			Engine::instance().maid()->push(port_connection->elem());
+			_engine.maid()->push(port_connection);
+			_engine.maid()->push(patch_connection);
+			_engine.maid()->push(port_connection->elem());
 	
 			if (m_patch->process_order() != NULL)
-				Engine::instance().maid()->push(m_patch->process_order());
+				_engine.maid()->push(m_patch->process_order());
 			m_patch->process_order(m_process_order);
 		} else {
 			m_succeeded = false;  // Ports weren't connected
 		}
 	}
-	QueuedEvent::execute(offset);
+	QueuedEvent::execute(nframes, start, end);
 }
 
 
@@ -271,7 +271,7 @@ TypedDisconnectionEvent<T>::post_process()
 	
 		_responder->respond_ok();
 	
-		Engine::instance().client_broadcaster()->send_disconnection(m_src_port->path(), m_dst_port->path());
+		_engine.client_broadcaster()->send_disconnection(m_src_port->path(), m_dst_port->path());
 	} else {
 		_responder->respond_error("Unable to disconnect ports.");
 	}
diff --git a/src/libs/engine/events/DisconnectionEvent.h b/src/libs/engine/events/DisconnectionEvent.h
index 3108f2f8..1dc53d13 100644
--- a/src/libs/engine/events/DisconnectionEvent.h
+++ b/src/libs/engine/events/DisconnectionEvent.h
@@ -46,12 +46,12 @@ template <typename T> class TypedDisconnectionEvent; // helper, defined below
 class DisconnectionEvent : public QueuedEvent
 {
 public:
-	DisconnectionEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& src_port_path, const string& dst_port_path);
-	DisconnectionEvent(CountedPtr<Responder> responder, SampleCount timestamp, Port* const src_port, Port* const dst_port);
+	DisconnectionEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& src_port_path, const string& dst_port_path);
+	DisconnectionEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, Port* const src_port, Port* const dst_port);
 	~DisconnectionEvent();
 
 	void pre_process();
-	void execute(SampleCount offset);
+	void execute(SampleCount nframes, FrameTime start, FrameTime end);
 	void post_process();
 
 private:
@@ -82,10 +82,10 @@ template <typename T>
 class TypedDisconnectionEvent : public QueuedEvent
 {
 public:
-	TypedDisconnectionEvent(CountedPtr<Responder> responder, SampleCount timestamp, OutputPort<T>* src_port, InputPort<T>* dst_port);
+	TypedDisconnectionEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, OutputPort<T>* src_port, InputPort<T>* dst_port);
 	
 	void pre_process();
-	void execute(SampleCount offset);
+	void execute(SampleCount nframes, FrameTime start, FrameTime end);
 	void post_process();
 
 private:
diff --git a/src/libs/engine/events/EnablePatchEvent.cpp b/src/libs/engine/events/EnablePatchEvent.cpp
index b2b3ee08..132aefcc 100644
--- a/src/libs/engine/events/EnablePatchEvent.cpp
+++ b/src/libs/engine/events/EnablePatchEvent.cpp
@@ -25,8 +25,8 @@
 namespace Ingen {
 
 
-EnablePatchEvent::EnablePatchEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& patch_path)
-: QueuedEvent(responder, timestamp),
+EnablePatchEvent::EnablePatchEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& patch_path)
+: QueuedEvent(engine, responder, timestamp),
   m_patch_path(patch_path),
   m_patch(NULL),
   m_process_order(NULL)
@@ -37,7 +37,7 @@ EnablePatchEvent::EnablePatchEvent(CountedPtr<Responder> responder, SampleCount
 void
 EnablePatchEvent::pre_process()
 {
-	m_patch = Engine::instance().object_store()->find_patch(m_patch_path);
+	m_patch = _engine.object_store()->find_patch(m_patch_path);
 	
 	if (m_patch != NULL) {
 		/* Any event that requires a new process order will set the patch's
@@ -52,16 +52,16 @@ EnablePatchEvent::pre_process()
 
 
 void
-EnablePatchEvent::execute(SampleCount offset)
+EnablePatchEvent::execute(SampleCount nframes, FrameTime start, FrameTime end)
 {
 	if (m_patch != NULL) {
-		m_patch->process(true);
+		m_patch->enable();
 
 		if (m_patch->process_order() == NULL)
 			m_patch->process_order(m_process_order);
 	}
 	
-	QueuedEvent::execute(offset);
+	QueuedEvent::execute(nframes, start, end);
 }
 
 
@@ -70,7 +70,7 @@ EnablePatchEvent::post_process()
 {
 	if (m_patch != NULL) {
 		_responder->respond_ok();
-		Engine::instance().client_broadcaster()->send_patch_enable(m_patch_path);
+		_engine.client_broadcaster()->send_patch_enable(m_patch_path);
 	} else {
 		_responder->respond_error(string("Patch ") + m_patch_path + " not found");
 	}
diff --git a/src/libs/engine/events/EnablePatchEvent.h b/src/libs/engine/events/EnablePatchEvent.h
index 4ae93099..8e39e3a7 100644
--- a/src/libs/engine/events/EnablePatchEvent.h
+++ b/src/libs/engine/events/EnablePatchEvent.h
@@ -37,10 +37,10 @@ class Node;
 class EnablePatchEvent : public QueuedEvent
 {
 public:
-	EnablePatchEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& patch_path);
+	EnablePatchEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& patch_path);
 	
 	void pre_process();
-	void execute(SampleCount offset);
+	void execute(SampleCount nframes, FrameTime start, FrameTime end);
 	void post_process();
 
 private:
diff --git a/src/libs/engine/events/LashRestoreDoneEvent.h b/src/libs/engine/events/LashRestoreDoneEvent.h
index b543905c..be07bed0 100644
--- a/src/libs/engine/events/LashRestoreDoneEvent.h
+++ b/src/libs/engine/events/LashRestoreDoneEvent.h
@@ -39,7 +39,7 @@ class Port;
 class LashRestoreDoneEvent : public QueuedEvent
 {
 public:
-	LashRestoreDoneEvent(CountedPtr<Responder> responder, SampleCount timestamp) : QueuedEvent(responder, timestamp) {}
+	LashRestoreDoneEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp) : QueuedEvent(engine, responder, timestamp) {}
 
 	void post_process()
 	{
diff --git a/src/libs/engine/events/LoadPluginsEvent.cpp b/src/libs/engine/events/LoadPluginsEvent.cpp
index cae25733..6962387b 100644
--- a/src/libs/engine/events/LoadPluginsEvent.cpp
+++ b/src/libs/engine/events/LoadPluginsEvent.cpp
@@ -25,11 +25,11 @@ using std::cerr;
 namespace Ingen {
 
 
-LoadPluginsEvent::LoadPluginsEvent(CountedPtr<Responder> responder, SampleCount timestamp)
-: QueuedEvent(responder, timestamp)
+LoadPluginsEvent::LoadPluginsEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp)
+: QueuedEvent(engine, responder, timestamp)
 {
 	cerr << "LOADING PLUGINS\n";
-	Engine::instance().node_factory()->load_plugins();
+	_engine.node_factory()->load_plugins();
 }
 
 
diff --git a/src/libs/engine/events/LoadPluginsEvent.h b/src/libs/engine/events/LoadPluginsEvent.h
index 0e40ca7e..ae784e3a 100644
--- a/src/libs/engine/events/LoadPluginsEvent.h
+++ b/src/libs/engine/events/LoadPluginsEvent.h
@@ -29,7 +29,7 @@ namespace Ingen {
 class LoadPluginsEvent : public QueuedEvent
 {
 public:
-	LoadPluginsEvent(CountedPtr<Responder> responder, SampleCount timestamp);
+	LoadPluginsEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp);
 	
 	void post_process();
 };
diff --git a/src/libs/engine/events/MidiLearnEvent.cpp b/src/libs/engine/events/MidiLearnEvent.cpp
index 814ecdb5..822573e0 100644
--- a/src/libs/engine/events/MidiLearnEvent.cpp
+++ b/src/libs/engine/events/MidiLearnEvent.cpp
@@ -30,15 +30,15 @@ namespace Ingen {
 void
 MidiLearnResponseEvent::post_process()
 {
-	Engine::instance().client_broadcaster()->send_control_change(m_port_path, m_value);
+	_engine.client_broadcaster()->send_control_change(m_port_path, m_value);
 }
 
 
 
 // MidiLearnEvent
 
-MidiLearnEvent::MidiLearnEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path)
-: QueuedEvent(responder, timestamp),
+MidiLearnEvent::MidiLearnEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path)
+: QueuedEvent(engine, responder, timestamp),
   m_node_path(node_path),
   m_node(NULL),
   m_response_event(NULL)
@@ -49,17 +49,17 @@ MidiLearnEvent::MidiLearnEvent(CountedPtr<Responder> responder, SampleCount time
 void
 MidiLearnEvent::pre_process()
 {
-	m_node = Engine::instance().object_store()->find_node(m_node_path);
-	m_response_event = new MidiLearnResponseEvent(m_node_path + "/Controller_Number", _time_stamp);
+	m_node = _engine.object_store()->find_node(m_node_path);
+	m_response_event = new MidiLearnResponseEvent(_engine, m_node_path + "/Controller_Number", _time);
 	
 	QueuedEvent::pre_process();
 }
 
 
 void
-MidiLearnEvent::execute(SampleCount offset)
+MidiLearnEvent::execute(SampleCount nframes, FrameTime start, FrameTime end)
 {	
-	QueuedEvent::execute(offset);
+	QueuedEvent::execute(nframes, start, end);
 	
 	// FIXME: this isn't very good at all.
 	if (m_node != NULL && m_node->plugin()->type() == Plugin::Internal
diff --git a/src/libs/engine/events/MidiLearnEvent.h b/src/libs/engine/events/MidiLearnEvent.h
index 558261a8..7a36706c 100644
--- a/src/libs/engine/events/MidiLearnEvent.h
+++ b/src/libs/engine/events/MidiLearnEvent.h
@@ -37,8 +37,8 @@ class ControlChangeEvent;
 class MidiLearnResponseEvent : public Event
 {
 public:
-	MidiLearnResponseEvent(const string& port_path, SampleCount timestamp)
-	: Event(NULL, timestamp),
+	MidiLearnResponseEvent(Engine& engine, const string& port_path, SampleCount timestamp)
+	: Event(engine, NULL, timestamp),
 	  m_port_path(port_path),
 	  m_value(0.0f)
 	{}
@@ -64,10 +64,10 @@ private:
 class MidiLearnEvent : public QueuedEvent
 {
 public:
-	MidiLearnEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path);
+	MidiLearnEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path);
 	
 	void pre_process();
-	void execute(SampleCount offset);
+	void execute(SampleCount nframes, FrameTime start, FrameTime end);
 	void post_process();
 
 private:
diff --git a/src/libs/engine/events/NoteOffEvent.cpp b/src/libs/engine/events/NoteOffEvent.cpp
index 027e9f1f..8145c208 100644
--- a/src/libs/engine/events/NoteOffEvent.cpp
+++ b/src/libs/engine/events/NoteOffEvent.cpp
@@ -27,8 +27,8 @@ namespace Ingen {
 
 /** Note off with patch explicitly passed - triggered by MIDI.
  */
-NoteOffEvent::NoteOffEvent(CountedPtr<Responder> responder, SampleCount timestamp, Node* node, uchar note_num)
-: Event(responder, timestamp),
+NoteOffEvent::NoteOffEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, Node* node, uchar note_num)
+: Event(engine, responder, timestamp),
   m_node(node),
   m_note_num(note_num)
 {
@@ -37,8 +37,8 @@ NoteOffEvent::NoteOffEvent(CountedPtr<Responder> responder, SampleCount timestam
 
 /** Note off event with lookup - triggered by OSC.
  */
-NoteOffEvent::NoteOffEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path, uchar note_num)
-: Event(responder, timestamp),
+NoteOffEvent::NoteOffEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path, uchar note_num)
+: Event(engine, responder, timestamp),
   m_node(NULL),
   m_node_path(node_path),
   m_note_num(note_num)
@@ -47,17 +47,19 @@ NoteOffEvent::NoteOffEvent(CountedPtr<Responder> responder, SampleCount timestam
 
 
 void
-NoteOffEvent::execute(SampleCount offset)
+NoteOffEvent::execute(SampleCount nframes, FrameTime start, FrameTime end)
 {	
+	assert(_time >= start && _time <= end);
+
 	if (m_node == NULL && m_node_path != "")
-		m_node = Engine::instance().object_store()->find_node(m_node_path);
+		m_node = _engine.object_store()->find_node(m_node_path);
 		
 	// FIXME: this isn't very good at all.
 	if (m_node != NULL && m_node->plugin()->type() == Plugin::Internal) {
 		if (m_node->plugin()->plug_label() == "note_in")
-			((MidiNoteNode*)m_node)->note_off(m_note_num, offset);
+			((MidiNoteNode*)m_node)->note_off(m_note_num, _time, nframes, start, end);
 		else if (m_node->plugin()->plug_label() == "trigger_in")
-			((MidiTriggerNode*)m_node)->note_off(m_note_num, offset);
+			((MidiTriggerNode*)m_node)->note_off(m_note_num, _time, nframes, start, end);
 	}
 }
 
diff --git a/src/libs/engine/events/NoteOffEvent.h b/src/libs/engine/events/NoteOffEvent.h
index 707077a1..e3e9a56b 100644
--- a/src/libs/engine/events/NoteOffEvent.h
+++ b/src/libs/engine/events/NoteOffEvent.h
@@ -34,10 +34,10 @@ class Node;
 class NoteOffEvent : public Event
 {
 public:
-	NoteOffEvent(CountedPtr<Responder> responder, SampleCount timestamp, Node* node, uchar note_num);
-	NoteOffEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path, uchar note_num);
+	NoteOffEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, Node* node, uchar note_num);
+	NoteOffEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path, uchar note_num);
 	
-	void execute(SampleCount offset);
+	void execute(SampleCount nframes, FrameTime start, FrameTime end);
 	void post_process();
 
 private:
diff --git a/src/libs/engine/events/NoteOnEvent.cpp b/src/libs/engine/events/NoteOnEvent.cpp
index cbbc0e1d..7a98c58d 100644
--- a/src/libs/engine/events/NoteOnEvent.cpp
+++ b/src/libs/engine/events/NoteOnEvent.cpp
@@ -30,8 +30,8 @@ namespace Ingen {
  *
  * Used to be triggered by MIDI.  Not used anymore.
  */
-NoteOnEvent::NoteOnEvent(CountedPtr<Responder> responder, SampleCount timestamp, Node* patch, uchar note_num, uchar velocity)
-: Event(responder, timestamp),
+NoteOnEvent::NoteOnEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, Node* patch, uchar note_num, uchar velocity)
+: Event(engine, responder, timestamp),
   m_node(patch),
   m_note_num(note_num),
   m_velocity(velocity),
@@ -44,8 +44,8 @@ NoteOnEvent::NoteOnEvent(CountedPtr<Responder> responder, SampleCount timestamp,
  *
  * Triggered by OSC.
  */
-NoteOnEvent::NoteOnEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path, uchar note_num, uchar velocity)
-: Event(responder, timestamp),
+NoteOnEvent::NoteOnEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path, uchar note_num, uchar velocity)
+: Event(engine, responder, timestamp),
   m_node(NULL),
   m_node_path(node_path),
   m_note_num(note_num),
@@ -56,18 +56,20 @@ NoteOnEvent::NoteOnEvent(CountedPtr<Responder> responder, SampleCount timestamp,
 
 
 void
-NoteOnEvent::execute(SampleCount offset)
+NoteOnEvent::execute(SampleCount nframes, FrameTime start, FrameTime end)
 {
+	assert(_time >= start && _time <= end);
+
 	// Lookup if neccessary
 	if (m_is_osc_triggered)
-		m_node = Engine::instance().object_store()->find_node(m_node_path);
+		m_node = _engine.object_store()->find_node(m_node_path);
 		
 	// FIXME: this isn't very good at all.
 	if (m_node != NULL && m_node->plugin()->type() == Plugin::Internal) {
 		if (m_node->plugin()->plug_label() == "note_in")
-			((MidiNoteNode*)m_node)->note_on(m_note_num, m_velocity, offset);
+			((MidiNoteNode*)m_node)->note_on(m_note_num, m_velocity, _time, nframes, start, end);
 		else if (m_node->plugin()->plug_label() == "trigger_in")
-			((MidiTriggerNode*)m_node)->note_on(m_note_num, m_velocity, offset);
+			((MidiTriggerNode*)m_node)->note_on(m_note_num, m_velocity, _time, nframes, start, end);
 	}
 }
 
diff --git a/src/libs/engine/events/NoteOnEvent.h b/src/libs/engine/events/NoteOnEvent.h
index 209e7137..92ffbca5 100644
--- a/src/libs/engine/events/NoteOnEvent.h
+++ b/src/libs/engine/events/NoteOnEvent.h
@@ -34,10 +34,10 @@ class Node;
 class NoteOnEvent : public Event
 {
 public:
-	NoteOnEvent(CountedPtr<Responder> responder, SampleCount timestamp, Node* patch, uchar note_num, uchar velocity);
-	NoteOnEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path, uchar note_num, uchar velocity);
+	NoteOnEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, Node* patch, uchar note_num, uchar velocity);
+	NoteOnEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path, uchar note_num, uchar velocity);
 	
-	void execute(SampleCount offset);
+	void execute(SampleCount nframes, FrameTime start, FrameTime end);
 	void post_process();
 
 private:
diff --git a/src/libs/engine/events/PingQueuedEvent.h b/src/libs/engine/events/PingQueuedEvent.h
index 10e3a3bb..883ee818 100644
--- a/src/libs/engine/events/PingQueuedEvent.h
+++ b/src/libs/engine/events/PingQueuedEvent.h
@@ -34,7 +34,7 @@ class Port;
 class PingQueuedEvent : public QueuedEvent
 {
 public:
-	PingQueuedEvent(CountedPtr<Responder> responder, SampleCount timestamp) : QueuedEvent(responder, timestamp) {}
+	PingQueuedEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp) : QueuedEvent(engine, responder, timestamp) {}
 
 	void post_process() { _responder->respond_ok(); }
 };
diff --git a/src/libs/engine/events/RegisterClientEvent.cpp b/src/libs/engine/events/RegisterClientEvent.cpp
index ab076059..e35b7fdb 100644
--- a/src/libs/engine/events/RegisterClientEvent.cpp
+++ b/src/libs/engine/events/RegisterClientEvent.cpp
@@ -22,11 +22,11 @@
 namespace Ingen {
 
 
-RegisterClientEvent::RegisterClientEvent(CountedPtr<Responder>       responder,
+RegisterClientEvent::RegisterClientEvent(Engine& engine, CountedPtr<Responder>       responder,
                                          SampleCount                 timestamp,
                                          ClientKey                   key,
                                          CountedPtr<ClientInterface> client)
-: QueuedEvent(responder, timestamp)
+: QueuedEvent(engine, responder, timestamp)
 , _key(key)
 , _client(client)
 {
@@ -36,7 +36,7 @@ RegisterClientEvent::RegisterClientEvent(CountedPtr<Responder>       responder,
 void
 RegisterClientEvent::pre_process()
 {  
-	Engine::instance().client_broadcaster()->register_client(_key, _client);
+	_engine.client_broadcaster()->register_client(_key, _client);
 
 	QueuedEvent::pre_process();
 }
diff --git a/src/libs/engine/events/RegisterClientEvent.h b/src/libs/engine/events/RegisterClientEvent.h
index bc26c3bb..d68a0f83 100644
--- a/src/libs/engine/events/RegisterClientEvent.h
+++ b/src/libs/engine/events/RegisterClientEvent.h
@@ -35,7 +35,7 @@ namespace Ingen {
 class RegisterClientEvent : public QueuedEvent
 {
 public:
-	RegisterClientEvent(CountedPtr<Responder>       responder,
+	RegisterClientEvent(Engine& engine, CountedPtr<Responder>       responder,
 	                    SampleCount                 timestamp,
 	                    ClientKey                   key,
 	                    CountedPtr<ClientInterface> client);
diff --git a/src/libs/engine/events/RenameEvent.cpp b/src/libs/engine/events/RenameEvent.cpp
index 25a54285..465f4946 100644
--- a/src/libs/engine/events/RenameEvent.cpp
+++ b/src/libs/engine/events/RenameEvent.cpp
@@ -27,8 +27,8 @@
 namespace Ingen {
 
 
-RenameEvent::RenameEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& path, const string& name)
-: QueuedEvent(responder, timestamp),
+RenameEvent::RenameEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& path, const string& name)
+: QueuedEvent(engine, responder, timestamp),
   m_old_path(path),
   m_name(name),
   m_new_path(m_old_path.parent().base_path() + name),
@@ -58,13 +58,13 @@ RenameEvent::pre_process()
 		return;
 	}
 
-	if (Engine::instance().object_store()->find(m_new_path)) {
+	if (_engine.object_store()->find(m_new_path)) {
 		m_error = OBJECT_EXISTS;
 		QueuedEvent::pre_process();
 		return;
 	}
 	
-	GraphObject* obj = Engine::instance().object_store()->find(m_old_path);
+	GraphObject* obj = _engine.object_store()->find(m_old_path);
 
 	if (obj == NULL) {
 		m_error = OBJECT_NOT_FOUND;
@@ -89,10 +89,10 @@ RenameEvent::pre_process()
 
 
 void
-RenameEvent::execute(SampleCount offset)
+RenameEvent::execute(SampleCount nframes, FrameTime start, FrameTime end)
 {
 	//cout << "Executing rename event...";
-	QueuedEvent::execute(offset);
+	QueuedEvent::execute(nframes, start, end);
 }
 
 
@@ -103,7 +103,7 @@ RenameEvent::post_process()
 	
 	if (m_error == NO_ERROR) {
 		_responder->respond_ok();
-		Engine::instance().client_broadcaster()->send_rename(m_old_path, m_new_path);
+		_engine.client_broadcaster()->send_rename(m_old_path, m_new_path);
 	} else {
 		if (m_error == OBJECT_EXISTS)
 			msg.append("Object already exists at ").append(m_new_path);
diff --git a/src/libs/engine/events/RenameEvent.h b/src/libs/engine/events/RenameEvent.h
index d13efea9..fd01820b 100644
--- a/src/libs/engine/events/RenameEvent.h
+++ b/src/libs/engine/events/RenameEvent.h
@@ -42,11 +42,11 @@ class DisconnectPortEvent;
 class RenameEvent : public QueuedEvent
 {
 public:
-	RenameEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& path, const string& name);
+	RenameEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& path, const string& name);
 	~RenameEvent();
 
 	void pre_process();
-	void execute(SampleCount offset);
+	void execute(SampleCount nframes, FrameTime start, FrameTime end);
 	void post_process();
 
 private:
diff --git a/src/libs/engine/events/RequestAllObjectsEvent.cpp b/src/libs/engine/events/RequestAllObjectsEvent.cpp
index b28294cc..5eb780b3 100644
--- a/src/libs/engine/events/RequestAllObjectsEvent.cpp
+++ b/src/libs/engine/events/RequestAllObjectsEvent.cpp
@@ -18,12 +18,14 @@
 #include "Responder.h"
 #include "Engine.h"
 #include "ObjectSender.h"
+#include "ClientBroadcaster.h"
+#include "ObjectStore.h"
 
 namespace Ingen {
 
 
-RequestAllObjectsEvent::RequestAllObjectsEvent(CountedPtr<Responder> responder, SampleCount timestamp)
-: QueuedEvent(responder, timestamp),
+RequestAllObjectsEvent::RequestAllObjectsEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp)
+: QueuedEvent(engine, responder, timestamp),
   m_client(CountedPtr<ClientInterface>(NULL))
 {
 }
@@ -32,7 +34,7 @@ RequestAllObjectsEvent::RequestAllObjectsEvent(CountedPtr<Responder> responder,
 void
 RequestAllObjectsEvent::pre_process()
 {
-	m_client = _responder->find_client();
+	m_client = _engine.client_broadcaster()->client(_responder->client_key());
 	
 	QueuedEvent::pre_process();
 }
@@ -43,9 +45,14 @@ RequestAllObjectsEvent::post_process()
 {
 	if (m_client) {
 		_responder->respond_ok();
-		ObjectSender::send_all(m_client.get());
+
+		// Everything is a child of the root patch, so this sends it all
+		Patch* root = _engine.object_store()->find_patch("/");
+		if (root)
+			ObjectSender::send_patch(m_client.get(), root);
+
 	} else {
-		_responder->respond_error("Invalid URL");
+		_responder->respond_error("Unable to find client to send all objects");
 	}
 }
 
diff --git a/src/libs/engine/events/RequestAllObjectsEvent.h b/src/libs/engine/events/RequestAllObjectsEvent.h
index 760a06ea..7651700f 100644
--- a/src/libs/engine/events/RequestAllObjectsEvent.h
+++ b/src/libs/engine/events/RequestAllObjectsEvent.h
@@ -35,7 +35,7 @@ namespace Shared {
 class RequestAllObjectsEvent : public QueuedEvent
 {
 public:
-	RequestAllObjectsEvent(CountedPtr<Responder> responder, SampleCount timestamp);
+	RequestAllObjectsEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp);
 
 	void pre_process();
 	void post_process();
diff --git a/src/libs/engine/events/RequestMetadataEvent.cpp b/src/libs/engine/events/RequestMetadataEvent.cpp
index e8112797..03d84d7f 100644
--- a/src/libs/engine/events/RequestMetadataEvent.cpp
+++ b/src/libs/engine/events/RequestMetadataEvent.cpp
@@ -27,8 +27,8 @@ using std::string;
 namespace Ingen {
 
 
-RequestMetadataEvent::RequestMetadataEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path, const string& key)
-: QueuedEvent(responder, timestamp),
+RequestMetadataEvent::RequestMetadataEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& node_path, const string& key)
+: QueuedEvent(engine, responder, timestamp),
   m_path(node_path),
   m_key(key),
   m_value(""),
@@ -41,10 +41,10 @@ RequestMetadataEvent::RequestMetadataEvent(CountedPtr<Responder> responder, Samp
 void
 RequestMetadataEvent::pre_process()
 {
-	m_client = _responder->find_client();
+	m_client = _engine.client_broadcaster()->client(_responder->client_key());
 	
 	if (m_client) {
-		m_object = Engine::instance().object_store()->find(m_path);
+		m_object = _engine.object_store()->find(m_path);
 		if (m_object == NULL) {
 			QueuedEvent::pre_process();
 			return;
diff --git a/src/libs/engine/events/RequestMetadataEvent.h b/src/libs/engine/events/RequestMetadataEvent.h
index 0b1cc267..4f99e023 100644
--- a/src/libs/engine/events/RequestMetadataEvent.h
+++ b/src/libs/engine/events/RequestMetadataEvent.h
@@ -37,7 +37,7 @@ namespace Shared {
 class RequestMetadataEvent : public QueuedEvent
 {
 public:
-	RequestMetadataEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& path, const string& key);
+	RequestMetadataEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& path, const string& key);
 
 	void pre_process();
 	void post_process();
diff --git a/src/libs/engine/events/RequestPluginsEvent.cpp b/src/libs/engine/events/RequestPluginsEvent.cpp
index 65dfb7aa..9efb2388 100644
--- a/src/libs/engine/events/RequestPluginsEvent.cpp
+++ b/src/libs/engine/events/RequestPluginsEvent.cpp
@@ -18,12 +18,13 @@
 #include "Responder.h"
 #include "Engine.h"
 #include "ClientBroadcaster.h"
+#include "NodeFactory.h"
 
 namespace Ingen {
 
 
-RequestPluginsEvent::RequestPluginsEvent(CountedPtr<Responder> responder, SampleCount timestamp)
-: QueuedEvent(responder, timestamp),
+RequestPluginsEvent::RequestPluginsEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp)
+: QueuedEvent(engine, responder, timestamp),
   m_client(CountedPtr<ClientInterface>(NULL))
 {
 }
@@ -32,8 +33,12 @@ RequestPluginsEvent::RequestPluginsEvent(CountedPtr<Responder> responder, Sample
 void
 RequestPluginsEvent::pre_process()
 {
-	m_client = _responder->find_client();
+	m_client = _engine.client_broadcaster()->client(_responder->client_key());
 	
+	// Take a copy to send in the post processing thread (to avoid problems
+	// because std::list isn't thread safe)
+	m_plugins = _engine.node_factory()->plugins();
+
 	QueuedEvent::pre_process();
 }
 
@@ -42,10 +47,10 @@ void
 RequestPluginsEvent::post_process()
 {
 	if (m_client) {
-		Engine::instance().client_broadcaster()->send_plugins_to(m_client.get());
+		_engine.client_broadcaster()->send_plugins_to(m_client.get(), m_plugins);
 		_responder->respond_ok();
 	} else {
-		_responder->respond_error("Invalid URL");
+		_responder->respond_error("Unable to find client to send plugins");
 	}
 }
 
diff --git a/src/libs/engine/events/RequestPluginsEvent.h b/src/libs/engine/events/RequestPluginsEvent.h
index 0a35a1ad..cd2d05fc 100644
--- a/src/libs/engine/events/RequestPluginsEvent.h
+++ b/src/libs/engine/events/RequestPluginsEvent.h
@@ -18,11 +18,13 @@
 #define REQUESTPLUGINSEVENT_H
 
 #include <string>
+#include <list>
 #include "QueuedEvent.h"
 using std::string;
 
 namespace Ingen {
 
+class Plugin;
 class Responder;
 namespace Shared {
 	class ClientInterface;
@@ -36,13 +38,14 @@ namespace Shared {
 class RequestPluginsEvent : public QueuedEvent
 {
 public:
-	RequestPluginsEvent(CountedPtr<Responder> responder, SampleCount timestamp);
+	RequestPluginsEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp);
 
 	void pre_process();
 	void post_process();
 
 private:
 	CountedPtr<ClientInterface> m_client;
+	std::list<Plugin*>          m_plugins;
 };
 
 
diff --git a/src/libs/engine/events/RequestPortValueEvent.cpp b/src/libs/engine/events/RequestPortValueEvent.cpp
index d02eed6a..830ef852 100644
--- a/src/libs/engine/events/RequestPortValueEvent.cpp
+++ b/src/libs/engine/events/RequestPortValueEvent.cpp
@@ -28,8 +28,8 @@ using std::string;
 namespace Ingen {
 
 
-RequestPortValueEvent::RequestPortValueEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& port_path)
-: QueuedEvent(responder, timestamp),
+RequestPortValueEvent::RequestPortValueEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& port_path)
+: QueuedEvent(engine, responder, timestamp),
   m_port_path(port_path),
   m_port(NULL),
   m_value(0.0),
@@ -41,22 +41,24 @@ RequestPortValueEvent::RequestPortValueEvent(CountedPtr<Responder> responder, Sa
 void
 RequestPortValueEvent::pre_process()
 {
-	m_client = _responder->find_client();
-	m_port = Engine::instance().object_store()->find_port(m_port_path);
+	m_client = _engine.client_broadcaster()->client(_responder->client_key());
+	m_port = _engine.object_store()->find_port(m_port_path);
 
 	QueuedEvent::pre_process();
 }
 
 
 void
-RequestPortValueEvent::execute(SampleCount offset)
+RequestPortValueEvent::execute(SampleCount nframes, FrameTime start, FrameTime end)
 {
+	assert(_time >= start && _time <= end);
+
 	if (m_port != NULL && m_port->type() == DataType::FLOAT)
-		m_value = ((TypedPort<Sample>*)m_port)->buffer(0)->value_at(offset);
+		m_value = ((TypedPort<Sample>*)m_port)->buffer(0)->value_at(_time - start);
 	else 
 		m_port = NULL; // triggers error response
 
-	QueuedEvent::execute(offset);
+	QueuedEvent::execute(nframes, start, end);
 }
 
 
@@ -70,7 +72,7 @@ RequestPortValueEvent::post_process()
 		_responder->respond_ok();
 		m_client->control_change(m_port_path, m_value);
 	} else {
-		_responder->respond_error("Invalid URL");
+		_responder->respond_error("Unable to find client to send port value");
 	}
 }
 
diff --git a/src/libs/engine/events/RequestPortValueEvent.h b/src/libs/engine/events/RequestPortValueEvent.h
index 9b809b3d..204f1911 100644
--- a/src/libs/engine/events/RequestPortValueEvent.h
+++ b/src/libs/engine/events/RequestPortValueEvent.h
@@ -37,10 +37,10 @@ using Shared::ClientInterface;
 class RequestPortValueEvent : public QueuedEvent
 {
 public:
-	RequestPortValueEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& port_path);
+	RequestPortValueEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& port_path);
 
 	void pre_process();
-	void execute(SampleCount offset);
+	void execute(SampleCount nframes, FrameTime start, FrameTime end);
 	void post_process();
 
 private:
diff --git a/src/libs/engine/events/SetMetadataEvent.cpp b/src/libs/engine/events/SetMetadataEvent.cpp
index 3d77b77b..1ce5d6f4 100644
--- a/src/libs/engine/events/SetMetadataEvent.cpp
+++ b/src/libs/engine/events/SetMetadataEvent.cpp
@@ -27,8 +27,8 @@ using std::string;
 namespace Ingen {
 
 
-SetMetadataEvent::SetMetadataEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& path, const string& key, const string& value)
-: QueuedEvent(responder, timestamp),
+SetMetadataEvent::SetMetadataEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& path, const string& key, const string& value)
+: QueuedEvent(engine, responder, timestamp),
   m_path(path),
   m_key(key),
   m_value(value),
@@ -40,7 +40,7 @@ SetMetadataEvent::SetMetadataEvent(CountedPtr<Responder> responder, SampleCount
 void
 SetMetadataEvent::pre_process()
 {
-	m_object = Engine::instance().object_store()->find(m_path);
+	m_object = _engine.object_store()->find(m_path);
 	if (m_object == NULL) {
 		QueuedEvent::pre_process();
 		return;
@@ -53,11 +53,11 @@ SetMetadataEvent::pre_process()
 
 
 void
-SetMetadataEvent::execute(SampleCount offset)
+SetMetadataEvent::execute(SampleCount nframes, FrameTime start, FrameTime end)
 {
 	// Do nothing
 	
-	QueuedEvent::execute(offset);
+	QueuedEvent::execute(nframes, start, end);
 }
 
 
@@ -70,7 +70,7 @@ SetMetadataEvent::post_process()
 		_responder->respond_error(msg);
 	} else {
 		_responder->respond_ok();
-		Engine::instance().client_broadcaster()->send_metadata_update(m_path, m_key, m_value);
+		_engine.client_broadcaster()->send_metadata_update(m_path, m_key, m_value);
 	}
 }
 
diff --git a/src/libs/engine/events/SetMetadataEvent.h b/src/libs/engine/events/SetMetadataEvent.h
index 7ea534a1..855aeb62 100644
--- a/src/libs/engine/events/SetMetadataEvent.h
+++ b/src/libs/engine/events/SetMetadataEvent.h
@@ -34,10 +34,10 @@ class GraphObject;
 class SetMetadataEvent : public QueuedEvent
 {
 public:
-	SetMetadataEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& path, const string& key, const string& value);
+	SetMetadataEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& path, const string& key, const string& value);
 	
 	void pre_process();
-	void execute(SampleCount offset);
+	void execute(SampleCount nframes, FrameTime start, FrameTime end);
 	void post_process();
 
 private:
diff --git a/src/libs/engine/events/SetPortValueEvent.cpp b/src/libs/engine/events/SetPortValueEvent.cpp
index 6331a4b5..4018139a 100644
--- a/src/libs/engine/events/SetPortValueEvent.cpp
+++ b/src/libs/engine/events/SetPortValueEvent.cpp
@@ -27,8 +27,8 @@ namespace Ingen {
 
 /** Voice-specific control setting
  */
-SetPortValueEvent::SetPortValueEvent(CountedPtr<Responder> responder, SampleCount timestamp, size_t voice_num, const string& port_path, Sample val)
-: Event(responder, timestamp),
+SetPortValueEvent::SetPortValueEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, size_t voice_num, const string& port_path, Sample val)
+: Event(engine, responder, timestamp),
   m_voice_num(voice_num),
   m_port_path(port_path),
   m_val(val),
@@ -38,8 +38,8 @@ SetPortValueEvent::SetPortValueEvent(CountedPtr<Responder> responder, SampleCoun
 }
 
 
-SetPortValueEvent::SetPortValueEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& port_path, Sample val)
-: Event(responder, timestamp),
+SetPortValueEvent::SetPortValueEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& port_path, Sample val)
+: Event(engine, responder, timestamp),
   m_voice_num(-1),
   m_port_path(port_path),
   m_val(val),
@@ -50,10 +50,12 @@ SetPortValueEvent::SetPortValueEvent(CountedPtr<Responder> responder, SampleCoun
 
 
 void
-SetPortValueEvent::execute(SampleCount offset)
+SetPortValueEvent::execute(SampleCount nframes, FrameTime start, FrameTime end)
 {
+	assert(_time >= start && _time <= end);
+
 	if (m_port == NULL)
-		m_port = Engine::instance().object_store()->find_port(m_port_path);
+		m_port = _engine.object_store()->find_port(m_port_path);
 
 	if (m_port == NULL) {
 		m_error = PORT_NOT_FOUND;
@@ -61,9 +63,9 @@ SetPortValueEvent::execute(SampleCount offset)
 		m_error = TYPE_MISMATCH;
 	} else {
 		if (m_voice_num == -1) 
-			((TypedPort<Sample>*)m_port)->set_value(m_val, offset);
+			((TypedPort<Sample>*)m_port)->set_value(m_val, _time - start);
 		else
-			((TypedPort<Sample>*)m_port)->set_value(m_voice_num, m_val, offset);
+			((TypedPort<Sample>*)m_port)->set_value(m_voice_num, m_val, _time - start);
 			//((TypedPort<Sample>*)m_port)->buffer(m_voice_num)->set(m_val, offset); // FIXME: check range
 	}
 }
@@ -76,13 +78,13 @@ SetPortValueEvent::post_process()
 		assert(m_port != NULL);
 		
 		_responder->respond_ok();
-		Engine::instance().client_broadcaster()->send_control_change(m_port_path, m_val);
+		_engine.client_broadcaster()->send_control_change(m_port_path, m_val);
 		
 		// Send patch port control change, if this is a bridge port
 		/*Port* parent_port = m_port->parent_node()->as_port();
 		if (parent_port != NULL) {
 			assert(parent_port->type() == DataType::FLOAT);
-			Engine::instance().client_broadcaster()->send_control_change(parent_port->path(), m_val);
+			_engine.client_broadcaster()->send_control_change(parent_port->path(), m_val);
 		}*/
 
 	} else if (m_error == PORT_NOT_FOUND) {
diff --git a/src/libs/engine/events/SetPortValueEvent.h b/src/libs/engine/events/SetPortValueEvent.h
index ecd1557a..2572df55 100644
--- a/src/libs/engine/events/SetPortValueEvent.h
+++ b/src/libs/engine/events/SetPortValueEvent.h
@@ -34,10 +34,10 @@ class Port;
 class SetPortValueEvent : public Event
 {
 public:
-	SetPortValueEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& port_path, Sample val);
-	SetPortValueEvent(CountedPtr<Responder> responder, SampleCount timestamp, size_t voice_num, const string& port_path, Sample val);
+	SetPortValueEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& port_path, Sample val);
+	SetPortValueEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, size_t voice_num, const string& port_path, Sample val);
 
-	void execute(SampleCount offset);
+	void execute(SampleCount nframes, FrameTime start, FrameTime end);
 	void post_process();
 
 private:
diff --git a/src/libs/engine/events/SetPortValueQueuedEvent.cpp b/src/libs/engine/events/SetPortValueQueuedEvent.cpp
index 8a5afc65..caee68a6 100644
--- a/src/libs/engine/events/SetPortValueQueuedEvent.cpp
+++ b/src/libs/engine/events/SetPortValueQueuedEvent.cpp
@@ -28,8 +28,8 @@ namespace Ingen {
 
 /** Voice-specific control setting
  */
-SetPortValueQueuedEvent::SetPortValueQueuedEvent(CountedPtr<Responder> responder, SampleCount timestamp, size_t voice_num, const string& port_path, Sample val)
-: QueuedEvent(responder, timestamp),
+SetPortValueQueuedEvent::SetPortValueQueuedEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, size_t voice_num, const string& port_path, Sample val)
+: QueuedEvent(engine, responder, timestamp),
   m_voice_num(voice_num),
   m_port_path(port_path),
   m_val(val),
@@ -39,8 +39,8 @@ SetPortValueQueuedEvent::SetPortValueQueuedEvent(CountedPtr<Responder> responder
 }
 
 
-SetPortValueQueuedEvent::SetPortValueQueuedEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& port_path, Sample val)
-: QueuedEvent(responder, timestamp),
+SetPortValueQueuedEvent::SetPortValueQueuedEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& port_path, Sample val)
+: QueuedEvent(engine, responder, timestamp),
   m_voice_num(-1),
   m_port_path(port_path),
   m_val(val),
@@ -54,7 +54,7 @@ void
 SetPortValueQueuedEvent::pre_process()
 {
 	if (m_port == NULL)
-		m_port = Engine::instance().object_store()->find_port(m_port_path);
+		m_port = _engine.object_store()->find_port(m_port_path);
 
 	if (m_port == NULL) {
 		m_error = PORT_NOT_FOUND;
@@ -67,16 +67,18 @@ SetPortValueQueuedEvent::pre_process()
 
 
 void
-SetPortValueQueuedEvent::execute(SampleCount offset)
+SetPortValueQueuedEvent::execute(SampleCount nframes, FrameTime start, FrameTime end)
 {
-	QueuedEvent::execute(offset);
+	assert(_time >= start && _time <= end);
+
+	QueuedEvent::execute(nframes, start, end);
 
 	if (m_error == NO_ERROR) {
 		assert(m_port != NULL);
 		if (m_voice_num == -1) 
-			((TypedPort<Sample>*)m_port)->set_value(m_val, offset);
+			((TypedPort<Sample>*)m_port)->set_value(m_val, _time - start);
 		else
-			((TypedPort<Sample>*)m_port)->buffer(m_voice_num)->set(m_val, offset); // FIXME: check range
+			((TypedPort<Sample>*)m_port)->buffer(m_voice_num)->set(m_val, _time - start); // FIXME: check range
 	}
 }
 
@@ -88,13 +90,13 @@ SetPortValueQueuedEvent::post_process()
 		assert(m_port != NULL);
 		
 		_responder->respond_ok();
-		Engine::instance().client_broadcaster()->send_control_change(m_port_path, m_val);
+		_engine.client_broadcaster()->send_control_change(m_port_path, m_val);
 		
 		// Send patch port control change, if this is a bridge port
 		/*Port* parent_port = m_port->parent_node()->as_port();
 		if (parent_port != NULL) {
 			assert(parent_port->type() == DataType::FLOAT);
-			Engine::instance().client_broadcaster()->send_control_change(parent_port->path(), m_val);
+			_engine.client_broadcaster()->send_control_change(parent_port->path(), m_val);
 		}*/
 
 	} else if (m_error == PORT_NOT_FOUND) {
diff --git a/src/libs/engine/events/SetPortValueQueuedEvent.h b/src/libs/engine/events/SetPortValueQueuedEvent.h
index 9e83e045..dc5add84 100644
--- a/src/libs/engine/events/SetPortValueQueuedEvent.h
+++ b/src/libs/engine/events/SetPortValueQueuedEvent.h
@@ -34,11 +34,11 @@ class Port;
 class SetPortValueQueuedEvent : public QueuedEvent
 {
 public:
-	SetPortValueQueuedEvent(CountedPtr<Responder> responder, SampleCount timestamp, const string& port_path, Sample val);
-	SetPortValueQueuedEvent(CountedPtr<Responder> responder, SampleCount timestamp, size_t voice_num, const string& port_path, Sample val);
+	SetPortValueQueuedEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& port_path, Sample val);
+	SetPortValueQueuedEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, size_t voice_num, const string& port_path, Sample val);
 
 	void pre_process();
-	void execute(SampleCount offset);
+	void execute(SampleCount nframes, FrameTime start, FrameTime end);
 	void post_process();
 
 private:
diff --git a/src/libs/engine/events/UnregisterClientEvent.cpp b/src/libs/engine/events/UnregisterClientEvent.cpp
index 5e720a24..13709959 100644
--- a/src/libs/engine/events/UnregisterClientEvent.cpp
+++ b/src/libs/engine/events/UnregisterClientEvent.cpp
@@ -23,8 +23,8 @@
 namespace Ingen {
 
 
-UnregisterClientEvent::UnregisterClientEvent(CountedPtr<Responder> responder, SampleCount timestamp, ClientKey key)
-: QueuedEvent(responder, timestamp)
+UnregisterClientEvent::UnregisterClientEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, ClientKey key)
+: QueuedEvent(engine, responder, timestamp)
 , _key(key)
 {
 }
@@ -33,7 +33,7 @@ UnregisterClientEvent::UnregisterClientEvent(CountedPtr<Responder> responder, Sa
 void
 UnregisterClientEvent::post_process()
 {
-	if (Engine::instance().client_broadcaster()->unregister_client(_key))
+	if (_engine.client_broadcaster()->unregister_client(_key))
 		_responder->respond_ok();
 	else
 		_responder->respond_error("Unable to unregister client");
diff --git a/src/libs/engine/events/UnregisterClientEvent.h b/src/libs/engine/events/UnregisterClientEvent.h
index 1523394e..29166345 100644
--- a/src/libs/engine/events/UnregisterClientEvent.h
+++ b/src/libs/engine/events/UnregisterClientEvent.h
@@ -39,7 +39,7 @@ using Shared::ClientKey;
 class UnregisterClientEvent : public QueuedEvent
 {
 public:
-	UnregisterClientEvent(CountedPtr<Responder> responder, SampleCount timestamp, ClientKey key);
+	UnregisterClientEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, ClientKey key);
 
 	void post_process();
 
diff --git a/src/libs/engine/types.h b/src/libs/engine/types.h
index 73cc5c73..b4c23486 100644
--- a/src/libs/engine/types.h
+++ b/src/libs/engine/types.h
@@ -27,6 +27,7 @@ typedef unsigned long ulong;
 typedef jack_default_audio_sample_t Sample;
 typedef jack_nframes_t              SampleCount;
 typedef jack_nframes_t              SampleRate;
+typedef jack_nframes_t              FrameTime;
 
 /** A type that Ingen can process/patch (eg can be stored in a port) */
 enum DataType { FLOAT, MIDI, UNKNOWN };
-- 
cgit v1.2.1