Skip to content

Commit 45fc6f9

Browse files
committed
Implement midi learn for CC messages. Fix: #58
1 parent e2e6e6d commit 45fc6f9

File tree

14 files changed

+1441
-1310
lines changed

14 files changed

+1441
-1310
lines changed

Builds/MacOSX/Dexed.xcodeproj/project.pbxproj

Lines changed: 654 additions & 1239 deletions
Large diffs are not rendered by default.

Builds/MacOSX/Dexed.xcodeproj/xcuserdata/asb2m10.xcuserdatad/xcschemes/xcschememanagement.plist

Lines changed: 0 additions & 57 deletions
This file was deleted.

Builds/MacOSX/Icon.icns

26.8 KB
Binary file not shown.

Builds/VisualStudio2017/icon.ico

20.8 KB
Binary file not shown.

LICENSE

Lines changed: 674 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Changelog
1919
---------
2020
#### Version 0.9.4
2121
* Standalone application version of Dexed
22+
* Midi Learn support for midi CC messages
2223
* More accurate detune
2324
* More accurate EG envelopes. thanks @jeremybernstein
2425
* Fix implementation for Midi CC 120 and 123 (All Sound Off / All Notes Off)
@@ -86,7 +87,6 @@ TODO - Dexed
8687

8788
TODO - msfa
8889
-----------
89-
* Better implementation of detune
9090
* Portamento implementation
9191
* Better Amplitude Modulation
9292
* Accurate live operator level envelope updates

Source/PluginData.cpp

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,16 @@ void DexedAudioProcessor::getStateInformation(MemoryBlock& destData) {
335335
blobSet.set("program", var((void *) &data, 161));
336336

337337
blobSet.copyToXmlAttributes(*dexedBlob);
338+
339+
XmlElement *midiCC = dexedState.createNewChildElement("midiCC");
340+
HashMap<int, Ctrl *>::Iterator i(mappedMidiCC);
341+
while(i.next()) {
342+
XmlElement *ccMapping = midiCC->createNewChildElement("mapping");
343+
ccMapping->setAttribute("cc", i.getKey());
344+
Ctrl *ctrl = i.getValue();
345+
ccMapping->setAttribute("target", ctrl->label);
346+
}
347+
338348
copyXmlToBinary(dexedState, destData);
339349
}
340350

@@ -399,7 +409,26 @@ void DexedAudioProcessor::setStateInformation(const void* source, int sizeInByte
399409
loadCartridge(cart);
400410
memcpy(data, program.getBinaryData()->getData(), 161);
401411

402-
lastStateSave = (long) time(NULL);
412+
mappedMidiCC.clear();
413+
XmlElement *midiCC = root->getChildByName("midiCC");
414+
if ( midiCC != nullptr ) {
415+
XmlElement *ccMapping = midiCC->getFirstChildElement();
416+
while (ccMapping != nullptr) {
417+
int cc = ccMapping->getIntAttribute("cc", -1);
418+
String target = ccMapping->getStringAttribute("target", "");
419+
if ( target.isNotEmpty() && cc != -1 ) {
420+
for(int i=0;i<ctrl.size();i++) {
421+
if ( ctrl[i]->label == target) {
422+
mappedMidiCC.set(cc, ctrl[i]);
423+
break;
424+
}
425+
}
426+
}
427+
ccMapping->getNextElement();
428+
}
429+
}
430+
431+
lastStateSave = (long) time(NULL);
403432
TRACE("setting VST STATE");
404433
updateUI();
405434
}

Source/PluginEditor.cpp

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ DexedAudioProcessorEditor::DexedAudioProcessorEditor (DexedAudioProcessor* owner
3535
: AudioProcessorEditor (ownerFilter),
3636
midiKeyboard (ownerFilter->keyboardState, MidiKeyboardComponent::horizontalKeyboard),
3737
cartManager(this)
38-
{
38+
{
3939
lookAndFeel = DXLookNFeel::getLookAndFeel();
4040
LookAndFeel::setDefaultLookAndFeel(lookAndFeel);
4141

@@ -95,8 +95,8 @@ DexedAudioProcessorEditor::DexedAudioProcessorEditor (DexedAudioProcessor* owner
9595

9696
DexedAudioProcessorEditor::~DexedAudioProcessorEditor() {
9797
stopTimer();
98-
processor->unbindUI();
99-
setLookAndFeel(nullptr);
98+
processor->unbindUI();
99+
setLookAndFeel(nullptr);
100100
}
101101

102102
//==============================================================================
@@ -341,3 +341,33 @@ void DexedAudioProcessorEditor::storeProgram() {
341341
delete externalFile;
342342
cartManager.resetActiveSysex();
343343
}
344+
345+
class MidiCCListener: public AlertWindow, Value::Listener {
346+
DexedAudioProcessorEditor *editor;
347+
Ctrl *target;
348+
public :
349+
MidiCCListener(DexedAudioProcessorEditor *editor, Ctrl *target) : AlertWindow("","Waiting for midi CC (controller change) message ...", AlertWindow::InfoIcon, editor) {
350+
this->editor = editor;
351+
this->target = target;
352+
addButton("Cancel", -1);
353+
editor->processor->lastCCUsed.addListener(this);
354+
}
355+
356+
~MidiCCListener() {
357+
editor->processor->lastCCUsed.removeListener(this);
358+
}
359+
360+
void valueChanged(Value &value) {
361+
int cc = value.getValue();
362+
editor->processor->mappedMidiCC.remove(cc);
363+
editor->processor->mappedMidiCC.set(cc, target);
364+
editor->processor->savePreference();
365+
exitModalState(0);
366+
}
367+
};
368+
369+
void DexedAudioProcessorEditor::discoverMidiCC(Ctrl *ctrl) {
370+
MidiCCListener ccListener(this, ctrl);
371+
ccListener.runModalLoop();
372+
}
373+

Source/PluginEditor.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class DexedAudioProcessorEditor : public AudioProcessorEditor, public ComboBox:
3636
OperatorEditor operators[6];
3737
Colour background;
3838
CartManager cartManager;
39-
ScopedPointer<DXLookNFeel> lookAndFeel;
39+
ScopedPointer<DXLookNFeel> lookAndFeel;
4040

4141
public:
4242
DexedAudioProcessor *processor;
@@ -55,7 +55,8 @@ class DexedAudioProcessorEditor : public AudioProcessorEditor, public ComboBox:
5555
void initProgram();
5656
void storeProgram();
5757
void cartShow();
58-
void parmShow();
58+
void parmShow();
59+
void discoverMidiCC(Ctrl *ctrl);
5960
};
6061

6162

Source/PluginParam.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,33 @@ void Ctrl::mouseEnter(const juce::MouseEvent &event) {
259259
updateDisplayName();
260260
}
261261

262+
void Ctrl::mouseDown(const juce::MouseEvent &event) {
263+
if ( event.mods.isRightButtonDown() || event.mods.isAnyModifierKeyDown()) {
264+
PopupMenu popup;
265+
266+
if ( parent->mappedMidiCC.containsValue(this) ) {
267+
popup.addItem(1, "Remove midi CC mapping for this controller");
268+
popup.addSeparator();
269+
}
270+
popup.addItem(2, "Map controller to midi CC");
271+
272+
switch(popup.show()) {
273+
case 1:
274+
parent->mappedMidiCC.removeValue(this);
275+
parent->savePreference();
276+
break;
277+
case 2:
278+
AudioProcessorEditor *editor = parent->getActiveEditor();
279+
if ( editor == NULL ) {
280+
return;
281+
}
282+
DexedAudioProcessorEditor *dexedEditor = (DexedAudioProcessorEditor *) editor;
283+
dexedEditor->discoverMidiCC(this);
284+
break;
285+
}
286+
}
287+
}
288+
262289
void Ctrl::updateDisplayName() {
263290
}
264291

Source/PluginParam.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ class Ctrl : public Slider::Listener, public Button::Listener, public ComboBox::
5858
void sliderValueChanged (Slider* moved);
5959
void buttonClicked (Button* buttonThatWasClicked);
6060
void mouseEnter(const MouseEvent &event);
61+
void mouseDown(const MouseEvent &event);
6162
virtual void updateDisplayName();
6263

6364
/**

Source/PluginProcessor.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,12 @@ DexedAudioProcessor::DexedAudioProcessor() {
9393
clipboardContent = -1;
9494
}
9595

96-
DexedAudioProcessor::~DexedAudioProcessor() {
97-
Logger *tmp = Logger::getCurrentLogger();
98-
if ( tmp != NULL ) {
99-
Logger::setCurrentLogger(NULL);
100-
delete tmp;
101-
}
96+
DexedAudioProcessor::~DexedAudioProcessor() {
97+
Logger *tmp = Logger::getCurrentLogger();
98+
if ( tmp != NULL ) {
99+
Logger::setCurrentLogger(NULL);
100+
delete tmp;
101+
}
102102
TRACE("Bye");
103103
}
104104

@@ -333,7 +333,14 @@ void DexedAudioProcessor::processMidiMessage(const MidiMessage *msg) {
333333
keyup(voices[note].midi_note);
334334
}
335335
break;
336-
}
336+
default:
337+
if ( mappedMidiCC.contains(ctrl) ) {
338+
Ctrl *linkedCtrl = mappedMidiCC[ctrl];
339+
linkedCtrl->publishValue((float) value / 127);
340+
}
341+
// this is used to notify the dialog that a CC value was received.
342+
lastCCUsed.setValue(ctrl);
343+
}
337344
}
338345
return;
339346

Source/PluginProcessor.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ public :
137137
int getEngineType();
138138
void setEngineType(int rs);
139139

140+
HashMap<int, Ctrl*> mappedMidiCC;
141+
140142
Array<Ctrl*> ctrl;
141143

142144
OperatorCtrl opCtrl[6];
@@ -232,6 +234,8 @@ public :
232234

233235
static File dexedAppDir;
234236
static File dexedCartDir;
237+
238+
Value lastCCUsed;
235239
private:
236240
//==============================================================================
237241
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DexedAudioProcessor)

0 commit comments

Comments
 (0)