diff --git a/app/translates/zh-CN/alert.txt b/app/translates/zh-CN/alert.txt index cef34425..675bff14 100644 --- a/app/translates/zh-CN/alert.txt +++ b/app/translates/zh-CN/alert.txt @@ -19,6 +19,7 @@ countries: cn "Bus Type Selector" = "总线类型选择器" "Plugin Param Selector" = "插件参数选择器" "MIDI CC Controller Selector" = "MIDI CC 控制器选择器" +"Audio Channel Link" = "音频通道连接" "Discard unsaved changes and exit?" = "放弃未保存的更改并退出?" "Discard unsaved changes and continue?" = "放弃未保存的更改并继续?" diff --git a/app/translates/zh-CN/main.txt b/app/translates/zh-CN/main.txt index 0a679340..8fd66501 100644 --- a/app/translates/zh-CN/main.txt +++ b/app/translates/zh-CN/main.txt @@ -131,3 +131,4 @@ countries: cn "MIDI Input" = "MIDI输入" "Sequencer Track" = "音序器轨道" "Mixer Track" = "混音器轨道" +"Channel Link" = "通道连接" diff --git a/src/audioCore/graph/PluginDecorator.cpp b/src/audioCore/graph/PluginDecorator.cpp index 3be39c9b..47b8bd70 100644 --- a/src/audioCore/graph/PluginDecorator.cpp +++ b/src/audioCore/graph/PluginDecorator.cpp @@ -76,6 +76,10 @@ void PluginDecorator::setPlugin( } } +const juce::AudioChannelSet& PluginDecorator::getAudioChannelSet() const { + return this->audioChannels; +} + bool PluginDecorator::canPluginAddBus(bool isInput) const { if (!this->plugin) { return false; } return this->plugin->canAddBus(isInput); diff --git a/src/audioCore/graph/PluginDecorator.h b/src/audioCore/graph/PluginDecorator.h index 281285c0..2954d6d1 100644 --- a/src/audioCore/graph/PluginDecorator.h +++ b/src/audioCore/graph/PluginDecorator.h @@ -17,6 +17,8 @@ class PluginDecorator final : public juce::AudioProcessor, void setPlugin( std::unique_ptr plugin, const juce::String& pluginIdentifier); + const juce::AudioChannelSet& getAudioChannelSet() const; + bool canPluginAddBus(bool isInput) const; bool canPluginRemoveBus(bool isInput) const; diff --git a/src/audioCore/quickAPI/QuickGet.cpp b/src/audioCore/quickAPI/QuickGet.cpp index c7e5f3e4..48133d0a 100644 --- a/src/audioCore/quickAPI/QuickGet.cpp +++ b/src/audioCore/quickAPI/QuickGet.cpp @@ -464,6 +464,33 @@ namespace quickAPI { return {}; } + const juce::AudioChannelSet getInstrChannelSet(int index) { + if (auto graph = AudioCore::getInstance()->getGraph()) { + if (auto instr = graph->getInstrumentProcessor(index)) { + return instr->getAudioChannelSet(); + } + } + return juce::AudioChannelSet{}; + } + + int getInstrInputChannelNum(int index) { + if (auto graph = AudioCore::getInstance()->getGraph()) { + if (auto instr = graph->getInstrumentProcessor(index)) { + return instr->getTotalNumInputChannels(); + } + } + return 0; + } + + int getInstrOutputChannelNum(int index) { + if (auto graph = AudioCore::getInstance()->getGraph()) { + if (auto instr = graph->getInstrumentProcessor(index)) { + return instr->getTotalNumOutputChannels(); + } + } + return 0; + } + EditorPointer getInstrEditor(int index) { if (auto graph = AudioCore::getInstance()->getGraph()) { if (auto instr = graph->getInstrumentProcessor(index)) { @@ -595,6 +622,33 @@ namespace quickAPI { return result; } + const juce::AudioChannelSet getMixerTrackChannelSet(int index) { + if (auto graph = AudioCore::getInstance()->getGraph()) { + if (auto track = graph->getTrackProcessor(index)) { + return track->getAudioChannelSet(); + } + } + return juce::AudioChannelSet{}; + } + + int getMixerTrackInputChannelNum(int index) { + if (auto graph = AudioCore::getInstance()->getGraph()) { + if (auto track = graph->getTrackProcessor(index)) { + return track->getTotalNumInputChannels(); + } + } + return 0; + } + + int getMixerTrackOutputChannelNum(int index) { + if (auto graph = AudioCore::getInstance()->getGraph()) { + if (auto track = graph->getTrackProcessor(index)) { + return track->getTotalNumOutputChannels(); + } + } + return 0; + } + const juce::String getMIDICCChannelName(int channel) { return utils::getMIDICCChannelName(channel); } diff --git a/src/audioCore/quickAPI/QuickGet.h b/src/audioCore/quickAPI/QuickGet.h index 2367df40..c61d8625 100644 --- a/src/audioCore/quickAPI/QuickGet.h +++ b/src/audioCore/quickAPI/QuickGet.h @@ -95,6 +95,9 @@ namespace quickAPI { bool getInstrMIDIInputFromDevice(int index); const juce::Array getInstrMIDIInputFromSource(int index); const juce::Array getInstrAudioOutputToMixer(int index); + const juce::AudioChannelSet getInstrChannelSet(int index); + int getInstrInputChannelNum(int index); + int getInstrOutputChannelNum(int index); EditorPointer getInstrEditor(int index); const juce::String getInstrName(PluginHolder pointer); bool getInstrBypass(PluginHolder pointer); @@ -122,6 +125,9 @@ namespace quickAPI { int getMixerTrackNum(); const juce::String getMixerTrackName(int index); const juce::StringArray getMixerTrackNameList(); + const juce::AudioChannelSet getMixerTrackChannelSet(int index); + int getMixerTrackInputChannelNum(int index); + int getMixerTrackOutputChannelNum(int index); const juce::String getMIDICCChannelName(int channel); const juce::StringArray getMIDICCChannelNameList(); diff --git a/src/ui/component/ChannelLinkView.cpp b/src/ui/component/ChannelLinkView.cpp new file mode 100644 index 00000000..6f48940b --- /dev/null +++ b/src/ui/component/ChannelLinkView.cpp @@ -0,0 +1,132 @@ +#include "ChannelLinkView.h" +#include "../lookAndFeel/LookAndFeelFactory.h" +#include "../misc/RCManager.h" +#include "../Utils.h" + +ChannelLinkViewContent::ChannelLinkViewContent( + const std::function& callback, + const juce::Array>& initList, + const juce::AudioChannelSet& srcChannels, const juce::AudioChannelSet& dstChannels, + int srcChannelNum, int dstChannelNum, const juce::String& srcName, const juce::String& dstName, + bool initIfEmpty) : callback(callback), srcChannels(srcChannels), dstChannels(dstChannels), + srcChannelNum(srcChannelNum), dstChannelNum(dstChannelNum), + srcName(srcName), dstName(dstName) { + /** Create Temp */ + this->temp.setRange(0, srcChannelNum * dstChannelNum, false); + for (auto& [srcc, dstc] : initList) { + this->temp.setBit(srcc * dstChannelNum + dstc); + } + + /** Init If Empty */ + if (initIfEmpty && initList.isEmpty()) { + int channelNum = std::min(srcChannelNum, dstChannelNum); + for (int i = 0; i < channelNum; i++) { + this->setLink(i, i, true); + } + } + + /** Change Size */ + auto size = this->getPreferedSize(); + this->setBounds(0, 0, size.getX(), size.getY()); +} + +juce::Point ChannelLinkViewContent::getPreferedSize() const { + auto screenSize = utils::getScreenSize(this); + int paddingWidth = screenSize.getWidth() * 0.05; + int paddingHeight = screenSize.getHeight() * 0.05; + int titleWidth = screenSize.getWidth() * 0.05; + int titleHeight = screenSize.getHeight() * 0.05; + int cellWidth = screenSize.getWidth() * 0.025; + int cellHeight = cellWidth; + + return { paddingWidth * 2 + titleWidth + cellWidth * (this->dstChannelNum + 2), + paddingHeight * 2 + titleHeight + cellHeight * (this->srcChannelNum + 2) }; +} + +void ChannelLinkViewContent::paint(juce::Graphics& g) { + /** TODO */ +} + +bool ChannelLinkViewContent::checkLink(int srcc, int dstc) { + return this->temp[srcc * this->dstChannelNum + dstc]; +} + +void ChannelLinkViewContent::setLink(int srcc, int dstc, bool link) { + if (link) { + this->temp.setBit(srcc * this->dstChannelNum + dstc); + } + else { + this->temp.clearBit(srcc * this->dstChannelNum + dstc); + } + this->callback(srcc, dstc, link); +} + +ChannelLinkView::ChannelLinkView( + const std::function& callback, + const juce::Array>& initList, + const juce::AudioChannelSet& srcChannels, const juce::AudioChannelSet& dstChannels, + int srcChannelNum, int dstChannelNum, const juce::String& srcName, const juce::String& dstName, + bool initIfEmpty) + : DocumentWindow(TRANS("Audio Channel Link"), juce::LookAndFeel::getDefaultLookAndFeel().findColour( + juce::ResizableWindow::ColourIds::backgroundColourId), + juce::DocumentWindow::closeButton, true) { + this->setUsingNativeTitleBar(true); + this->setResizable(true, false); + + /** Look And Feel */ + this->setLookAndFeel( + LookAndFeelFactory::getInstance()->forChannelLink()); + + /** Content */ + this->content = std::make_unique(TRANS("Channel Link")); + this->content->setViewedComponent(new ChannelLinkViewContent{ + callback, initList, srcChannels, dstChannels, + srcChannelNum, dstChannelNum, srcName, dstName, initIfEmpty + }); + this->content->setScrollOnDragMode( + juce::Viewport::ScrollOnDragMode::nonHover); + this->setContentNonOwned(this->content.get(), false); + + /** Icon */ + auto icon = RCManager::getInstance()->loadImage( + utils::getResourceFile("logo.png")); + this->setIcon(icon); + this->getPeer()->setIcon(icon); + + /** Resize */ + this->centreWithSize(800, 600); + juce::MessageManager::callAsync( + [comp = juce::Component::SafePointer(this)] { + if (comp) { + auto screenSize = utils::getScreenSize(comp); + int width = screenSize.getWidth() / 2; + int height = screenSize.getHeight() / 2; + + if (auto content = dynamic_cast( + comp->content->getViewedComponent())) { + auto size = content->getPreferedSize(); + width = std::min(width, size.getX()); + height = std::min(height, size.getY()); + } + + comp->centreWithSize(width, height); + } + } + ); +} + +void ChannelLinkView::paint(juce::Graphics& g) { + /** Color */ + auto& laf = this->getLookAndFeel(); + juce::Colour backgroundColor = laf.findColour( + juce::ResizableWindow::ColourIds::backgroundColourId); + + /** Background */ + g.setColour(backgroundColor); + g.fillAll(); +} + + +void ChannelLinkView::closeButtonPressed() { + this->exitModalState(); +} diff --git a/src/ui/component/ChannelLinkView.h b/src/ui/component/ChannelLinkView.h new file mode 100644 index 00000000..132cd0cf --- /dev/null +++ b/src/ui/component/ChannelLinkView.h @@ -0,0 +1,50 @@ +#pragma once + +#include + +class ChannelLinkViewContent final : public juce::Component { +public: + ChannelLinkViewContent() = delete; + ChannelLinkViewContent(const std::function& callback, + const juce::Array>& initList, + const juce::AudioChannelSet& srcChannels, const juce::AudioChannelSet& dstChannels, + int srcChannelNum, int dstChannelNum, const juce::String& srcName, const juce::String& dstName, + bool initIfEmpty); + + juce::Point getPreferedSize() const; + + void paint(juce::Graphics& g) override; + +private: + const std::function callback; + const juce::AudioChannelSet srcChannels, dstChannels; + const int srcChannelNum, dstChannelNum; + const juce::String srcName, dstName; + + juce::BigInteger temp; + + bool checkLink(int srcc, int dstc); + void setLink(int srcc, int dstc, bool link); + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ChannelLinkViewContent) +}; + +class ChannelLinkView final : public juce::DocumentWindow { +public: + ChannelLinkView() = delete; + ChannelLinkView(const std::function& callback, + const juce::Array>& initList, + const juce::AudioChannelSet& srcChannels, const juce::AudioChannelSet& dstChannels, + int srcChannelNum, int dstChannelNum, const juce::String& srcName, const juce::String& dstName, + bool initIfEmpty); + + void paint(juce::Graphics& g) override; + +private: + void closeButtonPressed() override; + +private: + std::unique_ptr content = nullptr; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ChannelLinkView) +}; diff --git a/src/ui/component/InstrIOComponent.cpp b/src/ui/component/InstrIOComponent.cpp index 30de933e..b65a6cb6 100644 --- a/src/ui/component/InstrIOComponent.cpp +++ b/src/ui/component/InstrIOComponent.cpp @@ -1,5 +1,6 @@ #include "InstrIOComponent.h" #include "../misc/DragSourceType.h" +#include "../misc/CoreActions.h" #include "../Utils.h" #include "../../audioCore/AC_API.h" @@ -108,14 +109,48 @@ void InstrIOComponent::showLinkMenu() { auto menu = this->createLinkMenu(); int result = menu.showAt(this); - /** TODO */ + if (this->isInput) { + if (result == InstrIOMenuType::Device) { + CoreActions::setInstrMIDIInputFromDevice(this->index, true); + } + else if (result >= InstrIOMenuType::NumBase) { + int src = result - InstrIOMenuType::NumBase; + CoreActions::setInstrMIDIInputFromSeqTrack(this->index, src, true); + } + } + else { + if (result >= InstrIOMenuType::NumBase) { + int track = result - InstrIOMenuType::NumBase; + + auto links = this->getOutputChannelLinks(track); + CoreActions::setInstrAudioOutputToMixerGUI( + this->index, track, true, links); + } + } } void InstrIOComponent::showUnlinkMenu() { auto menu = this->createUnlinkMenu(); int result = menu.showAt(this); - /** TODO */ + if (this->isInput) { + if (result == InstrIOMenuType::Device) { + CoreActions::setInstrMIDIInputFromDevice(this->index, false); + } + else if (result >= InstrIOMenuType::NumBase) { + int src = result - InstrIOMenuType::NumBase; + CoreActions::setInstrMIDIInputFromSeqTrack(this->index, src, false); + } + } + else { + if (result >= InstrIOMenuType::NumBase) { + int track = result - InstrIOMenuType::NumBase; + + auto links = this->getOutputChannelLinks(track); + CoreActions::setInstrAudioOutputToMixerGUI( + this->index, track, false, links); + } + } } juce::var InstrIOComponent::getDragSourceDescription() const { @@ -137,7 +172,8 @@ juce::PopupMenu InstrIOComponent::createLinkMenu() { juce::PopupMenu menu; if (this->isInput) { - menu.addItem(InstrIOMenuType::Device, TRANS("MIDI Input"), true, this->midiInputFromDevice); + menu.addItem(InstrIOMenuType::Device, TRANS("MIDI Input"), + !this->midiInputFromDevice, this->midiInputFromDevice); menu.addSeparator(); auto seqTracks = quickAPI::getSeqTrackNameList(); @@ -181,3 +217,13 @@ juce::PopupMenu InstrIOComponent::createUnlinkMenu() { return menu; } + +const juce::Array> InstrIOComponent::getOutputChannelLinks(int track) const { + juce::Array> result; + for (auto& [src, srcc, dst, dstc] : this->audioOutputToMixer) { + if ((src == this->index) && (dst == track)) { + result.add({ srcc, dstc }); + } + } + return result; +} diff --git a/src/ui/component/InstrIOComponent.h b/src/ui/component/InstrIOComponent.h index 8c7f74ac..020f91e1 100644 --- a/src/ui/component/InstrIOComponent.h +++ b/src/ui/component/InstrIOComponent.h @@ -34,6 +34,7 @@ class InstrIOComponent final : public juce::Component { juce::var getDragSourceDescription() const; juce::PopupMenu createLinkMenu(); juce::PopupMenu createUnlinkMenu(); + const juce::Array> getOutputChannelLinks(int track) const; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(InstrIOComponent) }; diff --git a/src/ui/lookAndFeel/ChannelLinkLookAndFeel.cpp b/src/ui/lookAndFeel/ChannelLinkLookAndFeel.cpp new file mode 100644 index 00000000..7715891d --- /dev/null +++ b/src/ui/lookAndFeel/ChannelLinkLookAndFeel.cpp @@ -0,0 +1,23 @@ +#include "ChannelLinkLookAndFeel.h" +#include "../misc/ColorMap.h" + +ChannelLinkLookAndFeel::ChannelLinkLookAndFeel() + : MainLookAndFeel() { + /** Background */ + this->setColour(juce::ResizableWindow::ColourIds::backgroundColourId, + ColorMap::getInstance()->get("ThemeColorB1")); + + /** Graph */ + this->setColour(juce::Label::ColourIds::backgroundColourId, + ColorMap::getInstance()->get("ThemeColorB1")); + this->setColour(juce::Label::ColourIds::textColourId, + ColorMap::getInstance()->get("ThemeColorB9"));/**< Channel Name */ + this->setColour(juce::Label::ColourIds::outlineColourId, + ColorMap::getInstance()->get("ThemeColorB9"));/**< Table Border */ + this->setColour(juce::Label::ColourIds::backgroundWhenEditingColourId, + ColorMap::getInstance()->get("ThemeColorB1"));/**< Link Background */ + this->setColour(juce::Label::ColourIds::textWhenEditingColourId, + ColorMap::getInstance()->get("ThemeColorB10"));/**< Title */ + this->setColour(juce::Label::ColourIds::outlineWhenEditingColourId, + ColorMap::getInstance()->get("ThemeColorA2"));/**< Link */ +} \ No newline at end of file diff --git a/src/ui/lookAndFeel/ChannelLinkLookAndFeel.h b/src/ui/lookAndFeel/ChannelLinkLookAndFeel.h new file mode 100644 index 00000000..c98e5e4b --- /dev/null +++ b/src/ui/lookAndFeel/ChannelLinkLookAndFeel.h @@ -0,0 +1,13 @@ +#pragma once + +#include +#include "MainLookAndFeel.h" + +class ChannelLinkLookAndFeel : public MainLookAndFeel { +public: + ChannelLinkLookAndFeel(); + +private: + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ChannelLinkLookAndFeel) +}; + diff --git a/src/ui/lookAndFeel/LookAndFeelFactory.cpp b/src/ui/lookAndFeel/LookAndFeelFactory.cpp index c9abaf58..a777d6c1 100644 --- a/src/ui/lookAndFeel/LookAndFeelFactory.cpp +++ b/src/ui/lookAndFeel/LookAndFeelFactory.cpp @@ -12,6 +12,7 @@ #include "SourceViewLookAndFeel.h" #include "InstrViewLookAndFeel.h" #include "PluginEditorLookAndFeel.h" +#include "ChannelLinkLookAndFeel.h" #include "../misc/ColorMap.h" #include @@ -82,6 +83,9 @@ void LookAndFeelFactory::initialise() { /** Plugin Editor */ this->pluginEditorLAF = std::make_unique(); + + /** Channel Link */ + this->channelLinkLAF = std::make_unique(); } void LookAndFeelFactory::setDefaultSansSerifTypeface(juce::Typeface::Ptr typeface) { @@ -137,6 +141,10 @@ juce::LookAndFeel_V4* LookAndFeelFactory::forPluginEditor() const { return this->pluginEditorLAF.get(); } +juce::LookAndFeel_V4* LookAndFeelFactory::forChannelLink() const { + return this->channelLinkLAF.get(); +} + LookAndFeelFactory* LookAndFeelFactory::getInstance() { return LookAndFeelFactory::instance ? LookAndFeelFactory::instance : (LookAndFeelFactory::instance = new LookAndFeelFactory{}); diff --git a/src/ui/lookAndFeel/LookAndFeelFactory.h b/src/ui/lookAndFeel/LookAndFeelFactory.h index 76afa431..83dbb28a 100644 --- a/src/ui/lookAndFeel/LookAndFeelFactory.h +++ b/src/ui/lookAndFeel/LookAndFeelFactory.h @@ -21,6 +21,7 @@ class LookAndFeelFactory final : private juce::DeletedAtShutdown { juce::LookAndFeel_V4* forSourceView() const; juce::LookAndFeel_V4* forInstrView() const; juce::LookAndFeel_V4* forPluginEditor() const; + juce::LookAndFeel_V4* forChannelLink() const; private: std::unique_ptr mainLAF = nullptr; @@ -36,6 +37,7 @@ class LookAndFeelFactory final : private juce::DeletedAtShutdown { std::unique_ptr sourceViewLAF = nullptr; std::unique_ptr instrViewLAF = nullptr; std::unique_ptr pluginEditorLAF = nullptr; + std::unique_ptr channelLinkLAF = nullptr; public: static LookAndFeelFactory* getInstance(); diff --git a/src/ui/misc/CoreActions.cpp b/src/ui/misc/CoreActions.cpp index 7d3a44b8..3f686fef 100644 --- a/src/ui/misc/CoreActions.cpp +++ b/src/ui/misc/CoreActions.cpp @@ -1,4 +1,5 @@ #include "CoreActions.h" +#include "../component/ChannelLinkView.h" #include "../dataModel/TrackListBoxModel.h" #include "../Utils.h" #include "../../audioCore/AC_API.h" @@ -219,6 +220,29 @@ void CoreActions::removeInstrParamCCLink(quickAPI::PluginHolder instr, int ccCha CoreActions::setInstrParamCCLink(instr, -1, ccChannel); } +void CoreActions::setInstrMIDIInputFromDevice(int index, bool input) { + auto action = input + ? std::unique_ptr(new ActionAddInstrMidiInput{ index }) + : std::unique_ptr(new ActionRemoveInstrMidiInput{ index }); + ActionDispatcher::getInstance()->dispatch(std::move(action)); +} + +void CoreActions::setInstrMIDIInputFromSeqTrack( + int index, int seqIndex, bool input) { + auto action = input + ? std::unique_ptr(new ActionAddSequencerTrackMidiOutputToInstr{ seqIndex, index }) + : std::unique_ptr(new ActionRemoveSequencerTrackMidiOutputToInstr{ seqIndex, index }); + ActionDispatcher::getInstance()->dispatch(std::move(action)); +} + +void CoreActions::setInstrAudioOutputToMixer( + int index, int channel, int mixerTrack, int mixerChannel, bool input) { + auto action = input + ? std::unique_ptr(new ActionAddInstrOutput{ index, channel, mixerTrack, mixerChannel }) + : std::unique_ptr(new ActionRemoveInstrOutput{ index, channel, mixerTrack, mixerChannel }); + ActionDispatcher::getInstance()->dispatch(std::move(action)); +} + void CoreActions::bypassEffect(quickAPI::PluginHolder effect, bool bypass) { auto action = std::unique_ptr( new ActionSetEffectBypassByPtr{ effect, bypass }); @@ -583,6 +607,37 @@ void CoreActions::addInstrParamCCLinkGUI(quickAPI::PluginHolder instr) { CoreActions::askForPluginParamGUIAsync(callback, instr, PluginType::Instr); } +void CoreActions::setInstrAudioOutputToMixerGUI(int index, int track, bool output, + const juce::Array>& links) { + /** Callback */ + auto callback = [index, track](int srcc, int dstc, bool output) { + CoreActions::setInstrAudioOutputToMixer(index, srcc, track, dstc, output); + }; + + /** Remove */ + if (!output) { + for (auto& [srcc, dstc] : links) { + callback(srcc, dstc, false); + } + return; + } + + /** Name */ + juce::String instrName = TRANS("Instrument") + " #" + juce::String{ index } + " " + quickAPI::getInstrName(index); + juce::String trackName = TRANS("Mixer Track") + " #" + juce::String{ track } + " " + quickAPI::getMixerTrackName(track); + + /** Channels */ + auto instrChannelSet = quickAPI::getInstrChannelSet(index); + auto trackChannelSet = quickAPI::getMixerTrackChannelSet(track); + int instrTotalChannels = quickAPI::getInstrOutputChannelNum(index); + int trackTotalChannels = quickAPI::getMixerTrackInputChannelNum(track); + + /** Ask For Channels */ + CoreActions::askForAudioChannelLinkGUIAsync(callback, links, + instrChannelSet, trackChannelSet, instrTotalChannels, trackTotalChannels, + instrName, trackName, true); +} + void CoreActions::editEffectParamCCLinkGUI(quickAPI::PluginHolder effect, int paramIndex, int defaultCC) { auto callback = [effect, paramIndex](int cc) { CoreActions::setEffectParamCCLink(effect, paramIndex, cc); }; @@ -1021,3 +1076,19 @@ void CoreActions::askForPluginMIDICCGUIAsync( } ), true); } + +void CoreActions::askForAudioChannelLinkGUIAsync( + const std::function& callback, + const juce::Array>& initList, + const juce::AudioChannelSet& srcChannels, const juce::AudioChannelSet& dstChannels, + int srcChannelNum, int dstChannelNum, const juce::String& srcName, const juce::String& dstName, + bool initIfEmpty) { + /** Create Editor */ + auto editor = new ChannelLinkView{ + callback, initList, srcChannels, dstChannels, + srcChannelNum, dstChannelNum, srcName, dstName, initIfEmpty }; + + /** Show Selector Async */ + editor->enterModalState(true, juce::ModalCallbackFunction::create( + [](int /*result*/) {}), true); +} diff --git a/src/ui/misc/CoreActions.h b/src/ui/misc/CoreActions.h index 5debfe59..fcb11e35 100644 --- a/src/ui/misc/CoreActions.h +++ b/src/ui/misc/CoreActions.h @@ -55,6 +55,9 @@ class CoreActions final { static void setInstrMIDIOutput(quickAPI::PluginHolder instr, bool output); static void setInstrParamCCLink(quickAPI::PluginHolder instr, int paramIndex, int ccChannel); static void removeInstrParamCCLink(quickAPI::PluginHolder instr, int ccChannel); + static void setInstrMIDIInputFromDevice(int index, bool input); + static void setInstrMIDIInputFromSeqTrack(int index, int seqIndex, bool input); + static void setInstrAudioOutputToMixer(int index, int channel, int mixerTrack, int mixerChannel, bool input); static void bypassEffect(quickAPI::PluginHolder effect, bool bypass); static void setEffectMIDIChannel(quickAPI::PluginHolder effect, int channel); @@ -97,6 +100,8 @@ class CoreActions final { static void insertInstrGUI(); static void editInstrParamCCLinkGUI(quickAPI::PluginHolder instr, int paramIndex, int defaultCC = -1); static void addInstrParamCCLinkGUI(quickAPI::PluginHolder instr); + static void setInstrAudioOutputToMixerGUI(int index, int track, bool output, + const juce::Array>& links); static void editEffectParamCCLinkGUI(quickAPI::PluginHolder effect, int paramIndex, int defaultCC = -1); static void addEffectParamCCLinkGUI(quickAPI::PluginHolder effect); @@ -124,4 +129,10 @@ class CoreActions final { const std::function& callback, quickAPI::PluginHolder plugin, PluginType type, int defaultCCChannel = -1); + static void askForAudioChannelLinkGUIAsync( + const std::function& callback, + const juce::Array>& initList, + const juce::AudioChannelSet& srcChannels, const juce::AudioChannelSet& dstChannels, + int srcChannelNum, int dstChannelNum, const juce::String& srcName, const juce::String& dstName, + bool initIfEmpty); };