Skip to content
Snippets Groups Projects
GenericProcessor.cpp 8.65 KiB
/*
    ------------------------------------------------------------------

    This file is part of the Open Ephys GUI
    Copyright (C) 2012 Open Ephys

    ------------------------------------------------------------------

    This program 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 3 of the License, or
    (at your option) any later version.

    This program 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 more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "GenericProcessor.h"
#include "../UI/UIComponent.h"

GenericProcessor::GenericProcessor(const String& name_) : 
    name(name_),
	sourceNode(0), destNode(0),
	isEnabled(true), 
	saveOrder(-1), loadOrder(-1),
	nextAvailableChannel(0), currentChannel(-1),
	wasConnected(false)
{
}

GenericProcessor::~GenericProcessor()
{
}

AudioProcessorEditor* GenericProcessor::createEditor()
{
	editor = new GenericEditor (this); 
	return editor;
}


void GenericProcessor::setParameter (int parameterIndex, float newValue)
{


}

void GenericProcessor::prepareToPlay (double sampleRate_, int estimatedSamplesPerBlock)
{
	// use the enable() function instead
	// prepareToPlay() is called by Juce as soon as a processor is created
	// enable() is only called by the ProcessorGraph just before the start of acquisition
}

void GenericProcessor::releaseResources() 
{	
	// use the disable() function instead
	// releaseResources() is called by Juce at unpredictable times
	// disable() is only called by the ProcessorGraph at the end of acquisition
}

int GenericProcessor::getNextChannel(bool increment)
{
	int chan = nextAvailableChannel;

	//std::cout << chan << std::endl;

	if (increment)
		nextAvailableChannel++;
	
	if (chan < getNumInputs())
		return chan;
	else
		return -1;

}

void GenericProcessor::resetConnections()
{
	//std::cout << "Resetting connections" << std::endl;
	nextAvailableChannel = 0;
	wasConnected = false;
}

void GenericProcessor::setNumSamples(MidiBuffer& midiMessages, int sampleIndex) {

	uint8 data[2];

	data[0] = BUFFER_SIZE; 	// most-significant byte
    data[1] = nodeId; 		// least-significant byte

    midiMessages.addEvent(data, 		// spike data
                          2, 			// total bytes
                          sampleIndex); // sample index

}

int GenericProcessor::getNumSamples(MidiBuffer& midiMessages) {

	int numRead = 0;

	if (midiMessages.getNumEvents() > 0) 
	{
			
		int m = midiMessages.getNumEvents();

		MidiBuffer::Iterator i (midiMessages);
		MidiMessage message(0xf4);

		int samplePosition = -5;

		while (i.getNextEvent (message, samplePosition)) {
			
			uint8* dataptr = message.getRawData();

			if (*dataptr == BUFFER_SIZE)
			{
				numRead = message.getTimeStamp();
			}
		}
	}

	return numRead;
}

void GenericProcessor::setSourceNode(GenericProcessor* sn)
{
	//std::cout << "My name is " << getName() << ". Setting source node." << std::endl;

	if (!isSource())
	{
	//	std::cout << " I am not a source." << std::endl;

		if (sn != 0)
		{

		//	std::cout << " The source is not blank." << std::endl;

			if (!sn->isSink())
			{
		//		std::cout << " The source is not a sink." << std::endl;

				if (sourceNode != sn) {

		//			std::cout << " The source is new and named " << sn->getName() << std::endl;
					
					if (this->isMerger())
						setMergerSourceNode(sn);
					else
						sourceNode = sn;

					sn->setDestNode(this);
					//setNumInputs(sn->getNumOutputs());
					//setSampleRate(sn->getSampleRate());
				} else {
		//			std::cout << "  The source node is not new." << std::endl;
				}
			} else {
		//		std::cout << " The source is a sink." << std::endl;
				sourceNode = 0;
			}

		} else {
	//		std::cout << " The source is blank." << std::endl;
			sourceNode = 0;
		}
	} else {
	//	std::cout << " I am a source. I can't have a source node." << std::endl;

		if (sn != 0)
			sn->setDestNode(this);
	}
}


void GenericProcessor::setDestNode(GenericProcessor* dn)
{


//	std::cout << "My name is " << getName() << ". Setting dest node." << std::endl;

	if (!isSink())
	{
	//	std::cout << "  I am not a sink." << std::endl;

		if (dn != 0)
		{
	//		std::cout << "  The dest node is not blank." << std::endl;

			if (!dn->isSource())
			{

		//		std::cout << "  The dest node is not a source." << std::endl;

				if (destNode != dn) 
				{
			//		std::cout << "  The dest node is new and named " << dn->getName() << std::endl;
//
					if (this->isSplitter())
						setSplitterDestNode(dn);
					else
						destNode = dn;

					dn->setSourceNode(this);
					//dn->setNumInputs(getNumOutputs());
					//dn->setSampleRate(getSampleRate());
				} else {
			//		std::cout << "  The dest node is not new." << std::endl;
				}
			} else {

			//	std::cout << "  The dest node is a source." << std::endl;

				destNode = 0;
			}
		} else {
		//	std::cout << "  The dest node is blank." << std::endl;

			destNode = 0;
		}
	} else {

		//std::cout << "  I am a sink, I can't have a dest node." << std::endl;
		//if (dn != 0)
		//	dn->setSourceNode(this);
	}
}

void GenericProcessor::clearSettings()
{
	settings.originalSource = 0;
	settings.numInputs = 0;
	settings.numOutputs = 0;
	settings.inputChannelNames.clear();
	settings.outputChannelNames.clear();
	settings.bitVolts.clear();
	settings.eventChannelIds.clear();
	settings.eventChannelNames.clear();
}

void GenericProcessor::update()
{

	std::cout << getName() << " updating settings." << std::endl;

	clearSettings();
	
	if (sourceNode != 0)
	{
		// everything is inherited except numOutputs
		settings = sourceNode->settings;
		settings.numInputs = settings.numOutputs;
		settings.numOutputs = settings.numInputs;

	} else {

		settings.sampleRate = getDefaultSampleRate();
		settings.numOutputs = getDefaultNumOutputs();

		for (int i = 0; i < getNumOutputs(); i++)
			settings.bitVolts.add(getDefaultBitVolts());

		generateDefaultChannelNames(settings.outputChannelNames);

	}

	if (this->isSink())
	{
		settings.numOutputs = 0;
		settings.outputChannelNames.clear();
	}

	updateSettings(); // custom settings code
	// required for the ProcessorGraph to know the
	// details of this processor:
	setPlayConfigDetails(getNumInputs(),  // numIns
		                 getNumOutputs(), // numOuts
		                 44100.0,         // sampleRate
		                 128);            // blockSize

	editor->update(); // update editor settings

}

void GenericProcessor::generateDefaultChannelNames(StringArray& names)
{
	names.clear();

	for (int i = 0; i < settings.numOutputs; i++)
	{
		String channelName = "CH";
		channelName += (i+1);
		names.add(channelName);
	}

}


int GenericProcessor::checkForEvents(MidiBuffer& midiMessages)
{

	if (midiMessages.getNumEvents() > 0) 
	{
			
		int m = midiMessages.getNumEvents();
		//std::cout << m << " events received by node " << getNodeId() << std::endl;

		MidiBuffer::Iterator i (midiMessages);
		MidiMessage message(0xf4);

		int samplePosition;
		i.setNextSamplePosition(samplePosition);

		while (i.getNextEvent (message, samplePosition)) {
			
			//int numbytes = message.getRawDataSize();
			uint8* dataptr = message.getRawData();

			handleEvent(*dataptr, message);

		}

	}

	return -1;

}

void GenericProcessor::addEvent(MidiBuffer& midiMessages,
							    uint8 type,
							    int sampleNum,
							    uint8 eventId,
							    uint8 eventChannel,
							    uint8 numBytes,
							    uint8* eventData)
{
	uint8 data[4+numBytes];

	data[0] = type;    // event type
    data[1] = nodeId;  // processor ID
    data[2] = eventId; // event ID
    data[3] = eventChannel; // event channel
    memcpy(&data[4], eventData, numBytes);

    midiMessages.addEvent(data, 		// spike data
                          sizeof(data), // total bytes
                          sampleNum);     // sample index
}

void GenericProcessor::processBlock (AudioSampleBuffer &buffer, MidiBuffer &midiMessages)
{
	
	int nSamples = getNumSamples(midiMessages); // removes first value from midimessages

	process(buffer, midiMessages, nSamples);

	setNumSamples(midiMessages, nSamples); // adds it back,
										   // even if it's unchanged

}