From ddb0bfbf9d576062b90a7349b9687269ee12a990 Mon Sep 17 00:00:00 2001 From: jsiegle <jsiegle@mit.edu> Date: Sun, 19 Jan 2014 14:54:42 -0500 Subject: [PATCH] Update ChannelMappingNode from spikesorting version --- Source/Processors/ChannelMappingNode.cpp | 54 ++-- Source/Processors/ChannelMappingNode.h | 1 + .../Editors/ChannelMappingEditor.cpp | 271 ++++++++++++++---- .../Processors/Editors/ChannelMappingEditor.h | 17 +- Source/Processors/Editors/ChannelSelector.cpp | 23 +- Source/Processors/Editors/ChannelSelector.h | 3 + 6 files changed, 279 insertions(+), 90 deletions(-) diff --git a/Source/Processors/ChannelMappingNode.cpp b/Source/Processors/ChannelMappingNode.cpp index ad738cad3..bff623d80 100644 --- a/Source/Processors/ChannelMappingNode.cpp +++ b/Source/Processors/ChannelMappingNode.cpp @@ -64,17 +64,34 @@ AudioProcessorEditor* ChannelMappingNode::createEditor() void ChannelMappingNode::updateSettings() { + int j; if (getNumInputs() > 0) channelBuffer.setSize(getNumInputs(), 10000); if (getNumInputs() != previousChannelCount) { previousChannelCount = getNumInputs(); + if (editorIsConfigured) + { + j = 0; + for (int i = 0; i < getNumInputs(); i++) + { + if (enabledChannelArray[i]) + { + j++; + } + else + { + channels.remove(j); + } + } + settings.numOutputs = j; + } } else { - int j=0; - for (int i=0; i < getNumInputs(); i++) + j = 0; + for (int i = 0; i < getNumInputs(); i++) { if (enabledChannelArray[i]) { @@ -106,6 +123,10 @@ void ChannelMappingNode::setParameter(int parameterIndex, float newValue) { enabledChannelArray.set(currentChannel, (newValue != 0) ? true : false); } + else if (parameterIndex == 4) + { + editorIsConfigured = (newValue != 0) ? true : false; + } else { channelArray.set(currentChannel, (int) newValue); @@ -118,40 +139,33 @@ void ChannelMappingNode::process(AudioSampleBuffer& buffer, int& nSamples) { int j=0; + int i=0; + int realChan; // use copy constructor to set the data to refer to channelBuffer = buffer; - // copy it back into the buffer according to the channel mapping buffer.clear(); - for (int i = 0; i < buffer.getNumChannels(); i++) + while (j < settings.numOutputs) { - if (enabledChannelArray[channelArray[i]]) + realChan = channelArray[i]; + if ((realChan < channelBuffer.getNumChannels()) && (enabledChannelArray[realChan])) { + // copy it back into the buffer according to the channel mapping buffer.addFrom(j, // destChannel 0, // destStartSample channelBuffer, // source - channelArray[i], // sourceChannel + realChan, // sourceChannel 0, // sourceStartSample nSamples, // numSamples 1.0f // gain to apply to source (positive for original signal) ); - j++; - } - - } - j=0; - // now do the referencing - for (int i = 0; i < buffer.getNumChannels(); i++) - { - int realChan = channelArray[i]; - if (enabledChannelArray[realChan]) - { - if ((referenceArray[realChan] > -1) && referenceChannels[referenceArray[realChan]] > -1) + // now do the referencing + if ((referenceArray[realChan] > -1) && (referenceChannels[referenceArray[realChan]] > -1) + && (referenceChannels[referenceArray[realChan]] < channelBuffer.getNumChannels())) { - buffer.addFrom(j, // destChannel 0, // destStartSample channelBuffer, // source @@ -163,6 +177,8 @@ void ChannelMappingNode::process(AudioSampleBuffer& buffer, } j++; } + i++; + } } diff --git a/Source/Processors/ChannelMappingNode.h b/Source/Processors/ChannelMappingNode.h index 2a9fc159b..3de6d7775 100644 --- a/Source/Processors/ChannelMappingNode.h +++ b/Source/Processors/ChannelMappingNode.h @@ -70,6 +70,7 @@ private: Array<bool> enabledChannelArray; int previousChannelCount; + bool editorIsConfigured; AudioSampleBuffer channelBuffer; diff --git a/Source/Processors/Editors/ChannelMappingEditor.cpp b/Source/Processors/Editors/ChannelMappingEditor.cpp index bc5602d8d..349150893 100644 --- a/Source/Processors/Editors/ChannelMappingEditor.cpp +++ b/Source/Processors/Editors/ChannelMappingEditor.cpp @@ -30,24 +30,34 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ChannelMappingEditor::ChannelMappingEditor(GenericProcessor* parentNode, bool useDefaultParameterEditors=true) - : GenericEditor(parentNode, useDefaultParameterEditors), previousChannelCount(0) + : GenericEditor(parentNode, useDefaultParameterEditors), previousChannelCount(0), isConfigured(false) { desiredWidth = 340; + scrollDistance = 0; + selectAllButton = new ElectrodeEditorButton("Select All",Font("Small Text",14,Font::plain)); selectAllButton->addListener(this); addAndMakeVisible(selectAllButton); - selectAllButton->setBounds(140,110,110,10); + selectAllButton->setBounds(125,110,110,10); selectAllButton->setToggleState(false, false); modifyButton = new ElectrodeEditorButton("Remap",Font("Small Text",14,Font::plain)); modifyButton->addListener(this); addAndMakeVisible(modifyButton); - modifyButton->setBounds(250,110,60,10); + modifyButton->setBounds(220,110,60,10); modifyButton->setToggleState(false, false); modifyButton->setClickingTogglesState(true); + resetButton = new ElectrodeEditorButton("Reset", Font("Small Text",14,Font::plain)); + resetButton->addListener(this); + addAndMakeVisible(resetButton); + resetButton->setBounds(285,110,60,10); + resetButton->setToggleState(true,false); + resetButton->setClickingTogglesState(false); + resetButton->setEnabled(false); + // channelSelector->setRadioStatus(true); for (int i = 0 ; i < NUM_REFERENCES; i++) @@ -77,46 +87,80 @@ ChannelMappingEditor::~ChannelMappingEditor() void ChannelMappingEditor::updateSettings() { + if (isConfigured) + { + if (getProcessor()->getNumInputs() > previousChannelCount) + { + createElectrodeButtons(getProcessor()->getNumInputs(),false); + previousChannelCount = getProcessor()->getNumInputs(); + } + else if (!reorderActive) + { + checkUnusedChannels(); + } - if (getProcessor()->getNumInputs() != previousChannelCount) + } else if (getProcessor()->getNumInputs() != previousChannelCount) { - createElectrodeButtons(getProcessor()->getNumInputs()); - previousChannelCount = getProcessor()->getNumInputs(); - } - } -void ChannelMappingEditor::createElectrodeButtons(int numNeeded) +void ChannelMappingEditor::createElectrodeButtons(int numNeeded, bool clearPrevious) { + int startButton; - electrodeButtons.clear(); - - referenceArray.clear(); - channelArray.clear(); - referenceChannels.clear(); - enabledChannelArray.clear(); + if (clearPrevious) + { + electrodeButtons.clear(); - int width = 20; - int height = 15; + referenceArray.clear(); + channelArray.clear(); + referenceChannels.clear(); + enabledChannelArray.clear(); + startButton=0; + previousClickedChan = -1; + previousShiftClickedChan = -1; + referenceButtons[0]->setToggleState(true,false); + selectedReference = 0; + modifyButton->setToggleState(false,false); + reorderActive = false; + channelSelector->activateButtons(); - int row = 0; - int column = 0; + } + else + { + startButton = previousChannelCount; + if (startButton > numNeeded) return; + //row = startButton/16; + //column = startButton % 16; + } - for (int i = 0; i < numNeeded; i++) + for (int i = startButton; i < numNeeded; i++) { ElectrodeButton* button = new ElectrodeButton(i+1); electrodeButtons.add(button); - button->setBounds(10+(column++)*(width), 30+row*(height), width, 15); - button->setToggleState(false,false); button->setRadioGroupId(0); + + // if (!getCollapsedState()) + // addAndMakeVisible(button); + // else + addChildComponent(button); // determine visibility in refreshButtonLocations() - addAndMakeVisible(button); button->addListener(this); - + if (reorderActive) + { + button->setToggleState(true,false); + electrodeButtons[i]->setClickingTogglesState(false); + electrodeButtons[i]->addMouseListener(this,false); + } + else + { + button->setToggleState(false,false); + electrodeButtons[i]->setClickingTogglesState(true); + } + referenceArray.add(-1); getProcessor()->setCurrentChannel(i); @@ -127,33 +171,55 @@ void ChannelMappingEditor::createElectrodeButtons(int numNeeded) channelArray.add(i+1); enabledChannelArray.add(true); - if (column % 16 == 0) - { - column = 0; - row++; - } - } - getProcessor()->setCurrentChannel(-1); - for (int i = 0; i < NUM_REFERENCES; i++) + + if (clearPrevious) { + getProcessor()->setCurrentChannel(-1); + for (int i = 0; i < NUM_REFERENCES; i++) + { - getProcessor()->setParameter(2,i); //Clear reference - referenceChannels.add(-1); + getProcessor()->setParameter(2,i); //Clear reference + referenceChannels.add(-1); + referenceButtons[i]->setEnabled(true); + } } + channelSelector->setRadioStatus(true); - referenceButtons[0]->setToggleState(true,false); - selectedReference = 0; + refreshButtonLocations(); +} - modifyButton->setToggleState(false,false); - reorderActive = false; - previousClickedChan = -1; - previousShiftClickedChan = -1; +void ChannelMappingEditor::refreshButtonLocations() +{ + int width = 19; + int height = 15; + int row = (int) -scrollDistance; + int column = 0; + for (int i = 0; i < electrodeButtons.size(); i++) + { - channelSelector->setRadioStatus(true); + ElectrodeButton* button = electrodeButtons[i]; + + button->setBounds(10+(column++)*(width), 30+row*(height), width, 15); + + if (row <= 4 && row >= 0 && !getCollapsedState()) + button->setVisible(true); + else + button->setVisible(false); + + if (column % 16 == 0) + { + column = 0; + row++; + } + } } +void ChannelMappingEditor::collapsedStateChanged() +{ + refreshButtonLocations(); +} void ChannelMappingEditor::buttonEvent(Button* button) { @@ -166,6 +232,14 @@ void ChannelMappingEditor::buttonEvent(Button* button) setChannelReference(electrodeButtons[i]); } previousClickedChan = -1; + setConfigured(true); + } + else if (button == resetButton) + { + createElectrodeButtons(getProcessor()->getNumInputs()); + previousChannelCount = getProcessor()->getNumInputs(); + setConfigured(false); + getEditorViewport()->makeEditorVisible(this, false, true); } else if (button == modifyButton) { @@ -174,7 +248,7 @@ void ChannelMappingEditor::buttonEvent(Button* button) channelSelector->activateButtons(); reorderActive = false; selectedReference = 0; - for (int i=0; i < referenceButtons.size(); i++) + for (int i = 0; i < referenceButtons.size(); i++) { referenceButtons[i]->setEnabled(true); } @@ -199,7 +273,7 @@ void ChannelMappingEditor::buttonEvent(Button* button) { electrodeButtons[i]->setToggleState(false,false); } - if (enabledChannelArray[electrodeButtons[i]->getChannelNum()-1]) + if ((enabledChannelArray[electrodeButtons[i]->getChannelNum()-1]) && (electrodeButtons[i]->getChannelNum() <= getProcessor()->getNumInputs())) { electrodeButtons[i]->setEnabled(true); } @@ -234,7 +308,7 @@ void ChannelMappingEditor::buttonEvent(Button* button) electrodeButtons[i]->setToggleState(false,false); } electrodeButtons[i]->addMouseListener(this,false); - + } selectAllButton->setEnabled(false); } @@ -245,7 +319,8 @@ void ChannelMappingEditor::buttonEvent(Button* button) Array<int> a; - if (referenceChannels[selectedReference] >= 0 ) + if ((referenceChannels[selectedReference] >= 0 ) + && (referenceChannels[selectedReference] < channelSelector->getNumChannels() )) { a.add(referenceChannels[selectedReference]); } @@ -269,6 +344,7 @@ void ChannelMappingEditor::buttonEvent(Button* button) { if (!reorderActive) { + setConfigured(true); int clickedChan = electrodeButtons.indexOf((ElectrodeButton*)button); if (ModifierKeys::getCurrentModifiers().isShiftDown() && (previousClickedChan >= 0)) @@ -419,16 +495,21 @@ void ChannelMappingEditor::channelChanged(int chan) { if (!reorderActive) { + setConfigured(true); getProcessor()->setCurrentChannel(chan-1); getProcessor()->setParameter(2,selectedReference); referenceChannels.set(selectedReference,chan-1); } } -void ChannelMappingEditor::saveEditorParameters(XmlElement* xml) +void ChannelMappingEditor::saveCustomParameters(XmlElement* xml) { xml->setAttribute("Type", "ChannelMappingEditor"); + //Made a bit generic in case future expansions need more settings + XmlElement* settingsXml = xml->createNewChildElement("SETTING"); + settingsXml->setAttribute("Type","visibleChannels"); + settingsXml->setAttribute("Value",previousChannelCount); for (int i = 0; i < channelArray.size(); i++) { XmlElement* channelXml = xml->createNewChildElement("CHANNEL"); @@ -446,9 +527,20 @@ void ChannelMappingEditor::saveEditorParameters(XmlElement* xml) } -void ChannelMappingEditor::loadEditorParameters(XmlElement* xml) +void ChannelMappingEditor::loadCustomParameters(XmlElement* xml) { - + setConfigured(true); + forEachXmlChildElementWithTagName(*xml, settingXml, "SETTING") + { + if (settingXml->getStringAttribute("Type").equalsIgnoreCase("visibleChannels")) + { + int nChans = settingXml->getIntAttribute("Value"); + if (nChans > getProcessor()->getNumInputs()) + { + createElectrodeButtons(nChans,false); + } + } + } forEachXmlChildElementWithTagName(*xml, channelXml, "CHANNEL") { int i = channelXml->getIntAttribute("Number"); @@ -467,7 +559,7 @@ void ChannelMappingEditor::loadEditorParameters(XmlElement* xml) electrodeButtons[i]->setChannelNum(mapping); electrodeButtons[i]->setEnabled(enabled); electrodeButtons[i]->repaint(); - + getProcessor()->setCurrentChannel(i); @@ -499,16 +591,18 @@ void ChannelMappingEditor::loadEditorParameters(XmlElement* xml) } for (int i = 0; i < electrodeButtons.size(); i++) + { + if (referenceArray[electrodeButtons[i]->getChannelNum()-1] == selectedReference) { - if (referenceArray[electrodeButtons[i]->getChannelNum()-1] == selectedReference) - { - electrodeButtons[i]->setToggleState(true,false); - } - else - { - electrodeButtons[i]->setToggleState(false,false); - } + electrodeButtons[i]->setToggleState(true,false); } + else + { + electrodeButtons[i]->setToggleState(false,false); + } + } + + refreshButtonLocations(); } @@ -569,7 +663,7 @@ void ChannelMappingEditor::mouseDrag(const MouseEvent &e) if (hoverButton != lastHoverButton) { - + electrodeButtons[lastHoverButton]->setVisible(true); electrodeButtons[hoverButton]->setVisible(false); @@ -605,7 +699,7 @@ void ChannelMappingEditor::mouseDrag(const MouseEvent &e) } electrodeButtons[hoverButton]->setChannelNum(draggingChannel); electrodeButtons[hoverButton]->setToggleState(enabledChannelArray[draggingChannel-1],false); - + lastHoverButton = hoverButton; repaint(); } @@ -622,7 +716,11 @@ void ChannelMappingEditor::mouseUp(const MouseEvent &e) isDragging = false; electrodeButtons[lastHoverButton]->setVisible(true); int from, to; - if (lastHoverButton < initialDraggedButton) + if (lastHoverButton == initialDraggedButton) + { + return; + } + else if (lastHoverButton < initialDraggedButton) { from = lastHoverButton; to = initialDraggedButton; @@ -637,6 +735,7 @@ void ChannelMappingEditor::mouseUp(const MouseEvent &e) { setChannelPosition(i,electrodeButtons[i]->getChannelNum()); } + setConfigured(true); } } @@ -651,6 +750,7 @@ void ChannelMappingEditor::mouseDoubleClick(const MouseEvent &e) { if ((reorderActive) && electrodeButtons.contains((ElectrodeButton*)e.originalComponent)) { + setConfigured(true); ElectrodeButton *button = (ElectrodeButton*)e.originalComponent; if (button->getToggleState()) @@ -669,4 +769,53 @@ void ChannelMappingEditor::mouseDoubleClick(const MouseEvent &e) } getEditorViewport()->makeEditorVisible(this, false, true); } -} \ No newline at end of file +} + +void ChannelMappingEditor::mouseWheelMove(const MouseEvent& event, + const MouseWheelDetails& wheel) +{ + + float maxScrollDistance = ceil(float(electrodeButtons.size() - 80) / 16.0f); + + // std::cout << "Got wheel move: " << wheel.deltaY << std::endl; + // channelSelector->shiftChannelsVertical(-wheel.deltaY); + scrollDistance -= wheel.deltaY*2; + + if (scrollDistance > maxScrollDistance) + scrollDistance = maxScrollDistance; + + if (scrollDistance < 0) + scrollDistance = 0; + + refreshButtonLocations(); +} + +void ChannelMappingEditor::checkUnusedChannels() +{ + for (int i = 0; i < electrodeButtons.size(); i++) + { + if (electrodeButtons[i]->getChannelNum() > getProcessor()->getNumInputs()) + { + electrodeButtons[i]->setEnabled(false); + } + else + { + if (enabledChannelArray[electrodeButtons[i]->getChannelNum()-1]) + { + electrodeButtons[i]->setEnabled(true); + } + else + { + electrodeButtons[i]->setEnabled(false); + } + } + } +} +void ChannelMappingEditor::setConfigured(bool state) +{ + isConfigured = state; + resetButton->setEnabled(state); + resetButton->setToggleState(!state,false); + getProcessor()->setParameter(4,state?1:0); +} + diff --git a/Source/Processors/Editors/ChannelMappingEditor.h b/Source/Processors/Editors/ChannelMappingEditor.h index b8e137194..74897536b 100644 --- a/Source/Processors/Editors/ChannelMappingEditor.h +++ b/Source/Processors/Editors/ChannelMappingEditor.h @@ -52,10 +52,10 @@ public: void updateSettings(); - void createElectrodeButtons(int numNeeded); + void createElectrodeButtons(int numNeeded, bool clearPrevious = true); - void saveEditorParameters(XmlElement* xml); - void loadEditorParameters(XmlElement* xml); + void saveCustomParameters(XmlElement* xml); + void loadCustomParameters(XmlElement* xml); void channelChanged(int chan); @@ -65,16 +65,24 @@ public: void mouseDoubleClick(const MouseEvent &e); + void mouseWheelMove(const MouseEvent& event, const MouseWheelDetails& wheel); + + void collapsedStateChanged(); private: void setChannelReference(ElectrodeButton *button); void setChannelPosition(int position, int channel); + void checkUnusedChannels(); + void setConfigured(bool state); + + void refreshButtonLocations(); OwnedArray<ElectrodeButton> electrodeButtons; OwnedArray<ElectrodeButton> referenceButtons; ScopedPointer<ElectrodeEditorButton> selectAllButton; ScopedPointer<ElectrodeEditorButton> modifyButton; + ScopedPointer<ElectrodeEditorButton> resetButton; Array<int> channelArray; Array<int> referenceArray; @@ -92,6 +100,9 @@ private: int initialDraggedButton; int draggingChannel; int lastHoverButton; + bool isConfigured; + + float scrollDistance; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ChannelMappingEditor); diff --git a/Source/Processors/Editors/ChannelSelector.cpp b/Source/Processors/Editors/ChannelSelector.cpp index 9866414f3..1433cd15e 100755 --- a/Source/Processors/Editors/ChannelSelector.cpp +++ b/Source/Processors/Editors/ChannelSelector.cpp @@ -143,7 +143,7 @@ void ChannelSelector::shiftChannelsVertical(float amount) offsetUD = jmax(offsetUD, float(parameterButtons.size())/8*-10.68f); } - std::cout << "offsetUD = " << offsetUD << std::endl; + //std::cout << "offsetUD = " << offsetUD << std::endl; refreshButtonBoundaries(); @@ -432,7 +432,11 @@ void ChannelSelector::setAudioStatus(int chan, bool b) } - +void ChannelSelector::clearAudio() +{ + for (int chan = 0; chan < audioButtons.size(); chan++) + audioButtons[chan]->setToggleState(false, true); +} int ChannelSelector::getDesiredWidth() { @@ -555,11 +559,12 @@ void ChannelSelector::buttonClicked(Button* button) //int channelNum = editor->getStartChannel() + b->getChannel() - 1; bool status = b->getToggleState(); + std::cout << "Requesting audio monitor for channel " << ch->num << std::endl; + if (acquisitionIsActive) // use setParameter to change parameter safely { editor->getProcessorGraph()-> - getAudioNode()-> - setChannelStatus(ch, status); + getAudioNode()->setChannelStatus(ch, status); } else // change parameter directly { @@ -590,8 +595,12 @@ void ChannelSelector::buttonClicked(Button* button) } } - else + else // parameter type { + + GenericEditor* editor = (GenericEditor*) getParentComponent(); + editor->channelChanged(b->getChannel()-1); + // do nothing if (radioStatus) // if radio buttons are active { @@ -832,8 +841,8 @@ void ChannelSelectorRegion::mouseWheelMove(const MouseEvent& event, const MouseWheelDetails& wheel) { - std::cout << "Got wheel move: " << wheel.deltaY << std::endl; - channelSelector->shiftChannelsVertical(wheel.deltaY); + // std::cout << "Got wheel move: " << wheel.deltaY << std::endl; + channelSelector->shiftChannelsVertical(-wheel.deltaY); } void ChannelSelectorRegion::paint(Graphics& g) diff --git a/Source/Processors/Editors/ChannelSelector.h b/Source/Processors/Editors/ChannelSelector.h index 466fc6196..e71ee2983 100755 --- a/Source/Processors/Editors/ChannelSelector.h +++ b/Source/Processors/Editors/ChannelSelector.h @@ -94,6 +94,9 @@ public: /** Set whether a particular channel should be monitored. */ void setAudioStatus(int, bool); + /** Sets all audio monitors to 'false' */ + void clearAudio(); + /** Set whether a particular channel is selected for editing parameters. */ void setParamStatus(int, bool); -- GitLab