From bb5e23ebbe3fa4dbc4e652df61551e509d096998 Mon Sep 17 00:00:00 2001 From: asb2m10 Date: Sun, 29 Sep 2024 18:31:36 -0400 Subject: [PATCH] Fix #378 operator clipboard data is now os text based --- Documentation/Keybindings.md | 2 -- README.md | 1 + Source/OperatorEditor.cpp | 6 ++-- Source/PluginData.cpp | 21 +++++++------ Source/PluginData.h | 58 ++++++++++++++++++++++++++++++++++++ Source/PluginProcessor.cpp | 2 -- Source/PluginProcessor.h | 6 +--- 7 files changed, 76 insertions(+), 20 deletions(-) diff --git a/Documentation/Keybindings.md b/Documentation/Keybindings.md index 6543c6f3..3ab5f285 100644 --- a/Documentation/Keybindings.md +++ b/Documentation/Keybindings.md @@ -7,6 +7,4 @@ | CTRL+G | Focus on global group | | CTRL+L | Open cartridge manager | | CTRL+P | Open parameter dialog | -| CTRL+C | Copy current context on clipboard as hexa | -| CTRL+V | Paste context from clipboard content | | SHIFT+UP or SHIFT+DOWN | On sliders, it steps 10 % | \ No newline at end of file diff --git a/README.md b/README.md index a36701a7..692b36a4 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ Changelog * UI Refresh * Accessibility implementation (including keyboard shortcuts) * Mono/Poly parameter is now a plugin parameter +* Copy/paste operator values are now text based (and system wide) * Fix Apple Logic startup issue #### Version 0.9.7 diff --git a/Source/OperatorEditor.cpp b/Source/OperatorEditor.cpp index 13a872c1..3eef23ee 100644 --- a/Source/OperatorEditor.cpp +++ b/Source/OperatorEditor.cpp @@ -599,9 +599,11 @@ void OperatorEditor::mouseDown(const MouseEvent &event) { if ( event.mods.isPopupMenu()) { PopupMenu popup; + bool hasClipboard = DexedClipboard().isOperatorData(); + popup.addItem(1, "Copy Operator Values"); - popup.addItem(2, "Paste Envelope Values", processor->hasClipboardContent()); - popup.addItem(3, "Paste Operator Values", processor->hasClipboardContent()); + popup.addItem(2, "Paste Envelope Values", hasClipboard); + popup.addItem(3, "Paste Operator Values", hasClipboard); popup.addSeparator(); popup.addItem(4, "Send current program to DX7"); diff --git a/Source/PluginData.cpp b/Source/PluginData.cpp index a23e5193..703d84f0 100644 --- a/Source/PluginData.cpp +++ b/Source/PluginData.cpp @@ -241,17 +241,25 @@ void DexedAudioProcessor::resetToInitVoice() { } void DexedAudioProcessor::copyToClipboard(int srcOp) { - memcpy(clipboard, data, 161); - clipboardContent = srcOp; + DexedClipboard clipboard(data + (srcOp *21), 21); + clipboard.write(String("Program: '") + getProgramName(getCurrentProgram()) + "' operator: " + String(6-srcOp)); } void DexedAudioProcessor::pasteOpFromClipboard(int destOp) { - memcpy(data+(destOp*21), clipboard+(clipboardContent*21), 21); + DexedClipboard clipboard; + + jassert(clipboard.isOperatorData()); + + memcpy(data+(destOp*21), clipboard.getRawData(), 21); triggerAsyncUpdate(); } void DexedAudioProcessor::pasteEnvFromClipboard(int destOp) { - memcpy(data+(destOp*21), clipboard+(clipboardContent*21), 8); + DexedClipboard clipboard; + + jassert(clipboard.isOperatorData()); + + memcpy(data+(destOp*21), clipboard.getRawData(), 8); triggerAsyncUpdate(); } @@ -301,11 +309,6 @@ void DexedAudioProcessor::sendSysexCartridge(File cart) { sysexComm.send(MidiMessage(syx_data, sz)); } - -bool DexedAudioProcessor::hasClipboardContent() { - return clipboardContent != -1; -} - //============================================================================== void DexedAudioProcessor::getStateInformation(MemoryBlock& destData) { // You should use this method to store your parameters in the memory block. diff --git a/Source/PluginData.h b/Source/PluginData.h index 4d0dfa2f..e78c9d58 100644 --- a/Source/PluginData.h +++ b/Source/PluginData.h @@ -255,4 +255,62 @@ class Cartridge { void packProgram(uint8_t *src, int idx, String name, char *opSwitch); }; +class DexedClipboard { + // In the future complete sysex will be supported + uint8_t content[SYSEX_SIZE]; + int size = 0; +public: + DexedClipboard() { + String text = SystemClipboard::getTextFromClipboard(); + // For now we only support operator clipboard + if ( text.length() < (21*2) ) { + TRACE("Clipboard is empty or too small"); + return; + } + + CharPointer_UTF8 t = text.getCharPointer(); + for(int i=0;i<21;i++) { + int high = CharacterFunctions::getHexDigitValue(t.getAndAdvance()); + if ( high == -1 ) { + TRACE("Malformed clipboard data"); + return; + } + + int low = CharacterFunctions::getHexDigitValue(t.getAndAdvance()); + if ( low == -1 ) { + TRACE("Malformed clipboard data"); + return; + } + + content[i] = (high << 4) + low; + } + size = 21; + } + + DexedClipboard(const uint8_t *data, int s) { + size = s; + memcpy(content, data, size); + } + + bool isOperatorData() { + if ( size == 21 ) + return true; + else + return false; + } + + uint8_t *getRawData() { + return content; + } + + void write(String description) { + String clipboardValue = String::toHexString(content, size, 0); + if ( description.isNotEmpty() ) { + clipboardValue.append("\n; ", 3); + clipboardValue.append(description, 1024); + } + SystemClipboard::copyTextToClipboard(clipboardValue); + } +}; + #endif // PLUGINDATA_H_INCLUDED diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index be261e55..0d510162 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -115,8 +115,6 @@ DexedAudioProcessor::DexedAudioProcessor() setCurrentProgram(0); nextMidi = NULL; midiMsg = NULL; - - clipboardContent = -1; mtsClient = NULL; mtsClient = MTS_RegisterClient(); diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h index 6222a7c2..32b1c45a 100644 --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -127,10 +127,7 @@ class DexedAudioProcessor : public AudioProcessor, public AsyncUpdater, public FmCore engineMsfa; EngineMkI engineMkI; EngineOpl engineOpl; - - char clipboard[161]; - signed char clipboardContent; - + void resolvAppDir(); void unpackOpSwitch(char packOpValue); @@ -204,7 +201,6 @@ public : void sendCurrentSysexProgram(); void sendCurrentSysexCartridge(); void sendSysexCartridge(File cart); - bool hasClipboardContent(); //============================================================================== AudioProcessorEditor* createEditor();