From 5c439580038d108066c583be44a5c2ae93853182 Mon Sep 17 00:00:00 2001 From: Ethan Blackwood Date: Fri, 7 Jun 2019 18:50:51 -0500 Subject: [PATCH 1/5] Start to play subprocessors separately and show Network Events TTLs (still buggy) --- Plugins/LfpDisplayNode/LfpDisplayCanvas.cpp | 134 +++------ Plugins/LfpDisplayNode/LfpDisplayCanvas.h | 29 +- Plugins/LfpDisplayNode/LfpDisplayEditor.cpp | 104 +++---- Plugins/LfpDisplayNode/LfpDisplayEditor.h | 7 +- Plugins/LfpDisplayNode/LfpDisplayNode.cpp | 286 +++++++++++--------- Plugins/LfpDisplayNode/LfpDisplayNode.h | 22 +- 6 files changed, 257 insertions(+), 325 deletions(-) diff --git a/Plugins/LfpDisplayNode/LfpDisplayCanvas.cpp b/Plugins/LfpDisplayNode/LfpDisplayCanvas.cpp index 3c3a34648..dabd01dc0 100644 --- a/Plugins/LfpDisplayNode/LfpDisplayCanvas.cpp +++ b/Plugins/LfpDisplayNode/LfpDisplayCanvas.cpp @@ -212,68 +212,35 @@ void LfpDisplayCanvas::endAnimation() void LfpDisplayCanvas::update() { - if (true) - { nChans = jmax(processor->getNumSubprocessorChannels(), 0); - std::cout << "Num chans: " << nChans << std::endl; + std::cout << "Num chans: " << nChans << std::endl; resizeSamplesPerPixelBuffer(nChans); - sampleRate.clear(); - screenBufferIndex.clear(); - lastScreenBufferIndex.clear(); - displayBufferIndex.clear(); + sampleRate = 30000; // default + + for (auto* arr : { &screenBufferIndex, &lastScreenBufferIndex, &displayBufferIndex }) + { + arr->clearQuick(); + arr->insertMultiple(0, 0, nChans + 1); // extra channel for events + } options->setEnabled(nChans != 0); // must manually ensure that overlapSelection propagates up to canvas channelOverlapFactor = options->selectedOverlapValue.getFloatValue(); std::cout << "Checking channels: " << nChans << std::endl; - for (int i = 0; i < processor->getNumInputs() + 1; i++) // extra channel for events - { - //std::cout << i << std::endl; - if (processor->getNumInputs() > 0) - { - if (i < processor->getNumInputs()) - { - if (processor->getDataChannel(i)->getSubProcessorIdx() == drawableSubprocessor) - { - sampleRate.add(processor->getDataChannel(i)->getSampleRate()); - //std::cout << "Adding sample rate " << processor->getDataChannel(i)->getSampleRate() << std::endl; - } - - } - else - { - //Since for now the canvas only supports one event channel, find the first TTL one and use that as sampleRate. - //This is a bit hackish and should be fixed for proper multi-ttl-channel support - for (int c = 0; c < processor->getTotalEventChannels(); c++) - { - if (processor->getEventChannel(c)->getChannelType() == EventChannel::TTL) - { - sampleRate.add(processor->getEventChannel(c)->getSampleRate()); - std::cout << "Sample rate = " << processor->getEventChannel(c)->getSampleRate() << std::endl; - - } - } - } - } - else + for (int i = 0, nInputs = processor->getNumInputs(); i < nInputs; i++) + { + if (processor->getDataSubprocId(i) == drawableSubprocessor) { - sampleRate.add(30000); + sampleRate = processor->getDataChannel(i)->getSampleRate(); + break; } - - // std::cout << "Sample rate for ch " << i << " = " << sampleRate[i] << std::endl; - displayBufferIndex.add(0); - screenBufferIndex.add(0); - lastScreenBufferIndex.add(0); } - lfpDisplay->setDisplayedSampleRate(sampleRate[0]); // only one sample rate possible for now - std::cout << "Setting display sample rate to " << sampleRate[0] << std::endl; - std::cout << "Checking channel alignment: " << nChans << std::endl; if (nChans != lfpDisplay->getNumChannels()) { @@ -319,8 +286,6 @@ void LfpDisplayCanvas::update() lfpDisplay->rebuildDrawableChannelsList(); } } - - } } @@ -410,7 +375,7 @@ void LfpDisplayCanvas::updateScreenBuffer() // std::cout << channel << " " << sbi << " " << dbi << " " << nSamples << std::endl; - float ratio = sampleRate[channel] * timebase / float(getWidth() - leftmargin - scrollBarThickness); // samples / pixel + float ratio = sampleRate * timebase / float(getWidth() - leftmargin - scrollBarThickness); // samples / pixel // this number is crucial: converting from samples to values (in px) for the screen buffer int valuesNeeded = (int) float(nSamples) / ratio; // N pixels needed for this update @@ -658,24 +623,16 @@ bool LfpDisplayCanvas::getDrawMethodState() return options->getDrawMethodState(); //drawMethodButton->getToggleState(); } -int LfpDisplayCanvas::getChannelSampleRate(int channel) -{ - return sampleRate[channel]; -} - void LfpDisplayCanvas::setDrawableSampleRate(float samplerate) { // std::cout << "setting the drawable sample rate in the canvas" << std::endl; displayedSampleRate = samplerate; - lfpDisplay->setDisplayedSampleRate(samplerate); } -void LfpDisplayCanvas::setDrawableSubprocessor(int idx) +void LfpDisplayCanvas::setDrawableSubprocessor(uint32 sp) { - drawableSubprocessor = idx; - lfpDisplay->setDisplayedSubprocessor(idx); - std::cout << "Setting LFP canvas subprocessor to " << idx << std::endl; - processor->setSubprocessor(idx); + drawableSubprocessor = sp; + std::cout << "Setting LFP canvas subprocessor to " << sp << std::endl; update(); } @@ -887,7 +844,7 @@ LfpDisplayOptions::LfpDisplayOptions(LfpDisplayCanvas* canvas_, LfpTimescale* ti voltageRanges[DataChannel::AUX_CHANNEL].add("2000"); //voltageRanges[DataChannel::AUX_CHANNEL].add("5000"); selectedVoltageRange[DataChannel::AUX_CHANNEL] = 9; - rangeGain[DataChannel::AUX_CHANNEL] = 0.001; //mV + rangeGain[DataChannel::AUX_CHANNEL] = 0.001f; //mV rangeSteps[DataChannel::AUX_CHANNEL] = 10; rangeUnits.add("mV"); typeNames.add("AUX"); @@ -1493,7 +1450,7 @@ void LfpDisplayOptions::buttonClicked(Button* b) if ((idx >= 0) && (b->getToggleState())) { - for (int i = 0; i < processor->getNumInputs(); i++) + for (int i = 0; i < lfpDisplay->getNumChannels(); i++) { if (lfpDisplay->channels[i]->getSelected()) { @@ -2172,7 +2129,7 @@ void LfpTimescale::setTimebase(float t) if (labelIncrement < 0.2) labelIncrement *= 2; else - labelIncrement += 0.2; + labelIncrement += 0.2f; } for (float i = labelIncrement; i < timebase; i += labelIncrement) @@ -2634,31 +2591,6 @@ void LfpDisplay::cacheNewChannelHeight(int r) cachedDisplayChannelHeight = r; } -float LfpDisplay::getDisplayedSampleRate() -{ - return drawableSampleRate; -} - -// Must manually call rebuildDrawableChannelsList after this is set, typically will happen -// already as a result of some other procedure -void LfpDisplay::setDisplayedSampleRate(float samplerate) -{ - std::cout << "Setting the displayed samplerate for LfpDisplayCanvas to " << samplerate << std::endl; - drawableSampleRate = samplerate; -} - -int LfpDisplay::getDisplayedSubprocessor() -{ - return drawableSubprocessorIdx; -} - -void LfpDisplay::setDisplayedSubprocessor(int subProcessorIdx) -{ - drawableSubprocessorIdx = subProcessorIdx; - refresh(); - -} - bool LfpDisplay::getChannelsReversed() { return channelsReversed; @@ -2673,7 +2605,7 @@ void LfpDisplay::setChannelsReversed(bool state) if (getSingleChannelState()) return; // don't reverse if single channel // reverse channels that are currently in drawableChannels - for (size_t i = 0, j = drawableChannels.size() - 1, len = drawableChannels.size()/2; + for (int i = 0, j = drawableChannels.size() - 1, len = drawableChannels.size()/2; i < len; i++, j--) { @@ -2708,7 +2640,7 @@ void LfpDisplay::setChannelsReversed(bool state) } // add the channels and channel info again - for (size_t i = 0, len = drawableChannels.size(); i < len; i++) + for (int i = 0, len = drawableChannels.size(); i < len; i++) { if (!drawableChannels[i].channel->getHidden()) @@ -2890,8 +2822,8 @@ void LfpDisplay::toggleSingleChannel(int chan) } // update drawableChannels, give only the single channel to focus on - Array channelsToDraw{lfpChannelTrack}; - drawableChannels = channelsToDraw; + drawableChannels.clearQuick(); + drawableChannels.add(lfpChannelTrack); addAndMakeVisible(lfpChannelTrack.channel); addAndMakeVisible(lfpChannelTrack.channelInfo); @@ -2940,7 +2872,7 @@ void LfpDisplay::rebuildDrawableChannelsList() drawableChannels = Array(); // iterate over all channels and select drawable ones - for (size_t i = 0, drawableChannelNum = 0; i < channels.size(); i++) + for (int i = 0, drawableChannelNum = 0; i < channels.size(); i++) { // std::cout << "\tchannel " << i << " has subprocessor index of " << channelInfo[i]->getSubprocessorIdx() << std::endl; // if channel[i] is not sourced from the correct subprocessor, then hide it and continue @@ -3279,7 +3211,7 @@ void LfpChannelDisplay::pxPaint() //draw zero line int m = getY()+center; - if(m > 0 & m < display->lfpChannelBitmap.getHeight()) + if(m > 0 && m < display->lfpChannelBitmap.getHeight()) { if ( bdLfpChannelBitmap.getPixelColour(i,m) == display->backgroundColour ) { // make sure we're not drawing over an existing plot from another channel bdLfpChannelBitmap.setPixelColour(i,m,Colour(50,50,50)); @@ -3294,7 +3226,7 @@ void LfpChannelDisplay::pxPaint() for (m = start; m <= start + jump*4; m += jump) { - if (m > 0 & m < display->lfpChannelBitmap.getHeight()) + if (m > 0 && m < display->lfpChannelBitmap.getHeight()) { if ( bdLfpChannelBitmap.getPixelColour(i,m) == display->backgroundColour ) // make sure we're not drawing over an existing plot from another channel bdLfpChannelBitmap.setPixelColour(i, m, Colour(80,80,80)); @@ -3431,7 +3363,7 @@ void LfpChannelDisplay::pxPaint() { int clipmarker = jto_wholechannel_clip; - if(clipmarker>0 & clipmarkerlfpChannelBitmap.getHeight()){ + if(clipmarker>0 && clipmarkerlfpChannelBitmap.getHeight()){ bdLfpChannelBitmap.setPixelColour(i,clipmarker-j,Colour(255,255,255)); } } @@ -3442,7 +3374,7 @@ void LfpChannelDisplay::pxPaint() { int clipmarker = jfrom_wholechannel_clip; - if(clipmarker>0 & clipmarkerlfpChannelBitmap.getHeight()){ + if(clipmarker>0 && clipmarkerlfpChannelBitmap.getHeight()){ bdLfpChannelBitmap.setPixelColour(i,clipmarker+j,Colour(255,255,255)); } } @@ -3455,7 +3387,7 @@ void LfpChannelDisplay::pxPaint() if (spikeFlag) // draw spikes { for (int k=jfrom_wholechannel; k<=jto_wholechannel; k++){ // draw line - if(k>0 & klfpChannelBitmap.getHeight()){ + if(k>0 && klfpChannelBitmap.getHeight()){ bdLfpChannelBitmap.setPixelColour(i,k,lineColour); } }; @@ -3473,7 +3405,7 @@ void LfpChannelDisplay::pxPaint() if (fmod((i+k),50)>25){ thiscolour=Colour(255,255,255); } - if(k>0 & klfpChannelBitmap.getHeight()){ + if(k>0 && klfpChannelBitmap.getHeight()){ bdLfpChannelBitmap.setPixelColour(i,k,thiscolour); } }; @@ -4059,7 +3991,7 @@ void SupersampledBitmapPlotter::plot(Image::BitmapData &bdLfpChannelBitmap, LfpB // int sampleCountThisPixel = lfpDisplay->canvas->getSampleCountPerPixel(pInfo.samp); int sampleCountThisPixel = pInfo.sampleCountPerPixel; - if (pInfo.samplerange>0 & sampleCountThisPixel>0) + if (pInfo.samplerange>0 && sampleCountThisPixel>0) { //float localHist[samplerange]; // simple histogram @@ -4113,7 +4045,7 @@ void SupersampledBitmapPlotter::plot(Image::BitmapData &bdLfpChannelBitmap, LfpB //Colour gradedColor = Colour(0,255,0); int ploty = pInfo.from + s + pInfo.y; - if(ploty>0 & ploty < display->lfpChannelBitmap.getHeight()) { + if(ploty>0 && ploty < display->lfpChannelBitmap.getHeight()) { bdLfpChannelBitmap.setPixelColour(pInfo.samp, pInfo.from + s + pInfo.y, gradedColor); } } diff --git a/Plugins/LfpDisplayNode/LfpDisplayCanvas.h b/Plugins/LfpDisplayNode/LfpDisplayCanvas.h index 3d2356b3a..304cccef6 100644 --- a/Plugins/LfpDisplayNode/LfpDisplayCanvas.h +++ b/Plugins/LfpDisplayNode/LfpDisplayCanvas.h @@ -119,9 +119,9 @@ class LfpDisplayCanvas : public Visualizer, /** Returns the subprocessor index of the given channel */ int getChannelSubprocessorIdx(int channel); - /** Delegates a subprocessor index for drawing to the LfpDisplay referenced by this + /** Delegates a subprocessor for drawing to the LfpDisplay referenced by this this canvas */ - void setDrawableSubprocessor(int idx); + void setDrawableSubprocessor(uint32 sp); const float getXCoord(int chan, int samp); const float getYCoord(int chan, int samp); @@ -168,7 +168,7 @@ class LfpDisplayCanvas : public Visualizer, private: - Array sampleRate; + float sampleRate; bool optionsDrawerIsOpen; @@ -176,7 +176,7 @@ class LfpDisplayCanvas : public Visualizer, float timeOffset; //int spread ; // vertical spacing between channels - int drawableSubprocessor; + uint32 drawableSubprocessor; float displayedSampleRate; //float waves[MAX_N_CHAN][MAX_N_SAMP*2]; // we need an x and y point for each sample @@ -502,24 +502,7 @@ class LfpDisplay : public Component int getChannelHeight(); LfpChannelColourScheme * getColourSchemePtr(); - - /** Returns the sample rate that is currently filtering the drawable channels */ - float getDisplayedSampleRate(); - - /** Sets the samplerate that displayed channels must be set to. No channels with - differing samplerates will be drawn to screen. - - This function does not automatically repopulate the drawableChannels list, so - rebuildDrawableChannelsList must be called before the screen is updated. - - @see LfpDisplayCanvas::setDrawableSampleRate, LfpDisplayNode::updateSettings - */ - void setDisplayedSampleRate(float samplerate); - - int getDisplayedSubprocessor(); - - void setDisplayedSubprocessor(int subProcessorIdx); - + /** Caches a new channel height without updating the channels */ void cacheNewChannelHeight(int r); @@ -647,7 +630,7 @@ class LfpDisplay : public Component int displaySkipAmt; int cachedDisplayChannelHeight; // holds a channel height if reset during single channel focus float drawableSampleRate; - int drawableSubprocessorIdx; + uint32 drawableSubprocessor; int totalHeight; diff --git a/Plugins/LfpDisplayNode/LfpDisplayEditor.cpp b/Plugins/LfpDisplayNode/LfpDisplayEditor.cpp index 59be368fc..1e06d530e 100644 --- a/Plugins/LfpDisplayNode/LfpDisplayEditor.cpp +++ b/Plugins/LfpDisplayNode/LfpDisplayEditor.cpp @@ -35,17 +35,15 @@ LfpDisplayEditor::LfpDisplayEditor(GenericProcessor* parentNode, bool useDefault desiredWidth = 180; + subprocessorSelectionLabel = new Label("Display subprocessor sample rate", "Display Subprocessor:"); + subprocessorSelectionLabel->setBounds(10, 30, 130, 20); + addAndMakeVisible(subprocessorSelectionLabel); + subprocessorSelection = new ComboBox("Subprocessor sample rate"); -// subprocessorSelection->setBounds(subprocessorSelectionLabel->getX()+5, subprocessorSelectionLabel->getBottom(), 60, 22); - subprocessorSelection->setBounds(10, 30, 55, 22); + subprocessorSelection->setBounds(10, 55, 130, 22); subprocessorSelection->addListener(this); addAndMakeVisible(subprocessorSelection); - subprocessorSelectionLabel = new Label("Display subprocessor sample rate", "Display Subproc."); - // subprocessorSelectionLabel->setBounds(10, 25, 140, 20); - subprocessorSelectionLabel->setBounds(subprocessorSelection->getRight(), subprocessorSelection->getY(), 100, 20); - addAndMakeVisible(subprocessorSelectionLabel); - subprocessorSampleRateLabel = new Label("Subprocessor sample rate label", "Sample Rate:"); subprocessorSampleRateLabel->setFont(Font(Font::getDefaultSerifFontName(), 14, Font::plain)); subprocessorSampleRateLabel->setBounds(subprocessorSelection->getX(), subprocessorSelection->getBottom() + 10, 200, 40); @@ -107,86 +105,74 @@ void LfpDisplayEditor::comboBoxChanged(juce::ComboBox *cb) { if (cb == subprocessorSelection) { - std::cout << "Setting subprocessor to " << cb->getSelectedId() << std::endl; - setCanvasDrawableSubprocessor(cb->getSelectedId() - 1); - String sampleRateLabelText = "Sample Rate: "; - sampleRateLabelText += String(inputSampleRates[cb->getSelectedId() - 1]); + std::cout << "Setting subprocessor to " << cb->getSelectedId() << std::endl; + uint32 subproc = inputSubprocessors[cb->getSelectedId() - 1]; + + String sampleRateLabelText = "Sample Rate: "; + sampleRateLabelText += String(inputSampleRates[subproc]); subprocessorSampleRateLabel->setText(sampleRateLabelText, dontSendNotification); + std::cout << sampleRateLabelText << std::endl; + + lfpProcessor->setSubprocessor(subproc); + if (canvas) + { + static_cast(canvas.get())->setDrawableSubprocessor(subproc); + } } } void LfpDisplayEditor::updateSubprocessorSelectorOptions() { // clear out the old data - inputSubprocessorIndices.clear(); + inputSubprocessors.clear(); inputSampleRates.clear(); subprocessorSelection->clear(dontSendNotification); if (lfpProcessor->getTotalDataChannels() != 0) { + HashMap subprocessorNames; for (int i = 0, len = lfpProcessor->getTotalDataChannels(); i < len; ++i) { - int subProcessorIdx = lfpProcessor->getDataChannel(i)->getSubProcessorIdx(); - - bool success = inputSubprocessorIndices.add(subProcessorIdx); - - if (success) inputSampleRates.set(subProcessorIdx, lfpProcessor->getDataChannel(i)->getSampleRate()); - + const DataChannel* ch = lfpProcessor->getDataChannel(i); + uint16 sourceNodeId = ch->getSourceNodeID(); + uint16 subProcessorIdx = ch->getSubProcessorIdx(); + uint32 subProcFullId = GenericProcessor::getProcessorFullId(sourceNodeId, subProcessorIdx); + + bool success = inputSubprocessors.add(subProcFullId); + + if (success) + { + inputSampleRates.set(subProcFullId, ch->getSampleRate()); + + String sourceName = ch->getSourceName(); + subprocessorNames.set(subProcFullId, + sourceName + " " + String(sourceNodeId) + "/" + String(subProcessorIdx)); + } } - for (int i = 0; i < inputSubprocessorIndices.size(); ++i) + for (int i = 0; i < inputSubprocessors.size(); ++i) { - subprocessorSelection->addItem(String(*(inputSubprocessorIndices.begin() + i)), i + 1); + subprocessorSelection->addItem(subprocessorNames[inputSubprocessors[i]], i + 1); } - if (defaultSubprocessor >= 0) - { - subprocessorSelection->setSelectedId(defaultSubprocessor + 1, sendNotification); - - String sampleRateLabelText = "Sample Rate: "; - sampleRateLabelText += String(inputSampleRates[*(inputSubprocessorIndices.begin() + defaultSubprocessor)]); - - subprocessorSampleRateLabel->setText(sampleRateLabelText, dontSendNotification); - //setCanvasDrawableSubprocessor(defaultSubprocessor); + uint32 selectedSubproc = lfpProcessor->getSubprocessor(); + int selectedSubprocId = (selectedSubproc ? inputSubprocessors.indexOf(selectedSubproc) : defaultSubprocessor) + 1; - return; - } + subprocessorSelection->setSelectedId(selectedSubprocId, sendNotification); } - - subprocessorSelection->addItem("None", 1); - subprocessorSelection->setSelectedId(1, dontSendNotification); - - String sampleRateLabelText = "Sample Rate: "; - subprocessorSampleRateLabel->setText(sampleRateLabelText, dontSendNotification); - //setCanvasDrawableSubprocessor(-1); -} - -void LfpDisplayEditor::setCanvasDrawableSubprocessor(int index) -{ - if (canvas) + else { - if (index >= 0) - { - ((LfpDisplayCanvas *)canvas.get())->setDrawableSubprocessor(*(inputSubprocessorIndices.begin() + index)); - float rate = lfpProcessor->getSubprocessorSampleRate(); + subprocessorSelection->addItem("None", 1); + subprocessorSelection->setSelectedId(1, dontSendNotification); - String sampleRateLabelText = "Sample Rate: "; - sampleRateLabelText += String(rate); - subprocessorSampleRateLabel->setText(sampleRateLabelText, dontSendNotification); - - std::cout << sampleRateLabelText << std::endl; - } - else - { - ((LfpDisplayCanvas *)canvas.get())->setDrawableSubprocessor(-1); - } - + String sampleRateLabelText = "Sample Rate: "; + subprocessorSampleRateLabel->setText(sampleRateLabelText, dontSendNotification); + //setCanvasDrawableSubprocessor(-1); } } - void LfpDisplayEditor::saveVisualizerParameters(XmlElement* xml) { diff --git a/Plugins/LfpDisplayNode/LfpDisplayEditor.h b/Plugins/LfpDisplayNode/LfpDisplayEditor.h index 168b2ec93..81fedbfc4 100644 --- a/Plugins/LfpDisplayNode/LfpDisplayEditor.h +++ b/Plugins/LfpDisplayNode/LfpDisplayEditor.h @@ -80,7 +80,7 @@ class LfpDisplayEditor : public VisualizerEditor, private: HashMap inputSampleRates; // hold the possible subprocessor sample rates - SortedSet inputSubprocessorIndices; + SortedSet inputSubprocessors; LfpDisplayNode* lfpProcessor; @@ -91,11 +91,6 @@ class LfpDisplayEditor : public VisualizerEditor, ScopedPointer