/* ------------------------------------------------------------------ This file is part of the Open Ephys GUI Copyright (C) 2013 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 "LfpDisplayNode.h" #include "Visualization/LfpDisplayCanvas.h" #include <stdio.h> LfpDisplayNode::LfpDisplayNode() : GenericProcessor("LFP Viewer"), displayBufferIndex(0), displayGain(1), bufferLength(5.0f), abstractFifo(100), ttlState(0) { std::cout << " LFPDisplayNodeConstructor" << std::endl; displayBuffer = new AudioSampleBuffer(8, 100); eventBuffer = new MidiBuffer(); Array<var> timeBaseValues; timeBaseValues.add(1); timeBaseValues.add(2); timeBaseValues.add(5); timeBaseValues.add(10); parameters.add(Parameter("timebase",timeBaseValues, 1, 0));//true);//a,0); Array<var> displayGainValues; displayGainValues.add(1); displayGainValues.add(2); displayGainValues.add(4); displayGainValues.add(8); parameters.add(Parameter("display gain",displayGainValues, 1, 1));//true);//a,0); arrayOfOnes = new float[5000]; for (int n = 0; n < 5000; n++) { arrayOfOnes[n] = 1; } } LfpDisplayNode::~LfpDisplayNode() { //deleteAndZero(displayBuffer); //deleteAndZero(eventBuffer); } AudioProcessorEditor* LfpDisplayNode::createEditor() { editor = new LfpDisplayEditor(this, true); return editor; } void LfpDisplayNode::updateSettings() { std::cout << "Setting num inputs on LfpDisplayNode to " << getNumInputs() << std::endl; } bool LfpDisplayNode::resizeBuffer() { int nSamples = (int) getSampleRate()*bufferLength; int nInputs = getNumInputs(); std::cout << "Resizing buffer. Samples: " << nSamples << ", Inputs: " << nInputs << std::endl; if (nSamples > 0 && nInputs > 0) { abstractFifo.setTotalSize(nSamples); displayBuffer->setSize(nInputs+1, nSamples); // add an extra channel for TTLs return true; } else { return false; } } bool LfpDisplayNode::enable() { if (resizeBuffer()) { LfpDisplayEditor* editor = (LfpDisplayEditor*) getEditor(); editor->enable(); return true; } else { return false; } } bool LfpDisplayNode::disable() { LfpDisplayEditor* editor = (LfpDisplayEditor*) getEditor(); editor->disable(); return true; } void LfpDisplayNode::setParameter (int parameterIndex, float newValue) { //Sets Parameter in parameters array for processor Parameter* parameterPointer=parameters.getRawDataPointer(); parameterPointer=parameterPointer+parameterIndex; parameterPointer->setValue(newValue, currentChannel); //std::cout << "Saving Parameter from " << currentChannel << ", channel "; LfpDisplayEditor* ed = (LfpDisplayEditor*) getEditor(); if (ed->canvas != 0) ed->canvas->setParameter(parameterIndex, newValue); } void LfpDisplayNode::handleEvent(int eventType, MidiMessage& event, int sampleNum) { if (eventType == TTL) { const uint8* dataptr = event.getRawData(); // int eventNodeId = *(dataptr+1); int eventId = *(dataptr+2); int eventChannel = *(dataptr+3); int eventTime = event.getTimeStamp(); int samplesLeft = totalSamples - eventTime; // std::cout << "Received event from " << eventNodeId << ", channel " // << eventChannel << ", with ID " << eventId << std::endl; // int bufferIndex = (displayBufferIndex + eventTime);// % displayBuffer->getNumSamples(); if (eventId == 1) { ttlState |= (1L << eventChannel); } else { ttlState &= ~(1L << eventChannel); } if (samplesLeft + bufferIndex < displayBuffer->getNumSamples()) { // std::cout << bufferIndex << " " << samplesLeft << " " << ttlState << std::endl; displayBuffer->copyFrom(displayBuffer->getNumChannels()-1, // destChannel bufferIndex, // destStartSample arrayOfOnes, // source samplesLeft, // numSamples float(ttlState)); // gain } else { int block2Size = (samplesLeft + bufferIndex) % displayBuffer->getNumSamples(); int block1Size = samplesLeft - block2Size; //std::cout << "OVERFLOW." << std::endl; //std::cout << bufferIndex << " " << block1Size << " " << ttlState << std::endl; displayBuffer->copyFrom(displayBuffer->getNumChannels()-1, // destChannel bufferIndex, // destStartSample arrayOfOnes, // source block1Size, // numSamples float(ttlState)); // gain //std::cout << 0 << " " << block2Size << " " << ttlState << std::endl; displayBuffer->copyFrom(displayBuffer->getNumChannels()-1, // destChannel 0, // destStartSample arrayOfOnes, // source block2Size, // numSamples float(ttlState)); // gain } // std::cout << "ttlState: " << ttlState << std::endl; // std::cout << "Received event from " << eventNodeId << // " on channel " << eventChannel << // " with value " << eventId << // " at timestamp " << event.getTimeStamp() << std::endl; } else if (eventType == TIMESTAMP) { const uint8* dataptr = event.getRawData(); // int eventNodeId = *(dataptr+1); // int eventId = *(dataptr+2); // int eventChannel = *(dataptr+3); // update the timestamp for the current buffer: memcpy(&bufferTimestamp, dataptr+4, 4); // double timeInSeconds = double(ts)/Time::getHighResolutionTicksPerSecond(); // //int64 timestamp = ts[0] << 32 + // // ts[1] << 16 + // // ts[2] << 8 + // // ts[3]; // //memcpy(ts, dataptr+4, 1); // std::cout << "Time in seconds is " << timeInSeconds << std::endl; // // std::cout << "Received event from " << eventNodeId << // // " on channel " << eventChannel << // // " with value " << eventId << // // " for time: " << ts << std::endl; } } void LfpDisplayNode::initializeEventChannel() { if (displayBufferIndex + totalSamples < displayBuffer->getNumSamples()) { // std::cout << getNumInputs()+1 << " " << displayBufferIndex << " " << totalSamples << " " << ttlState << std::endl; // displayBuffer->copyFrom(displayBuffer->getNumChannels()-1, // destChannel displayBufferIndex, // destStartSample arrayOfOnes, // source totalSamples, // numSamples float(ttlState)); // gain } else { int block2Size = (displayBufferIndex + totalSamples) % displayBuffer->getNumSamples(); int block1Size = totalSamples - block2Size; // std::cout << "OVERFLOW." << std::endl; // std::cout << bufferIndex << " " << block1Size << " " << ttlState << std::endl; displayBuffer->copyFrom(displayBuffer->getNumChannels()-1, // destChannel displayBufferIndex, // destStartSample arrayOfOnes, // source block1Size, // numSamples float(ttlState)); // gain // std::cout << 0 << " " << block2Size << " " << ttlState << std::endl; displayBuffer->copyFrom(displayBuffer->getNumChannels()-1, // destChannel 0, // destStartSample arrayOfOnes, // source block2Size, // numSamples float(ttlState)); // gain } } void LfpDisplayNode::process(AudioSampleBuffer &buffer, MidiBuffer &events, int& nSamples) { // 1. place any new samples into the displayBuffer //std::cout << "Display node sample count: " << nSamples << std::endl; ///buffer.getNumSamples() << std::endl; totalSamples = nSamples; displayBufferIndexEvents = displayBufferIndex; initializeEventChannel(); checkForEvents(events); // update timestamp, see if we got any TTL events int samplesLeft = displayBuffer->getNumSamples() - displayBufferIndex; if (nSamples < samplesLeft) { for (int chan = 0; chan < buffer.getNumChannels(); chan++) { displayBuffer->copyFrom(chan, // destChannel displayBufferIndex, // destStartSample buffer, // source chan, // source channel 0, // source start sample nSamples); // numSamples } displayBufferIndex += (nSamples); } else { int extraSamples = nSamples - samplesLeft; for (int chan = 0; chan < buffer.getNumChannels(); chan++) { displayBuffer->copyFrom(chan, // destChannel displayBufferIndex, // destStartSample buffer, // source chan, // source channel 0, // source start sample samplesLeft); // numSamples displayBuffer->copyFrom(chan, 0, buffer, chan, samplesLeft, extraSamples); } displayBufferIndex = extraSamples; } }