Mercurial > hg > touchkeys
changeset 41:85577160a0d4
Many changes: implement global application preferences on devices etc.; extended editor window support with Control mapping features for now
line wrap: on
line diff
--- a/Builds/Linux/Makefile Fri Mar 21 23:13:19 2014 +0000 +++ b/Builds/Linux/Makefile Sat Jun 21 23:32:33 2014 +0100 @@ -49,6 +49,7 @@ endif OBJECTS := \ + $(OBJDIR)/PreferencesComponent_8c094f62.o \ $(OBJDIR)/MainWindow_ca618186.o \ $(OBJDIR)/KeyboardZoneComponent_fd0d7a77.o \ $(OBJDIR)/ControlWindowMainComponent_c67f9014.o \ @@ -68,6 +69,7 @@ $(OBJDIR)/TouchkeyMultiFingerTriggerMappingFactory_e811112a.o \ $(OBJDIR)/TouchkeyKeyDivisionMapping_cea38eb0.o \ $(OBJDIR)/TouchkeyKeyDivisionMappingFactory_33b42a44.o \ + $(OBJDIR)/TouchkeyControlMappingExtendedEditor_bb11f4.o \ $(OBJDIR)/TouchkeyControlMappingShortEditor_993f27a5.o \ $(OBJDIR)/TouchkeyControlMapping_1e638c8e.o \ $(OBJDIR)/TouchkeyControlMappingFactory_1db276a6.o \ @@ -134,6 +136,11 @@ @echo Stripping TouchKeys -@strip --strip-unneeded $(OUTDIR)/$(TARGET) +$(OBJDIR)/PreferencesComponent_8c094f62.o: ../../Source/GUI/PreferencesComponent.cpp + -@mkdir -p $(OBJDIR) + @echo "Compiling PreferencesComponent.cpp" + @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" + $(OBJDIR)/MainWindow_ca618186.o: ../../Source/GUI/MainWindow.cpp -@mkdir -p $(OBJDIR) @echo "Compiling MainWindow.cpp" @@ -229,6 +236,11 @@ @echo "Compiling TouchkeyKeyDivisionMappingFactory.cpp" @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" +$(OBJDIR)/TouchkeyControlMappingExtendedEditor_bb11f4.o: ../../Source/Mappings/Control/TouchkeyControlMappingExtendedEditor.cpp + -@mkdir -p $(OBJDIR) + @echo "Compiling TouchkeyControlMappingExtendedEditor.cpp" + @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" + $(OBJDIR)/TouchkeyControlMappingShortEditor_993f27a5.o: ../../Source/Mappings/Control/TouchkeyControlMappingShortEditor.cpp -@mkdir -p $(OBJDIR) @echo "Compiling TouchkeyControlMappingShortEditor.cpp"
--- a/Builds/Linux32/Makefile Fri Mar 21 23:13:19 2014 +0000 +++ b/Builds/Linux32/Makefile Sat Jun 21 23:32:33 2014 +0100 @@ -49,6 +49,7 @@ endif OBJECTS := \ + $(OBJDIR)/PreferencesComponent_8c094f62.o \ $(OBJDIR)/MainWindow_ca618186.o \ $(OBJDIR)/KeyboardZoneComponent_fd0d7a77.o \ $(OBJDIR)/ControlWindowMainComponent_c67f9014.o \ @@ -68,6 +69,7 @@ $(OBJDIR)/TouchkeyMultiFingerTriggerMappingFactory_e811112a.o \ $(OBJDIR)/TouchkeyKeyDivisionMapping_cea38eb0.o \ $(OBJDIR)/TouchkeyKeyDivisionMappingFactory_33b42a44.o \ + $(OBJDIR)/TouchkeyControlMappingExtendedEditor_bb11f4.o \ $(OBJDIR)/TouchkeyControlMappingShortEditor_993f27a5.o \ $(OBJDIR)/TouchkeyControlMapping_1e638c8e.o \ $(OBJDIR)/TouchkeyControlMappingFactory_1db276a6.o \ @@ -134,6 +136,11 @@ @echo Stripping TouchKeys -@strip --strip-unneeded $(OUTDIR)/$(TARGET) +$(OBJDIR)/PreferencesComponent_8c094f62.o: ../../Source/GUI/PreferencesComponent.cpp + -@mkdir -p $(OBJDIR) + @echo "Compiling PreferencesComponent.cpp" + @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" + $(OBJDIR)/MainWindow_ca618186.o: ../../Source/GUI/MainWindow.cpp -@mkdir -p $(OBJDIR) @echo "Compiling MainWindow.cpp" @@ -229,6 +236,11 @@ @echo "Compiling TouchkeyKeyDivisionMappingFactory.cpp" @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" +$(OBJDIR)/TouchkeyControlMappingExtendedEditor_bb11f4.o: ../../Source/Mappings/Control/TouchkeyControlMappingExtendedEditor.cpp + -@mkdir -p $(OBJDIR) + @echo "Compiling TouchkeyControlMappingExtendedEditor.cpp" + @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" + $(OBJDIR)/TouchkeyControlMappingShortEditor_993f27a5.o: ../../Source/Mappings/Control/TouchkeyControlMappingShortEditor.cpp -@mkdir -p $(OBJDIR) @echo "Compiling TouchkeyControlMappingShortEditor.cpp"
--- a/Source/Display/KeyboardTesterDisplay.cpp Fri Mar 21 23:13:19 2014 +0000 +++ b/Source/Display/KeyboardTesterDisplay.cpp Sat Jun 21 23:32:33 2014 +0100 @@ -88,8 +88,6 @@ // Restore to the original location we used when drawing the keys glPopMatrix(); - - needsUpdate_ = false; glFlush(); } @@ -119,7 +117,7 @@ else keySensorActive_[key] &= ~(1 << sensor); currentlyActiveKey_ = key; - needsUpdate_ = true; + tellCanvasToRepaint(); if(allSensorsGood(currentlyActiveKey_)) { controller_.touchkeySensorTestSetKey(key + 1);
--- a/Source/GUI/ControlWindowMainComponent.cpp Fri Mar 21 23:13:19 2014 +0000 +++ b/Source/GUI/ControlWindowMainComponent.cpp Sat Jun 21 23:32:33 2014 +0100 @@ -554,9 +554,9 @@ counter++; } - if(!lastSelectedDeviceExists) + if(!lastSelectedDeviceExists && lastSelectedMidiInputID_ >= 0) controller_->disablePrimaryMIDIInputPort(); - if(!lastSelectedAuxDeviceExists) + if(!lastSelectedAuxDeviceExists && lastSelectedMidiAuxInputID_ >= 0) controller_->disableAllMIDIInputPorts(true); }
--- a/Source/GUI/GraphicsDisplayWindow.h Fri Mar 21 23:13:19 2014 +0000 +++ b/Source/GUI/GraphicsDisplayWindow.h Sat Jun 21 23:32:33 2014 +0100 @@ -51,8 +51,8 @@ getConstrainer()->setFixedAspectRatio(display_.keyboardAspectRatio()); setBoundsConstrained(getBounds()); - // Show window - setVisible(true); + // Don't show window yet + setVisible(false); } ~GraphicsDisplayWindow()
--- a/Source/GUI/MainWindow.cpp Fri Mar 21 23:13:19 2014 +0000 +++ b/Source/GUI/MainWindow.cpp Sat Jun 21 23:32:33 2014 +0100 @@ -127,6 +127,8 @@ #ifdef ENABLE_TOUCHKEYS_SENSOR_TEST menu.addCommandItem(&commandManager_, kCommandTestTouchkeySensors); #endif + menu.addSeparator(); + menu.addCommandItem(&commandManager_, kCommandPreferences); } else if(menuIndex == 3) { // Window menu.addCommandItem(&commandManager_, kCommandShowControlWindow); @@ -170,6 +172,8 @@ #ifdef ENABLE_TOUCHKEYS_SENSOR_TEST kCommandTestTouchkeySensors, #endif + kCommandPreferences, + // Window kCommandShowControlWindow, kCommandShowKeyboardWindow @@ -279,6 +283,11 @@ result.setTicked(controller_.touchkeySensorTestIsRunning()); break; #endif + case kCommandPreferences: + result.setInfo("Preferences...", "General application preferences", controlCategory, 0); + result.setTicked(false); + result.setActive(true); + break; // *** Window Menu *** case kCommandShowControlWindow: @@ -339,6 +348,9 @@ controller_.touchkeySensorTestStop(); break; #endif + case kCommandPreferences: + controller_.showPreferencesWindow(); + break; case kCommandShowControlWindow: toFront(true); break;
--- a/Source/GUI/MainWindow.h Fri Mar 21 23:13:19 2014 +0000 +++ b/Source/GUI/MainWindow.h Sat Jun 21 23:32:33 2014 +0100 @@ -52,6 +52,7 @@ kCommandLoggingPlay, kCommandEnableExperimentalMappings, kCommandTestTouchkeySensors, + kCommandPreferences, // Window menu kCommandShowControlWindow = 0x2030,
--- a/Source/GUI/MappingEditorComponent.h Fri Mar 21 23:13:19 2014 +0000 +++ b/Source/GUI/MappingEditorComponent.h Sat Jun 21 23:32:33 2014 +0100 @@ -47,6 +47,11 @@ // Method to synchronize the GUI state to the underlying // state of the mapping. Implemented in the subclass. virtual void synchronize() {} + + // Get a human-readable name for the mapping + // Generally, extended editors should implement this but short editors + // don't need to + virtual String getDescription() { return "Mapping"; } virtual void paint (Graphics& g) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Source/GUI/MappingExtendedEditorWindow.h Sat Jun 21 23:32:33 2014 +0100 @@ -0,0 +1,92 @@ +/* + ============================================================================== + + MappingExtendedEditorWindow.h + Created: 18 Jun 2014 10:57:00am + Author: Andrew McPherson + + ============================================================================== +*/ + +#ifndef MAPPINGEXTENDEDEDITORWINDOW_H_INCLUDED +#define MAPPINGEXTENDEDEDITORWINDOW_H_INCLUDED + +#include "../../JuceLibraryCode/JuceHeader.h" +#include "../TouchKeys/MidiKeyboardSegment.h" +#include "../Mappings/MappingFactory.h" +#include "MappingListComponent.h" + +//============================================================================== +/* +*/ +class MappingExtendedEditorWindow : public DocumentWindow +{ +public: + MappingExtendedEditorWindow(MappingListComponent& listComponent, + MidiKeyboardSegment& segment, MappingFactory& factory) + : DocumentWindow("", Colours::lightgrey, DocumentWindow::minimiseButton | DocumentWindow::closeButton), + listComponent_(listComponent), segment_(segment), factory_(factory), editor_(0) + { + setUsingNativeTitleBar(true); + setResizable(false, false); + + if((segment_.indexOfMappingFactory(&factory_) >= 0) && factory_.hasExtendedEditor()) { + editor_ = factory_.createExtendedEditor(); + + // Set properties + setContentOwned(editor_, true); + + // Start interface in sync + editor_->synchronize(); + } + + // Show window + setVisible(true); + } + + ~MappingExtendedEditorWindow() + { + } + + // Method used by Juce timer which we will use for periodic UI updates + // from the underlying system state + void synchronize() { + if(editor_ == 0) + return; + editor_->synchronize(); + setName(editor_->getDescription()); + } + + // Check whether this window still points to a valid mapping + bool isValid() { + if(segment_.indexOfMappingFactory(&factory_) < 0) + return false; + return true; + } + + // Return the factory associated with this window + MappingFactory *factory() { + return &factory_; + } + + void closeButtonPressed() { + // Close the window and delete it + listComponent_.closeExtendedEditorWindow(this); + } + + void resized() { + // This method is where you should set the bounds of any child + // components that your component contains.. + } + +private: + MappingListComponent& listComponent_; + MidiKeyboardSegment& segment_; + MappingFactory& factory_; + MappingEditorComponent *editor_; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MappingExtendedEditorWindow) +}; + + +#endif // MAPPINGEXTENDEDEDITORWINDOW_H_INCLUDED
--- a/Source/GUI/MappingListComponent.cpp Fri Mar 21 23:13:19 2014 +0000 +++ b/Source/GUI/MappingListComponent.cpp Sat Jun 21 23:32:33 2014 +0100 @@ -25,6 +25,7 @@ #include "../JuceLibraryCode/JuceHeader.h" #include "MappingListComponent.h" +#include "MappingExtendedEditorWindow.h" //============================================================================== MappingListComponent::MappingListComponent() : controller_(0), keyboardSegment_(0), @@ -38,28 +39,9 @@ listBox_.setRowHeight(72); } -MappingListComponent::~MappingListComponent() {} - -#if 0 -void MappingListComponent::paint (Graphics& g) { - /* This demo code just fills the component's background and - draws some placeholder text to get you started. - - You should replace everything in this method with your own - drawing code.. - */ - - g.fillAll (Colours::white); // clear the background - - g.setColour (Colours::grey); - g.drawRect (getLocalBounds(), 1); // draw an outline around the component - - g.setColour (Colours::lightblue); - g.setFont (14.0f); - g.drawText ("MappingListComponent", getLocalBounds(), - Justification::centred, true); // draw some placeholder text +MappingListComponent::~MappingListComponent() { + clearExtendedEditorWindows(); } -#endif void MappingListComponent::resized() { // This method is where you should set the bounds of any child @@ -126,12 +108,12 @@ } -void MappingListComponent::synchronize() -{ +void MappingListComponent::synchronize() { if(keyboardSegment_ != 0) { if(lastMappingFactoryIdentifier_ != keyboardSegment_->mappingFactoryUniqueIdentifier()) { lastMappingFactoryIdentifier_ = keyboardSegment_->mappingFactoryUniqueIdentifier(); listBox_.updateContent(); + updateExtendedEditorWindows(); } } @@ -140,6 +122,106 @@ if(listItem != 0) listItem->synchronize(); } + + synchronizeExtendedEditorWindows(); +} + +// Open an extended editor window for the given component +// Store the new window in the list; it is deleted when it is closed +void MappingListComponent::openExtendedEditorWindow(MappingFactory *factory) { + if(factory == 0) + return; + + ScopedLock sl(extendedEditorWindowsMutex_); + + MappingExtendedEditorWindow *window = new MappingExtendedEditorWindow(*this, + *keyboardSegment_, *factory); + extendedEditorWindows_.push_back(window); +} + +// Close an extended editor window and remove it from the list +void MappingListComponent::closeExtendedEditorWindow(MappingExtendedEditorWindow *window) { + ScopedLock sl(extendedEditorWindowsMutex_); + + closeExtendedEditorWindowHelper(window); +} + +MappingExtendedEditorWindow* MappingListComponent::extendedEditorWindowForFactory(MappingFactory *factory) { + ScopedLock sl(extendedEditorWindowsMutex_); + + list<MappingExtendedEditorWindow*>::iterator it; + for(it = extendedEditorWindows_.begin(); it != extendedEditorWindows_.end(); ++it) { + if((*it)->factory() == factory) + return *it; + } + + return 0; +} + +// Update extended editor windows +void MappingListComponent::synchronizeExtendedEditorWindows() { + // Update extended editor windows + ScopedLock sl(extendedEditorWindowsMutex_); + + list<MappingExtendedEditorWindow*>::iterator it; + for(it = extendedEditorWindows_.begin(); it != extendedEditorWindows_.end(); ++it) { + (*it)->synchronize(); + } +} + +// Close an extended editor window and remove it from the list (interval version without lock) +void MappingListComponent::closeExtendedEditorWindowHelper(MappingExtendedEditorWindow *window) { + window->setVisible(false); + + list<MappingExtendedEditorWindow*>::iterator it; + bool found = true; + + // Remove this window from the list (handling multiple entries just in case) + while(found) { + found = false; + for(it = extendedEditorWindows_.begin(); it != extendedEditorWindows_.end(); ++it) { + if(*it == window) { + extendedEditorWindows_.erase(it); + found = true; + break; + } + } + } + + // Delete the window which in turn deletes the editor component + delete window; +} + +// Find the invalid extended editor windows and close them +void MappingListComponent::updateExtendedEditorWindows() { + ScopedLock sl(extendedEditorWindowsMutex_); + + list<MappingExtendedEditorWindow*>::iterator it; + bool found = true; + + // Remove the window from the list if it is invalid + while(found) { + found = false; + for(it = extendedEditorWindows_.begin(); it != extendedEditorWindows_.end(); ++it) { + if(!(*it)->isValid()) { + closeExtendedEditorWindowHelper(*it); + found = true; + break; + } + } + } +} + +// Remove all extend editor windows +void MappingListComponent::clearExtendedEditorWindows() { + ScopedLock sl(extendedEditorWindowsMutex_); + + list<MappingExtendedEditorWindow*>::iterator it; + for(it = extendedEditorWindows_.begin(); it != extendedEditorWindows_.end(); ++it) { + delete *it; + } + + extendedEditorWindows_.clear(); } #endif // TOUCHKEYS_NO_GUI
--- a/Source/GUI/MappingListComponent.h Fri Mar 21 23:13:19 2014 +0000 +++ b/Source/GUI/MappingListComponent.h Sat Jun 21 23:32:33 2014 +0100 @@ -27,12 +27,15 @@ #define __MAPPINGLISTCOMPONENT_H_51502151__ #include <vector> +#include <list> #include "../JuceLibraryCode/JuceHeader.h" #include "../MainApplicationController.h" #include "../TouchKeys/MidiKeyboardSegment.h" #include "MappingListItem.h" #include "../Mappings/MappingFactory.h" +class MappingExtendedEditorWindow; + //============================================================================== /* */ @@ -62,6 +65,13 @@ // Add or delete a mapping based on a Factory class created elsewhere void addMapping(MappingFactory* factory); void deleteMapping(MappingFactory* factory); + + // Return which segment this component refers to + int segmentNumber() { + if(keyboardSegment_ == 0) + return -1; + return keyboardSegment_->outputPort(); + } // *** ListBox methods *** int getNumRows(); @@ -78,11 +88,36 @@ // Update UI state to reflect underlying system state void synchronize(); + // *** Extended editor window methods *** + // Open an extended editor window for the given component + void openExtendedEditorWindow(MappingFactory *factory); + + // Close an extended editor window and remove it from the list + void closeExtendedEditorWindow(MappingExtendedEditorWindow *window); + + // Find an extended editor window for a given factory, if it exists + MappingExtendedEditorWindow *extendedEditorWindowForFactory(MappingFactory *factory); + private: + // Sync the UI for the extended editor windows + void synchronizeExtendedEditorWindows(); + + // Internal helper function for closing window + void closeExtendedEditorWindowHelper(MappingExtendedEditorWindow *window); + + // Find the invalid editor windows and clsoe them + void updateExtendedEditorWindows(); + + // Close all extended editor windows + void clearExtendedEditorWindows(); + ListBox listBox_; MainApplicationController *controller_; MidiKeyboardSegment *keyboardSegment_; + CriticalSection extendedEditorWindowsMutex_; + list<MappingExtendedEditorWindow*> extendedEditorWindows_; + int lastMappingFactoryIdentifier_; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MappingListComponent)
--- a/Source/GUI/MappingListItem.cpp Fri Mar 21 23:13:19 2014 +0000 +++ b/Source/GUI/MappingListItem.cpp Sat Jun 21 23:32:33 2014 +0100 @@ -20,6 +20,7 @@ //[Headers] You can add your own extra header files here... #ifndef TOUCHKEYS_NO_GUI #include "MappingListComponent.h" +#include "MappingExtendedEditorWindow.h" //[/Headers] #include "MappingListItem.h" @@ -157,6 +158,14 @@ else if (buttonThatWasClicked == showDetailsButton) { //[UserButtonCode_showDetailsButton] -- add your button handler code here.. + // Create an extended editor window + MappingExtendedEditorWindow *window = listComponent_.extendedEditorWindowForFactory(factory_); + if(window != 0) { + window->setVisible(true); + window->toFront(true); + } + else if(factory_->hasExtendedEditor()) + listComponent_.openExtendedEditorWindow(factory_); //[/UserButtonCode_showDetailsButton] } else if (buttonThatWasClicked == deleteButton) @@ -215,12 +224,9 @@ } if(factory_->hasExtendedEditor()) { - // Has an extended editor: make one and keep it around for adding to a new window - mappingLongEditorComponent = factory_->createExtendedEditor(); showDetailsButton->setEnabled(true); } else { - mappingLongEditorComponent = nullptr; showDetailsButton->setEnabled(false); } @@ -242,8 +248,6 @@ // Update the short and long components if present if(mappingShortEditorComponent != 0) mappingShortEditorComponent->synchronize(); - if(mappingLongEditorComponent != 0) - mappingLongEditorComponent->synchronize(); } //[/MiscUserCode]
--- a/Source/GUI/MappingListItem.h Fri Mar 21 23:13:19 2014 +0000 +++ b/Source/GUI/MappingListItem.h Sat Jun 21 23:32:33 2014 +0100 @@ -67,8 +67,6 @@ //[UserVariables] -- You can add your own custom variables in this section. MappingFactory *factory_; MappingListComponent& listComponent_; - - ScopedPointer<MappingEditorComponent> mappingLongEditorComponent; //[/UserVariables] //==============================================================================
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Source/GUI/PreferencesComponent.cpp Sat Jun 21 23:32:33 2014 +0100 @@ -0,0 +1,251 @@ +/* + ============================================================================== + + This is an automatically generated GUI class created by the Introjucer! + + Be careful when adding custom code to these files, as only the code within + the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded + and re-saved. + + Created with Introjucer version: 3.1.0 + + ------------------------------------------------------------------------------ + + The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-13 by Raw Material Software Ltd. + + ============================================================================== +*/ + +//[Headers] You can add your own extra header files here... +#include "../MainApplicationController.h" +//[/Headers] + +#include "PreferencesComponent.h" + + +//[MiscUserDefs] You can add your own user definitions and misc code here... +//[/MiscUserDefs] + +//============================================================================== +PreferencesComponent::PreferencesComponent () + : controller_(0) +{ + addAndMakeVisible (startupPresetComboBox = new ComboBox ("Startup preset combo box")); + startupPresetComboBox->setEditableText (false); + startupPresetComboBox->setJustificationType (Justification::centredLeft); + startupPresetComboBox->setTextWhenNothingSelected (String::empty); + startupPresetComboBox->setTextWhenNoChoicesAvailable ("(no choices)"); + startupPresetComboBox->addListener (this); + + addAndMakeVisible (label4 = new Label ("new label", + "Load preset on startup:")); + label4->setFont (Font (15.00f, Font::plain)); + label4->setJustificationType (Justification::centredLeft); + label4->setEditable (false, false, false); + label4->setColour (TextEditor::textColourId, Colours::black); + label4->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); + + addAndMakeVisible (startTouchKeysButton = new ToggleButton ("auto start TouchKeys button")); + startTouchKeysButton->setButtonText ("Start TouchKeys on startup"); + startTouchKeysButton->addListener (this); + + addAndMakeVisible (autodetectButton = new ToggleButton ("Autodetect button")); + autodetectButton->setButtonText ("Autodetect TouchKeys octave on each start"); + autodetectButton->addListener (this); + + addAndMakeVisible (defaultsButton = new TextButton ("new button")); + defaultsButton->setButtonText ("Reset to Defaults..."); + defaultsButton->addListener (this); + + + //[UserPreSize] + //[/UserPreSize] + + setSize (296, 152); + + + //[Constructor] You can add your own custom stuff here.. + + // Initialise the combo box + startupPresetComboBox->addItem("None", kStartupPresetNone); + startupPresetComboBox->addItem("Vibrato and Pitch Bend", kStartupPresetVibratoPitchBend); + startupPresetComboBox->addItem("Last Saved", kStartupPresetLastSaved); + startupPresetComboBox->addItem("Choose...", kStartupPresetChoose); + + //[/Constructor] +} + +PreferencesComponent::~PreferencesComponent() +{ + //[Destructor_pre]. You can add your own custom destruction code here.. + //[/Destructor_pre] + + startupPresetComboBox = nullptr; + label4 = nullptr; + startTouchKeysButton = nullptr; + autodetectButton = nullptr; + defaultsButton = nullptr; + + + //[Destructor]. You can add your own custom destruction code here.. + //[/Destructor] +} + +//============================================================================== +void PreferencesComponent::paint (Graphics& g) +{ + //[UserPrePaint] Add your own custom painting code here.. + //[/UserPrePaint] + + g.fillAll (Colour (0xffd2d2d2)); + + //[UserPaint] Add your own custom painting code here.. + //[/UserPaint] +} + +void PreferencesComponent::resized() +{ + startupPresetComboBox->setBounds (16, 32, 264, 24); + label4->setBounds (16, 8, 160, 24); + startTouchKeysButton->setBounds (16, 64, 208, 24); + autodetectButton->setBounds (16, 88, 272, 24); + defaultsButton->setBounds (16, 120, 144, 24); + //[UserResized] Add your own custom resize handling here.. + //[/UserResized] +} + +void PreferencesComponent::comboBoxChanged (ComboBox* comboBoxThatHasChanged) +{ + //[UsercomboBoxChanged_Pre] + if(controller_ == 0) + return; + //[/UsercomboBoxChanged_Pre] + + if (comboBoxThatHasChanged == startupPresetComboBox) + { + //[UserComboBoxCode_startupPresetComboBox] -- add your combo box handling code here.. + int selection = startupPresetComboBox->getSelectedId(); + if(selection == kStartupPresetNone) { + controller_->setPrefsStartupPresetNone(); + } + else if(selection == kStartupPresetVibratoPitchBend) { + controller_->setPrefsStartupPresetVibratoPitchBend(); + } + else if(selection == kStartupPresetLastSaved) { + controller_->setPrefsStartupPresetLastSaved(); + } + else if(selection == kStartupPresetChoose) { + // Bring up window to choose a preset + FileChooser myChooser ("Select a preset...", + File::nonexistent, // File::getSpecialLocation (File::userHomeDirectory), + "*.tkpreset"); + if(myChooser.browseForFileToOpen()) { + controller_->setPrefsStartupPreset(myChooser.getResult().getFullPathName()); + } + // Otherwise user clicked cancel and we go back to whatever was there before + } + //[/UserComboBoxCode_startupPresetComboBox] + } + + //[UsercomboBoxChanged_Post] + //[/UsercomboBoxChanged_Post] +} + +void PreferencesComponent::buttonClicked (Button* buttonThatWasClicked) +{ + //[UserbuttonClicked_Pre] + if(controller_ == 0) + return; + //[/UserbuttonClicked_Pre] + + if (buttonThatWasClicked == startTouchKeysButton) + { + //[UserButtonCode_startTouchKeysButton] -- add your button handler code here.. + controller_->setPrefsAutoStartTouchKeys(startTouchKeysButton->getToggleState()); + //[/UserButtonCode_startTouchKeysButton] + } + else if (buttonThatWasClicked == autodetectButton) + { + //[UserButtonCode_autodetectButton] -- add your button handler code here.. + controller_->setPrefsAutodetectOctave(autodetectButton->getToggleState()); + //[/UserButtonCode_autodetectButton] + } + else if (buttonThatWasClicked == defaultsButton) + { + //[UserButtonCode_defaultsButton] -- add your button handler code here.. + controller_->resetPreferences(); + //[/UserButtonCode_defaultsButton] + } + + //[UserbuttonClicked_Post] + //[/UserbuttonClicked_Post] +} + + + +//[MiscUserCode] You can add your own definitions of your custom methods or any other code here... + +// Synchronize the UI state with the underlying state of the controller +void PreferencesComponent::synchronize(bool forceUpdates) { + if(controller_ == 0) + return; + + startTouchKeysButton->setToggleState(controller_->getPrefsAutoStartTouchKeys(), dontSendNotification); + autodetectButton->setToggleState(controller_->getPrefsAutodetectOctave(), dontSendNotification); + + if(controller_->getPrefsStartupPresetNone()) + startupPresetComboBox->setSelectedId(kStartupPresetNone); + else if(controller_->getPrefsStartupPresetVibratoPitchBend()) + startupPresetComboBox->setSelectedId(kStartupPresetVibratoPitchBend); + else if(controller_->getPrefsStartupPresetLastSaved()) + startupPresetComboBox->setSelectedId(kStartupPresetLastSaved); + else { + String path = controller_->getPrefsStartupPreset(); + startupPresetComboBox->setText(path); + } +} + +//[/MiscUserCode] + + +//============================================================================== +#if 0 +/* -- Introjucer information section -- + + This is where the Introjucer stores the metadata that describe this GUI layout, so + make changes in here at your peril! + +BEGIN_JUCER_METADATA + +<JUCER_COMPONENT documentType="Component" className="PreferencesComponent" componentName="" + parentClasses="public Component" constructorParams="" variableInitialisers="controller_(0)" + snapPixels="8" snapActive="1" snapShown="1" overlayOpacity="0.330" + fixedSize="1" initialWidth="296" initialHeight="152"> + <BACKGROUND backgroundColour="ffd2d2d2"/> + <COMBOBOX name="Startup preset combo box" id="244410f02f6c1c72" memberName="startupPresetComboBox" + virtualName="" explicitFocusOrder="0" pos="16 32 264 24" editable="0" + layout="33" items="" textWhenNonSelected="" textWhenNoItems="(no choices)"/> + <LABEL name="new label" id="e9b3daa69a8ac5c" memberName="label4" virtualName="" + explicitFocusOrder="0" pos="16 8 160 24" edTextCol="ff000000" + edBkgCol="0" labelText="Load preset on startup:" editableSingleClick="0" + editableDoubleClick="0" focusDiscardsChanges="0" fontname="Default font" + fontsize="15" bold="0" italic="0" justification="33"/> + <TOGGLEBUTTON name="auto start TouchKeys button" id="62c82600413ca060" memberName="startTouchKeysButton" + virtualName="" explicitFocusOrder="0" pos="16 64 208 24" buttonText="Start TouchKeys on startup" + connectedEdges="0" needsCallback="1" radioGroupId="0" state="0"/> + <TOGGLEBUTTON name="Autodetect button" id="69a491dfca4ea997" memberName="autodetectButton" + virtualName="" explicitFocusOrder="0" pos="16 88 272 24" buttonText="Autodetect TouchKeys octave on each start" + connectedEdges="0" needsCallback="1" radioGroupId="0" state="0"/> + <TEXTBUTTON name="new button" id="89690e14d6bf00c0" memberName="defaultsButton" + virtualName="" explicitFocusOrder="0" pos="16 120 144 24" buttonText="Reset to Defaults..." + connectedEdges="0" needsCallback="1" radioGroupId="0"/> +</JUCER_COMPONENT> + +END_JUCER_METADATA +*/ +#endif + + +//[EndFile] You can add extra defines here... +//[/EndFile]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Source/GUI/PreferencesComponent.h Sat Jun 21 23:32:33 2014 +0100 @@ -0,0 +1,96 @@ +/* + ============================================================================== + + This is an automatically generated GUI class created by the Introjucer! + + Be careful when adding custom code to these files, as only the code within + the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded + and re-saved. + + Created with Introjucer version: 3.1.0 + + ------------------------------------------------------------------------------ + + The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-13 by Raw Material Software Ltd. + + ============================================================================== +*/ + +#ifndef __JUCE_HEADER_248C56742F074362__ +#define __JUCE_HEADER_248C56742F074362__ + +//[Headers] -- You can add your own extra header files here -- +#include "JuceHeader.h" + +class MainApplicationController; +//[/Headers] + + + +//============================================================================== +/** + //[Comments] + An auto-generated component, created by the Introjucer. + + Describe your class and how it works here! + //[/Comments] +*/ +class PreferencesComponent : public Component, + public ComboBoxListener, + public ButtonListener +{ +public: + //============================================================================== + PreferencesComponent (); + ~PreferencesComponent(); + + //============================================================================== + //[UserMethods] -- You can add your own custom methods in this section. + + void setMainApplicationController(MainApplicationController *controller) { + // Attach the user interface to the controller and vice-versa + controller_ = controller; + } + + // Synchronize UI state to match underlying state of the back end + void synchronize(bool forceUpdates = false); + + //[/UserMethods] + + void paint (Graphics& g); + void resized(); + void comboBoxChanged (ComboBox* comboBoxThatHasChanged); + void buttonClicked (Button* buttonThatWasClicked); + + + +private: + //[UserVariables] -- You can add your own custom variables in this section. + enum { + kStartupPresetNone = 1, + kStartupPresetVibratoPitchBend, + kStartupPresetLastSaved, + kStartupPresetChoose + }; + + MainApplicationController *controller_; // Pointer to the main application controller + + //[/UserVariables] + + //============================================================================== + ScopedPointer<ComboBox> startupPresetComboBox; + ScopedPointer<Label> label4; + ScopedPointer<ToggleButton> startTouchKeysButton; + ScopedPointer<ToggleButton> autodetectButton; + ScopedPointer<TextButton> defaultsButton; + + + //============================================================================== + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PreferencesComponent) +}; + +//[EndFile] You can add extra defines here... +//[/EndFile] + +#endif // __JUCE_HEADER_248C56742F074362__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Source/GUI/PreferencesWindow.h Sat Jun 21 23:32:33 2014 +0100 @@ -0,0 +1,65 @@ +/* + ============================================================================== + + PreferencesWindow.h + Created: 17 Jun 2014 11:22:44pm + Author: Andrew McPherson + + ============================================================================== +*/ + +#ifndef PREFERENCESWINDOW_H_INCLUDED +#define PREFERENCESWINDOW_H_INCLUDED + +#include "../../JuceLibraryCode/JuceHeader.h" +#include "PreferencesComponent.h" +#include "../MainApplicationController.h" + +//============================================================================== +/* +*/ +class PreferencesWindow : public DocumentWindow, public Timer +{ +public: + PreferencesWindow(MainApplicationController& controller) + : DocumentWindow("Preferences", Colours::lightgrey, DocumentWindow::allButtons) + { + // Make a new preferences component + preferencesComponent_ = new PreferencesComponent(); + preferencesComponent_->setMainApplicationController(&controller); + + // Set properties + setContentOwned(preferencesComponent_, true); + setUsingNativeTitleBar(true); + setResizable(false, false); + + // Don't show window yet + setVisible(false); + + // Start a timer that will keep the interface in sync with the application + startTimer(50); + } + + ~PreferencesWindow() + { + } + + // Method used by Juce timer which we will use for periodic UI updates + // from the underlying system state + void timerCallback() { + preferencesComponent_->synchronize(); + } + + void closeButtonPressed() + { + setVisible(false); + } + +private: + PreferencesComponent *preferencesComponent_; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PreferencesWindow) +}; + + +#endif // PREFERENCESWINDOW_H_INCLUDED
--- a/Source/Main.cpp Fri Mar 21 23:13:19 2014 +0000 +++ b/Source/Main.cpp Sat Jun 21 23:32:33 2014 +0100 @@ -26,6 +26,8 @@ #ifndef TOUCHKEYS_NO_GUI #include "GUI/MainWindow.h" #include "GUI/GraphicsDisplayWindow.h" +#include "GUI/PreferencesWindow.h" +#include "GUI/PreferencesComponent.h" #include "Display/OpenGLJuceCanvas.h" //============================================================================== @@ -45,8 +47,11 @@ mainWindow_ = new MainWindow(controller_); keyboardDisplayWindow_ = new GraphicsDisplayWindow("TouchKeys Display", controller_.keyboardDisplay()); + preferencesWindow_ = new PreferencesWindow(controller_); controller_.setKeyboardDisplayWindow(keyboardDisplayWindow_); + controller_.setPreferencesWindow(preferencesWindow_); + controller_.initialise(); } void shutdown() { @@ -57,7 +62,9 @@ mainWindow_ = nullptr; // (deletes our window) controller_.setKeyboardDisplayWindow(0); // Delete display window and disconnect from controller + controller_.setPreferencesWindow(0); keyboardDisplayWindow_ = nullptr; + preferencesWindow_ = nullptr; } //============================================================================== @@ -76,6 +83,7 @@ private: ScopedPointer<MainWindow> mainWindow_; ScopedPointer<GraphicsDisplayWindow> keyboardDisplayWindow_; + ScopedPointer<PreferencesWindow> preferencesWindow_; MainApplicationController controller_; };
--- a/Source/MainApplicationController.cpp Fri Mar 21 23:13:19 2014 +0000 +++ b/Source/MainApplicationController.cpp Sat Jun 21 23:32:33 2014 +0100 @@ -56,6 +56,7 @@ keyboardDisplayWindow_(0), keyboardTesterDisplay_(0), keyboardTesterWindow_(0), + preferencesWindow_(0), #endif segmentCounter_(0), loggingActive_(false) @@ -70,18 +71,30 @@ keyboardController_.setMidiOutputController(&midiOutputController_); keyboardController_.setGUI(&keyboardDisplay_); midiInputController_.setMidiOutputController(&midiOutputController_); - - // Set up an initial OSC transmit host/port - oscTransmitter_.addAddress(kDefaultOscTransmitHost, kDefaultOscTransmitPort); // Set up default logging directory loggingDirectory_ = (File::getSpecialLocation(File::userHomeDirectory).getFullPathName() + "/Desktop").toUTF8(); + // Configure application properties + PropertiesFile::Options options; + options.applicationName = "TouchKeys"; + options.folderName = "TouchKeys"; + options.filenameSuffix = ".properties"; + options.osxLibrarySubFolder = "Application Support"; + applicationProperties_.setStorageParameters(options); + // Defaults for display, until we get other information keyboardDisplay_.setKeyboardRange(36, 72); // Add one keyboard segment at the beginning midiSegmentAdd(); + + // Load the current preferences + loadApplicationPreferences(); + + // Set up an initial OSC transmit host/port if none has been loaded + if(oscTransmitter_.addresses().size() == 0) + oscTransmitter_.addAddress(kDefaultOscTransmitHost, kDefaultOscTransmitPort); } MainApplicationController::~MainApplicationController() { @@ -91,6 +104,46 @@ #endif } +// Actions here run in the JUCE initialise() method once the application is loaded +void MainApplicationController::initialise() { + // Load a preset if enabled + if(getPrefsStartupPresetLastSaved()) { + if(applicationProperties_.getUserSettings()->containsKey("LastSavedPreset")) { + String presetFile = applicationProperties_.getUserSettings()->getValue("LastSavedPreset"); + if(presetFile != "") { + loadPresetFromFile(presetFile.toUTF8()); + } + } + } + else if(getPrefsStartupPresetVibratoPitchBend()) { + if(midiInputController_.numSegments() > 0) { + MidiKeyboardSegment *segment = midiInputController_.segment(0); + + MappingFactory *factory = new TouchkeyVibratoMappingFactory(keyboardController_, *segment); + if(factory != 0) + segment->addMappingFactory(factory); + factory = new TouchkeyPitchBendMappingFactory(keyboardController_, *segment); + if(factory != 0) + segment->addMappingFactory(factory); + } + } + else if(!getPrefsStartupPresetNone()) { + String presetFile = getPrefsStartupPreset(); + if(presetFile != "") { + loadPresetFromFile(presetFile.toUTF8()); + } + } + + // Automatically start the TouchKeys if the preferences are enabled + if(getPrefsAutoStartTouchKeys() && applicationProperties_.getUserSettings()->containsKey("TouchKeysDevice")) { + String tkDevicePath = applicationProperties_.getUserSettings()->getValue("TouchKeysDevice"); + if(touchkeyDeviceExists(tkDevicePath.toUTF8())) { + // Exists: try to open and run + touchkeyDeviceStartupSequence(tkDevicePath.toUTF8()); + } + } +} + bool MainApplicationController::touchkeyDeviceStartupSequence(const char * path) { #ifdef TOUCHKEY_ENTROPY_GENERATOR_ENABLE if(!strcmp(path, "/dev/Entropy Generator") || !strcmp(path, "\\\\.\\Entropy Generator")) { @@ -137,6 +190,13 @@ // Success! touchkeyErrorMessage_ = ""; touchkeyErrorOccurred_ = false; + + showKeyboardDisplayWindow(); + + // Automatically detect the lowest octave if set + if(getPrefsAutodetectOctave()) + touchkeyDeviceAutodetectLowestMidiNote(); + return true; } @@ -212,6 +272,27 @@ return devices; } +void MainApplicationController::touchkeyDeviceClearErrorMessage() { + touchkeyErrorMessage_ = ""; + touchkeyErrorOccurred_ = false; +} + +// Check whether a given touchkey device exists +bool MainApplicationController::touchkeyDeviceExists(const char * path) { + String pathString(path); + File tkDeviceFile(pathString); + return tkDeviceFile.existsAsFile(); +} + +// Select a particular touchkey device +bool MainApplicationController::openTouchkeyDevice(const char * path) { + bool success = touchkeyController_.openDevice(path); + + if(success) + applicationProperties_.getUserSettings()->setValue("TouchKeysDevice", String(path)); + return success; +} + // Close the currently open TouchKeys device void MainApplicationController::closeTouchkeyDevice() { #ifdef TOUCHKEY_ENTROPY_GENERATOR_ENABLE @@ -239,6 +320,21 @@ return true; } +// Start/stop the TouchKeys data collection +bool MainApplicationController::startTouchkeyDevice() { + return touchkeyController_.startAutoGathering(); +} + +void MainApplicationController::stopTouchkeyDevice() { + touchkeyController_.stopAutoGathering(); +} + +// Status queries on TouchKeys +// Returns true if device has been opened +bool MainApplicationController::touchkeyDeviceIsOpen() { + return touchkeyController_.isOpen(); +} + // Return true if device is collecting data bool MainApplicationController::touchkeyDeviceIsRunning() { #ifdef TOUCHKEY_ENTROPY_GENERATOR_ENABLE @@ -251,6 +347,35 @@ #endif } +// Returns true if an error has occurred +bool MainApplicationController::touchkeyDeviceErrorOccurred() { + return touchkeyErrorOccurred_; +} + +// Return the error message if one occurred +std::string MainApplicationController::touchkeyDeviceErrorMessage() { + return touchkeyErrorMessage_; +} + +// How many octaves on the current device +int MainApplicationController::touchkeyDeviceNumberOfOctaves() { + return touchkeyController_.numberOfOctaves(); +} + +// Return the lowest MIDI note +int MainApplicationController::touchkeyDeviceLowestMidiNote() { + return touchkeyController_.lowestMidiNote(); +} + +// Set the lowest MIDI note for the TouchKeys +void MainApplicationController::touchkeyDeviceSetLowestMidiNote(int note) { + keyboardDisplay_.clearAllTouches(); + touchkeyEmulator_.setLowestMidiNote(note); + touchkeyController_.setLowestMidiNote(note); + + applicationProperties_.getUserSettings()->setValue("TouchKeysLowestMIDINote", note); +} + // Start an autodetection routine to match touch data to MIDI void MainApplicationController::touchkeyDeviceAutodetectLowestMidiNote() { if(touchkeyAutodetecting_) @@ -325,7 +450,7 @@ // consider renumbering every time a segment is removed so that we always have an index // 0-N which corresponds to the indexes within MidiInputController (and also the layout // of the tabs). - MidiKeyboardSegment *newSegment = midiInputController_.addSegment(segmentCounter_++, 12, 127); + MidiKeyboardSegment *newSegment = midiInputController_.addSegment(segmentCounter_, 12, 127); // Set up defaults newSegment->setModePassThrough(); @@ -335,10 +460,15 @@ newSegment->setOutputTransposition(0); newSegment->setUsesKeyboardPitchWheel(true); + // Enable the MIDI output for this segment if it exists in the preferences + loadMIDIOutputFromApplicationPreferences(segmentCounter_); + // Enable standalone mode on the new segment if generally enabled if(touchkeyStandaloneModeEnabled_) newSegment->enableTouchkeyStandaloneMode(); + segmentCounter_++; + return newSegment; } @@ -354,6 +484,90 @@ midiInputController_.removeSegment(segment); } +// Enable one MIDI input port either as primary or auxiliary +void MainApplicationController::enableMIDIInputPort(int portNumber, bool isPrimary) { + midiInputController_.enablePort(portNumber, isPrimary); + if(isPrimary) + applicationProperties_.getUserSettings()->setValue("MIDIInputPrimary", + midiInputController_.deviceName(portNumber)); + else + applicationProperties_.getUserSettings()->setValue("MIDIInputAuxiliary", + midiInputController_.deviceName(portNumber)); +} + +// Enable all available MIDI input ports, with one in particular selected as primary +void MainApplicationController::enableAllMIDIInputPorts(int primaryPortNumber) { + midiInputController_.enableAllPorts(primaryPortNumber); + applicationProperties_.getUserSettings()->setValue("MIDIInputPrimary", + midiInputController_.deviceName(primaryPortNumber)); + applicationProperties_.getUserSettings()->setValue("MIDIInputAuxiliary", "__all__"); +} + +// Disable a particular MIDI input port number +// For now, the preferences for auxiliary ports don't update; could add a complete list of enabled aux ports +void MainApplicationController::disableMIDIInputPort(int portNumber) { + if(portNumber == selectedMIDIPrimaryInputPort()) + applicationProperties_.getUserSettings()->setValue("MIDIInputPrimary", ""); + midiInputController_.disablePort(portNumber); +} + +// Disable the current primary MIDI input port +void MainApplicationController::disablePrimaryMIDIInputPort() { + applicationProperties_.getUserSettings()->setValue("MIDIInputPrimary", ""); + midiInputController_.disablePrimaryPort(); +} + +// Disable either all MIDI input ports or all auxiliary inputs +void MainApplicationController::disableAllMIDIInputPorts(bool auxiliaryOnly) { + applicationProperties_.getUserSettings()->setValue("MIDIInputAuxiliary", ""); + if(!auxiliaryOnly) + applicationProperties_.getUserSettings()->setValue("MIDIInputPrimary", ""); + midiInputController_.disableAllPorts(auxiliaryOnly); +} + +// Enable a particular MIDI output port, associating it with a segment +void MainApplicationController::enableMIDIOutputPort(int identifier, int deviceNumber) { + midiOutputController_.enablePort(identifier, deviceNumber); + + String zoneName = "MIDIOutputZone"; + zoneName += identifier; + applicationProperties_.getUserSettings()->setValue(zoneName, midiOutputController_.deviceName(deviceNumber)); +} + +#ifndef JUCE_WINDOWS +// Create a virtual (inter-application) MIDI output port +void MainApplicationController::enableMIDIOutputVirtualPort(int identifier, const char *name) { + midiOutputController_.enableVirtualPort(identifier, name); + + String zoneName = "MIDIOutputZone"; + zoneName += identifier; + String zoneValue = "__virtual__"; + zoneValue += String(name); + applicationProperties_.getUserSettings()->setValue(zoneName, zoneValue); +} +#endif + +// Disable a particular MIDI output port +void MainApplicationController::disableMIDIOutputPort(int identifier) { + String zoneName = "MIDIOutputZone"; + zoneName += identifier; + applicationProperties_.getUserSettings()->setValue(zoneName, ""); + + midiOutputController_.disablePort(identifier); +} + +// Disable all MIDI output ports +void MainApplicationController::disableAllMIDIOutputPorts() { + std::vector<std::pair<int, int> > enabledPorts = midiOutputController_.enabledPorts(); + for(int i = 0; i < enabledPorts.size(); i++) { + // For each active zone, set output port to disabled in preferences + String zoneName = "MIDIOutputZone"; + zoneName += enabledPorts[i].first; + applicationProperties_.getUserSettings()->setValue(zoneName, ""); + } + + midiOutputController_.disableAllPorts(); +} // Enable TouchKeys standalone mode void MainApplicationController::midiTouchkeysStandaloneModeEnable() { @@ -362,6 +576,8 @@ for(int i = 0; i < midiInputController_.numSegments(); i++) { midiInputController_.segment(i)->enableTouchkeyStandaloneMode(); } + + applicationProperties_.getUserSettings()->setValue("MIDIInputPrimary", "__standalone__"); } void MainApplicationController::midiTouchkeysStandaloneModeDisable() { @@ -370,6 +586,147 @@ for(int i = 0; i < midiInputController_.numSegments(); i++) { midiInputController_.segment(i)->disableTouchkeyStandaloneMode(); } + + if(applicationProperties_.getUserSettings()->getValue("MIDIInputPrimary") == "__standalone__") + applicationProperties_.getUserSettings()->setValue("MIDIInputPrimary", ""); +} + +// *** OSC device methods *** + +// Return whether OSC transmission is enabled +bool MainApplicationController::oscTransmitEnabled() { + return oscTransmitter_.enabled(); +} + +// Set whether OSC transmission is enabled +void MainApplicationController::oscTransmitSetEnabled(bool enable) { + oscTransmitter_.setEnabled(enable); + applicationProperties_.getUserSettings()->setValue("OSCTransmitEnabled", enable); +} + +// Return whether raw frame transmission is enabled +bool MainApplicationController::oscTransmitRawDataEnabled() { + return touchkeyController_.transmitRawDataEnabled(); +} + +// Set whether raw frame transmission is enabled +void MainApplicationController::oscTransmitSetRawDataEnabled(bool enable) { + touchkeyController_.setTransmitRawData(enable); + applicationProperties_.getUserSettings()->setValue("OSCTransmitRawDataEnabled", enable); +} + +// Return the addresses to which OSC messages are sent +std::vector<lo_address> MainApplicationController::oscTransmitAddresses() { + return oscTransmitter_.addresses(); +} + +// Add a new address for sending OSC messages to +int MainApplicationController::oscTransmitAddAddress(const char * host, const char * port, int proto) { + int indexOfNewAddress = oscTransmitter_.addAddress(host, port, proto); + + if(indexOfNewAddress >= 0) { + // Successfully added; update preferences + String keyName = "OSCTransmitHost"; + keyName += indexOfNewAddress; + applicationProperties_.getUserSettings()->setValue(keyName, String(host)); + + keyName = "OSCTransmitPort"; + keyName += indexOfNewAddress; + applicationProperties_.getUserSettings()->setValue(keyName, String(port)); + + keyName = "OSCTransmitProtocol"; + keyName += indexOfNewAddress; + applicationProperties_.getUserSettings()->setValue(keyName, proto); + } + + return indexOfNewAddress; +} + +// Remove a particular OSC address from the send list +void MainApplicationController::oscTransmitRemoveAddress(int index) { + oscTransmitter_.removeAddress(index); + + // Remove this destination from the preferences, if it exists + String keyName = "OSCTransmitHost"; + keyName += index; + + if(applicationProperties_.getUserSettings()->containsKey(keyName)) { + applicationProperties_.getUserSettings()->setValue(keyName, ""); + + keyName = "OSCTransmitPort"; + keyName += index; + applicationProperties_.getUserSettings()->setValue(keyName, ""); + + keyName = "OSCTransmitProtocol"; + keyName += index; + applicationProperties_.getUserSettings()->setValue(keyName, (int)0); + } +} + +// Remove all OSC addresses from the send list +void MainApplicationController::oscTransmitClearAddresses() { + oscTransmitter_.clearAddresses(); + + for(int index = 0; index < 16; index++) { + // Go through and clear preferences for recent OSC hosts; + // 16 hosts is a sanity check + + String keyName = "OSCTransmitHost"; + keyName += index; + + if(applicationProperties_.getUserSettings()->containsKey(keyName)) { + applicationProperties_.getUserSettings()->setValue(keyName, ""); + + keyName = "OSCTransmitPort"; + keyName += index; + applicationProperties_.getUserSettings()->setValue(keyName, ""); + + keyName = "OSCTransmitProtocol"; + keyName += index; + applicationProperties_.getUserSettings()->setValue(keyName, (int)0); + } + } + +} + +// OSC Input (receiver) methods +// Enable or disable on the OSC receive, and report is status +bool MainApplicationController::oscReceiveEnabled() { + return oscReceiveEnabled_; +} + +// Enable method returns true on success (false only if it was +// unable to set the port) +bool MainApplicationController::oscReceiveSetEnabled(bool enable) { + applicationProperties_.getUserSettings()->setValue("OSCReceiveEnabled", enable); + + if(enable && !oscReceiveEnabled_) { + oscReceiveEnabled_ = true; + return oscReceiver_.setPort(oscReceivePort_); + } + else if(!enable && oscReceiveEnabled_) { + oscReceiveEnabled_ = false; + return oscReceiver_.setPort(0); + } + return true; +} + +// Whether the OSC server is running (false means couldn't open port) +bool MainApplicationController::oscReceiveRunning() { + return oscReceiver_.running(); +} + +// Get the current OSC receive port +int MainApplicationController::oscReceivePort() { + return oscReceivePort_; +} + +// Set the current OSC receive port (returns true on success) +bool MainApplicationController::oscReceiveSetPort(int port) { + applicationProperties_.getUserSettings()->setValue("OSCReceivePort", port); + + oscReceivePort_ = port; + return oscReceiver_.setPort(port); } // OSC handler method @@ -406,8 +763,10 @@ // std::cout << "Found difference of " << noteDifference << std::endl; currentMinNote -= noteDifference; - if(currentMinNote >= 0 && currentMinNote <= 127) + if(currentMinNote >= 0 && currentMinNote <= 127) { touchkeyController_.setLowestMidiNote(currentMinNote); + applicationProperties_.getUserSettings()->setValue("TouchKeysLowestMIDINote", currentMinNote); + } touchkeyDeviceStopAutodetecting(); } @@ -541,7 +900,13 @@ XmlElement* segmentsElement = midiInputController_.getSegmentPreset(); mainElement.addChildElement(segmentsElement); - return mainElement.writeToFile(outputFile, ""); + bool result = mainElement.writeToFile(outputFile, ""); + + if(result) { + applicationProperties_.getUserSettings()->setValue("LastSavedPreset", outputFile.getFullPathName()); + } + + return result; } // Clear the current preset and restore default settings @@ -554,6 +919,207 @@ midiSegmentAdd(); } +// Whether to automatically start the TouchKeys on startup +bool MainApplicationController::getPrefsAutoStartTouchKeys() { + if(!applicationProperties_.getUserSettings()->containsKey("StartupStartTouchKeys")) + return false; + return applicationProperties_.getUserSettings()->getBoolValue("StartupStartTouchKeys"); +} + +void MainApplicationController::setPrefsAutoStartTouchKeys(bool autoStart) { + applicationProperties_.getUserSettings()->setValue("StartupStartTouchKeys", autoStart); +} + +// Whether to automatically detect the TouchKeys octave when they start +bool MainApplicationController::getPrefsAutodetectOctave() { + if(!applicationProperties_.getUserSettings()->containsKey("StartupAutodetectTouchKeysOctave")) + return false; + return applicationProperties_.getUserSettings()->getBoolValue("StartupAutodetectTouchKeysOctave"); +} + +void MainApplicationController::setPrefsAutodetectOctave(bool autoDetect) { + applicationProperties_.getUserSettings()->setValue("StartupAutodetectTouchKeysOctave", autoDetect); +} + +// Which preset (if any) to load at startup +void MainApplicationController::setPrefsStartupPresetNone() { + applicationProperties_.getUserSettings()->setValue("StartupPreset", "__none__"); +} +bool MainApplicationController::getPrefsStartupPresetNone() { + // By default, no prefs means no preset + if(!applicationProperties_.getUserSettings()->containsKey("StartupPreset")) + return true; + if(applicationProperties_.getUserSettings()->getValue("StartupPreset") == "__none__") + return true; + return false; +} + +void MainApplicationController::setPrefsStartupPresetVibratoPitchBend() { + applicationProperties_.getUserSettings()->setValue("StartupPreset", "__vib_pb__"); +} +bool MainApplicationController::getPrefsStartupPresetVibratoPitchBend() { + if(!applicationProperties_.getUserSettings()->containsKey("StartupPreset")) + return false; + if(applicationProperties_.getUserSettings()->getValue("StartupPreset") == "__vib_pb__") + return true; + return false; +} + +void MainApplicationController::setPrefsStartupPresetLastSaved() { + applicationProperties_.getUserSettings()->setValue("StartupPreset", "__last__"); +} +bool MainApplicationController::getPrefsStartupPresetLastSaved() { + if(!applicationProperties_.getUserSettings()->containsKey("StartupPreset")) + return false; + if(applicationProperties_.getUserSettings()->getValue("StartupPreset") == "__last__") + return true; + return false; +} + +void MainApplicationController::setPrefsStartupPreset(String const& path) { + applicationProperties_.getUserSettings()->setValue("StartupPreset", path); +} +String MainApplicationController::getPrefsStartupPreset() { + if(!applicationProperties_.getUserSettings()->containsKey("StartupPreset")) + return ""; + return applicationProperties_.getUserSettings()->getValue("StartupPreset"); +} + +// Reset application preferences to defaults +void MainApplicationController::resetPreferences() { + // TODO: reset settings now, not after restart + applicationProperties_.getUserSettings()->clear(); + + setPrefsStartupPresetVibratoPitchBend(); + setPrefsAutodetectOctave(true); +} + +// Load the current devices from a global preferences file +void MainApplicationController::loadApplicationPreferences(){ + PropertiesFile *props = applicationProperties_.getUserSettings(); + + if(props == 0) + return; + + // A few first-time defaults if the properties file is missing + if(props->getAllProperties().size() == 0) { + resetPreferences(); + } + + // Load TouchKeys settings + if(props->containsKey("TouchKeysDevice")) { + // TODO + } + if(props->containsKey("TouchKeysLowestMIDINote")) { + int note = props->getIntValue("TouchKeysLowestMIDINote"); + if(note >= 0 && note <= 127) + touchkeyDeviceSetLowestMidiNote(note); + } + + // Load MIDI input settings + if(props->containsKey("MIDIInputPrimary")) { + String deviceName = props->getValue("MIDIInputPrimary"); + if(deviceName == "__standalone__") { + midiTouchkeysStandaloneModeEnable(); + } + else { + int index = midiInputController_.indexOfDeviceNamed(deviceName); + // cout << "primary input id " << index << " name " << deviceName << endl; + if(index >= 0) + enableMIDIInputPort(index, true); + } + } + if(props->containsKey("MIDIInputAuxiliary")) { + String deviceName = props->getValue("MIDIInputAuxiliary"); + int index = midiInputController_.indexOfDeviceNamed(deviceName); + // cout << "aux input id " << index << " name " << deviceName << endl; + if(index >= 0) + enableMIDIInputPort(index, false); + } + + // MIDI output settings are loaded when segments are created + + // OSC settings + if(props->containsKey("OSCTransmitEnabled")) { + bool enable = props->getBoolValue("OSCTransmitEnabled"); + oscTransmitSetEnabled(enable); + } + if(props->containsKey("OSCTransmitRawDataEnabled")) { + bool enable = props->getBoolValue("OSCTransmitRawDataEnabled"); + oscTransmitSetRawDataEnabled(enable); + } + + for(int i = 0; i < 16; i++) { + String keyName = "OSCTransmitHost"; + String host, port; + int protocol = LO_UDP; + + keyName += i; + if(props->containsKey(keyName)) { + host = props->getValue(keyName); + } + else + continue; + + keyName = "OSCTransmitPort"; + keyName += i; + if(props->containsKey(keyName)) { + port = props->getValue(keyName); + } + else + continue; + + keyName = "OSCTransmitProtocol"; + keyName += i; + if(props->containsKey(keyName)) { + protocol = props->getIntValue(keyName); + } + // okay to go ahead without protocol; use default + + // Check for validity + if(host != "" && port != "" && (protocol == LO_UDP || protocol == LO_TCP)) { + oscTransmitter_.addAddress(host.toUTF8(), port.toUTF8(), protocol); + } + } + + if(props->containsKey("OSCReceiveEnabled")) { + bool enable = props->getBoolValue("OSCReceiveEnabled"); + oscReceiveSetEnabled(enable); + } + if(props->containsKey("OSCReceivePort")) { + int port = props->getIntValue("OSCReceivePort"); + if(port >= 1 && port <= 65535) + oscReceiveSetPort(port); + } + +} + +// Load the MIDI output device for a given zone +void MainApplicationController::loadMIDIOutputFromApplicationPreferences(int zone) { + PropertiesFile *props = applicationProperties_.getUserSettings(); + + String keyName = "MIDIOutputZone"; + keyName += zone; + + if(props->containsKey(keyName)) { + String output = props->getValue(keyName); + if(output.startsWith("__virtual__")) { +#ifndef JUCE_WINDOWS + // Open virtual port with the name that follows + String virtualPortName = output.substring(11); // length of "__virtual__" + midiOutputController_.enableVirtualPort(zone, virtualPortName.toUTF8()); +#endif + } + else { + String deviceName = props->getValue(keyName); + int index = midiOutputController_.indexOfDeviceNamed(deviceName); + // cout << "zone " << zone << " id " << index << " name " << deviceName << endl; + if(index >= 0) + enableMIDIOutputPort(zone, index); + } + } +} + #ifdef ENABLE_TOUCHKEYS_SENSOR_TEST // Start testing the TouchKeys sensors. Returns true on success. bool MainApplicationController::touchkeySensorTestStart(const char *path, int firstKey) {
--- a/Source/MainApplicationController.h Fri Mar 21 23:13:19 2014 +0000 +++ b/Source/MainApplicationController.h Sat Jun 21 23:32:33 2014 +0100 @@ -54,6 +54,7 @@ #ifndef TOUCHKEYS_NO_GUI #include "GUI/GraphicsDisplayWindow.h" +#include "GUI/PReferencesWindow.h" class KeyboardTesterDisplay; #endif @@ -72,6 +73,9 @@ // *** Destructor *** ~MainApplicationController(); + // *** Startup actions *** + void initialise(); + // *** TouchKeys device methods *** // Return the path prefix of the TouchKeys device @@ -84,58 +88,45 @@ // start data collection, all in one method. Returns true if successful. // Will set the error message string if not bool touchkeyDeviceStartupSequence(const char * path); - void touchkeyDeviceClearErrorMessage() { - touchkeyErrorMessage_ = ""; - touchkeyErrorOccurred_ = false; - } + void touchkeyDeviceClearErrorMessage(); + + // Check whether a given touchkey device exists + bool touchkeyDeviceExists(const char * path); // Select a particular touchkey device - bool openTouchkeyDevice(const char * path) { - return touchkeyController_.openDevice(path); - } + bool openTouchkeyDevice(const char * path); + void closeTouchkeyDevice(); // Check for device present bool touchkeyDeviceCheckForPresence(int waitMilliseconds = 250, int tries = 10); // Start/stop the TouchKeys data collection - bool startTouchkeyDevice() { - return touchkeyController_.startAutoGathering(); - } - void stopTouchkeyDevice() { - touchkeyController_.stopAutoGathering(); - } + bool startTouchkeyDevice(); + void stopTouchkeyDevice(); // Status queries on TouchKeys // Returns true if device has been opened - bool touchkeyDeviceIsOpen() { - return touchkeyController_.isOpen(); - } + bool touchkeyDeviceIsOpen(); + // Return true if device is collecting data bool touchkeyDeviceIsRunning(); // Returns true if an error has occurred - bool touchkeyDeviceErrorOccurred() { - return touchkeyErrorOccurred_; - } + bool touchkeyDeviceErrorOccurred(); + // Return the error message if one occurred - std::string touchkeyDeviceErrorMessage() { - return touchkeyErrorMessage_; - } + std::string touchkeyDeviceErrorMessage(); + // How many octaves on the current device - int touchkeyDeviceNumberOfOctaves() { - return touchkeyController_.numberOfOctaves(); - } + int touchkeyDeviceNumberOfOctaves(); + // Return the lowest MIDI note - int touchkeyDeviceLowestMidiNote() { - return touchkeyController_.lowestMidiNote(); - } + int touchkeyDeviceLowestMidiNote(); + // Set the lowest MIDI note for the TouchKeys - void touchkeyDeviceSetLowestMidiNote(int note) { - keyboardDisplay_.clearAllTouches(); - touchkeyEmulator_.setLowestMidiNote(note); - touchkeyController_.setLowestMidiNote(note); - } + void touchkeyDeviceSetLowestMidiNote(int note); + // Attempt to autodetect the correct TouchKey octave from MIDI data void touchkeyDeviceAutodetectLowestMidiNote(); void touchkeyDeviceStopAutodetecting(); @@ -172,35 +163,17 @@ void midiSegmentRemove(MidiKeyboardSegment *segment); // Select MIDI input/output devices - void enableMIDIInputPort(int portNumber, bool isPrimary) { - midiInputController_.enablePort(portNumber, isPrimary); - } - void enableAllMIDIInputPorts(int primaryPortNumber) { - midiInputController_.enableAllPorts(primaryPortNumber); - } - void disableMIDIInputPort(int portNumber) { - midiInputController_.disablePort(portNumber); - } - void disablePrimaryMIDIInputPort() { - midiInputController_.disablePrimaryPort(); - } - void disableAllMIDIInputPorts(bool auxiliaryOnly) { - midiInputController_.disableAllPorts(auxiliaryOnly); - } - void enableMIDIOutputPort(int identifier, int deviceNumber) { - midiOutputController_.enablePort(identifier, deviceNumber); - } + void enableMIDIInputPort(int portNumber, bool isPrimary); + void enableAllMIDIInputPorts(int primaryPortNumber); + void disableMIDIInputPort(int portNumber); + void disablePrimaryMIDIInputPort(); + void disableAllMIDIInputPorts(bool auxiliaryOnly); + void enableMIDIOutputPort(int identifier, int deviceNumber); #ifndef JUCE_WINDOWS - void enableMIDIOutputVirtualPort(int identifier, const char *name) { - midiOutputController_.enableVirtualPort(identifier, name); - } + void enableMIDIOutputVirtualPort(int identifier, const char *name); #endif - void disableMIDIOutputPort(int identifier) { - midiOutputController_.disablePort(identifier); - } - void disableAllMIDIOutputPorts() { - midiOutputController_.disableAllPorts(); - } + void disableMIDIOutputPort(int identifier); + void disableAllMIDIOutputPorts(); // Get selected MIDI input/output devices by ID int selectedMIDIPrimaryInputPort() { @@ -226,64 +199,31 @@ // *** OSC device methods *** - bool oscTransmitEnabled() { - return oscTransmitter_.enabled(); - } - void oscTransmitSetEnabled(bool enable) { - oscTransmitter_.setEnabled(enable); - } - bool oscTransmitRawDataEnabled() { - return touchkeyController_.transmitRawDataEnabled(); - } - void oscTransmitSetRawDataEnabled(bool enable) { - touchkeyController_.setTransmitRawData(enable); - } - std::vector<lo_address> oscTransmitAddresses() { - return oscTransmitter_.addresses(); - } - int oscTransmitAddAddress(const char * host, const char * port, int proto = LO_UDP) { - return oscTransmitter_.addAddress(host, port, proto); - } - void oscTransmitRemoveAddress(int index) { - return oscTransmitter_.removeAddress(index); - } - void oscTransmitClearAddresses() { - return oscTransmitter_.clearAddresses(); - } + bool oscTransmitEnabled(); + void oscTransmitSetEnabled(bool enable); + bool oscTransmitRawDataEnabled(); + void oscTransmitSetRawDataEnabled(bool enable); + std::vector<lo_address> oscTransmitAddresses(); + int oscTransmitAddAddress(const char * host, const char * port, int proto = LO_UDP); + void oscTransmitRemoveAddress(int index); + void oscTransmitClearAddresses(); // OSC Input (receiver) methods // Enable or disable on the OSC receive, and report is status - bool oscReceiveEnabled() { - return oscReceiveEnabled_; - } + bool oscReceiveEnabled(); + // Enable method returns true on success (false only if it was // unable to set the port) - bool oscReceiveSetEnabled(bool enable) { - if(enable && !oscReceiveEnabled_) { - oscReceiveEnabled_ = true; - return oscReceiver_.setPort(oscReceivePort_); - } - else if(!enable && oscReceiveEnabled_) { - oscReceiveEnabled_ = false; - return oscReceiver_.setPort(0); - } - return true; - } + bool oscReceiveSetEnabled(bool enable); // Whether the OSC server is running (false means couldn't open port) - bool oscReceiveRunning() { - return oscReceiver_.running(); - } + bool oscReceiveRunning(); + // Get the current OSC receive port - int oscReceivePort() { - return oscReceivePort_; - } + int oscReceivePort(); + // Set the current OSC receive port (returns true on success) - bool oscReceiveSetPort(int port) { - oscReceivePort_ = port; - return oscReceiver_.setPort(port); - } - + bool oscReceiveSetPort(int port); // *** Display methods *** @@ -296,6 +236,13 @@ keyboardDisplayWindow_->toFront(true); } } + void setPreferencesWindow(PreferencesWindow *window) { preferencesWindow_ = window; } + void showPreferencesWindow() { + if(preferencesWindow_ != 0) { + preferencesWindow_->setVisible(true); + preferencesWindow_->toFront(true); + } + } #endif // *** Logging methods *** @@ -311,7 +258,6 @@ bool oscHandlerMethod(const char *path, const char *types, int numValues, lo_arg **values, void *data); - // *** Mapping methods *** // Return the number of mapping factory types available int numberOfMappingFactories(); @@ -344,6 +290,38 @@ // Clears the current preset and restores default settings to zones/mappings void clearPreset(); + // *** Preferences *** + + // Whether to automatically start the TouchKeys on startup + bool getPrefsAutoStartTouchKeys(); + void setPrefsAutoStartTouchKeys(bool autoStart); + + // Whether to automatically detect the TouchKeys octave when they start + bool getPrefsAutodetectOctave(); + void setPrefsAutodetectOctave(bool autoDetect); + + // Which preset (if any) to load at startup + void setPrefsStartupPresetNone(); + bool getPrefsStartupPresetNone(); + + void setPrefsStartupPresetLastSaved(); + bool getPrefsStartupPresetLastSaved(); + + void setPrefsStartupPresetVibratoPitchBend(); + bool getPrefsStartupPresetVibratoPitchBend(); + + void setPrefsStartupPreset(String const& path); + String getPrefsStartupPreset(); + + // Reset all preferences + void resetPreferences(); + + // Load global preferences from file + void loadApplicationPreferences(); + + // Load a MIDI output device from preexisting application preferences + void loadMIDIOutputFromApplicationPreferences(int zone); + #ifdef ENABLE_TOUCHKEYS_SENSOR_TEST // *** TouchKeys sensor testing methods *** // Start testing the TouchKeys sensors @@ -370,6 +348,9 @@ bool savePresetHelper(File& outputFile); bool loadPresetHelper(File const& inputFile); + // Application properties: for managing preferences + ApplicationProperties applicationProperties_; + // TouchKeys objects PianoKeyboard keyboardController_; MidiInputController midiInputController_; @@ -403,6 +384,7 @@ DocumentWindow *keyboardDisplayWindow_; KeyboardTesterDisplay *keyboardTesterDisplay_; GraphicsDisplayWindow *keyboardTesterWindow_; + PreferencesWindow *preferencesWindow_; #endif // Segment info
--- a/Source/Mappings/Control/TouchkeyControlMapping.cpp Fri Mar 21 23:13:19 2014 +0000 +++ b/Source/Mappings/Control/TouchkeyControlMapping.cpp Sat Jun 21 23:32:33 2014 +0100 @@ -366,12 +366,12 @@ if(latestValue > 0) latestValue = 0; } + + if(direction_ == kDirectionNegative) + latestValue = -latestValue; + else if((direction_ == kDirectionBoth) && latestValue < 0) + latestValue = -latestValue; } - - if(direction_ == kDirectionNegative) - latestValue = -latestValue; - else if((direction_ == kDirectionBoth) && latestValue < 0) - latestValue = -latestValue; sendControlMessage(latestValue); lastControlValue_ = latestValue;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Source/Mappings/Control/TouchkeyControlMappingExtendedEditor.cpp Sat Jun 21 23:32:33 2014 +0100 @@ -0,0 +1,751 @@ +/* + ============================================================================== + + This is an automatically generated GUI class created by the Introjucer! + + Be careful when adding custom code to these files, as only the code within + the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded + and re-saved. + + Created with Introjucer version: 3.1.0 + + ------------------------------------------------------------------------------ + + The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-13 by Raw Material Software Ltd. + + ============================================================================== +*/ + +//[Headers] You can add your own extra header files here... +//[/Headers] + +#include "TouchkeyControlMappingExtendedEditor.h" + + +//[MiscUserDefs] You can add your own user definitions and misc code here... +//[/MiscUserDefs] + +//============================================================================== +TouchkeyControlMappingExtendedEditor::TouchkeyControlMappingExtendedEditor (TouchkeyControlMappingFactory& factory) + : factory_(factory) +{ + addAndMakeVisible (inputRangeLowEditor = new TextEditor ("range low text editor")); + inputRangeLowEditor->setMultiLine (false); + inputRangeLowEditor->setReturnKeyStartsNewLine (false); + inputRangeLowEditor->setReadOnly (false); + inputRangeLowEditor->setScrollbarsShown (true); + inputRangeLowEditor->setCaretVisible (true); + inputRangeLowEditor->setPopupMenuEnabled (true); + inputRangeLowEditor->setText (String::empty); + + addAndMakeVisible (rangeLabel = new Label ("range label", + "Input Range:")); + rangeLabel->setFont (Font (15.00f, Font::plain)); + rangeLabel->setJustificationType (Justification::centredLeft); + rangeLabel->setEditable (false, false, false); + rangeLabel->setColour (TextEditor::textColourId, Colours::black); + rangeLabel->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); + + addAndMakeVisible (controlLabel = new Label ("control label", + "To Control:")); + controlLabel->setFont (Font (15.00f, Font::plain)); + controlLabel->setJustificationType (Justification::centredRight); + controlLabel->setEditable (false, false, false); + controlLabel->setColour (TextEditor::textColourId, Colours::black); + controlLabel->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); + + addAndMakeVisible (controlComboBox = new ComboBox ("control combo box")); + controlComboBox->setEditableText (false); + controlComboBox->setJustificationType (Justification::centredLeft); + controlComboBox->setTextWhenNothingSelected (String::empty); + controlComboBox->setTextWhenNoChoicesAvailable ("(no choices)"); + controlComboBox->addListener (this); + + addAndMakeVisible (controlLabel2 = new Label ("control label", + "Parameter:")); + controlLabel2->setFont (Font (15.00f, Font::plain)); + controlLabel2->setJustificationType (Justification::centredLeft); + controlLabel2->setEditable (false, false, false); + controlLabel2->setColour (TextEditor::textColourId, Colours::black); + controlLabel2->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); + + addAndMakeVisible (parameterComboBox = new ComboBox ("parameter combo box")); + parameterComboBox->setEditableText (false); + parameterComboBox->setJustificationType (Justification::centredLeft); + parameterComboBox->setTextWhenNothingSelected (String::empty); + parameterComboBox->setTextWhenNoChoicesAvailable ("(no choices)"); + parameterComboBox->addListener (this); + + addAndMakeVisible (controlLabel3 = new Label ("control label", + "Type:")); + controlLabel3->setFont (Font (15.00f, Font::plain)); + controlLabel3->setJustificationType (Justification::centredRight); + controlLabel3->setEditable (false, false, false); + controlLabel3->setColour (TextEditor::textColourId, Colours::black); + controlLabel3->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); + + addAndMakeVisible (typeComboBox = new ComboBox ("type combo box")); + typeComboBox->setEditableText (false); + typeComboBox->setJustificationType (Justification::centredLeft); + typeComboBox->setTextWhenNothingSelected (String::empty); + typeComboBox->setTextWhenNoChoicesAvailable ("(no choices)"); + typeComboBox->addListener (this); + + addAndMakeVisible (inputRangeHighEditor = new TextEditor ("range hi text editor")); + inputRangeHighEditor->setMultiLine (false); + inputRangeHighEditor->setReturnKeyStartsNewLine (false); + inputRangeHighEditor->setReadOnly (false); + inputRangeHighEditor->setScrollbarsShown (true); + inputRangeHighEditor->setCaretVisible (true); + inputRangeHighEditor->setPopupMenuEnabled (true); + inputRangeHighEditor->setText (String::empty); + + addAndMakeVisible (rangeLabel2 = new Label ("range label", + "-")); + rangeLabel2->setFont (Font (15.00f, Font::plain)); + rangeLabel2->setJustificationType (Justification::centredLeft); + rangeLabel2->setEditable (false, false, false); + rangeLabel2->setColour (TextEditor::textColourId, Colours::black); + rangeLabel2->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); + + addAndMakeVisible (rangeLabel3 = new Label ("range label", + "Output Range:")); + rangeLabel3->setFont (Font (15.00f, Font::plain)); + rangeLabel3->setJustificationType (Justification::centredLeft); + rangeLabel3->setEditable (false, false, false); + rangeLabel3->setColour (TextEditor::textColourId, Colours::black); + rangeLabel3->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); + + addAndMakeVisible (outputRangeLowEditor = new TextEditor ("output range low text editor")); + outputRangeLowEditor->setMultiLine (false); + outputRangeLowEditor->setReturnKeyStartsNewLine (false); + outputRangeLowEditor->setReadOnly (false); + outputRangeLowEditor->setScrollbarsShown (true); + outputRangeLowEditor->setCaretVisible (true); + outputRangeLowEditor->setPopupMenuEnabled (true); + outputRangeLowEditor->setText (String::empty); + + addAndMakeVisible (outputRangeHighEditor = new TextEditor ("output range hi text editor")); + outputRangeHighEditor->setMultiLine (false); + outputRangeHighEditor->setReturnKeyStartsNewLine (false); + outputRangeHighEditor->setReadOnly (false); + outputRangeHighEditor->setScrollbarsShown (true); + outputRangeHighEditor->setCaretVisible (true); + outputRangeHighEditor->setPopupMenuEnabled (true); + outputRangeHighEditor->setText (String::empty); + + addAndMakeVisible (rangeLabel4 = new Label ("range label", + "-")); + rangeLabel4->setFont (Font (15.00f, Font::plain)); + rangeLabel4->setJustificationType (Justification::centredLeft); + rangeLabel4->setEditable (false, false, false); + rangeLabel4->setColour (TextEditor::textColourId, Colours::black); + rangeLabel4->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); + + addAndMakeVisible (controlLabel4 = new Label ("control label", + "Direction:")); + controlLabel4->setFont (Font (15.00f, Font::plain)); + controlLabel4->setJustificationType (Justification::centredRight); + controlLabel4->setEditable (false, false, false); + controlLabel4->setColour (TextEditor::textColourId, Colours::black); + controlLabel4->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); + + addAndMakeVisible (directionComboBox = new ComboBox ("direction combo box")); + directionComboBox->setEditableText (false); + directionComboBox->setJustificationType (Justification::centredLeft); + directionComboBox->setTextWhenNothingSelected (String::empty); + directionComboBox->setTextWhenNoChoicesAvailable ("(no choices)"); + directionComboBox->addListener (this); + + addAndMakeVisible (titleLabel = new Label ("title label", + "Control Mapping (Zone N, #M)")); + titleLabel->setFont (Font (15.00f, Font::bold)); + titleLabel->setJustificationType (Justification::centredLeft); + titleLabel->setEditable (false, false, false); + titleLabel->setColour (TextEditor::textColourId, Colours::black); + titleLabel->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); + + addAndMakeVisible (rangeLabel5 = new Label ("range label", + "Threshold:")); + rangeLabel5->setFont (Font (15.00f, Font::plain)); + rangeLabel5->setJustificationType (Justification::centredLeft); + rangeLabel5->setEditable (false, false, false); + rangeLabel5->setColour (TextEditor::textColourId, Colours::black); + rangeLabel5->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); + + addAndMakeVisible (thresholdEditor = new TextEditor ("threshold text editor")); + thresholdEditor->setMultiLine (false); + thresholdEditor->setReturnKeyStartsNewLine (false); + thresholdEditor->setReadOnly (false); + thresholdEditor->setScrollbarsShown (true); + thresholdEditor->setCaretVisible (true); + thresholdEditor->setPopupMenuEnabled (true); + thresholdEditor->setText (String::empty); + + addAndMakeVisible (cc14BitButton = new ToggleButton ("new toggle button")); + cc14BitButton->setButtonText ("Use 14-bit CC"); + cc14BitButton->addListener (this); + + addAndMakeVisible (ignore2FingersButton = new ToggleButton ("ignore 2 fingers toggle button")); + ignore2FingersButton->setButtonText ("Ignore 2 Fingers"); + ignore2FingersButton->addListener (this); + + addAndMakeVisible (ignore3FingersButton = new ToggleButton ("ignore 3 fingers toggle button")); + ignore3FingersButton->setButtonText ("Ignore 3 Fingers"); + ignore3FingersButton->addListener (this); + + addAndMakeVisible (controlLabel6 = new Label ("control label", + "Out of Range:")); + controlLabel6->setFont (Font (15.00f, Font::plain)); + controlLabel6->setJustificationType (Justification::centredRight); + controlLabel6->setEditable (false, false, false); + controlLabel6->setColour (TextEditor::textColourId, Colours::black); + controlLabel6->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); + + addAndMakeVisible (outOfRangeComboBox = new ComboBox ("out of range combo box")); + outOfRangeComboBox->setEditableText (false); + outOfRangeComboBox->setJustificationType (Justification::centredLeft); + outOfRangeComboBox->setTextWhenNothingSelected (String::empty); + outOfRangeComboBox->setTextWhenNoChoicesAvailable ("(no choices)"); + outOfRangeComboBox->addListener (this); + + addAndMakeVisible (rangeLabel6 = new Label ("range label", + "Default Output:")); + rangeLabel6->setFont (Font (15.00f, Font::plain)); + rangeLabel6->setJustificationType (Justification::centredLeft); + rangeLabel6->setEditable (false, false, false); + rangeLabel6->setColour (TextEditor::textColourId, Colours::black); + rangeLabel6->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); + + addAndMakeVisible (outputDefaultEditor = new TextEditor ("output default text editor")); + outputDefaultEditor->setMultiLine (false); + outputDefaultEditor->setReturnKeyStartsNewLine (false); + outputDefaultEditor->setReadOnly (false); + outputDefaultEditor->setScrollbarsShown (true); + outputDefaultEditor->setCaretVisible (true); + outputDefaultEditor->setPopupMenuEnabled (true); + outputDefaultEditor->setText (String::empty); + + + //[UserPreSize] + parameterComboBox->addItem("X Position", TouchkeyControlMapping::kInputParameterXPosition); + parameterComboBox->addItem("Y Position", TouchkeyControlMapping::kInputParameterYPosition); + parameterComboBox->addItem("Contact Area", TouchkeyControlMapping::kInputParameterTouchSize); + parameterComboBox->addItem("2-Finger Mean", TouchkeyControlMapping::kInputParameter2FingerMean); + parameterComboBox->addItem("2-Finger Distance", TouchkeyControlMapping::kInputParameter2FingerDistance); + + typeComboBox->addItem("Absolute", TouchkeyControlMapping::kTypeAbsolute); + typeComboBox->addItem("1st Touch Relative", TouchkeyControlMapping::kTypeFirstTouchRelative); + typeComboBox->addItem("Note Onset Relative", TouchkeyControlMapping::kTypeNoteOnsetRelative); + + controlComboBox->addItem("Pitch Wheel", MidiKeyboardSegment::kControlPitchWheel); + controlComboBox->addItem("Channel Pressure", MidiKeyboardSegment::kControlChannelAftertouch); + controlComboBox->addItem("Poly Aftertouch", MidiKeyboardSegment::kControlPolyphonicAftertouch); + for(int i = 1; i <= 119; i++) { + controlComboBox->addItem(String(i), i); + } + + directionComboBox->addItem("Normal", TouchkeyControlMapping::kDirectionPositive); + directionComboBox->addItem("Reverse", TouchkeyControlMapping::kDirectionNegative); + directionComboBox->addItem("Always Positive", TouchkeyControlMapping::kDirectionBoth); + + outOfRangeComboBox->addItem("Ignore", OscMidiConverter::kOutOfRangeIgnore); + outOfRangeComboBox->addItem("Clip", OscMidiConverter::kOutOfRangeClip); + outOfRangeComboBox->addItem("Extrapolate", OscMidiConverter::kOutOfRangeExtrapolate); + //[/UserPreSize] + + setSize (448, 248); + + + //[Constructor] You can add your own custom stuff here.. + inputRangeLowEditor->addListener(this); + inputRangeHighEditor->addListener(this); + outputRangeLowEditor->addListener(this); + outputRangeHighEditor->addListener(this); + outputDefaultEditor->addListener(this); + thresholdEditor->addListener(this); + //[/Constructor] +} + +TouchkeyControlMappingExtendedEditor::~TouchkeyControlMappingExtendedEditor() +{ + //[Destructor_pre]. You can add your own custom destruction code here.. + //[/Destructor_pre] + + inputRangeLowEditor = nullptr; + rangeLabel = nullptr; + controlLabel = nullptr; + controlComboBox = nullptr; + controlLabel2 = nullptr; + parameterComboBox = nullptr; + controlLabel3 = nullptr; + typeComboBox = nullptr; + inputRangeHighEditor = nullptr; + rangeLabel2 = nullptr; + rangeLabel3 = nullptr; + outputRangeLowEditor = nullptr; + outputRangeHighEditor = nullptr; + rangeLabel4 = nullptr; + controlLabel4 = nullptr; + directionComboBox = nullptr; + titleLabel = nullptr; + rangeLabel5 = nullptr; + thresholdEditor = nullptr; + cc14BitButton = nullptr; + ignore2FingersButton = nullptr; + ignore3FingersButton = nullptr; + controlLabel6 = nullptr; + outOfRangeComboBox = nullptr; + rangeLabel6 = nullptr; + outputDefaultEditor = nullptr; + + + //[Destructor]. You can add your own custom destruction code here.. + //[/Destructor] +} + +//============================================================================== +void TouchkeyControlMappingExtendedEditor::paint (Graphics& g) +{ + //[UserPrePaint] Add your own custom painting code here.. + //[/UserPrePaint] + + g.fillAll (Colour (0xffd2d2d2)); + + //[UserPaint] Add your own custom painting code here.. + //[/UserPaint] +} + +void TouchkeyControlMappingExtendedEditor::resized() +{ + inputRangeLowEditor->setBounds (112, 72, 56, 24); + rangeLabel->setBounds (8, 72, 104, 24); + controlLabel->setBounds (256, 40, 64, 24); + controlComboBox->setBounds (320, 40, 112, 24); + controlLabel2->setBounds (8, 40, 72, 24); + parameterComboBox->setBounds (80, 40, 160, 24); + controlLabel3->setBounds (264, 104, 56, 24); + typeComboBox->setBounds (320, 104, 112, 24); + inputRangeHighEditor->setBounds (184, 72, 56, 24); + rangeLabel2->setBounds (168, 72, 16, 24); + rangeLabel3->setBounds (8, 104, 96, 24); + outputRangeLowEditor->setBounds (112, 104, 56, 24); + outputRangeHighEditor->setBounds (184, 104, 56, 24); + rangeLabel4->setBounds (168, 104, 16, 24); + controlLabel4->setBounds (248, 136, 72, 24); + directionComboBox->setBounds (320, 136, 112, 24); + titleLabel->setBounds (8, 8, 424, 24); + rangeLabel5->setBounds (8, 168, 72, 24); + thresholdEditor->setBounds (112, 168, 56, 24); + cc14BitButton->setBounds (320, 72, 112, 24); + ignore2FingersButton->setBounds (8, 192, 128, 24); + ignore3FingersButton->setBounds (8, 216, 128, 24); + controlLabel6->setBounds (216, 168, 104, 24); + outOfRangeComboBox->setBounds (320, 168, 112, 24); + rangeLabel6->setBounds (8, 136, 96, 24); + outputDefaultEditor->setBounds (112, 136, 56, 24); + //[UserResized] Add your own custom resize handling here.. + //[/UserResized] +} + +void TouchkeyControlMappingExtendedEditor::comboBoxChanged (ComboBox* comboBoxThatHasChanged) +{ + //[UsercomboBoxChanged_Pre] + //[/UsercomboBoxChanged_Pre] + + if (comboBoxThatHasChanged == controlComboBox) + { + //[UserComboBoxCode_controlComboBox] -- add your combo box handling code here.. + int controller = controlComboBox->getSelectedId(); + factory_.setController(controller); + //[/UserComboBoxCode_controlComboBox] + } + else if (comboBoxThatHasChanged == parameterComboBox) + { + //[UserComboBoxCode_parameterComboBox] -- add your combo box handling code here.. + int param = parameterComboBox->getSelectedId(); + factory_.setInputParameter(param); + //[/UserComboBoxCode_parameterComboBox] + } + else if (comboBoxThatHasChanged == typeComboBox) + { + //[UserComboBoxCode_typeComboBox] -- add your combo box handling code here.. + int type = typeComboBox->getSelectedId(); + factory_.setInputType(type); + //[/UserComboBoxCode_typeComboBox] + } + else if (comboBoxThatHasChanged == directionComboBox) + { + //[UserComboBoxCode_directionComboBox] -- add your combo box handling code here.. + int direction = directionComboBox->getSelectedId(); + factory_.setDirection(direction); + //[/UserComboBoxCode_directionComboBox] + } + else if (comboBoxThatHasChanged == outOfRangeComboBox) + { + //[UserComboBoxCode_outOfRangeComboBox] -- add your combo box handling code here.. + int behavior = outOfRangeComboBox->getSelectedId(); + factory_.setOutOfRangeBehavior(behavior); + //[/UserComboBoxCode_outOfRangeComboBox] + } + + //[UsercomboBoxChanged_Post] + //[/UsercomboBoxChanged_Post] +} + +void TouchkeyControlMappingExtendedEditor::buttonClicked (Button* buttonThatWasClicked) +{ + //[UserbuttonClicked_Pre] + //[/UserbuttonClicked_Pre] + + if (buttonThatWasClicked == cc14BitButton) + { + //[UserButtonCode_cc14BitButton] -- add your button handler code here.. + factory_.setUses14BitControl(cc14BitButton->getToggleState()); + //[/UserButtonCode_cc14BitButton] + } + else if (buttonThatWasClicked == ignore2FingersButton) + { + //[UserButtonCode_ignore2FingersButton] -- add your button handler code here.. + factory_.setIgnoresTwoFingers(ignore2FingersButton->getToggleState()); + //[/UserButtonCode_ignore2FingersButton] + } + else if (buttonThatWasClicked == ignore3FingersButton) + { + //[UserButtonCode_ignore3FingersButton] -- add your button handler code here.. + factory_.setIgnoresThreeFingers(ignore3FingersButton->getToggleState()); + //[/UserButtonCode_ignore3FingersButton] + } + + //[UserbuttonClicked_Post] + //[/UserbuttonClicked_Post] +} + + + +//[MiscUserCode] You can add your own definitions of your custom methods or any other code here... + +void TouchkeyControlMappingExtendedEditor::textEditorReturnKeyPressed(TextEditor &editor) +{ + if(&editor == inputRangeLowEditor) { + float range = atof(inputRangeLowEditor->getText().toUTF8()); + factory_.setRangeInputMin(range); + factory_.setRangeInputCenter(range); + } + else if(&editor == inputRangeHighEditor) { + float range = atof(inputRangeHighEditor->getText().toUTF8()); + factory_.setRangeInputMax(range); + } + else if(&editor == outputRangeLowEditor) { + float range = atof(outputRangeLowEditor->getText().toUTF8()); + factory_.setRangeOutputMin(range); + } + else if(&editor == outputRangeHighEditor) { + float range = atof(outputRangeHighEditor->getText().toUTF8()); + factory_.setRangeOutputMax(range); + } + else if(&editor == outputDefaultEditor) { + float range = atof(outputDefaultEditor->getText().toUTF8()); + factory_.setRangeOutputDefault(range); + } + else if(&editor == thresholdEditor) { + float thresh = atof(thresholdEditor->getText().toUTF8()); + factory_.setThreshold(thresh); + } +} + +void TouchkeyControlMappingExtendedEditor::textEditorEscapeKeyPressed(TextEditor &editor) +{ + +} + +void TouchkeyControlMappingExtendedEditor::textEditorFocusLost(TextEditor &editor) +{ + textEditorReturnKeyPressed(editor); +} + +void TouchkeyControlMappingExtendedEditor::synchronize() +{ + // Set the title label + titleLabel->setText(getDescriptionHelper("Control Mapping"), dontSendNotification); + + // Update the editors to reflect the current status + if(!inputRangeLowEditor->hasKeyboardFocus(true)) { + float value = factory_.getRangeInputMin(); + char st[16]; +#ifdef _MSC_VER + _snprintf_s(st, 16, _TRUNCATE, "%.2f", value); +#else + snprintf(st, 16, "%.2f", value); +#endif + inputRangeLowEditor->setText(st); + } + + if(!inputRangeHighEditor->hasKeyboardFocus(true)) { + float value = factory_.getRangeInputMax(); + char st[16]; +#ifdef _MSC_VER + _snprintf_s(st, 16, _TRUNCATE, "%.2f", value); +#else + snprintf(st, 16, "%.2f", value); +#endif + + inputRangeHighEditor->setText(st); + } + + if(!outputRangeLowEditor->hasKeyboardFocus(true)) { + float value = factory_.getRangeOutputMin(); + char st[16]; +#ifdef _MSC_VER + _snprintf_s(st, 16, _TRUNCATE, "%.2f", value); +#else + snprintf(st, 16, "%.2f", value); +#endif + + outputRangeLowEditor->setText(st); + } + + if(!outputRangeHighEditor->hasKeyboardFocus(true)) { + float value = factory_.getRangeOutputMax(); + char st[16]; +#ifdef _MSC_VER + _snprintf_s(st, 16, _TRUNCATE, "%.2f", value); +#else + snprintf(st, 16, "%.2f", value); +#endif + + outputRangeHighEditor->setText(st); + } + + if(!outputDefaultEditor->hasKeyboardFocus(true)) { + float value = factory_.getRangeOutputDefault(); + char st[16]; +#ifdef _MSC_VER + _snprintf_s(st, 16, _TRUNCATE, "%.2f", value); +#else + snprintf(st, 16, "%.2f", value); +#endif + + outputDefaultEditor->setText(st); + } + + if(factory_.getInputType() == TouchkeyControlMapping::kTypeFirstTouchRelative + || factory_.getInputType() == TouchkeyControlMapping::kTypeNoteOnsetRelative) { + thresholdEditor->setEnabled(true); + if(!thresholdEditor->hasKeyboardFocus(true)) { + float value = factory_.getThreshold(); + char st[16]; +#ifdef _MSC_VER + _snprintf_s(st, 16, _TRUNCATE, "%.2f", value); +#else + snprintf(st, 16, "%.2f", value); +#endif + + thresholdEditor->setText(st); + } + + if(typeWasAbsolute_) { + // Add all three direction items + directionComboBox->clear(); + directionComboBox->addItem("Normal", TouchkeyControlMapping::kDirectionPositive); + directionComboBox->addItem("Reverse", TouchkeyControlMapping::kDirectionNegative); + directionComboBox->addItem("Always Positive", TouchkeyControlMapping::kDirectionBoth); + } + + typeWasAbsolute_ = false; + } + else { + thresholdEditor->setEnabled(false); + thresholdEditor->setText("", false); + + if(!typeWasAbsolute_) { + // Add only one direction item + directionComboBox->clear(); + directionComboBox->addItem("Normal", TouchkeyControlMapping::kDirectionPositive); + } + + typeWasAbsolute_ = true; + } + + if(factory_.getController() == MidiKeyboardSegment::kControlPitchWheel) { + cc14BitButton->setEnabled(false); + cc14BitButton->setToggleState(true, dontSendNotification); + } + else if(factory_.getController() == MidiKeyboardSegment::kControlPolyphonicAftertouch || + factory_.getController() == MidiKeyboardSegment::kControlChannelAftertouch) { + cc14BitButton->setEnabled(false); + cc14BitButton->setToggleState(false, dontSendNotification); + } + else { + cc14BitButton->setEnabled(true); + cc14BitButton->setToggleState(factory_.getUses14BitControl(), dontSendNotification); + } + ignore2FingersButton->setToggleState(factory_.getIgnoresTwoFingers(), dontSendNotification); + ignore3FingersButton->setToggleState(factory_.getIgnoresThreeFingers(), dontSendNotification); + + parameterComboBox->setSelectedId(factory_.getInputParameter(), dontSendNotification); + typeComboBox->setSelectedId(factory_.getInputType(), dontSendNotification); + controlComboBox->setSelectedId(factory_.getController(), dontSendNotification); + directionComboBox->setSelectedId(factory_.getDirection(), dontSendNotification); + outOfRangeComboBox->setSelectedId(factory_.getOutOfRangeBehavior(), dontSendNotification); +} + +// Return a human-readable description of this mapping for the window +String TouchkeyControlMappingExtendedEditor::getDescription() { + return getDescriptionHelper("Control"); +} + +// Return a human-readable description of this mapping for the window +String TouchkeyControlMappingExtendedEditor::getDescriptionHelper(String baseName) { + String desc = baseName; + + desc += " (Zone "; + + int zone = factory_.segment().outputPort(); + desc += zone; + desc += ", #"; + + int mappingNumber = factory_.segment().indexOfMappingFactory(&factory_); + desc += mappingNumber; + desc += ")"; + + return desc; +} + +//[/MiscUserCode] + + +//============================================================================== +#if 0 +/* -- Introjucer information section -- + + This is where the Introjucer stores the metadata that describe this GUI layout, so + make changes in here at your peril! + +BEGIN_JUCER_METADATA + +<JUCER_COMPONENT documentType="Component" className="TouchkeyControlMappingExtendedEditor" + componentName="" parentClasses="public MappingEditorComponent, public TextEditor::Listener" + constructorParams="TouchkeyControlMappingFactory& factory" + variableInitialisers="factory_(factory)" snapPixels="8" snapActive="1" + snapShown="1" overlayOpacity="0.330" fixedSize="1" initialWidth="448" + initialHeight="248"> + <BACKGROUND backgroundColour="ffd2d2d2"/> + <TEXTEDITOR name="range low text editor" id="db0f62c03a58af03" memberName="inputRangeLowEditor" + virtualName="" explicitFocusOrder="0" pos="112 72 56 24" initialText="" + multiline="0" retKeyStartsLine="0" readonly="0" scrollbars="1" + caret="1" popupmenu="1"/> + <LABEL name="range label" id="1ca2d422f4c37b7f" memberName="rangeLabel" + virtualName="" explicitFocusOrder="0" pos="8 72 104 24" edTextCol="ff000000" + edBkgCol="0" labelText="Input Range:" editableSingleClick="0" + editableDoubleClick="0" focusDiscardsChanges="0" fontname="Default font" + fontsize="15" bold="0" italic="0" justification="33"/> + <LABEL name="control label" id="f953b12999632418" memberName="controlLabel" + virtualName="" explicitFocusOrder="0" pos="256 40 64 24" edTextCol="ff000000" + edBkgCol="0" labelText="To Control:" editableSingleClick="0" + editableDoubleClick="0" focusDiscardsChanges="0" fontname="Default font" + fontsize="15" bold="0" italic="0" justification="34"/> + <COMBOBOX name="control combo box" id="f1c84bb5fd2730fb" memberName="controlComboBox" + virtualName="" explicitFocusOrder="0" pos="320 40 112 24" editable="0" + layout="33" items="" textWhenNonSelected="" textWhenNoItems="(no choices)"/> + <LABEL name="control label" id="5ef7c1b78fdcf616" memberName="controlLabel2" + virtualName="" explicitFocusOrder="0" pos="8 40 72 24" edTextCol="ff000000" + edBkgCol="0" labelText="Parameter:" editableSingleClick="0" editableDoubleClick="0" + focusDiscardsChanges="0" fontname="Default font" fontsize="15" + bold="0" italic="0" justification="33"/> + <COMBOBOX name="parameter combo box" id="f12f6f6e31042be1" memberName="parameterComboBox" + virtualName="" explicitFocusOrder="0" pos="80 40 160 24" editable="0" + layout="33" items="" textWhenNonSelected="" textWhenNoItems="(no choices)"/> + <LABEL name="control label" id="9ded92e82db31777" memberName="controlLabel3" + virtualName="" explicitFocusOrder="0" pos="264 104 56 24" edTextCol="ff000000" + edBkgCol="0" labelText="Type:" editableSingleClick="0" editableDoubleClick="0" + focusDiscardsChanges="0" fontname="Default font" fontsize="15" + bold="0" italic="0" justification="34"/> + <COMBOBOX name="type combo box" id="82d38054016f6c4f" memberName="typeComboBox" + virtualName="" explicitFocusOrder="0" pos="320 104 112 24" editable="0" + layout="33" items="" textWhenNonSelected="" textWhenNoItems="(no choices)"/> + <TEXTEDITOR name="range hi text editor" id="c34ac3e87db289d1" memberName="inputRangeHighEditor" + virtualName="" explicitFocusOrder="0" pos="184 72 56 24" initialText="" + multiline="0" retKeyStartsLine="0" readonly="0" scrollbars="1" + caret="1" popupmenu="1"/> + <LABEL name="range label" id="19e0ad80306cc4c0" memberName="rangeLabel2" + virtualName="" explicitFocusOrder="0" pos="168 72 16 24" edTextCol="ff000000" + edBkgCol="0" labelText="-" editableSingleClick="0" editableDoubleClick="0" + focusDiscardsChanges="0" fontname="Default font" fontsize="15" + bold="0" italic="0" justification="33"/> + <LABEL name="range label" id="24ab2fe34fec697f" memberName="rangeLabel3" + virtualName="" explicitFocusOrder="0" pos="8 104 96 24" edTextCol="ff000000" + edBkgCol="0" labelText="Output Range:" editableSingleClick="0" + editableDoubleClick="0" focusDiscardsChanges="0" fontname="Default font" + fontsize="15" bold="0" italic="0" justification="33"/> + <TEXTEDITOR name="output range low text editor" id="15865c99a3cac858" memberName="outputRangeLowEditor" + virtualName="" explicitFocusOrder="0" pos="112 104 56 24" initialText="" + multiline="0" retKeyStartsLine="0" readonly="0" scrollbars="1" + caret="1" popupmenu="1"/> + <TEXTEDITOR name="output range hi text editor" id="6f3a73d113c72696" memberName="outputRangeHighEditor" + virtualName="" explicitFocusOrder="0" pos="184 104 56 24" initialText="" + multiline="0" retKeyStartsLine="0" readonly="0" scrollbars="1" + caret="1" popupmenu="1"/> + <LABEL name="range label" id="a86c42d542ee8780" memberName="rangeLabel4" + virtualName="" explicitFocusOrder="0" pos="168 104 16 24" edTextCol="ff000000" + edBkgCol="0" labelText="-" editableSingleClick="0" editableDoubleClick="0" + focusDiscardsChanges="0" fontname="Default font" fontsize="15" + bold="0" italic="0" justification="33"/> + <LABEL name="control label" id="ff30dace0846c523" memberName="controlLabel4" + virtualName="" explicitFocusOrder="0" pos="248 136 72 24" edTextCol="ff000000" + edBkgCol="0" labelText="Direction:" editableSingleClick="0" editableDoubleClick="0" + focusDiscardsChanges="0" fontname="Default font" fontsize="15" + bold="0" italic="0" justification="34"/> + <COMBOBOX name="direction combo box" id="c46a92a83dfb204b" memberName="directionComboBox" + virtualName="" explicitFocusOrder="0" pos="320 136 112 24" editable="0" + layout="33" items="" textWhenNonSelected="" textWhenNoItems="(no choices)"/> + <LABEL name="title label" id="2346b62ce034bea2" memberName="titleLabel" + virtualName="" explicitFocusOrder="0" pos="8 8 424 24" edTextCol="ff000000" + edBkgCol="0" labelText="Control Mapping (Zone N, #M)" editableSingleClick="0" + editableDoubleClick="0" focusDiscardsChanges="0" fontname="Default font" + fontsize="15" bold="1" italic="0" justification="33"/> + <LABEL name="range label" id="41edb21ea9cb0304" memberName="rangeLabel5" + virtualName="" explicitFocusOrder="0" pos="8 168 72 24" edTextCol="ff000000" + edBkgCol="0" labelText="Threshold:" editableSingleClick="0" editableDoubleClick="0" + focusDiscardsChanges="0" fontname="Default font" fontsize="15" + bold="0" italic="0" justification="33"/> + <TEXTEDITOR name="threshold text editor" id="48a7ef0bf62a7fe6" memberName="thresholdEditor" + virtualName="" explicitFocusOrder="0" pos="112 168 56 24" initialText="" + multiline="0" retKeyStartsLine="0" readonly="0" scrollbars="1" + caret="1" popupmenu="1"/> + <TOGGLEBUTTON name="new toggle button" id="f75c92be72563883" memberName="cc14BitButton" + virtualName="" explicitFocusOrder="0" pos="320 72 112 24" buttonText="Use 14-bit CC" + connectedEdges="0" needsCallback="1" radioGroupId="0" state="0"/> + <TOGGLEBUTTON name="ignore 2 fingers toggle button" id="ec82d35a4bbc6688" memberName="ignore2FingersButton" + virtualName="" explicitFocusOrder="0" pos="8 192 128 24" buttonText="Ignore 2 Fingers" + connectedEdges="0" needsCallback="1" radioGroupId="0" state="0"/> + <TOGGLEBUTTON name="ignore 3 fingers toggle button" id="9b08149fc48c8b0" memberName="ignore3FingersButton" + virtualName="" explicitFocusOrder="0" pos="8 216 128 24" buttonText="Ignore 3 Fingers" + connectedEdges="0" needsCallback="1" radioGroupId="0" state="0"/> + <LABEL name="control label" id="668b66775f7ab754" memberName="controlLabel6" + virtualName="" explicitFocusOrder="0" pos="216 168 104 24" edTextCol="ff000000" + edBkgCol="0" labelText="Out of Range:" editableSingleClick="0" + editableDoubleClick="0" focusDiscardsChanges="0" fontname="Default font" + fontsize="15" bold="0" italic="0" justification="34"/> + <COMBOBOX name="out of range combo box" id="6c7a92d782955f43" memberName="outOfRangeComboBox" + virtualName="" explicitFocusOrder="0" pos="320 168 112 24" editable="0" + layout="33" items="" textWhenNonSelected="" textWhenNoItems="(no choices)"/> + <LABEL name="range label" id="6f03f49baf05157b" memberName="rangeLabel6" + virtualName="" explicitFocusOrder="0" pos="8 136 96 24" edTextCol="ff000000" + edBkgCol="0" labelText="Default Output:" editableSingleClick="0" + editableDoubleClick="0" focusDiscardsChanges="0" fontname="Default font" + fontsize="15" bold="0" italic="0" justification="33"/> + <TEXTEDITOR name="output default text editor" id="403f9ffcb91633fd" memberName="outputDefaultEditor" + virtualName="" explicitFocusOrder="0" pos="112 136 56 24" initialText="" + multiline="0" retKeyStartsLine="0" readonly="0" scrollbars="1" + caret="1" popupmenu="1"/> +</JUCER_COMPONENT> + +END_JUCER_METADATA +*/ +#endif + + +//[EndFile] You can add extra defines here... +//[/EndFile]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Source/Mappings/Control/TouchkeyControlMappingExtendedEditor.h Sat Jun 21 23:32:33 2014 +0100 @@ -0,0 +1,110 @@ +/* + ============================================================================== + + This is an automatically generated GUI class created by the Introjucer! + + Be careful when adding custom code to these files, as only the code within + the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded + and re-saved. + + Created with Introjucer version: 3.1.0 + + ------------------------------------------------------------------------------ + + The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-13 by Raw Material Software Ltd. + + ============================================================================== +*/ + +#ifndef __JUCE_HEADER_AD461861885EB942__ +#define __JUCE_HEADER_AD461861885EB942__ + +//[Headers] -- You can add your own extra header files here -- +#include "JuceHeader.h" +#include "TouchkeyControlMappingFactory.h" +//[/Headers] + + + +//============================================================================== +/** + //[Comments] + An auto-generated component, created by the Introjucer. + + Describe your class and how it works here! + //[/Comments] +*/ +class TouchkeyControlMappingExtendedEditor : public MappingEditorComponent, + public TextEditor::Listener, + public ComboBoxListener, + public ButtonListener +{ +public: + //============================================================================== + TouchkeyControlMappingExtendedEditor (TouchkeyControlMappingFactory& factory); + ~TouchkeyControlMappingExtendedEditor(); + + //============================================================================== + //[UserMethods] -- You can add your own custom methods in this section. + void textEditorTextChanged(TextEditor &editor) {} + void textEditorReturnKeyPressed(TextEditor &editor); + void textEditorEscapeKeyPressed(TextEditor &editor); + void textEditorFocusLost(TextEditor &editor); + + void synchronize(); + String getDescription(); + //[/UserMethods] + + void paint (Graphics& g); + void resized(); + void comboBoxChanged (ComboBox* comboBoxThatHasChanged); + void buttonClicked (Button* buttonThatWasClicked); + + + +private: + //[UserVariables] -- You can add your own custom variables in this section. + String getDescriptionHelper(String baseName); + + TouchkeyControlMappingFactory& factory_; + bool typeWasAbsolute_; + //[/UserVariables] + + //============================================================================== + ScopedPointer<TextEditor> inputRangeLowEditor; + ScopedPointer<Label> rangeLabel; + ScopedPointer<Label> controlLabel; + ScopedPointer<ComboBox> controlComboBox; + ScopedPointer<Label> controlLabel2; + ScopedPointer<ComboBox> parameterComboBox; + ScopedPointer<Label> controlLabel3; + ScopedPointer<ComboBox> typeComboBox; + ScopedPointer<TextEditor> inputRangeHighEditor; + ScopedPointer<Label> rangeLabel2; + ScopedPointer<Label> rangeLabel3; + ScopedPointer<TextEditor> outputRangeLowEditor; + ScopedPointer<TextEditor> outputRangeHighEditor; + ScopedPointer<Label> rangeLabel4; + ScopedPointer<Label> controlLabel4; + ScopedPointer<ComboBox> directionComboBox; + ScopedPointer<Label> titleLabel; + ScopedPointer<Label> rangeLabel5; + ScopedPointer<TextEditor> thresholdEditor; + ScopedPointer<ToggleButton> cc14BitButton; + ScopedPointer<ToggleButton> ignore2FingersButton; + ScopedPointer<ToggleButton> ignore3FingersButton; + ScopedPointer<Label> controlLabel6; + ScopedPointer<ComboBox> outOfRangeComboBox; + ScopedPointer<Label> rangeLabel6; + ScopedPointer<TextEditor> outputDefaultEditor; + + + //============================================================================== + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TouchkeyControlMappingExtendedEditor) +}; + +//[EndFile] You can add extra defines here... +//[/EndFile] + +#endif // __JUCE_HEADER_AD461861885EB942__
--- a/Source/Mappings/Control/TouchkeyControlMappingFactory.cpp Fri Mar 21 23:13:19 2014 +0000 +++ b/Source/Mappings/Control/TouchkeyControlMappingFactory.cpp Sat Jun 21 23:32:33 2014 +0100 @@ -24,6 +24,7 @@ #include "TouchkeyControlMappingFactory.h" #include "TouchkeyControlMappingShortEditor.h" +#include "TouchkeyControlMappingExtendedEditor.h" const int TouchkeyControlMappingFactory::kDefaultController = 1; const float TouchkeyControlMappingFactory::kDefaultOutputRangeMin = 0.0; @@ -51,6 +52,13 @@ // ***** Accessors / Modifiers ***** +int TouchkeyControlMappingFactory::getDirection() { + // Get the direction of motion. This is always positive for + if(inputType_ == TouchkeyControlMapping::kTypeAbsolute) + return TouchkeyControlMapping::kDirectionPositive; + return direction_; +} + void TouchkeyControlMappingFactory::setInputParameter(int inputParameter) { inputParameter_ = inputParameter; } @@ -91,7 +99,8 @@ } setMidiParameters(controller, inputRangeMin_, inputRangeMax_, inputRangeCenter_, - outputDefault_, outputRangeMin_, outputRangeMax_); + outputDefault_, outputRangeMin_, outputRangeMax_, + -1, use14BitControl_, outOfRangeBehavior_); // Listen to incoming controls from the keyboard too, if this is enabled // in MidiKeyboardSegment @@ -113,7 +122,8 @@ // return; //midiConverter_->setControlMinValue(controlName_.c_str(), inputRangeMin_); setMidiParameters(midiControllerNumber_, inputRangeMin_, inputRangeMax_, inputRangeCenter_, - outputDefault_, outputRangeMin_, outputRangeMax_); + outputDefault_, outputRangeMin_, outputRangeMax_, + -1, use14BitControl_, outOfRangeBehavior_); } void TouchkeyControlMappingFactory::setRangeInputMax(float inputMax) { @@ -129,7 +139,8 @@ // return; //midiConverter_->setControlMaxValue(controlName_.c_str(), inputRangeMax_); setMidiParameters(midiControllerNumber_, inputRangeMin_, inputRangeMax_, inputRangeCenter_, - outputDefault_, outputRangeMin_, outputRangeMax_); + outputDefault_, outputRangeMin_, outputRangeMax_, + -1, use14BitControl_, outOfRangeBehavior_); } void TouchkeyControlMappingFactory::setRangeInputCenter(float inputCenter) { @@ -145,28 +156,32 @@ // return; //midiConverter_->setControlCenterValue(controlName_.c_str(), inputRangeCenter_); setMidiParameters(midiControllerNumber_, inputRangeMin_, inputRangeMax_, inputRangeCenter_, - outputDefault_, outputRangeMin_, outputRangeMax_); + outputDefault_, outputRangeMin_, outputRangeMax_, + -1, use14BitControl_, outOfRangeBehavior_); } void TouchkeyControlMappingFactory::setRangeOutputMin(float outputMin) { outputRangeMin_ = outputMin; setMidiParameters(midiControllerNumber_, inputRangeMin_, inputRangeMax_, inputRangeCenter_, - outputDefault_, outputRangeMin_, outputRangeMax_); + outputDefault_, outputRangeMin_, outputRangeMax_, + -1, use14BitControl_, outOfRangeBehavior_); } void TouchkeyControlMappingFactory::setRangeOutputMax(float outputMax) { outputRangeMax_ = outputMax; setMidiParameters(midiControllerNumber_, inputRangeMin_, inputRangeMax_, inputRangeCenter_, - outputDefault_, outputRangeMin_, outputRangeMax_); + outputDefault_, outputRangeMin_, outputRangeMax_, + -1, use14BitControl_, outOfRangeBehavior_); } void TouchkeyControlMappingFactory::setRangeOutputDefault(float outputDefault) { outputDefault_ = outputDefault; setMidiParameters(midiControllerNumber_, inputRangeMin_, inputRangeMax_, inputRangeCenter_, - outputDefault_, outputRangeMin_, outputRangeMax_); + outputDefault_, outputRangeMin_, outputRangeMax_, + -1, use14BitControl_, outOfRangeBehavior_); } void TouchkeyControlMappingFactory::setThreshold(float threshold) { @@ -185,11 +200,32 @@ direction_ = direction; } +void TouchkeyControlMappingFactory::setOutOfRangeBehavior(int behavior) { + outOfRangeBehavior_ = behavior; + + setMidiParameters(midiControllerNumber_, inputRangeMin_, inputRangeMax_, inputRangeCenter_, + outputDefault_, outputRangeMin_, outputRangeMax_, + -1, use14BitControl_, outOfRangeBehavior_); +} + +void TouchkeyControlMappingFactory::setUses14BitControl(bool use) { + use14BitControl_ = use; + + setMidiParameters(midiControllerNumber_, inputRangeMin_, inputRangeMax_, inputRangeCenter_, + outputDefault_, outputRangeMin_, outputRangeMax_, + -1, use14BitControl_, outOfRangeBehavior_); +} + // ***** GUI Support ***** MappingEditorComponent* TouchkeyControlMappingFactory::createBasicEditor() { return new TouchkeyControlMappingShortEditor(*this); } +MappingEditorComponent* TouchkeyControlMappingFactory::createExtendedEditor() { + return new TouchkeyControlMappingExtendedEditor(*this); +} + + // ****** Preset Save/Load ****** XmlElement* TouchkeyControlMappingFactory::getPreset() { PropertySet properties;
--- a/Source/Mappings/Control/TouchkeyControlMappingFactory.h Fri Mar 21 23:13:19 2014 +0000 +++ b/Source/Mappings/Control/TouchkeyControlMappingFactory.h Sat Jun 21 23:32:33 2014 +0100 @@ -68,7 +68,9 @@ float getThreshold() { return threshold_; } bool getIgnoresTwoFingers() { return ignoresTwoFingers_; } bool getIgnoresThreeFingers() { return ignoresThreeFingers_; } - int getDirection() { return direction_; } + int getDirection(); + int getOutOfRangeBehavior() { return outOfRangeBehavior_; } + bool getUses14BitControl() { return use14BitControl_; } void setInputParameter(int inputParameter); void setInputType(int inputType); @@ -84,12 +86,14 @@ void setIgnoresTwoFingers(bool ignoresTwo); void setIgnoresThreeFingers(bool ignoresThree); void setDirection(int direction); + void setOutOfRangeBehavior(int behavior); + void setUses14BitControl(bool use); // ***** GUI Support ***** bool hasBasicEditor() { return true; } MappingEditorComponent* createBasicEditor(); - bool hasExtendedEditor() { return false; } - MappingEditorComponent* createExtendedEditor() { return nullptr; } + bool hasExtendedEditor() { return true; } + MappingEditorComponent* createExtendedEditor(); // ****** Preset Save/Load ****** XmlElement* getPreset();
--- a/Source/Mappings/TouchkeyBaseMappingFactory.h Fri Mar 21 23:13:19 2014 +0000 +++ b/Source/Mappings/TouchkeyBaseMappingFactory.h Sat Jun 21 23:32:33 2014 +0100 @@ -56,6 +56,7 @@ controlName_(""), inputRangeMin_(0.0), inputRangeMax_(1.0), inputRangeCenter_(0.0), outOfRangeBehavior_(OscMidiConverter::kOutOfRangeClip), + use14BitControl_(false), midiControllerNumber_(-1), bypassed_(false), activeNotes_(0x0FFF) {} // ***** Destructor ***** @@ -185,6 +186,7 @@ inputRangeMax_ = inputMaxValue; inputRangeCenter_ = inputCenterValue; outOfRangeBehavior_ = outOfRangeBehavior; + use14BitControl_ = use14BitControl; // Remove listener on previous name (if any) //midiConverter_.removeAllControls(); @@ -448,6 +450,7 @@ float inputRangeMin_, inputRangeMax_; // Input ranges float inputRangeCenter_; int outOfRangeBehavior_; // What happens to out of range inputs + bool use14BitControl_; // Whether to use a 14-bit control int midiControllerNumber_; // Which controller to use bool bypassed_; // Whether the mapping has been bypassed by UI
--- a/Source/TouchKeys/MidiInputController.cpp Fri Mar 21 23:13:19 2014 +0000 +++ b/Source/TouchKeys/MidiInputController.cpp Sat Jun 21 23:32:33 2014 +0100 @@ -286,6 +286,26 @@ return ports; } +// Get the name of a particular MIDI input port +String MidiInputController::deviceName(int portNumber) { + StringArray const& deviceStrings = MidiInput::getDevices(); + if(portNumber < 0 || portNumber >= deviceStrings.size()) + return ""; + return deviceStrings[portNumber]; +} + +// Find the index of a device with a given name; return -1 if not found +int MidiInputController::indexOfDeviceNamed(String const& name) { + StringArray const& deviceStrings = MidiInput::getDevices(); + + for(int i = 0; i < deviceStrings.size(); i++) { + if(name == deviceStrings[i]) + return i; + } + + return -1; +} + // Add a new keyboard segment. Returns a pointer to the newly created segment MidiKeyboardSegment* MidiInputController::addSegment(int outputPortNumber, int noteMin, int noteMax,
--- a/Source/TouchKeys/MidiInputController.h Fri Mar 21 23:13:19 2014 +0000 +++ b/Source/TouchKeys/MidiInputController.h Sat Jun 21 23:32:33 2014 +0100 @@ -80,6 +80,10 @@ void disableAllPorts(bool auxiliaryOnly); int primaryActivePort(); vector<int> auxiliaryActivePorts(); + + // Get the name of a particular port index + String deviceName(int portNumber); + int indexOfDeviceNamed(String const& name); // Set/query the output controller MidiOutputController* midiOutputController() { return midiOutputController_; }
--- a/Source/TouchKeys/MidiKeyboardSegment.cpp Fri Mar 21 23:13:19 2014 +0000 +++ b/Source/TouchKeys/MidiKeyboardSegment.cpp Sat Jun 21 23:32:33 2014 +0100 @@ -540,6 +540,20 @@ return mappingFactories_; } +// Return the specific index of a mapping factory for this segment +int MidiKeyboardSegment::indexOfMappingFactory(MappingFactory *factory) { + vector<MappingFactory*>::iterator it; + int i = 0; + + for(it = mappingFactories_.begin(); it != mappingFactories_.end(); ++it) { + if(*it == factory) + return i; + i++; + } + + return -1; +} + // Get an XML element describing current settings (for saving presets) // This element will need to be released (or added to another XML element // that is released) by the caller
--- a/Source/TouchKeys/MidiKeyboardSegment.h Fri Mar 21 23:13:19 2014 +0000 +++ b/Source/TouchKeys/MidiKeyboardSegment.h Sat Jun 21 23:32:33 2014 +0100 @@ -225,10 +225,15 @@ // Return a list of current mapping factories. vector<MappingFactory*> const& mappingFactories(); + + // Return the specific index of this mapping factory + int indexOfMappingFactory(MappingFactory *factory); // Return a unique identifier of the mapping state, so we know when something has changed int mappingFactoryUniqueIdentifier() { return mappingFactoryUniqueIdentifier_; } + + // **** Preset methods **** // Get an XML element describing current settings (for saving presets)
--- a/Source/TouchKeys/MidiOutputController.cpp Fri Mar 21 23:13:19 2014 +0000 +++ b/Source/TouchKeys/MidiOutputController.cpp Sat Jun 21 23:32:33 2014 +0100 @@ -165,6 +165,26 @@ return ports; } +// Get the name of a particular MIDI input port +String MidiOutputController::deviceName(int portNumber) { + StringArray const& deviceStrings = MidiOutput::getDevices(); + if(portNumber < 0 || portNumber >= deviceStrings.size()) + return ""; + return deviceStrings[portNumber]; +} + +// Find the index of a device with a given name; return -1 if not found +int MidiOutputController::indexOfDeviceNamed(String const& name) { + StringArray const& deviceStrings = MidiOutput::getDevices(); + + for(int i = 0; i < deviceStrings.size(); i++) { + if(name == deviceStrings[i]) + return i; + } + + return -1; +} + // Send a MIDI Note On message void MidiOutputController::sendNoteOn(int port, unsigned char channel, unsigned char note, unsigned char velocity) { sendMessage(port,
--- a/Source/TouchKeys/MidiOutputController.h Fri Mar 21 23:13:19 2014 +0000 +++ b/Source/TouchKeys/MidiOutputController.h Sat Jun 21 23:32:33 2014 +0100 @@ -61,6 +61,12 @@ int enabledPort(int identifier); std::vector<std::pair<int, int> > enabledPorts(); + // Get the name of a particular port index + String deviceName(int portNumber); + + // Find the index of a device with a given name; return -1 if not found + int indexOfDeviceNamed(String const& name); + // Send MIDI messages void sendNoteOn(int port, unsigned char channel, unsigned char note, unsigned char velocity); void sendNoteOff(int port, unsigned char channel, unsigned char note, unsigned char velocity = 64);
--- a/Source/TouchKeys/OscMidiConverter.cpp Fri Mar 21 23:13:19 2014 +0000 +++ b/Source/TouchKeys/OscMidiConverter.cpp Sat Jun 21 23:32:33 2014 +0100 @@ -189,11 +189,18 @@ #endif } + // For 14-bit CC messages, multiply by 128 first to keep the same apparent range as + // the 7-bit version but adding extra resolution on the second CC number. This should + // not be done for pitch wheel where the values are already normalised to 14 bits. + if(controllerIs14Bit_ && controller_ != MidiKeyboardSegment::kControlPitchWheel) + controlValue *= 128.0; + int roundedControlValue = (int)floorf(controlValue + 0.5f); - if(roundedControlValue > controlMaxValue_) - roundedControlValue = controlMaxValue_; - if(roundedControlValue < controlMinValue_) - roundedControlValue = controlMinValue_; + int maxValue = controllerIs14Bit_ ? 16383 : 127; + if(roundedControlValue > maxValue) + roundedControlValue = maxValue; + if(roundedControlValue < 0) + roundedControlValue = 0; return roundedControlValue; }
--- a/Source/TouchKeys/OscMidiConverter.h Fri Mar 21 23:13:19 2014 +0000 +++ b/Source/TouchKeys/OscMidiConverter.h Sat Jun 21 23:32:33 2014 +0100 @@ -42,7 +42,7 @@ public: // Behavior for out-of-range inputs. enum { - kOutOfRangeIgnore = 0, + kOutOfRangeIgnore = 1, kOutOfRangeClip, kOutOfRangeExtrapolate };
--- a/TouchKeys.jucer Fri Mar 21 23:13:19 2014 +0000 +++ b/TouchKeys.jucer Sat Jun 21 23:32:33 2014 +0100 @@ -9,6 +9,12 @@ <FILE id="TLhblr" name="tk-icon-512.png" compile="0" resource="1" file="Resources/tk-icon-512.png"/> <GROUP id="{76BA3848-7941-BF85-9F61-26651AA83B29}" name="Source"> <GROUP id="{A75C239F-4C55-DB1F-52C8-665A12DD86F8}" name="GUI"> + <FILE id="MNTGnN" name="PreferencesWindow.h" compile="0" resource="0" + file="Source/GUI/PreferencesWindow.h"/> + <FILE id="pQJbuq" name="PreferencesComponent.cpp" compile="1" resource="0" + file="Source/GUI/PreferencesComponent.cpp"/> + <FILE id="NJXJef" name="PreferencesComponent.h" compile="0" resource="0" + file="Source/GUI/PreferencesComponent.h"/> <FILE id="EqmxWo" name="MainWindow.cpp" compile="1" resource="0" file="Source/GUI/MainWindow.cpp"/> <FILE id="dCLyAi" name="MainWindow.h" compile="0" resource="0" file="Source/GUI/MainWindow.h"/> <FILE id="AJnPIz" name="KeyboardZoneComponent.cpp" compile="1" resource="0" @@ -31,6 +37,8 @@ file="Source/GUI/MappingListItem.h"/> <FILE id="xrkguc" name="MappingEditorComponent.h" compile="0" resource="0" file="Source/GUI/MappingEditorComponent.h"/> + <FILE id="E9Won5" name="MappingExtendedEditorWindow.h" compile="0" + resource="0" file="Source/GUI/MappingExtendedEditorWindow.h"/> </GROUP> <GROUP id="{C6DAB7D2-B0E8-B89F-2891-B0D8BD8F53F7}" name="Mappings"> <GROUP id="{555624D9-7465-1F1E-FFBD-8A4D46B28C27}" name="Vibrato"> @@ -102,6 +110,10 @@ resource="0" file="Source/Mappings/KeyDivision/TouchkeyKeyDivisionMappingFactory.h"/> </GROUP> <GROUP id="{F18CE313-6599-FF00-12CD-4CDA50007E1C}" name="Control"> + <FILE id="Fh9cxx" name="TouchkeyControlMappingExtendedEditor.cpp" compile="1" + resource="0" file="Source/Mappings/Control/TouchkeyControlMappingExtendedEditor.cpp"/> + <FILE id="FfUw61" name="TouchkeyControlMappingExtendedEditor.h" compile="0" + resource="0" file="Source/Mappings/Control/TouchkeyControlMappingExtendedEditor.h"/> <FILE id="sTWDBG" name="TouchkeyControlMappingShortEditor.cpp" compile="1" resource="0" file="Source/Mappings/Control/TouchkeyControlMappingShortEditor.cpp"/> <FILE id="j4D4dO" name="TouchkeyControlMappingShortEditor.h" compile="0" @@ -260,9 +272,9 @@ bigIcon="b3DhPc"> <CONFIGURATIONS> <CONFIGURATION name="Debug" osxSDK="default" osxCompatibility="default" osxArchitecture="64BitIntel" - isDebug="1" optimisation="1" targetName="TouchKeys"/> + isDebug="1" optimisation="1" targetName="TouchKeys" headerPath="/usr/local/include"/> <CONFIGURATION name="Release" osxSDK="default" osxCompatibility="10.6 SDK" osxArchitecture="64BitUniversal" - isDebug="0" optimisation="2" targetName="TouchKeys"/> + isDebug="0" optimisation="2" targetName="TouchKeys" headerPath="/usr/local/include"/> </CONFIGURATIONS> <MODULEPATHS> <MODULEPATH id="juce_opengl" path="../juce/modules"/>