diff --git a/.github/workflows/irc.yml b/.github/workflows/irc.yml index b1e801773..539fa1d2a 100644 --- a/.github/workflows/irc.yml +++ b/.github/workflows/irc.yml @@ -7,10 +7,14 @@ jobs: runs-on: ubuntu-latest name: IRC notification steps: - - name: IRC notification - uses: Gottox/irc-message-action@v2 - with: - channel: '#kxstudio' - nickname: kxstudio-bot - message: |- - ${{ github.actor }} pushed ${{ github.event.head_commit.message }} ${{ github.event.compare }} + - name: Format message + id: message + run: | + message="${{ github.actor }} pushed $(echo '${{ github.event.commits[0].message }}' | head -n 1) ${{ github.event.commits[0].url }}" + echo ::set-output name=message::"${message}" + - name: IRC notification + uses: Gottox/irc-message-action@v2 + with: + channel: '#kxstudio' + nickname: kxstudio-bot + message: ${{ steps.message.outputs.message }} diff --git a/source/backend/plugin/CarlaPluginJuce.cpp b/source/backend/plugin/CarlaPluginJuce.cpp index 1af03a5a5..4d02c0d45 100644 --- a/source/backend/plugin/CarlaPluginJuce.cpp +++ b/source/backend/plugin/CarlaPluginJuce.cpp @@ -496,11 +496,16 @@ public: uiName += " (GUI)"; } - AEffect* const effect = fDesc.pluginFormatName == "VST" || fDesc.pluginFormatName == "VST2" - ? (AEffect*)fInstance->getPlatformSpecificData() - : nullptr; + AEffect* const vst2effect = fDesc.pluginFormatName == "VST" || fDesc.pluginFormatName == "VST2" + ? (AEffect*)fInstance->getPlatformSpecificData() + : nullptr; - fWindow = new JucePluginWindow(opts.frontendWinId, opts.pluginsAreStandalone, effect); + v3_plugin_view** const vst3view = fDesc.pluginFormatName == "VST3" + ? (v3_plugin_view**)editor->getPlatformSpecificData() + : nullptr; + + fWindow = new JucePluginWindow(opts.frontendWinId, opts.pluginsAreStandalone, + vst2effect, vst3view); fWindow->setName(uiName); } diff --git a/source/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp b/source/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp index 229099e49..ce0d515ce 100644 --- a/source/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp +++ b/source/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp @@ -1305,6 +1305,11 @@ struct VST3PluginWindow : public AudioProcessorEditor, view = nullptr; } + void* getPlatformSpecificData() + { + return view; + } + #if JUCE_LINUX Steinberg::tresult PLUGIN_API queryInterface (const Steinberg::TUID iid, void** obj) override { diff --git a/source/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.cpp b/source/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.cpp index 670cb3969..72e706725 100644 --- a/source/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.cpp +++ b/source/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.cpp @@ -46,6 +46,7 @@ AudioProcessorEditor::~AudioProcessorEditor() removeComponentListener (resizeListener.get()); } +void* AudioProcessorEditor::getPlatformSpecificData() { return nullptr; } void AudioProcessorEditor::setControlHighlight (ParameterControlHighlightInfo) {} int AudioProcessorEditor::getControlParameterIndex (Component&) { return -1; } diff --git a/source/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h b/source/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h index 07d3765f4..4f2dc0487 100644 --- a/source/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h +++ b/source/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h @@ -55,6 +55,11 @@ public: ~AudioProcessorEditor() override; + /** Returns a pointer to some kind of platform-specific data about the plugin. + E.g. For a VST3, this value can be cast to an IPlugView*. + */ + virtual void* getPlatformSpecificData(); + //============================================================================== /** The AudioProcessor that this editor represents. */ AudioProcessor& processor; diff --git a/source/utils/JucePluginWindow.hpp b/source/utils/JucePluginWindow.hpp index 5fad055ea..c83ddb3e8 100644 --- a/source/utils/JucePluginWindow.hpp +++ b/source/utils/JucePluginWindow.hpp @@ -20,6 +20,7 @@ #include "CarlaJuceUtils.hpp" #include "CarlaVst2Utils.hpp" +#include "CarlaVst3Utils.hpp" #include "AppConfig.h" #include "juce_gui_basics/juce_gui_basics.h" @@ -43,17 +44,18 @@ namespace juce { class JucePluginWindow : public DialogWindow { public: - JucePluginWindow(const uintptr_t parentId, const bool isStandalone, AEffect* const vstEffect) + JucePluginWindow(const uintptr_t parentId, const bool isStandalone, + AEffect* const vst2effect, v3_plugin_view** const vst3view) : DialogWindow("JucePluginWindow", Colour(50, 50, 200), true, false), fIsStandalone(isStandalone), fClosed(false), fShown(false), fTransientId(parentId), - fLastKeyIndex(0), - fLastKeyValue(0), - fLastModifiers(), - fVstEffect(vstEffect) + fLastKeys(), + fVst2Effect(vst2effect), + fVst3View(vst3view) { + carla_zeroStruct(fLastKeys); setVisible(false); setOpaque(true); setResizable(false, false); @@ -88,7 +90,7 @@ public: if (DialogWindow::keyPressed (key)) return true; - if (fVstEffect != nullptr) + if (fVst2Effect != nullptr) { const int juceKeyCode = key.getKeyCode(); int vstKeyIndex = 0; @@ -179,11 +181,150 @@ public: else vstKeyIndex = juceKeyCode; } while (false); - fLastKeyIndex = vstKeyIndex; - fLastKeyValue = vstKeyValue; - return fVstEffect->dispatcher (fVstEffect, effEditKeyDown, - vstKeyIndex, vstKeyValue, - nullptr, 0.0f) != 0; + fLastKeys.vst2.index = vstKeyIndex; + fLastKeys.vst2.value = vstKeyValue; + return fVst2Effect->dispatcher (fVst2Effect, effEditKeyDown, vstKeyIndex, vstKeyValue, nullptr, 0.0f) != 0; + } + + if (fVst3View != nullptr) + { + const int juceKeyCode = key.getKeyCode(); + const int juceKeyMods = key.getModifiers().getRawFlags(); + int16_t vst3KeyChar = 0; + int16_t vst3KeyCode = 0; + int16_t vst3KeyMods = 0; + + // KEY_NEXT 8 + // KEY_SELECT 17 + // KEY_SELECT 18 + // KEY_SNAPSHOT 20 + // KEY_HELP 23 + // KEY_NUMLOCK 52 + // KEY_SCROLL 53 + // KEY_VOLUME_UP 63 + // KEY_VOLUME_DOWN 64 + + do { + /**/ if (juceKeyCode == KeyPress::spaceKey) + { + vst3KeyChar = ' '; + vst3KeyCode = 7; + } + else if (juceKeyCode == KeyPress::escapeKey) + { + vst3KeyCode = 6; + } + else if (juceKeyCode == KeyPress::returnKey) + { + vst3KeyChar = '\n'; + vst3KeyCode = 19; // NOTE: 4 is '\r' while 19 is '\n' + } + else if (juceKeyCode == KeyPress::tabKey) + { + vst3KeyChar = '\t'; + vst3KeyCode = 2; + } + + else if (juceKeyCode == KeyPress::deleteKey) vst3KeyCode = 22; + else if (juceKeyCode == KeyPress::backspaceKey) vst3KeyCode = 1; + else if (juceKeyCode == KeyPress::insertKey) vst3KeyCode = 21; + + else if (juceKeyCode == KeyPress::upKey) vst3KeyCode = 12; + else if (juceKeyCode == KeyPress::downKey) vst3KeyCode = 14; + else if (juceKeyCode == KeyPress::leftKey) vst3KeyCode = 11; + else if (juceKeyCode == KeyPress::rightKey) vst3KeyCode = 13; + else if (juceKeyCode == KeyPress::pageUpKey) vst3KeyCode = 15; + else if (juceKeyCode == KeyPress::pageDownKey) vst3KeyCode = 16; + else if (juceKeyCode == KeyPress::homeKey) vst3KeyCode = 10; + else if (juceKeyCode == KeyPress::endKey) vst3KeyCode = 9; + + else if (juceKeyCode == KeyPress::F1Key) vst3KeyCode = 40; + else if (juceKeyCode == KeyPress::F2Key) vst3KeyCode = 41; + else if (juceKeyCode == KeyPress::F3Key) vst3KeyCode = 42; + else if (juceKeyCode == KeyPress::F4Key) vst3KeyCode = 43; + else if (juceKeyCode == KeyPress::F5Key) vst3KeyCode = 44; + else if (juceKeyCode == KeyPress::F6Key) vst3KeyCode = 45; + else if (juceKeyCode == KeyPress::F7Key) vst3KeyCode = 46; + else if (juceKeyCode == KeyPress::F8Key) vst3KeyCode = 47; + else if (juceKeyCode == KeyPress::F9Key) vst3KeyCode = 48; + else if (juceKeyCode == KeyPress::F10Key) vst3KeyCode = 49; + else if (juceKeyCode == KeyPress::F11Key) vst3KeyCode = 50; + else if (juceKeyCode == KeyPress::F12Key) vst3KeyCode = 51; + + else if (juceKeyCode == KeyPress::F13Key) vst3KeyCode = 65; + else if (juceKeyCode == KeyPress::F14Key) vst3KeyCode = 66; + else if (juceKeyCode == KeyPress::F15Key) vst3KeyCode = 67; + else if (juceKeyCode == KeyPress::F16Key) vst3KeyCode = 68; + else if (juceKeyCode == KeyPress::F17Key) vst3KeyCode = 69; + else if (juceKeyCode == KeyPress::F18Key) vst3KeyCode = 70; + else if (juceKeyCode == KeyPress::F19Key) vst3KeyCode = 71; + else if (juceKeyCode == KeyPress::F20Key) break; + else if (juceKeyCode == KeyPress::F21Key) break; + else if (juceKeyCode == KeyPress::F22Key) break; + else if (juceKeyCode == KeyPress::F23Key) break; + else if (juceKeyCode == KeyPress::F24Key) break; + else if (juceKeyCode == KeyPress::F25Key) break; + else if (juceKeyCode == KeyPress::F26Key) break; + else if (juceKeyCode == KeyPress::F27Key) break; + else if (juceKeyCode == KeyPress::F28Key) break; + else if (juceKeyCode == KeyPress::F29Key) break; + else if (juceKeyCode == KeyPress::F30Key) break; + else if (juceKeyCode == KeyPress::F31Key) break; + else if (juceKeyCode == KeyPress::F32Key) break; + else if (juceKeyCode == KeyPress::F33Key) break; + else if (juceKeyCode == KeyPress::F34Key) break; + else if (juceKeyCode == KeyPress::F35Key) break; + + else if (juceKeyCode == KeyPress::numberPad0) vst3KeyCode = 24; + else if (juceKeyCode == KeyPress::numberPad1) vst3KeyCode = 25; + else if (juceKeyCode == KeyPress::numberPad2) vst3KeyCode = 26; + else if (juceKeyCode == KeyPress::numberPad3) vst3KeyCode = 27; + else if (juceKeyCode == KeyPress::numberPad4) vst3KeyCode = 28; + else if (juceKeyCode == KeyPress::numberPad5) vst3KeyCode = 29; + else if (juceKeyCode == KeyPress::numberPad6) vst3KeyCode = 30; + else if (juceKeyCode == KeyPress::numberPad7) vst3KeyCode = 31; + else if (juceKeyCode == KeyPress::numberPad8) vst3KeyCode = 32; + else if (juceKeyCode == KeyPress::numberPad9) vst3KeyCode = 33; + + else if (juceKeyCode == KeyPress::numberPadAdd) vst3KeyCode = 35; + else if (juceKeyCode == KeyPress::numberPadSubtract) vst3KeyCode = 37; + else if (juceKeyCode == KeyPress::numberPadMultiply) vst3KeyCode = 34; + else if (juceKeyCode == KeyPress::numberPadDivide) vst3KeyCode = 39; + else if (juceKeyCode == KeyPress::numberPadSeparator) vst3KeyCode = 36; + else if (juceKeyCode == KeyPress::numberPadDecimalPoint) vst3KeyCode = 38; + else if (juceKeyCode == KeyPress::numberPadEquals) vst3KeyCode = 57; + + else if (juceKeyCode == KeyPress::numberPadDelete) break; + + else if (juceKeyCode == KeyPress::playKey) vst3KeyCode = 59; + else if (juceKeyCode == KeyPress::stopKey) vst3KeyCode = 60; + else if (juceKeyCode == KeyPress::fastForwardKey) vst3KeyCode = 62; + else if (juceKeyCode == KeyPress::rewindKey) vst3KeyCode = 61; + + else + { + vst3KeyChar = static_cast(juceKeyCode); + + if ((juceKeyCode >= 0x30 && juceKeyCode <= 0x39) || (juceKeyCode >= 0x41 && juceKeyCode <= 0x5A)) + vst3KeyCode = static_cast(juceKeyCode - 0x30 + 128); + } + } while (false); + + if (juceKeyMods & ModifierKeys::shiftModifier) + vst3KeyMods |= 1 << 0; + if (juceKeyMods & ModifierKeys::altModifier) + vst3KeyMods |= 1 << 1; + if (juceKeyMods & ModifierKeys::commandModifier) + vst3KeyMods |= 1 << 2; +#if JUCE_MAC || JUCE_IOS + if (juceKeyMods & ModifierKeys::ctrlModifier) + vst3KeyMods |= 1 << 3; +#endif + + fLastKeys.vst3.keychar = vst3KeyChar; + fLastKeys.vst3.keycode = vst3KeyCode; + fLastKeys.vst3.keymods = vst3KeyMods; + return v3_cpp_obj(fVst3View)->on_key_down (fVst3View, vst3KeyChar, vst3KeyCode, vst3KeyMods) == V3_TRUE; } if (Component* const comp = getContentComponent()) @@ -197,14 +338,21 @@ public: if (DialogWindow::keyStateChanged (isKeyDown)) return true; - if (fVstEffect != nullptr && (fLastKeyIndex != 0 || fLastKeyValue != 0) && ! isKeyDown) + if (fVst2Effect != nullptr && (fLastKeys.vst2.index != 0 || fLastKeys.vst2.value != 0) && ! isKeyDown) { - const int vstKeyIndex = fLastKeyIndex; - const int vstKeyValue = fLastKeyValue; - fLastKeyIndex = fLastKeyValue = 0; - return fVstEffect->dispatcher (fVstEffect, effEditKeyUp, - vstKeyIndex, vstKeyValue, - nullptr, 0.0f) != 0; + const int vstKeyIndex = fLastKeys.vst2.index; + const int vstKeyValue = fLastKeys.vst2.value; + fLastKeys.vst2.index = fLastKeys.vst2.value = 0; + return fVst2Effect->dispatcher (fVst2Effect, effEditKeyUp, vstKeyIndex, vstKeyValue, nullptr, 0.0f) != 0; + } + + if (fVst3View != nullptr && (fLastKeys.vst3.keychar != 0 || fLastKeys.vst3.keycode != 0) && ! isKeyDown) + { + const int16_t vst3KeyChar = fLastKeys.vst3.keychar; + const int16_t vst3KeyCode = fLastKeys.vst3.keycode; + const int16_t vst3KeyMods = fLastKeys.vst3.keymods; + fLastKeys.vst3.keychar = fLastKeys.vst3.keycode = fLastKeys.vst3.keymods = 0; + return v3_cpp_obj(fVst3View)->on_key_up (fVst3View, vst3KeyChar, vst3KeyCode, vst3KeyMods) == V3_TRUE; } if (Component* const comp = getContentComponent()) @@ -217,37 +365,97 @@ public: { DialogWindow::modifierKeysChanged (modifiers); - if (fVstEffect != nullptr) + if (fVst2Effect != nullptr) + { + const int oldRawFlags = fLastKeys.vst2.rmods; + const int newRawFlags = modifiers.getRawFlags(); + + if ((oldRawFlags & ModifierKeys::shiftModifier) != (newRawFlags & ModifierKeys::shiftModifier)) + { + fVst2Effect->dispatcher (fVst2Effect, + (newRawFlags & ModifierKeys::shiftModifier) ? effEditKeyDown : effEditKeyUp, + 0, 54, nullptr, 0.0f); + } + + if ((oldRawFlags & ModifierKeys::ctrlModifier) != (newRawFlags & ModifierKeys::ctrlModifier)) + { + fVst2Effect->dispatcher (fVst2Effect, + (newRawFlags & ModifierKeys::ctrlModifier) ? effEditKeyDown : effEditKeyUp, + 0, 55, nullptr, 0.0f); + } + + if ((oldRawFlags & ModifierKeys::altModifier) != (newRawFlags & ModifierKeys::altModifier)) + { + fVst2Effect->dispatcher (fVst2Effect, + (newRawFlags & ModifierKeys::altModifier) ? effEditKeyDown : effEditKeyUp, + 0, 56, nullptr, 0.0f); + } + + if ((oldRawFlags & ModifierKeys::popupMenuClickModifier) != (newRawFlags & ModifierKeys::popupMenuClickModifier)) + { + fVst2Effect->dispatcher (fVst2Effect, + (newRawFlags & ModifierKeys::popupMenuClickModifier) ? effEditKeyDown : effEditKeyUp, + 0, 58, nullptr, 0.0f); + } + + fLastKeys.vst2.rmods = newRawFlags; + } + + if (fVst3View != nullptr) { - const int oldRawFlags = fLastModifiers.getRawFlags(); + const int oldRawFlags = fLastKeys.vst3.rmods; const int newRawFlags = modifiers.getRawFlags(); if ((oldRawFlags & ModifierKeys::shiftModifier) != (newRawFlags & ModifierKeys::shiftModifier)) { - fVstEffect->dispatcher (fVstEffect, (newRawFlags & ModifierKeys::shiftModifier) ? effEditKeyDown : effEditKeyUp, 0, - 54, nullptr, 0.0f); + if (newRawFlags & ModifierKeys::shiftModifier) + v3_cpp_obj(fVst3View)->on_key_down (fVst3View, 0, 54, fLastKeys.vst3.keymods); + else + v3_cpp_obj(fVst3View)->on_key_up (fVst3View, 0, 54, fLastKeys.vst3.keymods); } if ((oldRawFlags & ModifierKeys::ctrlModifier) != (newRawFlags & ModifierKeys::ctrlModifier)) { - fVstEffect->dispatcher (fVstEffect, (newRawFlags & ModifierKeys::ctrlModifier) ? effEditKeyDown : effEditKeyUp, 0, - 55, nullptr, 0.0f); + if (newRawFlags & ModifierKeys::ctrlModifier) + v3_cpp_obj(fVst3View)->on_key_down (fVst3View, 0, 55, fLastKeys.vst3.keymods); + else + v3_cpp_obj(fVst3View)->on_key_up (fVst3View, 0, 55, fLastKeys.vst3.keymods); } if ((oldRawFlags & ModifierKeys::altModifier) != (newRawFlags & ModifierKeys::altModifier)) { - fVstEffect->dispatcher (fVstEffect, (newRawFlags & ModifierKeys::altModifier) ? effEditKeyDown : effEditKeyUp, 0, - 56, nullptr, 0.0f); + if (newRawFlags & ModifierKeys::altModifier) + v3_cpp_obj(fVst3View)->on_key_down (fVst3View, 0, 56, fLastKeys.vst3.keymods); + else + v3_cpp_obj(fVst3View)->on_key_up (fVst3View, 0, 56, fLastKeys.vst3.keymods); } if ((oldRawFlags & ModifierKeys::popupMenuClickModifier) != (newRawFlags & ModifierKeys::popupMenuClickModifier)) { - fVstEffect->dispatcher (fVstEffect, (newRawFlags & ModifierKeys::popupMenuClickModifier) ? effEditKeyDown : effEditKeyUp, 0, - 58, nullptr, 0.0f); + if (newRawFlags & ModifierKeys::popupMenuClickModifier) + v3_cpp_obj(fVst3View)->on_key_down (fVst3View, 0, 58, fLastKeys.vst3.keymods); + else + v3_cpp_obj(fVst3View)->on_key_up (fVst3View, 0, 58, fLastKeys.vst3.keymods); } + + fLastKeys.vst3.rmods = newRawFlags; } + } + + void focusGained (const FocusChangeType cause) override + { + DialogWindow::focusGained (cause); + + if (fVst3View != nullptr) + v3_cpp_obj(fVst3View)->on_focus (fVst3View, true); + } + + void focusLost (const FocusChangeType cause) + { + if (fVst3View != nullptr) + v3_cpp_obj(fVst3View)->on_focus (fVst3View, false); - fLastModifiers = modifiers; + DialogWindow::focusLost (cause); } void hide() @@ -306,9 +514,22 @@ private: volatile bool fClosed; bool fShown; const uintptr_t fTransientId; - int fLastKeyIndex, fLastKeyValue; - ModifierKeys fLastModifiers; - AEffect* const fVstEffect; + union { + struct { + int index; + int value; + int rmods; + } vst2; + + struct { + int16_t keychar; + int16_t keycode; + int16_t keymods; + int rmods; + } vst3; + } fLastKeys; + AEffect* const fVst2Effect; + v3_plugin_view** const fVst3View; void setTransient() {