Skip to content

Commit

Permalink
Add ChannelLinkView
Browse files Browse the repository at this point in the history
  • Loading branch information
FangCunWuChang committed Jan 28, 2024
1 parent 52200c9 commit 43f10ba
Show file tree
Hide file tree
Showing 16 changed files with 428 additions and 3 deletions.
1 change: 1 addition & 0 deletions app/translates/zh-CN/alert.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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?" = "放弃未保存的更改并继续?"
Expand Down
1 change: 1 addition & 0 deletions app/translates/zh-CN/main.txt
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,4 @@ countries: cn
"MIDI Input" = "MIDI输入"
"Sequencer Track" = "音序器轨道"
"Mixer Track" = "混音器轨道"
"Channel Link" = "通道连接"
4 changes: 4 additions & 0 deletions src/audioCore/graph/PluginDecorator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions src/audioCore/graph/PluginDecorator.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ class PluginDecorator final : public juce::AudioProcessor,
void setPlugin(
std::unique_ptr<juce::AudioPluginInstance> plugin, const juce::String& pluginIdentifier);

const juce::AudioChannelSet& getAudioChannelSet() const;

bool canPluginAddBus(bool isInput) const;
bool canPluginRemoveBus(bool isInput) const;

Expand Down
54 changes: 54 additions & 0 deletions src/audioCore/quickAPI/QuickGet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down Expand Up @@ -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);
}
Expand Down
6 changes: 6 additions & 0 deletions src/audioCore/quickAPI/QuickGet.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ namespace quickAPI {
bool getInstrMIDIInputFromDevice(int index);
const juce::Array<MIDILink> getInstrMIDIInputFromSource(int index);
const juce::Array<AudioLink> 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);
Expand Down Expand Up @@ -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();
Expand Down
132 changes: 132 additions & 0 deletions src/ui/component/ChannelLinkView.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#include "ChannelLinkView.h"
#include "../lookAndFeel/LookAndFeelFactory.h"
#include "../misc/RCManager.h"
#include "../Utils.h"

ChannelLinkViewContent::ChannelLinkViewContent(
const std::function<void(int, int, bool)>& callback,
const juce::Array<std::tuple<int, int>>& 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<int> 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<void(int, int, bool)>& callback,
const juce::Array<std::tuple<int, int>>& 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<juce::Viewport>(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<ChannelLinkViewContent*>(
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();
}
50 changes: 50 additions & 0 deletions src/ui/component/ChannelLinkView.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#pragma once

#include <JuceHeader.h>

class ChannelLinkViewContent final : public juce::Component {
public:
ChannelLinkViewContent() = delete;
ChannelLinkViewContent(const std::function<void(int, int, bool)>& callback,
const juce::Array<std::tuple<int, int>>& 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<int> getPreferedSize() const;

void paint(juce::Graphics& g) override;

private:
const std::function<void(int, int, bool)> 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<void(int, int, bool)>& callback,
const juce::Array<std::tuple<int, int>>& 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<juce::Viewport> content = nullptr;

JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ChannelLinkView)
};
52 changes: 49 additions & 3 deletions src/ui/component/InstrIOComponent.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "InstrIOComponent.h"
#include "../misc/DragSourceType.h"
#include "../misc/CoreActions.h"
#include "../Utils.h"
#include "../../audioCore/AC_API.h"

Expand Down Expand Up @@ -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 {
Expand All @@ -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();
Expand Down Expand Up @@ -181,3 +217,13 @@ juce::PopupMenu InstrIOComponent::createUnlinkMenu() {

return menu;
}

const juce::Array<std::tuple<int, int>> InstrIOComponent::getOutputChannelLinks(int track) const {
juce::Array<std::tuple<int, int>> result;
for (auto& [src, srcc, dst, dstc] : this->audioOutputToMixer) {
if ((src == this->index) && (dst == track)) {
result.add({ srcc, dstc });
}
}
return result;
}
1 change: 1 addition & 0 deletions src/ui/component/InstrIOComponent.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class InstrIOComponent final : public juce::Component {
juce::var getDragSourceDescription() const;
juce::PopupMenu createLinkMenu();
juce::PopupMenu createUnlinkMenu();
const juce::Array<std::tuple<int, int>> getOutputChannelLinks(int track) const;

JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(InstrIOComponent)
};
Loading

0 comments on commit 43f10ba

Please sign in to comment.