diff --git a/Source/CoreServices.cpp b/Source/CoreServices.cpp
index 69f3cd426a6da4b56874b7cb575094b5f06775c8..46b68398ec1c4b74bf70d4008d9f045d211991b3 100644
--- a/Source/CoreServices.cpp
+++ b/Source/CoreServices.cpp
@@ -80,12 +80,17 @@ void highlightEditor(GenericEditor* ed)
 
 int64 getGlobalTimestamp()
 {
-    return getMessageCenter()->getTimestamp();
+    return static_cast<MessageCenter*>(&(getMessageCenter()->processor))->getGlobalTimestamp();
 }
 
 int64 getSoftwareTimestamp()
 {
-	return getMessageCenter()->getTimestamp(true);
+	return static_cast<MessageCenter*>(&(getMessageCenter()->processor))->getGlobalTimestamp(true);
+}
+
+float getGlobalSampleRate()
+{
+	return static_cast<MessageCenter*>(&(getMessageCenter()->processor))->getGlobalSampleRate();
 }
 
 void setRecordingDirectory(String dir)
diff --git a/Source/CoreServices.h b/Source/CoreServices.h
index 56dbf6887ff10a4b02c93789fdf87f736dc267bb..e4f6ec2c42ac55a09c091712b56589c28f3a8aac 100644
--- a/Source/CoreServices.h
+++ b/Source/CoreServices.h
@@ -63,6 +63,11 @@ Defaults to the first hardware timestamp source or the software one if
 no hardware timestamping is present*/
 PLUGIN_API int64 getGlobalTimestamp();
 
+/** Gets the sample rate selected on the MessageCenter interface
+Defaults to the dample rate of the first hardware source or 
+the software high resolution timer if no hardware source is present*/
+PLUGIN_API float getGlobalSampleRate();
+
 /** Gets the software timestamp based on a high resolution timer aligned to the start of each processing block */
 PLUGIN_API int64 getSoftwareTimestamp();
 
diff --git a/Source/Plugins/BasicSpikeDisplay/SpikeDetector/SpikeDetector.cpp b/Source/Plugins/BasicSpikeDisplay/SpikeDetector/SpikeDetector.cpp
index 15d2d6bddc890ed0602dd02346fb3df7464a28e0..1908013f59fe3ca472723f92cc8c014ae7f7f533 100644
--- a/Source/Plugins/BasicSpikeDisplay/SpikeDetector/SpikeDetector.cpp
+++ b/Source/Plugins/BasicSpikeDisplay/SpikeDetector/SpikeDetector.cpp
@@ -94,10 +94,6 @@ void SpikeDetector::createSpikeChannels()
 		}
 		SpikeChannel* spk = new SpikeChannel(SpikeChannel::typeFromNumChannels(nChans), this, chans);
 		spk->setNumSamples(elec->prePeakSamples, elec->postPeakSamples);
-		//We currently have no means to prevent creating spikes from channels from different sources
-		//We assume that all come from the same source, thus sharing sample rate ans bitvolts. By default, set it to the
-		//first channel.
-		spk->setSampleRate(chans[0]->getSampleRate());
 		spikeChannelArray.add(spk);
 	}
 }
diff --git a/Source/Plugins/LfpDisplayNode/LfpDisplayNode.cpp b/Source/Plugins/LfpDisplayNode/LfpDisplayNode.cpp
index 4fdb6eb06b0223421904f41b97d381510c77aeb2..dcf2d80a8186a062266a6b56a6f096996faf282b 100644
--- a/Source/Plugins/LfpDisplayNode/LfpDisplayNode.cpp
+++ b/Source/Plugins/LfpDisplayNode/LfpDisplayNode.cpp
@@ -163,8 +163,9 @@ void LfpDisplayNode::handleEvent(const EventChannel* eventInfo, const MidiMessag
         const int eventChannel      = ttl->getChannel();
         const int eventTime         = samplePosition;
         const uint32 eventSourceNodeId = getProcessorFullId(ttl->getSourceID(), ttl->getSubProcessorIdx());
-        const int nSamples          = numSamples.at (eventSourceNodeId);
-        const int samplesToFill     = nSamples - eventTime;
+        const int nSamples          = getNumSourceSamples (eventSourceNodeId);
+        int samplesToFill     = nSamples - eventTime;
+		if (samplesToFill < 0) samplesToFill = 0;
 
         //	std::cout << "Received event from " << eventSourceNode << ", channel "
         //	          << eventChannel << ", with ID " << eventId << ", copying to "
@@ -230,7 +231,7 @@ void LfpDisplayNode::initializeEventChannels()
         const int chan        = channelForEventSource[eventSourceNodes[i]];
         const int index       = displayBufferIndex[chan];
         const int samplesLeft = displayBuffer->getNumSamples() - index;
-        const int nSamples    = numSamples.at(eventSourceNodes[i]);
+        const int nSamples    = getNumSourceSamples(eventSourceNodes[i]);
 
         if (nSamples < samplesLeft)
         {
diff --git a/Source/Plugins/PhaseDetector/PhaseDetector.cpp b/Source/Plugins/PhaseDetector/PhaseDetector.cpp
index d952139487482954f4303351e6d5b90fbc358a9c..3447a1272ab24ec34c68c3ecc3ea656bdd935854 100644
--- a/Source/Plugins/PhaseDetector/PhaseDetector.cpp
+++ b/Source/Plugins/PhaseDetector/PhaseDetector.cpp
@@ -51,13 +51,40 @@ AudioProcessorEditor* PhaseDetector::createEditor()
     return editor;
 }
 
-void PhaseDetector::getDefaultEventInfo(Array<DefaultEventInfo>& events, int subProcessorIdx) const
+void PhaseDetector::createEventChannels()
 {
-	if (subProcessorIdx != 0) return;
-	events.add(DefaultEventInfo(EventChannel::TTL, 8, 1));
+	moduleEventChannels.clear();
+	for (int i = 0; i < modules.size(); i++)
+	{
+		const DataChannel* in = getDataChannel(modules[i].inputChan);
+		EventChannel* ev = new EventChannel(EventChannel::TTL, 8, 1, in->getSampleRate(), this);
+		ev->setName("Phase detector output " + String(i+1));
+		ev->setDescription("Triggers when the input signal mets a given phase condition");
+		String typeDesc;
+		switch (modules[i].type)
+		{
+		case PEAK: typeDesc = "Positive peak"; break;
+		case FALLING_ZERO: typeDesc = "Zero crossing with negative slope"; break;
+		case TROUGH: typeDesc = "Negative peak"; break;
+		case RISING_ZERO: typeDesc = "Zero crossing with positive slope"; break;
+		default: typeDesc = "No phase selected"; break;
+		}
+		MetaDataDescriptor md(MetaDataDescriptor::CHAR, 34, "Phase Type", "Description of the phase condition", "string.extraInfo");
+		MetaDataValue mv(md);
+		mv.setValue(typeDesc);
+		ev->addMetaData(md, mv);
+		md = MetaDataDescriptor(MetaDataDescriptor::UINT16, 3, "Source Channel",
+			"Index at its source, Source processor ID and Sub Processor index of the channel that triggers this event", "source.channel.identifier.full");
+		mv = MetaDataValue(md);
+		uint16 sourceInfo[3];
+		sourceInfo[0] = in->getSourceIndex();
+		sourceInfo[1] = in->getSourceNodeID();
+		sourceInfo[3] = in->getSubProcessorIdx();
+		mv.setValue(static_cast<const uint16*>(sourceInfo));
+		ev->addMetaData(md, mv);
+	}
 }
 
-
 void PhaseDetector::addModule()
 {
     DetectorModule m = DetectorModule();
@@ -145,8 +172,6 @@ void PhaseDetector::updateSettings()
 
 bool PhaseDetector::enable()
 {
-	//This is to avoid having to look for the channel every time
-	outputEventChannel = getEventChannel(getEventChannelIndex(0, getNodeId()));
     return true;
 }
 
@@ -206,11 +231,9 @@ void PhaseDetector::process (AudioSampleBuffer& buffer)
                 {
                     if (module.type == PEAK)
                     {
-						//A "whole ttl word" does not have any meaning on this processor, so we just create a dummy one
-						//Another option, to take into account for the future, is to create an entire TTL event object for each module
 						uint8 ttlData = 1 << module.outputChan;
-						TTLEventPtr event = TTLEvent::createTTLEvent(outputEventChannel, getTimestamp(module.inputChan) + i, &ttlData, sizeof(uint8), module.outputChan);
-						addEvent(outputEventChannel, event, i);
+						TTLEventPtr event = TTLEvent::createTTLEvent(moduleEventChannels[i], getTimestamp(module.inputChan) + i, &ttlData, sizeof(uint8), module.outputChan);
+						addEvent(moduleEventChannels[i], event, i);
                         module.samplesSinceTrigger = 0;
                         module.wasTriggered = true;
                     }
@@ -224,8 +247,8 @@ void PhaseDetector::process (AudioSampleBuffer& buffer)
                     if (module.type == FALLING_ZERO)
                     {
 						uint8 ttlData = 1 << module.outputChan;
-						TTLEventPtr event = TTLEvent::createTTLEvent(outputEventChannel, getTimestamp(module.inputChan) + i, &ttlData, sizeof(uint8), module.outputChan);
-						addEvent(outputEventChannel, event, i);
+						TTLEventPtr event = TTLEvent::createTTLEvent(moduleEventChannels[i], getTimestamp(module.inputChan) + i, &ttlData, sizeof(uint8), module.outputChan);
+						addEvent(moduleEventChannels[i], event, i);
                         module.samplesSinceTrigger = 0;
                         module.wasTriggered = true;
                     }
@@ -237,8 +260,8 @@ void PhaseDetector::process (AudioSampleBuffer& buffer)
                     if (module.type == TROUGH)
                     {
 						uint8 ttlData = 1 << module.outputChan;
-						TTLEventPtr event = TTLEvent::createTTLEvent(outputEventChannel, getTimestamp(module.inputChan) + i, &ttlData, sizeof(uint8), module.outputChan);
-						addEvent(outputEventChannel, event, i);
+						TTLEventPtr event = TTLEvent::createTTLEvent(moduleEventChannels[i], getTimestamp(module.inputChan) + i, &ttlData, sizeof(uint8), module.outputChan);
+						addEvent(moduleEventChannels[i], event, i);
                         module.samplesSinceTrigger = 0;
                         module.wasTriggered = true;
                     }
@@ -252,8 +275,8 @@ void PhaseDetector::process (AudioSampleBuffer& buffer)
                     if (module.type == RISING_ZERO)
                     {
 						uint8 ttlData = 1 << module.outputChan;
-						TTLEventPtr event = TTLEvent::createTTLEvent(outputEventChannel, getTimestamp(module.inputChan) + i, &ttlData, sizeof(uint8), module.outputChan);
-						addEvent(outputEventChannel, event, i);
+						TTLEventPtr event = TTLEvent::createTTLEvent(moduleEventChannels[i], getTimestamp(module.inputChan) + i, &ttlData, sizeof(uint8), module.outputChan);
+						addEvent(moduleEventChannels[i], event, i);
                         module.samplesSinceTrigger = 0;
                         module.wasTriggered = true;
                     }
@@ -268,8 +291,8 @@ void PhaseDetector::process (AudioSampleBuffer& buffer)
                     if (module.samplesSinceTrigger > 1000)
                     {
 						uint8 ttlData = 0;
-						TTLEventPtr event = TTLEvent::createTTLEvent(outputEventChannel, getTimestamp(module.inputChan) + i, &ttlData, sizeof(uint8), module.outputChan);
-						addEvent(outputEventChannel, event, i);
+						TTLEventPtr event = TTLEvent::createTTLEvent(moduleEventChannels[i], getTimestamp(module.inputChan) + i, &ttlData, sizeof(uint8), module.outputChan);
+						addEvent(moduleEventChannels[i], event, i);
                         module.wasTriggered = false;
                     }
                     else
diff --git a/Source/Plugins/PhaseDetector/PhaseDetector.h b/Source/Plugins/PhaseDetector/PhaseDetector.h
index 010978fa4a4ead0aae3a3eb6b4f7df31bca88f37..bd5b449540f0fb124e77a2a1056157934b29b509 100644
--- a/Source/Plugins/PhaseDetector/PhaseDetector.h
+++ b/Source/Plugins/PhaseDetector/PhaseDetector.h
@@ -52,7 +52,7 @@ public:
     bool enable() override;
 
     void updateSettings() override;
-	void getDefaultEventInfo(Array<DefaultEventInfo>& events, int subProcessorIdx = 0) const override;
+	void createEventChannels() override;
 
     void addModule();
     void setActiveModule (int);
@@ -98,7 +98,7 @@ private:
     bool fallingPos;
     bool fallingNeg;
 
-	const EventChannel* outputEventChannel;
+	Array<const EventChannel*> moduleEventChannels;
 
     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PhaseDetector);
 };
diff --git a/Source/Plugins/SerialInput/SerialInput.cpp b/Source/Plugins/SerialInput/SerialInput.cpp
index 5c90d831a9c86c3981fd04571b96d594722db65b..24690561cf040ec7af792a7efd180310c21f43c3 100644
--- a/Source/Plugins/SerialInput/SerialInput.cpp
+++ b/Source/Plugins/SerialInput/SerialInput.cpp
@@ -63,8 +63,11 @@ SerialInput::~SerialInput()
 void SerialInput::createEventChannels()
 {
 	//It's going to be raw binary data, so let's make it uint8
-	EventChannel* chan = new EventChannel(EventChannel::UINT8_ARRAY, 1, MAX_MSG_SIZE, this);
-	chan->addEventMetaData(new MetaDataDescriptor(MetaDataDescriptor::UINT64, 1, "Read Bytes", "Number of actual read bytes in the buffer", "bufferLength"));
+	EventChannel* chan = new EventChannel(EventChannel::UINT8_ARRAY, 1, MAX_MSG_SIZE, CoreServices::getGlobalSampleRate(), this);
+	chan->setName("Serial message");
+	chan->setDescription("Data received via serial port");
+	chan->setDescriptor("buffer.rawData");
+	chan->addEventMetaData(new MetaDataDescriptor(MetaDataDescriptor::UINT64, 1, "Read Bytes", "Number of actual read bytes in the buffer", "buffer.size"));
 	eventChannelArray.add(chan);
 }
 
diff --git a/Source/Processors/AudioNode/AudioNode.cpp b/Source/Processors/AudioNode/AudioNode.cpp
index f5066997256d47f987a66ec52ad7f7fb992aaf94..29ff3ddf1ed349bac061aa0e801092cf3d93a2f4 100755
--- a/Source/Processors/AudioNode/AudioNode.cpp
+++ b/Source/Processors/AudioNode/AudioNode.cpp
@@ -319,7 +319,7 @@ void AudioNode::process(AudioSampleBuffer& buffer)
 
                     int remainingSamples = numSamplesExpected[i] - samplesToCopyFromOverflowBuffer;
 
-                    int samplesAvailable = numSamples.at(getProcessorFullId(dataChannelArray[i]->getSourceNodeID(), dataChannelArray[i]->getSubProcessorIdx()));
+                    int samplesAvailable = getNumSourceSamples(dataChannelArray[i]->getSourceNodeID(), dataChannelArray[i]->getSubProcessorIdx());
 
                     int samplesToCopyFromIncomingBuffer = ((remainingSamples <= samplesAvailable) ?
                                                            remainingSamples :
diff --git a/Source/Processors/Channel/InfoObjects.cpp b/Source/Processors/Channel/InfoObjects.cpp
index 96eabd3203551c1364eb10e7694dcaa374ffe43a..7bf9dfc3c73fdd90c1a89210a068e283db51e8f1 100644
--- a/Source/Processors/Channel/InfoObjects.cpp
+++ b/Source/Processors/Channel/InfoObjects.cpp
@@ -114,19 +114,15 @@ String NamedInfoObject::getDescription() const
 }
 
 //InfoObjectCommon
-InfoObjectCommon::InfoObjectCommon(uint16 idx, uint16 typeidx, const GenericProcessor* source, uint16 subproc)
+InfoObjectCommon::InfoObjectCommon(uint16 idx, uint16 typeidx, float sampleRate, const GenericProcessor* source, uint16 subproc)
 	:	NodeInfoBase(source->getNodeId()),
 		SourceProcessorInfo(source, subproc),
 		m_sourceIndex(idx),
-		m_sourceTypeIndex(typeidx)
+		m_sourceTypeIndex(typeidx),
+		m_sampleRate(sampleRate)
 {
 }
 
-void InfoObjectCommon::setSampleRate(float sampleRate)
-{
-	m_sampleRate = sampleRate;
-}
-
 float InfoObjectCommon::getSampleRate() const
 {
 	return m_sampleRate;
@@ -145,8 +141,8 @@ uint16 InfoObjectCommon::getSourceTypeIndex() const
 
 //DataChannel
 
-DataChannel::DataChannel(DataChannelTypes type, GenericProcessor* source, uint16 subproc) :
-	InfoObjectCommon(source->dataChannelCount++, source->dataChannelTypeCount[type]++, source, subproc),
+DataChannel::DataChannel(DataChannelTypes type, float sampleRate, GenericProcessor* source, uint16 subproc) :
+	InfoObjectCommon(source->dataChannelCount++, source->dataChannelTypeCount[type]++, sampleRate, source, subproc),
 	m_type(type)
 {
 	setName(getDefaultName());
@@ -224,7 +220,6 @@ void DataChannel::reset()
 	m_isEnabled = true;
 	m_isMonitored = false;
 	m_isRecording = false;
-	setSampleRate(44100);
 }
 
 String DataChannel::getDefaultName() const
@@ -245,8 +240,8 @@ String DataChannel::getDefaultName() const
 }
 
 //EventChannel
-EventChannel::EventChannel(EventChannelTypes type, unsigned int nChannels, unsigned int dataLength, GenericProcessor* source, uint16 subproc)
-	: InfoObjectCommon(source->eventChannelCount++, source->eventChannelTypeCount[type]++, source, subproc),
+EventChannel::EventChannel(EventChannelTypes type, unsigned int nChannels, unsigned int dataLength, float sampleRate, GenericProcessor* source, uint16 subproc)
+	: InfoObjectCommon(source->eventChannelCount++, source->eventChannelTypeCount[type]++, sampleRate, source, subproc),
 		m_type(type)
 {
 	m_numChannels = nChannels;
@@ -347,8 +342,8 @@ String EventChannel::getDefaultName() const
 //SpikeChannel
 
 SpikeChannel::SpikeChannel(ElectrodeTypes type, GenericProcessor* source, const Array<const DataChannel*>& sourceChannels, uint16 subproc)
-	: InfoObjectCommon(source->spikeChannelCount++, source->spikeChannelTypeCount[type]++, source, subproc),
-	m_type(type)
+	: InfoObjectCommon(source->spikeChannelCount++, source->spikeChannelTypeCount[type]++, sourceChannels[0]->getSampleRate(), source, subproc),
+	m_type(type) //We define the sample rate of the whole spike to be equal to that of the first channel. A spike composed from channels from different sample rates has no sense
 {
 	int n = sourceChannels.size();
 	jassert(n == getNumChannels(type));
diff --git a/Source/Processors/Channel/InfoObjects.h b/Source/Processors/Channel/InfoObjects.h
index 3a652b6014579b22cb8c6171a98873c978352e82..70f1f255cf1656615bad10cbd2330ad87c428430 100644
--- a/Source/Processors/Channel/InfoObjects.h
+++ b/Source/Processors/Channel/InfoObjects.h
@@ -132,7 +132,7 @@ class PLUGIN_API InfoObjectCommon :
 	public NodeInfoBase, public SourceProcessorInfo, public NamedInfoObject
 {
 protected:
-	InfoObjectCommon(uint16 idx, uint16 typeidx, const GenericProcessor* source, uint16 subproc = 0);
+	InfoObjectCommon(uint16 idx, uint16 typeidx, float sampleRate, const GenericProcessor* source, uint16 subproc = 0);
 
 public:
 	enum InfoObjectType
@@ -143,9 +143,6 @@ public:
 		INVALID = 100
 	};
 
-	/** Sets the sample rate value for this channel. */
-	void setSampleRate(float sampleRate);
-
 	/** Returns the sample rate value for this channel. */
 	float getSampleRate() const;
 
@@ -164,7 +161,7 @@ private:
 	const uint16 m_sourceIndex;
 	/** Index of this particular subtype in the source processor */
 	const uint16 m_sourceTypeIndex;
-	float m_sampleRate{ 44100.0f };
+	const float m_sampleRate;
 };
 
 // ------- Main objects -------//
@@ -185,12 +182,11 @@ public:
 
 	/** Default constructor for creating Channels from scratch.
 		@param type The type of data this channel represents (HEADSTAGE, ADC, AUX)
-		@param idx The index of this data channel in the source processor
-		@param typeidx The index of this particular type of data channel in the source processor
+		@param sampleRate the sample rate this channel is acquiring data
 		@param source A pointer to the source processor
 		@param subproc Optional. The source subprocessor index.
 	*/
-	DataChannel(DataChannelTypes type, GenericProcessor* source, uint16 subproc = 0);
+	DataChannel(DataChannelTypes type, float sampleRate, GenericProcessor* source, uint16 subproc = 0);
 
 	/** Copy constructor. */
 	DataChannel(const DataChannel& ch);
@@ -274,8 +270,7 @@ public:
 	@param type The type of event this channel represents (TTL, TEXT, BYINARY_MSG)
 	@param numChannels The number of virtual channels
 	@param dataLength The length of the event payload
-	@param idx The index of this event channel in the source processor
-	@param typeidx The index of this particular type of event channel in the source processor
+	@param sampleRate the sample rate this channel timestamps are referred to
 	@param source A pointer to the source processor
 	@param subproc Optional. The source subprocessor index.
 
@@ -289,7 +284,7 @@ public:
 	-For typed array events, the number of elements
 
 	*/
-	EventChannel(EventChannelTypes type, unsigned int numChannels, unsigned int dataLength, GenericProcessor* source, uint16 subproc = 0);
+	EventChannel(EventChannelTypes type, unsigned int numChannels, unsigned int dataLength, float sampleRate, GenericProcessor* source, uint16 subproc = 0);
 
 	~EventChannel();
 
@@ -350,8 +345,6 @@ public:
 
 	/** Default constructor 
 		@param type The type of electrode this channel represents (SINGLE, STEREOTRODE, TETRODE)
-		@param idx The index of this spike channel in the source processor
-		@param typeidx The index of this particular type of spike channel in the source processor
 		@param source A pointer to the source processor
 		@param souceChannels An array containing const pointers to the channels that originate the data for this spike electrode
 		@param subproc Optional. The source subprocessor index.
diff --git a/Source/Processors/Channel/MetaData.cpp b/Source/Processors/Channel/MetaData.cpp
index b4f7759985441784bc2eb866332655bd0b311709..6e73d3d0351ce6a2c1876b937ec514b47c8c5b81 100644
--- a/Source/Processors/Channel/MetaData.cpp
+++ b/Source/Processors/Channel/MetaData.cpp
@@ -46,10 +46,26 @@ bool checkMetaDataType(MetaDataDescriptor::MetaDataTypes baseType)
 
 MetaDataDescriptor::MetaDataDescriptor(MetaDataDescriptor::MetaDataTypes t, unsigned int length, String n, String d, String dm)
 	: m_name(n), m_description(d), m_descriptor(dm), m_type(t), m_length(length)
-{};
+{}
 
 MetaDataDescriptor::~MetaDataDescriptor() {};
 
+MetaDataDescriptor::MetaDataDescriptor(const MetaDataDescriptor& other)
+	:ReferenceCountedObject(),
+	m_name(other.m_name), m_descriptor(other.m_descriptor), m_description(other.m_description),
+	m_type(other.m_type), m_length(other.m_length)
+{}
+
+MetaDataDescriptor& MetaDataDescriptor::operator=(const MetaDataDescriptor& other)
+{
+	m_name = other.m_name;
+	m_descriptor = other.m_descriptor;
+	m_description = other.m_description;
+	m_type = other.m_type;
+	m_length = other.m_length;
+	return *this;
+}
+
 MetaDataDescriptor::MetaDataTypes MetaDataDescriptor::getType() const { return m_type; }
 unsigned int MetaDataDescriptor::getLength() const { return m_length; }
 size_t MetaDataDescriptor::getDataSize() const { return m_length*getTypeSize(m_type); }
@@ -149,7 +165,8 @@ void MetaDataValue::allocSpace()
 }
 
 MetaDataValue::MetaDataValue(const MetaDataValue& v)
-	: m_type(v.m_type), m_length(v.m_length), m_size(v.m_size)
+	: ReferenceCountedObject(),
+	m_type(v.m_type), m_length(v.m_length), m_size(v.m_size)
 {
 	allocSpace();
 	setValue(v.m_data.getData());
@@ -243,10 +260,31 @@ MetaDataInfoObject::MetaDataInfoObject() {}
 
 void MetaDataInfoObject::addMetaData(MetaDataDescriptor* desc, MetaDataValue* val)
 {
+	if (desc->getType() != val->getDataType() || desc->getLength() != val->getDataLength())
+	{
+		jassertfalse;
+		//This will cause a segfault if the software tries to use the pointers after calling this method
+		//Since this method should NEVER be called with non-matching metadata description and value, it's
+		//better than just leave dangling pointers.
+		delete desc;
+		delete val;
+		return;
+	}
 	m_metaDataDescriptorArray.add(desc);
 	m_metaDataValueArray.add(val);
 }
 
+void MetaDataInfoObject::addMetaData(const MetaDataDescriptor& desc, const MetaDataValue& val)
+{
+	if (desc.getType() != val.getDataType() || desc.getLength() != val.getDataLength())
+	{
+		jassertfalse;
+		return;
+	}
+	m_metaDataDescriptorArray.add(new MetaDataDescriptor(desc));
+	m_metaDataValueArray.add(new MetaDataValue(val));
+}
+
 const MetaDataDescriptor* MetaDataInfoObject::getMetaDataDescriptor(int index) const
 {
 	return m_metaDataDescriptorArray[index];
@@ -278,6 +316,18 @@ void MetaDataEventObject::addEventMetaData(MetaDataDescriptor* desc)
 	m_totalSize += desc->getDataSize();
 }
 
+void MetaDataEventObject::addEventMetaData(const MetaDataDescriptor& desc)
+{
+	if (eventMetaDataLock)
+	{
+		//throw assertion when debugging
+		jassertfalse;
+		return;
+	}
+	m_eventMetaDataDescriptorArray.add(new MetaDataDescriptor(desc));
+	m_totalSize += desc.getDataSize();
+}
+
 size_t MetaDataEventObject::getTotalEventMetaDataSize() const
 {
 	return m_totalSize;
diff --git a/Source/Processors/Channel/MetaData.h b/Source/Processors/Channel/MetaData.h
index db5b8481f3f83fa9a1f2a596604152f1c6f53cfa..60801fc3ccfb9fee28003c56fe1e1acf6376f11e 100644
--- a/Source/Processors/Channel/MetaData.h
+++ b/Source/Processors/Channel/MetaData.h
@@ -69,6 +69,9 @@ public:
 	*/
 	MetaDataDescriptor(MetaDataTypes type, unsigned int length, String name, String humanDescription, String machineDescriptor);
 	~MetaDataDescriptor();
+	MetaDataDescriptor(const MetaDataDescriptor& other);
+	MetaDataDescriptor& operator=(const MetaDataDescriptor& other);
+
 	/** Gets the primitive type of this field */
 	MetaDataTypes getType() const;
 	/** Gets the number of elements in this field */
@@ -88,11 +91,11 @@ public:
 	static size_t getTypeSize(MetaDataTypes type);
 private:
 	MetaDataDescriptor() = delete;
-	const String m_name;
-	const String m_descriptor;
-	const String m_description;
-	const MetaDataTypes m_type;
-	const unsigned int m_length;
+	String m_name;
+	String m_descriptor;
+	String m_description;
+	MetaDataTypes m_type;
+	unsigned int m_length;
 
 	JUCE_LEAK_DETECTOR(MetaDataDescriptor);
 };
@@ -169,6 +172,7 @@ protected:
 	MetaDataInfoObject();
 public:
 	void addMetaData(MetaDataDescriptor* desc, MetaDataValue* val);
+	void addMetaData(const MetaDataDescriptor& desc, const MetaDataValue& val);
 	const MetaDataDescriptor* getMetaDataDescriptor(int index) const;
 	const MetaDataValue* getMetaDataValue(int index) const;
 	const int getMetaDataCount() const;
@@ -195,6 +199,7 @@ class PLUGIN_API MetaDataEventObject : private MetaDataEventLock
 public:
 	//This method will only work when creating the info object, but not for those copied down the chain
 	void addEventMetaData(MetaDataDescriptor* desc);
+	void addEventMetaData(const MetaDataDescriptor& desc);
 	const MetaDataDescriptor* getEventMetaDataDescriptor(int index) const;
 	size_t getTotalEventMetaDataSize() const;
 	const int getEventMetaDataCount() const;
diff --git a/Source/Processors/GenericProcessor/GenericProcessor.cpp b/Source/Processors/GenericProcessor/GenericProcessor.cpp
index 2dd813feda5e59186fd8d86c3629d6c8eadb2fce..79cbadf38bb8ed7344974e796b5db0081ed3e2ea 100755
--- a/Source/Processors/GenericProcessor/GenericProcessor.cpp
+++ b/Source/Processors/GenericProcessor/GenericProcessor.cpp
@@ -443,8 +443,7 @@ void GenericProcessor::createDataChannelsByType(DataChannel::DataChannelTypes ty
 		int nChans = getDefaultNumDataOutputs(type, sub);
 		for (int i = 0; i < nChans; i++)
 		{
-			DataChannel* chan = new DataChannel(type, this, sub);
-			chan->setSampleRate(getSampleRate(sub));
+			DataChannel* chan = new DataChannel(type, getSampleRate(sub), this, sub);
 			chan->setBitVolts(getBitVolts(sub));
 			chan->addToHistoricString(getName());
 			chan->m_nodeID = nodeId;
@@ -465,8 +464,7 @@ void GenericProcessor::createEventChannels()
 		{
 			if (events[i].type != EventChannel::INVALID && events[i].nChannels > 0 && events[i].length > 0)
 			{
-				EventChannel* chan = new EventChannel(events[i].type, events[i].nChannels, events[i].length, this, sub);
-				chan->setSampleRate(getSampleRate(sub));
+				EventChannel* chan = new EventChannel(events[i].type, events[i].nChannels, events[i].length, events[i].sampleRate, this, sub);
 				chan->m_nodeID = nodeId;
 				eventChannelArray.add(chan);
 			}
@@ -564,7 +562,7 @@ uint32 GenericProcessor::getNumSamples (int channelNum) const
     {
         nSamples = numSamples.at (sourceID);
     }
-    catch (std::exception& e)
+    catch (...)
     {
         return 0;
     }
@@ -598,7 +596,7 @@ uint64 GenericProcessor::getTimestamp (int channelNum) const
     {
         ts = timestamps.at (sourceID);
     }
-    catch (std::exception& e)
+    catch (...)
     {
         return 0;
     }
@@ -606,6 +604,44 @@ uint64 GenericProcessor::getTimestamp (int channelNum) const
     return ts;
 }
 
+uint32 GenericProcessor::getNumSourceSamples(uint16 processorID, uint16 subProcessorIdx) const
+{
+	return getNumSourceSamples(getProcessorFullId(processorID, subProcessorIdx));
+}
+
+uint32 GenericProcessor::getNumSourceSamples(uint32 fullSourceID) const
+{
+	uint32 nSamples;
+	try
+	{
+		nSamples = numSamples.at(fullSourceID);
+	}
+	catch (...)
+	{
+		return 0;
+	}
+	return nSamples;
+}
+
+uint64 GenericProcessor::getSourceTimestamp(uint16 processorID, uint16 subProcessorIdx) const
+{
+	return getSourceTimestamp(getProcessorFullId(processorID, subProcessorIdx));
+}
+
+uint64 GenericProcessor::getSourceTimestamp(uint32 fullSourceID) const
+{
+	uint64 ts;
+	try
+	{
+		ts = timestamps.at(fullSourceID);
+	}
+	catch (...)
+	{
+		return 0;
+	}
+	return ts;
+}
+
 
 /** Used to set the timestamp for a given buffer, for a given channel. */
 void GenericProcessor::setTimestampAndSamples(uint64 timestamp, uint32 nSamples, int subProcessorIdx)
@@ -1165,19 +1201,20 @@ bool GenericProcessor::disable()
     return true;
 }
 
-GenericProcessor::DefaultEventInfo::DefaultEventInfo(EventChannel::EventChannelTypes t, unsigned int c, unsigned int l)
+GenericProcessor::DefaultEventInfo::DefaultEventInfo(EventChannel::EventChannelTypes t, unsigned int c, unsigned int l, float s)
 	:type(t),
 	nChannels(c),
-	length(l)
+	length(l),
+	sampleRate(s)
 {
 }
 
 GenericProcessor::DefaultEventInfo::DefaultEventInfo()
 	:type(EventChannel::INVALID),
 	nChannels(0),
-	length(0)
-{
-}
+	length(0),
+	sampleRate(44100)
+{}
 
 uint32 GenericProcessor::getProcessorFullId(uint16 sid, uint16 subid)
 {
diff --git a/Source/Processors/GenericProcessor/GenericProcessor.h b/Source/Processors/GenericProcessor/GenericProcessor.h
index d7b1617268e207207bb96c07cb8c93b048d10562..1bd477930074e2dd5eb961205c98c0ffdda0aba3 100755
--- a/Source/Processors/GenericProcessor/GenericProcessor.h
+++ b/Source/Processors/GenericProcessor/GenericProcessor.h
@@ -466,6 +466,24 @@ public:
     /** Used to get the timestamp for a given buffer, for a given channel. */
     uint64 getTimestamp (int channelNumber) const;
 
+	/** Used to get the number of samples a specific source generates. 
+	Look by source ID and subprocessor index */
+	uint32 getNumSourceSamples(uint16 processorID, uint16 subProcessorIdx) const;
+
+	/** Used to get the number of samples a specific source generates.
+	Look by full source ID.
+	@see GenericProcessor::getProcessorFullId(uint16,uint16) */
+	uint32 getNumSourceSamples(uint32 fullSourceID) const;
+
+	/** Used to get the current timestamp of a specific source.
+	Look by source ID and subprocessor index */
+	uint64 getSourceTimestamp(uint16 processorID, uint16 subProcessorIdx) const;
+
+	/** Used to get the current timestamp of a specific source.
+	Look by full source ID.
+	@see GenericProcessor::getProcessorFullId(uint16,uint16) */
+	uint64 getSourceTimestamp(uint32 fullSourceID) const;
+
     /** Used to set the timestamp for a given buffer, for a given source node. */
     void setTimestampAndSamples (uint64 timestamp, uint32 nSamples, int subProcessorIdx = 0);
 
@@ -505,10 +523,11 @@ public:
 	{
 	public:
 		DefaultEventInfo();
-		DefaultEventInfo(EventChannel::EventChannelTypes type, unsigned int nChans, unsigned int length);
+		DefaultEventInfo(EventChannel::EventChannelTypes type, unsigned int nChans, unsigned int length, float SampleRate);
 		EventChannel::EventChannelTypes type{ EventChannel::INVALID };
 		unsigned int nChannels{ 0 };
 		unsigned int length{ 0 };
+		float sampleRate{ 44100 };
 	};
 
 protected:
@@ -538,9 +557,6 @@ protected:
 	Called by createEventChannels(). It is not needed to implement if createEventChannels() is overriden */
 	virtual void getDefaultEventInfo(Array<DefaultEventInfo>& events, int subProcessorIdx = 0) const;
 
-	std::map<uint32, uint32> numSamples;
-	std::map<uint32, int64> timestamps;
-
     /** Sets whether processor will have behaviour like Source, Sink, Splitter, Utility or Merge */
     void setProcessorType (PluginProcessorType processorType);
 
@@ -576,6 +592,9 @@ protected:
 	void updateChannelIndexes(bool updateNodeID = true);
 
 private:
+	std::map<uint32, uint32> numSamples;
+	std::map<uint32, int64> timestamps;
+
 	void createDataChannelsByType(DataChannel::DataChannelTypes type);
 
 	/** Each processor has a unique integer ID that can be used to identify it.*/
diff --git a/Source/Processors/MessageCenter/MessageCenter.cpp b/Source/Processors/MessageCenter/MessageCenter.cpp
index 168aea03b5fdd7149bcac24c815a91b865698dc1..31267d3e11605b4567c1efad4b6cda2d0c770ac1 100644
--- a/Source/Processors/MessageCenter/MessageCenter.cpp
+++ b/Source/Processors/MessageCenter/MessageCenter.cpp
@@ -29,7 +29,7 @@
 //---------------------------------------------------------------------
 
 MessageCenter::MessageCenter() :
-    GenericProcessor("Message Center"), newEventAvailable(false), isRecording(false), sourceNodeId(0), 
+GenericProcessor("Message Center"), newEventAvailable(false), isRecording(false), sourceNodeId(0), sourceNodeSubIdx(0),
 	timestampSource(nullptr), lastTime(0), softTimestamp(0)
 {
 
@@ -46,11 +46,9 @@ MessageCenter::~MessageCenter()
 
 void MessageCenter::addSpecialProcessorChannels(Array<EventChannel*>& channels) 
 {
-	EventChannel* chan = new EventChannel(EventChannel::TEXT, 1, MAX_MSG_LENGTH, this, 0);
+	EventChannel* chan = new EventChannel(EventChannel::TEXT, 1, MAX_MSG_LENGTH, getGlobalSampleRate(), this, 0);
 	chan->setName("GUI Messages");
 	chan->setDescription("Messages from the GUI Message Center");
-	if (sourceNodeId)
-		chan->setSampleRate(static_cast<GenericProcessor*>(AccessClass::getProcessorGraph()->getNodeForId(sourceNodeId)->getProcessor())->getSampleRate());
 	channels.add(chan);
 	eventChannelArray.add(new EventChannel(*chan));
 	updateChannelIndexes();
@@ -110,9 +108,15 @@ bool MessageCenter::disable()
     return true;
 }
 
-void MessageCenter::setSourceNodeId(int id)
+void MessageCenter::setSourceNodeId(int id, int sub)
 {
     sourceNodeId = id;
+	sourceNodeSubIdx = sub;
+	AudioProcessorGraph::Node* node = AccessClass::getProcessorGraph()->getNodeForId(sourceNodeId);
+	if (node)
+	{
+		timestampSource = static_cast<GenericProcessor*>(node->getProcessor());
+	}
 }
 
 int MessageCenter::getSourceNodeId()
@@ -120,18 +124,31 @@ int MessageCenter::getSourceNodeId()
     return sourceNodeId;
 }
 
-int64 MessageCenter::getTimestamp(bool softwareTime)
+int MessageCenter::getSourceSubIdx()
 {
-    if (!softwareTime && sourceNodeId > 0)
-        return timestampSource->getTimestamp(0);
+	return sourceNodeSubIdx;
+}
+
+int64 MessageCenter::getGlobalTimestamp(bool softwareTime)
+{
+	if (!softwareTime && sourceNodeId > 0)
+		return timestampSource->getSourceTimestamp(sourceNodeId, sourceNodeSubIdx);
     else
         return (softTimestamp);
 }
 
+float MessageCenter::getGlobalSampleRate()
+{
+	if (sourceNodeId > 0)
+		return timestampSource->getSampleRate(sourceNodeSubIdx);
+	else
+		return Time::getHighResolutionTicksPerSecond();
+}
+
 void MessageCenter::process(AudioSampleBuffer& buffer)
 {
 	softTimestamp = Time::getHighResolutionTicks() - lastTime;
-    setTimestampAndSamples(getTimestamp(), 0);
+    setTimestampAndSamples(getGlobalTimestamp(), 0);
     if (needsToSendTimestampMessage)
     {
 		MidiBuffer& eventBuffer = *AccessClass::ExternalProcessorAccessor::getMidiBuffer(this);
@@ -151,7 +168,7 @@ void MessageCenter::process(AudioSampleBuffer& buffer)
 
 		eventString = eventString.dropLastCharacters(eventString.length() - MAX_MSG_LENGTH);
 
-		TextEventPtr event = TextEvent::createTextEvent(getEventChannel(0), getTimestamp(), eventString);
+		TextEventPtr event = TextEvent::createTextEvent(getEventChannel(0), getGlobalTimestamp(), eventString);
 		addEvent(getEventChannel(0), event, 0);
 
         newEventAvailable = false;
diff --git a/Source/Processors/MessageCenter/MessageCenter.h b/Source/Processors/MessageCenter/MessageCenter.h
index 0090719a35e24b455a99c09b2637ec82fea883d4..5413436ab1942475689d2580f6f83fe972e9a968 100644
--- a/Source/Processors/MessageCenter/MessageCenter.h
+++ b/Source/Processors/MessageCenter/MessageCenter.h
@@ -75,13 +75,15 @@ public:
         needsToSendTimestampMessage = false;
     }
 
-    void setSourceNodeId(int id);
+    void setSourceNodeId(int id, int sub);
     int getSourceNodeId();
+	int getSourceSubIdx();
 
     void addSourceProcessor(GenericProcessor* p);
     void removeSourceProcessor(GenericProcessor* p);
 
-    int64 getTimestamp(bool softwareTime = false);
+    int64 getGlobalTimestamp(bool softwareTime = false);
+	float getGlobalSampleRate();
 	
 	void addSpecialProcessorChannels(Array<EventChannel*>& channel);
 private:
@@ -89,7 +91,8 @@ private:
     bool newEventAvailable;
     bool isRecording;
     int sourceNodeId;
-    GenericProcessor* timestampSource;
+	int sourceNodeSubIdx;
+    const GenericProcessor* timestampSource;
     int64 lastTime, softTimestamp;
     bool needsToSendTimestampMessage;
 
diff --git a/Source/Processors/MessageCenter/MessageCenterEditor.cpp b/Source/Processors/MessageCenter/MessageCenterEditor.cpp
index b32f0d4e7cd45a9c0d4b882485bb67fd96b740bb..83da998a85761e48174fe0a4e7ac4eb26823e8ed 100644
--- a/Source/Processors/MessageCenter/MessageCenterEditor.cpp
+++ b/Source/Processors/MessageCenter/MessageCenterEditor.cpp
@@ -170,11 +170,6 @@ void MessageCenterEditor::resized()
         sendMessageButton->setBounds(getWidth()-50, 5, 45, getHeight()-10);
 }
 
-int64 MessageCenterEditor::getTimestamp(bool softwareTimestamp)
-{
-    return messageCenter->getTimestamp(softwareTimestamp);
-}
-
 void MessageCenterEditor::actionListenerCallback(const String& message)
 {
 
@@ -189,6 +184,7 @@ void MessageCenterEditor::saveStateToXml(XmlElement* xml)
 {
     XmlElement* messageEditorState = xml->createNewChildElement("MESSAGECENTER");
     messageEditorState->setAttribute("sourceNodeId",messageCenter->getSourceNodeId());
+	messageEditorState->setAttribute("sourceSubProcessorIdx", messageCenter->getSourceSubIdx());
 }
 
 void MessageCenterEditor::loadStateFromXml(XmlElement* xml)
@@ -197,7 +193,7 @@ void MessageCenterEditor::loadStateFromXml(XmlElement* xml)
     {
         if (xmlNode->hasTagName("MESSAGECENTER"))
         {
-            messageCenter->setSourceNodeId(xmlNode->getIntAttribute("sourceNodeId"));
+            messageCenter->setSourceNodeId(xmlNode->getIntAttribute("sourceNodeId"), xmlNode->getIntAttribute("sourceSubProcessorIdx"));
         }
     }
 }
@@ -225,22 +221,31 @@ void MessageCenterEditor::mouseDown(const MouseEvent& event)
         PopupMenu::dismissAllActiveMenus();
         sourceMenu->clear();
         sourceMenu->addItem(1,"Software timer",true,messageCenter->getSourceNodeId() == 0);
+		Array<int> sourceIdx;
+		Array<int> subIdx;
         for (int i=0; i < sourcesList.size(); i++)
         {
             GenericProcessor* p = sourcesList[i];
-            sourceMenu->addItem(i+2,p->getName(),true,(p->getNodeId() == messageCenter->getSourceNodeId()));
+			int numSub = p->getNumSubProcessors();
+			for (int j = 0; j < numSub; j++)
+			{
+				String text = (numSub > 1) ? p->getName() + "(" + String(j + 1) + ")" : p->getName();
+				sourceMenu->addItem(i + 2, text, true, (p->getNodeId() == messageCenter->getSourceNodeId() && j == messageCenter->getSourceSubIdx()));
+				sourceIdx.add(i);
+				subIdx.add(j);
+			}
         }
         res = sourceMenu->show(0,50,0,0);
 
         if (res > 1)
         {
-            GenericProcessor* p = sourcesList[res-2];
-			std::cout << "Selecting " << p->getName() << " with id " << p->getNodeId() << " as message source" << std::endl;
-			messageCenter->setSourceNodeId(p->getNodeId());
+            GenericProcessor* p = sourcesList[sourceIdx[res-2]];
+			std::cout << "Selecting " << p->getName() << " with id " << p->getNodeId() << " subprocessor: " << subIdx[res-2] <<" as message source" << std::endl;
+			messageCenter->setSourceNodeId(p->getNodeId(), subIdx[res-2]);
         }
         else if (res == 1)
         {
-            messageCenter->setSourceNodeId(0);
+            messageCenter->setSourceNodeId(0,0);
         }
     }
 }
diff --git a/Source/Processors/MessageCenter/MessageCenterEditor.h b/Source/Processors/MessageCenter/MessageCenterEditor.h
index 126a931dd7fc4130cb84fb03423ff06171895c76..49f4fa68181eb19bd44903b5b8e86f380aca5b81 100644
--- a/Source/Processors/MessageCenter/MessageCenterEditor.h
+++ b/Source/Processors/MessageCenter/MessageCenterEditor.h
@@ -72,8 +72,6 @@ public:
 
     void mouseDown(const MouseEvent& event);
 
-    int64 getTimestamp(bool softwareTimestamp = false);
-
 private:
 
     void buttonClicked(Button* button);
diff --git a/Source/Processors/ProcessorGraph/ProcessorGraph.cpp b/Source/Processors/ProcessorGraph/ProcessorGraph.cpp
index 0ba2515f1e82157cae8f686e687afe3af2b04d37..d793803e88b39d614416625025e669f7ccfcce64 100644
--- a/Source/Processors/ProcessorGraph/ProcessorGraph.cpp
+++ b/Source/Processors/ProcessorGraph/ProcessorGraph.cpp
@@ -109,11 +109,11 @@ void* ProcessorGraph::createNewProcessor(Array<var>& description, int id)//,
 			// by default, all source nodes record automatically
 			processor->setAllChannelsToRecord();
 			if (processor->isGeneratesTimestamps())
-			{
+			{ //If there are no source processors and we add one, set it as default for global timestamps and samplerates
 				getMessageCenter()->addSourceProcessor(processor);
 				if (getMessageCenter()->getSourceNodeId() == 0)
 				{
-					getMessageCenter()->setSourceNodeId(processor->getNodeId());
+					getMessageCenter()->setSourceNodeId(processor->getNodeId(),0);
 				}
 			}
 		}
@@ -560,7 +560,7 @@ void ProcessorGraph::removeProcessor(GenericProcessor* processor)
 				}
 			}
         }
-        getMessageCenter()->setSourceNodeId(newId);
+        getMessageCenter()->setSourceNodeId(newId, 0);
     }
 
 }
diff --git a/Source/Processors/SourceNode/SourceNode.cpp b/Source/Processors/SourceNode/SourceNode.cpp
index 5c388814e7fe709927060419d9e5359542f6bbbf..fa5f74ca13798eab9aa8106566c95c95a1b4b88c 100755
--- a/Source/Processors/SourceNode/SourceNode.cpp
+++ b/Source/Processors/SourceNode/SourceNode.cpp
@@ -182,8 +182,7 @@ void SourceNode::createEventChannels()
 			nChans = jmin(nChans, 64); //Just 64 TTL channels per source for now
 			if (nChans > 0)
 			{
-				EventChannel* chan = new EventChannel(EventChannel::TTL, nChans, 0, this, i);
-				chan->setSampleRate(dataThread->getSampleRate(i));
+				EventChannel* chan = new EventChannel(EventChannel::TTL, nChans, 0, dataThread->getSampleRate(i), this, i);
 				eventChannelArray.add(chan);
 				ttlChannels.add(chan);
 			}