diff --git a/Plugins/BasicSpikeDisplay/SpikeDisplayNode/SpikeDisplayNode.cpp b/Plugins/BasicSpikeDisplay/SpikeDisplayNode/SpikeDisplayNode.cpp index e56a1146d..15f39bbdf 100644 --- a/Plugins/BasicSpikeDisplay/SpikeDisplayNode/SpikeDisplayNode.cpp +++ b/Plugins/BasicSpikeDisplay/SpikeDisplayNode/SpikeDisplayNode.cpp @@ -106,7 +106,7 @@ void SpikeDisplayNode::setParameter(int param, float val) for (auto ch : chan->localChannelIndexes) { - msg += String(ch) + " "; + msg += String(ch + 1) + " "; } //std::cout << "MESSAGE: " << msg << std::endl; diff --git a/Plugins/LfpDisplayNode/LfpChannelDisplay.cpp b/Plugins/LfpDisplayNode/LfpChannelDisplay.cpp index 532231a73..faf7313f0 100644 --- a/Plugins/LfpDisplayNode/LfpChannelDisplay.cpp +++ b/Plugins/LfpDisplayNode/LfpChannelDisplay.cpp @@ -243,7 +243,7 @@ void LfpChannelDisplay::pxPaint() double a = (canvasSplit->getYCoordMax(chan, index)/range*channelHeightFloat); double b = (canvasSplit->getYCoordMin(chan, index)/range*channelHeightFloat); - double mean = (canvasSplit->getMean(chan)/range*channelHeightFloat); + double mean = (canvasSplit->getScreenBufferMean(chan)/range*channelHeightFloat); if (drawWithOffsetCorrection) { @@ -508,7 +508,7 @@ void LfpChannelDisplay::pxPaintHistory(int playhead, int rightEdge, int maxScree double a = (canvasSplit->getYCoordMax(chan, index) / range * channelHeightFloat); double b = (canvasSplit->getYCoordMin(chan, index) / range * channelHeightFloat); - double mean = (canvasSplit->getMean(chan) / range * channelHeightFloat); + double mean = (canvasSplit->getScreenBufferMean(chan) / range * channelHeightFloat); if (drawWithOffsetCorrection) { diff --git a/Plugins/LfpDisplayNode/LfpChannelDisplayInfo.cpp b/Plugins/LfpDisplayNode/LfpChannelDisplayInfo.cpp index f65a08f92..e91af3586 100644 --- a/Plugins/LfpDisplayNode/LfpChannelDisplayInfo.cpp +++ b/Plugins/LfpDisplayNode/LfpChannelDisplayInfo.cpp @@ -247,7 +247,7 @@ void LfpChannelDisplayInfo::paint(Graphics& g) g.setColour(Colours::grey); g.drawText(String(canvasSplit->getStd(chan)), 5, center+110,41,10,Justification::centred,false); - g.drawText(String(canvasSplit->getMean(chan)), 5, center+60,41,10,Justification::centred,false); + g.drawText(String(canvasSplit->getDisplayBufferMean(chan)), 5, center+60,41,10,Justification::centred,false); if (x > 0) { diff --git a/Plugins/LfpDisplayNode/LfpDisplayCanvas.cpp b/Plugins/LfpDisplayNode/LfpDisplayCanvas.cpp index 18087a32e..5b5aa6c0b 100644 --- a/Plugins/LfpDisplayNode/LfpDisplayCanvas.cpp +++ b/Plugins/LfpDisplayNode/LfpDisplayCanvas.cpp @@ -1548,7 +1548,7 @@ uint16 LfpDisplaySplitter::getChannelStreamId(int channel) return processor->getContinuousChannel(channel)->getStreamId(); } -float LfpDisplaySplitter::getMean(int chan) +float LfpDisplaySplitter::getScreenBufferMean(int chan) { float total = 0.0f; float numPts = 0; @@ -1566,16 +1566,51 @@ float LfpDisplaySplitter::getMean(int chan) return total / numPts; } +float LfpDisplaySplitter::getDisplayBufferMean(int chan) +{ + float total = 0.0f; + float numPts = 0; + + float sample = 0.0f; + + // use 0.1s of sample to compute Mean and Std + float totalPoints = 0.1 * sampleRate; + + for (int samp = displayBufferIndex[chan] - totalPoints; samp < displayBufferIndex[chan]; samp += 1) + { + if (samp >= 0) // read the beginning of the buffer + sample = *displayBuffer->getReadPointer(chan, samp); + else // read the end of the buffer if negative index + sample = *displayBuffer->getReadPointer(chan, displayBuffer->getNumSamples() - samp); + + total += sample; + numPts++; + } + + //std::cout << sample << std::endl; + + return total / numPts; +} + float LfpDisplaySplitter::getStd(int chan) { float std = 0.0f; + float sample = 0.0f; - float mean = getMean(chan); + float mean = getDisplayBufferMean(chan); float numPts = 1; - for (int samp = 0; samp < (lfpDisplay->getWidth() - leftmargin); samp += 10) + // use 0.1s of sample to compute Mean and Std + float totalPoints = 0.1 * sampleRate; + + for (int samp = displayBufferIndex[chan] - totalPoints; samp < displayBufferIndex[chan]; samp += 1) { - std += pow((*screenBufferMean->getReadPointer(chan, samp) - mean),2); + if (samp >= 0) // read the beginning of the buffer + sample = *displayBuffer->getReadPointer(chan, samp); + else // read the end of the buffer if negative index + sample = *displayBuffer->getReadPointer(chan, displayBuffer->getNumSamples() - samp); + + std += pow((sample - mean),2); numPts++; } diff --git a/Plugins/LfpDisplayNode/LfpDisplayCanvas.h b/Plugins/LfpDisplayNode/LfpDisplayCanvas.h index 884a81edc..83d3b76e0 100644 --- a/Plugins/LfpDisplayNode/LfpDisplayCanvas.h +++ b/Plugins/LfpDisplayNode/LfpDisplayCanvas.h @@ -263,8 +263,11 @@ class LfpDisplaySplitter : public Component, /** Gets the event channel state for a particular sample */ const float getEventState(int samp); - /** Returns the mean of a given channel */ - float getMean(int chan); + /** Returns the mean of a given channel, computed from the screen buffer */ + float getScreenBufferMean(int chan); + + /** Returns the mean of a given channel, computed from the display buffer */ + float getDisplayBufferMean(int chan); /** Returns the standard deviation of a given channnel*/ float getStd(int chan); diff --git a/Source/Processors/AudioMonitor/AudioMonitor.cpp b/Source/Processors/AudioMonitor/AudioMonitor.cpp index 86002e738..8edc1c8fe 100644 --- a/Source/Processors/AudioMonitor/AudioMonitor.cpp +++ b/Source/Processors/AudioMonitor/AudioMonitor.cpp @@ -26,12 +26,92 @@ #include -AudioMonitor::AudioMonitor() - : GenericProcessor ("Audio Monitor"), +AudioMonitorSettings::AudioMonitorSettings() + : numChannels(0), + sampleRate(0), destBufferSampleRate(44100.0f), estimatedSamples(1024) { +} + +void AudioMonitorSettings::createFilters (int nChans, float sampleRate_) +{ + numChannels = nChans; + sampleRate = sampleRate_; + + bandpassfilters.clear(); + antialiasingfilters.clear(); + + Dsp::Params bandpassParams; + bandpassParams[0] = sampleRate; // sample rate + bandpassParams[1] = 2; // order + bandpassParams[2] = (7000 + 100) / 2; // center frequency + bandpassParams[3] = 7000 - 100; // bandwidth + + for (int n = 0; n < numChannels; ++n) + { + bandpassfilters.add(new Dsp::SmoothedFilterDesign + , // order + 1, // number of channels (must be const) + Dsp::DirectFormII>(1)); // realization + + bandpassfilters.getLast()->setParams (bandpassParams); + + antialiasingfilters.add(new Dsp::SmoothedFilterDesign(1024)); + } + + updateAntiAliasingFilterParameters(); + +} + +void AudioMonitorSettings::updateAntiAliasingFilterParameters () +{ + Dsp::Params antialiasingParams; + antialiasingParams[0] = destBufferSampleRate; // sample rate + antialiasingParams[1] = destBufferSampleRate / 2; // cutoff frequency + antialiasingParams[2] = 1.25; //Q // + + for (int i = 0; i < numChannels; ++i) + { + antialiasingfilters[i]->setParams(antialiasingParams); + } +} + +void AudioMonitorSettings::setOutputSampleRate(double outputSampleRate, double estimatedSamplesPerBlock) +{ + destBufferSampleRate = outputSampleRate; + estimatedSamples = estimatedSamplesPerBlock; + + numSamplesExpected = (sampleRate / destBufferSampleRate) * estimatedSamples; + ratio = sampleRate/destBufferSampleRate; + + samplesInBackupBuffer.clear(); + samplesInOverflowBuffer.clear(); + + bufferA.clear(); + bufferB.clear(); + bufferSwap.clear(); + + for (int i = 0; i < numChannels; i++) + { + samplesInBackupBuffer.emplace(i, 0.0f); + samplesInOverflowBuffer.emplace(i, 0.0f); + + bufferA.emplace(i, std::make_unique>(1, (int)destBufferSampleRate)); + bufferB.emplace(i, std::make_unique>(1, (int)destBufferSampleRate)); + bufferSwap.emplace(i, false); + } + + updateAntiAliasingFilterParameters(); +} + + +AudioMonitor::AudioMonitor() + : GenericProcessor ("Audio Monitor") +{ + tempBuffer = std::make_unique(); addBooleanParameter(Parameter::GLOBAL_SCOPE, @@ -47,21 +127,9 @@ AudioMonitor::AudioMonitor() addSelectedChannelsParameter(Parameter::STREAM_SCOPE, String("Channels"), - "Channels to monitor", - 4); - - for (int i = 0; i < MAX_CHANNELS; i++) - { - - bandpassfilters.add (new Dsp::SmoothedFilterDesign - , // order - 1, // number of channels (must be const) - Dsp::DirectFormII> (1)); // realization - - antialiasingfilters.add (new Dsp::SmoothedFilterDesign (1024)); - } + "Channels to monitor"); + tempBuffer->setSize(1, 4096); } @@ -76,21 +144,13 @@ AudioProcessorEditor* AudioMonitor::createEditor() void AudioMonitor::updateSettings() { updatePlaybackBuffer(); - + + settings.update (getDataStreams()); + for (auto stream : dataStreams) { - - Array* activeChannels = stream->getParameter("Channels")->getValue().getArray(); - - if (activeChannels->size() > 0) - { - selectedStream = stream->getStreamId(); - - for (int i = 0; i < activeChannels->size(); i++) - { - updateFilter(i, selectedStream); - } - } + settings[stream->getStreamId()]->createFilters(stream->getChannelCount(), + stream->getSampleRate()); } } @@ -111,132 +171,30 @@ void AudioMonitor::updatePlaybackBuffer() void AudioMonitor::prepareToPlay(double sampleRate_, int estimatedSamplesPerBlock) { - - destBufferSampleRate = sampleRate_; - estimatedSamples = estimatedSamplesPerBlock; - recreateBuffers(); - -} - - -void AudioMonitor::recreateBuffers() -{ - numSamplesExpected.clear(); - sourceBufferSampleRate.clear(); - - ratio.clear(); - - for (int i = 0; i < getNumInputs(); i++) + for (auto stream : dataStreams) { - numSamplesExpected.emplace(i, - continuousChannels[i]->getSampleRate() - / destBufferSampleRate - * estimatedSamples); - - sourceBufferSampleRate.emplace(i, continuousChannels[i]->getSampleRate()); - - ratio.emplace(i, sourceBufferSampleRate[i]/destBufferSampleRate); - + settings[stream->getStreamId()]->setOutputSampleRate(sampleRate_, estimatedSamplesPerBlock); } - - samplesInBackupBuffer.clear(); - samplesInOverflowBuffer.clear(); - - bufferA.clear(); - bufferB.clear(); - bufferSwap.clear(); - - for (int i = 0; i < MAX_CHANNELS; i++) - { - - samplesInBackupBuffer.emplace(i, 0.0f); - samplesInOverflowBuffer.emplace(i, 0.0f); - - bufferA.emplace(i, std::make_unique>(1,44100)); - bufferB.emplace(i, std::make_unique>(1,44100)); - bufferSwap.emplace(i, false); - - } - - tempBuffer->setSize(1, 4096); } void AudioMonitor::parameterValueChanged(Parameter* param) { - LOGD("Audio Monitor: Value changed for ", param->getName(), ": ", (int)param->getValue()); + LOGD("Audio Monitor: Value changed for ", param->getName()); if (param->getName().equalsIgnoreCase("Channels")) { - - selectedStream = param->getStreamId(); - Array* activeChannels = param->getValue().getArray(); - - if (activeChannels->size() == 0) - LOGA("No channels selected."); LOGD("Num selected channels: ", activeChannels->size()); - - for (int i = 0; i < activeChannels->size(); i++) - { - - int localIndex =(int) activeChannels->getReference(i); - - LOGA("Selected channel ", localIndex); - - auto continuousChannels = getDataStream(selectedStream)->getContinuousChannels(); - - if (continuousChannels.size() > localIndex) - { - int globalIndex = continuousChannels[localIndex]->getGlobalIndex(); - - updateFilter(i, selectedStream); - } - - } - - // clear monitored channels on all other streams - //for (auto stream : dataStreams) - //{ - // if (stream->getStreamId() != selectedStream) - // { - // stream->getParameter("Channels")->currentValue = Array(); - // } - //} } } - -void AudioMonitor::updateFilter(int i, uint16 streamId) -{ - - Dsp::Params params1; - params1[0] = getDataStream(streamId)->getSampleRate(); // sample rate - params1[1] = 2; // order - params1[2] = (7000 + 100) / 2; // center frequency - params1[3] = 7000 - 100; // bandwidth - - bandpassfilters[i]->setParams (params1); - - double cutoffFreq = destBufferSampleRate / 2; // upsample - - double sampleFreq = destBufferSampleRate; // upsample - - Dsp::Params params2; - params2[0] = sampleFreq; // sample rate - params2[1] = cutoffFreq; // cutoff frequency - params2[2] = 1.25; //Q // - - antialiasingfilters[i]->setParams(params2); - -} - void AudioMonitor::handleBroadcastMessage(String msg) { - LOGD("Audio Monitor received message: ", msg); + LOGC("Audio Monitor received message: ", msg); StringArray parts = StringArray::fromTokens(msg, " ", ""); @@ -248,23 +206,45 @@ void AudioMonitor::handleBroadcastMessage(String msg) if (command.equalsIgnoreCase("SELECT")) { - if (parts.size() >= 4) + if(parts.size() == 3) + { + String command = parts[2]; + + if (command.equalsIgnoreCase ("NONE")) + { + Array ch; + + for (auto stream : getDataStreams()) + stream->getParameter ("channels")->setNextValue (ch); + + } + } + else if (parts.size() >= 4) { uint16 streamId = parts[2].getIntValue(); - - DataStream* stream = getDataStream(streamId); - + + DataStream* stream = getDataStream (streamId); + if (stream != nullptr) { - - int localChannel = parts[3].getIntValue() - 1; - - if (localChannel >= 0 && localChannel < stream->getContinuousChannels().size()) + Array ch; + int channelCount = 0; + + while (channelCount < (parts.size() - 3)) { - Array ch; - ch.add(localChannel); - - stream->getParameter("Channels")->setNextValue(ch); + int localChannel = parts[channelCount + 3].getIntValue() - 1; + + if (localChannel >= 0 && localChannel < stream->getContinuousChannels().size()) + { + ch.add (localChannel); + } + + channelCount++; + } + + if (ch.size() > 0) + { + stream->getParameter ("Channels")->setNextValue (ch); } } } @@ -293,7 +273,7 @@ void AudioMonitor::process (AudioBuffer& buffer) if (stream->getStreamId() == selectedStream && (*stream)["enable_stream"]) { - + auto streamSettings = settings[selectedStream]; AudioSampleBuffer* overflowBuffer; AudioSampleBuffer* backupBuffer; @@ -308,34 +288,34 @@ void AudioMonitor::process (AudioBuffer& buffer) tempBuffer->clear(); - if (!bufferSwap[i]) + if (!streamSettings->bufferSwap[localIndex]) { - overflowBuffer = bufferA[i].get(); - backupBuffer = bufferB[i].get(); + overflowBuffer = streamSettings->bufferA[localIndex].get(); + backupBuffer = streamSettings->bufferB[localIndex].get(); - bufferSwap[i] = true; + streamSettings->bufferSwap[localIndex] = true; } else { - overflowBuffer = bufferB[i].get(); - backupBuffer = bufferA[i].get(); + overflowBuffer = streamSettings->bufferB[localIndex].get(); + backupBuffer = streamSettings->bufferA[localIndex].get(); - bufferSwap[i] = false; + streamSettings->bufferSwap[localIndex] = false; } backupBuffer->clear(); - samplesInOverflowBuffer[i] = samplesInBackupBuffer[i]; // size of buffer after last round - samplesInBackupBuffer[i] = 0; + streamSettings->samplesInOverflowBuffer[localIndex] = streamSettings->samplesInBackupBuffer[localIndex]; // size of buffer after last round + streamSettings->samplesInBackupBuffer[localIndex] = 0; double orphanedSamples = 0; // 1. copy overflow buffer double samplesToCopyFromOverflowBuffer = - ((samplesInOverflowBuffer[i] <= numSamplesExpected[globalIndex]) ? - samplesInOverflowBuffer[i] : - numSamplesExpected[globalIndex]); + ((streamSettings->samplesInOverflowBuffer[localIndex] <= streamSettings->numSamplesExpected) ? + streamSettings->samplesInOverflowBuffer[localIndex] : + streamSettings->numSamplesExpected); // LOGD("Number of samples to copy: ", samplesToCopyFromOverflowBuffer); @@ -353,7 +333,7 @@ void AudioMonitor::process (AudioBuffer& buffer) 1.0f // gain to apply ); - double leftoverSamples = samplesInOverflowBuffer[i] - samplesToCopyFromOverflowBuffer; + double leftoverSamples = streamSettings->samplesInOverflowBuffer[localIndex] - samplesToCopyFromOverflowBuffer; //std::cout << "Copying to backup buffer: " << leftoverSamples << std::endl; @@ -370,10 +350,10 @@ void AudioMonitor::process (AudioBuffer& buffer) ); } - samplesInBackupBuffer[i] = leftoverSamples; + streamSettings->samplesInBackupBuffer[localIndex] = leftoverSamples; } - double remainingSamples = double(numSamplesExpected[globalIndex]) - samplesToCopyFromOverflowBuffer; + double remainingSamples = double(streamSettings->numSamplesExpected) - samplesToCopyFromOverflowBuffer; double samplesAvailable = double(getNumSamplesInBlock(selectedStream)); @@ -404,11 +384,12 @@ void AudioMonitor::process (AudioBuffer& buffer) //std::cout << "Orphaned samples: " << orphanedSamples << std::endl; - if (orphanedSamples > 0 && (samplesInBackupBuffer[i] + orphanedSamples < backupBuffer->getNumSamples())) + if (orphanedSamples > 0 && + (streamSettings->samplesInBackupBuffer[localIndex] + orphanedSamples < backupBuffer->getNumSamples())) { backupBuffer->addFrom(0, // destination channel - samplesInBackupBuffer[i], // destination start sample + streamSettings->samplesInBackupBuffer[localIndex], // destination start sample buffer, // source globalIndex, // source channel (int) remainingSamples, // source start sample @@ -416,7 +397,7 @@ void AudioMonitor::process (AudioBuffer& buffer) 1.0f // gain to apply ); - samplesInBackupBuffer[i] = samplesInBackupBuffer[i] + orphanedSamples; + streamSettings->samplesInBackupBuffer[localIndex] += orphanedSamples; } @@ -431,7 +412,7 @@ void AudioMonitor::process (AudioBuffer& buffer) if (totalCopied == 0) continue; - bandpassfilters[i]->process(totalCopied, &ptr); + streamSettings->bandpassfilters[localIndex]->process(totalCopied, &ptr); /*if (i == 0) { @@ -484,7 +465,7 @@ void AudioMonitor::process (AudioBuffer& buffer) 1, // number of samples alpha); // gain to apply to source - subSampleOffset += ratio[globalIndex]; + subSampleOffset += streamSettings->ratio; while (subSampleOffset >= 1.0) { diff --git a/Source/Processors/AudioMonitor/AudioMonitor.h b/Source/Processors/AudioMonitor/AudioMonitor.h index bf3c2d1e3..38f217cc1 100644 --- a/Source/Processors/AudioMonitor/AudioMonitor.h +++ b/Source/Processors/AudioMonitor/AudioMonitor.h @@ -31,7 +31,47 @@ #include "../GenericProcessor/GenericProcessor.h" #include "../Dsp/Dsp.h" -#define MAX_CHANNELS 4 +/** + Creates and holds the filter settings for one input stream in the AudioMonitor. +*/ +class AudioMonitorSettings +{ +public: + + AudioMonitorSettings(); + + int numChannels; + float sampleRate; + double destBufferSampleRate; + double estimatedSamples; + + /** Bandpass filters (1 per channel)*/ + OwnedArray bandpassfilters; + + /** Antialiasing filters (1 per channel)*/ + OwnedArray antialiasingfilters; + + std::map>> bufferA; + std::map>> bufferB; + + /** Per-channel buffer state information*/ + std::map samplesInBackupBuffer; + std::map samplesInOverflowBuffer; + std::map bufferSwap; + double numSamplesExpected; + double ratio; + + /** Creates new filters when input settings change*/ + void createFilters(int numChannels, float sampleRate); + + /** Updates filters when parameters change*/ + void updateAntiAliasingFilterParameters(); + + /** Re-sets the copy buffers prior to starting acquisition*/ + void setOutputSampleRate(double outputSampleRate, double estimatedSamplesPerBlock); + +}; + /** Reads data from a file. @@ -68,39 +108,16 @@ class AudioMonitor : public GenericProcessor /** Resets the connections prior to a new round of data acquisition. */ void resetConnections() override; - - /** Updates the bandpass filter parameters, given the currently monitored stream*/ - void updateFilter(int i, uint16 streamId); /** Allows other processors to configure the Audio Monitor during acquisition*/ void handleBroadcastMessage(String message) override; -private: - - /** Re-sets the copy buffers prior to acquisition*/ - void recreateBuffers(); - - std::map>> bufferA; - std::map>> bufferB; + void setSelectedStream(uint16 streamId) { selectedStream = streamId; } - /** Per-channel buffer state information*/ - std::map samplesInBackupBuffer; - std::map samplesInOverflowBuffer; - std::map sourceBufferSampleRate; - std::map bufferSwap; - - std::map numSamplesExpected; - std::map ratio; - - double destBufferSampleRate; - double estimatedSamples; +private: - /** 4 bandpass filters (1 per selected channel)*/ - OwnedArray bandpassfilters; + StreamSettings settings; - /** 4 antialiasing filters (1 per selected channel)*/ - OwnedArray antialiasingfilters; - /** Holds the data for one channel, before it's copied to the output*/ std::unique_ptr> tempBuffer; diff --git a/Source/Processors/AudioMonitor/AudioMonitorEditor.cpp b/Source/Processors/AudioMonitor/AudioMonitorEditor.cpp index da8e8bf9c..9df78a60a 100644 --- a/Source/Processors/AudioMonitor/AudioMonitorEditor.cpp +++ b/Source/Processors/AudioMonitor/AudioMonitorEditor.cpp @@ -176,16 +176,16 @@ AudioMonitorEditor::AudioMonitorEditor (GenericProcessor* parentNode) { audioMonitor = static_cast(parentNode); - addSelectedChannelsParameterEditor("Channels", 10, 35); + addSelectedChannelsParameterEditor("Channels", 15, 35); Parameter* muteParam = parentNode->getParameter("mute_audio"); - addCustomParameterEditor(new MonitorMuteButton(muteParam), 135, 35); + addCustomParameterEditor(new MonitorMuteButton(muteParam), 130, 35); Parameter* outputParam = parentNode->getParameter("audio_output"); - addCustomParameterEditor(new AudioOutputSelector(outputParam), 20, 65); + addCustomParameterEditor(new AudioOutputSelector(outputParam), 15, 65); spikeChannelSelector = std::make_unique("Spike Channels"); - spikeChannelSelector->setBounds(20, 100, 140, 20); + spikeChannelSelector->setBounds(15, 100, 140, 20); for (int i = 0; i < audioMonitor->getTotalSpikeChannels() ; i++) { @@ -198,11 +198,12 @@ AudioMonitorEditor::AudioMonitorEditor (GenericProcessor* parentNode) spikeChannelSelector->addListener(this); addAndMakeVisible(spikeChannelSelector.get()); - desiredWidth = 180; + desiredWidth = 170; } void AudioMonitorEditor::selectedStreamHasChanged() { + audioMonitor->setSelectedStream(selectedStream); if (selectedStream == 0) { diff --git a/Source/Processors/Parameter/Parameter.cpp b/Source/Processors/Parameter/Parameter.cpp index b52b26de7..e71219441 100755 --- a/Source/Processors/Parameter/Parameter.cpp +++ b/Source/Processors/Parameter/Parameter.cpp @@ -361,10 +361,24 @@ SelectedChannelsParameter::SelectedChannelsParameter(GenericProcessor* processor void SelectedChannelsParameter::setNextValue(var newValue_) { - if (newValue_.getArray()->size() <= maxSelectableChannels) + if (newValue_ == currentValue) + return; + + int arraySize = newValue_.getArray()->size(); + if (arraySize <= maxSelectableChannels && arraySize <= channelCount) { + for (int i = 0; i < arraySize; i++) + { + if ((int) newValue_[i] < 0 || (int) newValue_[i] >= channelCount) + return; + } + newValue = newValue_; } + else + { + return; + } processor->parameterChangeRequest(this); } @@ -446,9 +460,23 @@ Array SelectedChannelsParameter::parseSelectedString(const String& input) return selectedChannels; } -void SelectedChannelsParameter::setChannelCount(int count) +void SelectedChannelsParameter::setChannelCount(int newCount) { - channelCount = count; + if (channelCount > newCount && getScope() != ParameterScope::SPIKE_CHANNEL_SCOPE) + { + Array values; + for (int i = 0; i < currentValue.getArray()->size(); i++) + { + if ((int) currentValue[i] < newCount) + { + values.add (currentValue[i]); + } + } + + currentValue = values; + } + + channelCount = newCount; // std::cout << "Setting selected channels channels count to " << count << " at " << this << std::endl; } diff --git a/Source/Processors/ProcessorGraph/ProcessorGraph.cpp b/Source/Processors/ProcessorGraph/ProcessorGraph.cpp index 24abae466..72d5f75fc 100644 --- a/Source/Processors/ProcessorGraph/ProcessorGraph.cpp +++ b/Source/Processors/ProcessorGraph/ProcessorGraph.cpp @@ -664,7 +664,14 @@ void ProcessorGraph::clearSignalChain() std::unique_ptr editor; editor.swap(processor->editor); editor.reset(); + Node::Ptr node = removeNode(nodeId); + + // Decrement reference count for the node + // Ensures processor destructor gets called + while (node->getReferenceCount() > 1) + node->decReferenceCount(); + node.reset(); } @@ -1356,6 +1363,12 @@ void ProcessorGraph::removeProcessor(GenericProcessor* processor) editor.reset(); Node::Ptr node = removeNode(nodeId); + + // Decrement reference count for the node + // Ensures processor destructor gets called + while (node->getReferenceCount() > 1) + node->decReferenceCount(); + node.reset(); } diff --git a/Source/Processors/RecordNode/RecordNode.cpp b/Source/Processors/RecordNode/RecordNode.cpp index b8ff0321f..37a23ae99 100755 --- a/Source/Processors/RecordNode/RecordNode.cpp +++ b/Source/Processors/RecordNode/RecordNode.cpp @@ -790,7 +790,7 @@ void RecordNode::handleSpike(SpikePtr spike) eventMonitor->receivedSpikes++; - if (recordSpikes) + if (recordSpikes && isRecording) { spike->setTimestampInSeconds(synchronizer.convertSampleNumberToTimestamp(spike->getStreamId(), spike->getSampleNumber())); diff --git a/Source/UI/ControlPanel.cpp b/Source/UI/ControlPanel.cpp index a08acc542..b536ff8db 100755 --- a/Source/UI/ControlPanel.cpp +++ b/Source/UI/ControlPanel.cpp @@ -528,27 +528,26 @@ void ControlPanel::startAcquisition(bool recordingShouldAlsoStart) graph->updateConnections(); - if (audio->beginCallbacks()) // starts acquisition callbacks + graph->startAcquisition(); // inform processors acquisition is starting + + if (recordingShouldAlsoStart) { - if (recordingShouldAlsoStart) - { - startRecording(); - playButton->setToggleState(true, dontSendNotification); - } + startRecording(); + playButton->setToggleState(true, dontSendNotification); + } - playButton->getNormalImage()->replaceColour(defaultButtonColour, Colours::yellow); + playButton->getNormalImage()->replaceColour(defaultButtonColour, Colours::yellow); - clock->start(); // starts the clock - audioEditor->disable(); + clock->start(); // starts the clock + audioEditor->disable(); - stopTimer(); - startTimer(250); // refresh every 250 ms + stopTimer(); + startTimer(250); // refresh every 250 ms - recordSelector->setEnabled(false); // why is this outside the "if" statement? - recordOptionsButton->setEnabled(false); - - graph->startAcquisition(); // start data flow - } + recordSelector->setEnabled(false); // why is this outside the "if" statement? + recordOptionsButton->setEnabled(false); + + audio->beginCallbacks(); } }