commit 2fccfd62984d6bb416458de95074de15d4ad9ef1
parent e0d23b53fe12e463d846d2f75025cd03934e8830
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date: Fri, 9 Aug 2024 19:09:29 +0200
Merge branch 'oss/main' into priv/n2x
# Conflicts:
# doc/changelog.txt
# source/jucePluginLib/midiports.cpp
# source/jucePluginLib/midiports.h
Diffstat:
6 files changed, 94 insertions(+), 9 deletions(-)
diff --git a/doc/changelog.txt b/doc/changelog.txt
@@ -17,6 +17,10 @@ NodalRed2x:
- [Fix] Do not attempt to boot a rom that is not for N2x
+Vavra:
+
+- [Imp] Physical MIDI in/out can now be selected via global context menu
+
Xenia:
- [Fix] Do not expose parameters for parts 9-16 as the machine only has 8
diff --git a/source/jucePluginEditorLib/midiPorts.cpp b/source/jucePluginEditorLib/midiPorts.cpp
@@ -6,11 +6,13 @@
namespace
{
+ constexpr const char* const g_none = "<none>";
+
void initComboBox(juce::ComboBox* _combo, const juce::Array<juce::MidiDeviceInfo>& _entries, const juce::String& _selectedEntry)
{
int inIndex = 0;
- _combo->addItem("<none>", 1);
+ _combo->addItem(g_none, 1);
for (int i = 0; i < _entries.size(); i++)
{
@@ -24,30 +26,76 @@ namespace
_combo->setSelectedItemIndex(inIndex, juce::dontSendNotification);
}
+
+ uint32_t createMenu(juce::PopupMenu& _menu, const juce::Array<juce::MidiDeviceInfo>& _devices, const juce::String& _current, const std::function<void(juce::String)>& _onSelect)
+ {
+ _menu.addItem(g_none, true, _current.isEmpty(), [_onSelect]
+ {
+ _onSelect({});
+ });
+
+ for (const auto& device : _devices)
+ {
+ _menu.addItem(device.name, true, device.identifier == _current, [id = device.identifier, _onSelect]
+ {
+ _onSelect(id);
+ });
+ }
+ return _devices.size();
+ }
}
namespace jucePluginEditorLib
{
MidiPorts::MidiPorts(const genericUI::Editor& _editor, Processor& _processor) : m_processor(_processor)
{
- m_midiIn = _editor.findComponentT<juce::ComboBox>("MidiIn", false);
+ m_midiIn = _editor.findComponentT<juce::ComboBox>("MidiIn" , false);
m_midiOut = _editor.findComponentT<juce::ComboBox>("MidiOut", false);
if(m_midiIn)
{
- const auto* in = getMidiPorts().getMidiInput();
- initComboBox(m_midiIn, juce::MidiInput::getAvailableDevices(), in != nullptr ? in->getIdentifier() : juce::String());
+ initComboBox(m_midiIn, juce::MidiInput::getAvailableDevices(), getMidiPorts().getInputId());
m_midiIn->onChange = [this]{ updateMidiInput(m_midiIn->getSelectedItemIndex()); };
}
if(m_midiOut)
{
- const auto* out = getMidiPorts().getMidiOutput();
- initComboBox(m_midiOut, juce::MidiOutput::getAvailableDevices(), out != nullptr ? out->getIdentifier() : juce::String());
+ initComboBox(m_midiOut, juce::MidiOutput::getAvailableDevices(), getMidiPorts().getOutputId());
m_midiOut->onChange = [this]{ updateMidiOutput(m_midiOut->getSelectedItemIndex()); };
}
}
+ void MidiPorts::createMidiInputMenu(juce::PopupMenu& _menu, pluginLib::MidiPorts& _ports)
+ {
+ createMenu(_menu, juce::MidiInput::getAvailableDevices(), _ports.getInputId(), [&_ports](const juce::String& _id)
+ {
+ if(!_ports.setMidiInput(_id))
+ showMidiPortFailedMessage(_ports.getProcessor(), "Input");
+ });
+ }
+
+ void MidiPorts::createMidiOutputMenu(juce::PopupMenu& _menu, pluginLib::MidiPorts& _ports)
+ {
+ createMenu(_menu, juce::MidiOutput::getAvailableDevices(), _ports.getOutputId(), [&_ports](const juce::String& _id)
+ {
+ if(!_ports.setMidiOutput(_id))
+ showMidiPortFailedMessage(_ports.getProcessor(), "Output");
+ });
+ }
+
+ void MidiPorts::createMidiPortsMenu(juce::PopupMenu& _menu, pluginLib::MidiPorts& _ports)
+ {
+ juce::PopupMenu inputs, outputs, ports;
+
+ createMidiInputMenu(inputs, _ports);
+ createMidiOutputMenu(outputs, _ports);
+
+ ports.addSubMenu("Input", inputs);
+ ports.addSubMenu("Output", outputs);
+
+ _menu.addSubMenu("MIDI Ports", ports);
+ }
+
pluginLib::MidiPorts& MidiPorts::getMidiPorts() const
{
return m_processor.getMidiPorts();
@@ -55,7 +103,12 @@ namespace jucePluginEditorLib
void MidiPorts::showMidiPortFailedMessage(const char* _name) const
{
- juce::NativeMessageBox::showMessageBoxAsync(juce::MessageBoxIconType::WarningIcon, m_processor.getProperties().name,
+ showMidiPortFailedMessage(m_processor, _name);
+ }
+
+ void MidiPorts::showMidiPortFailedMessage(const pluginLib::Processor& _processor, const char* _name)
+ {
+ juce::NativeMessageBox::showMessageBoxAsync(juce::MessageBoxIconType::WarningIcon, _processor.getProperties().name,
std::string("Failed to open Midi ") + _name + ".\n\n"
"Make sure that the device is not already in use by another program.", nullptr, juce::ModalCallbackFunction::create([](int){}));
}
diff --git a/source/jucePluginEditorLib/midiPorts.h b/source/jucePluginEditorLib/midiPorts.h
@@ -2,6 +2,7 @@
namespace pluginLib
{
+ class Processor;
class MidiPorts;
}
@@ -12,6 +13,7 @@ namespace genericUI
namespace juce
{
+ class PopupMenu;
struct MidiDeviceInfo;
class String;
class AudioDeviceManager;
@@ -27,10 +29,16 @@ namespace jucePluginEditorLib
public:
explicit MidiPorts(const genericUI::Editor& _editor, Processor& _processor);
+ static void createMidiInputMenu(juce::PopupMenu& _menu, pluginLib::MidiPorts&);
+ static void createMidiOutputMenu(juce::PopupMenu& _menu, pluginLib::MidiPorts&);
+ static void createMidiPortsMenu(juce::PopupMenu& _menu, pluginLib::MidiPorts&);
+
private:
pluginLib::MidiPorts& getMidiPorts() const;
void showMidiPortFailedMessage(const char* _name) const;
+ static void showMidiPortFailedMessage(const pluginLib::Processor& _processor, const char* _name);
+
void updateMidiInput(int _index) const;
void updateMidiOutput(int _index) const;
diff --git a/source/jucePluginLib/midiports.cpp b/source/jucePluginLib/midiports.cpp
@@ -28,6 +28,16 @@ namespace pluginLib
return m_midiInput.get();
}
+ juce::String MidiPorts::getInputId() const
+ {
+ return getMidiInput() != nullptr ? getMidiInput()->getIdentifier() : juce::String();
+ }
+
+ juce::String MidiPorts::getOutputId() const
+ {
+ return getMidiOutput() != nullptr ? getMidiOutput()->getIdentifier() : juce::String();
+ }
+
void MidiPorts::saveChunkData(baseLib::BinaryStream& _binaryStream) const
{
baseLib::ChunkWriter cw(_binaryStream, "mpIO", 1);
diff --git a/source/jucePluginLib/midiports.h b/source/jucePluginLib/midiports.h
@@ -31,11 +31,17 @@ namespace pluginLib
MidiPorts& operator = (const MidiPorts&) = delete;
MidiPorts& operator = (MidiPorts&&) = delete;
- bool setMidiOutput(const juce::String& _out);
+ auto& getProcessor() const { return m_processor; }
+
juce::MidiOutput* getMidiOutput() const;
- bool setMidiInput(const juce::String& _in);
juce::MidiInput* getMidiInput() const;
+ bool setMidiOutput(const juce::String& _out);
+ bool setMidiInput(const juce::String& _in);
+
+ juce::String getInputId() const;
+ juce::String getOutputId() const;
+
void saveChunkData(baseLib::BinaryStream& _binaryStream) const;
void loadChunkData(baseLib::ChunkReader& _cr);
diff --git a/source/mqJucePlugin/PluginEditorState.cpp b/source/mqJucePlugin/PluginEditorState.cpp
@@ -3,6 +3,8 @@
#include "mqEditor.h"
#include "PluginProcessor.h"
+#include "jucePluginEditorLib/midiPorts.h"
+
#include "synthLib/os.h"
const std::vector<PluginEditorState::Skin> g_includedSkins =
@@ -31,6 +33,8 @@ void PluginEditorState::initContextMenu(juce::PopupMenu& _menu)
gainMenu.addItem("+12 dB", true, gain == 4, [&p] { p.setOutputGain(4); });
_menu.addSubMenu("Output Gain", gainMenu);
+
+ jucePluginEditorLib::MidiPorts::createMidiPortsMenu(_menu, p.getMidiPorts());
}
bool PluginEditorState::initAdvancedContextMenu(juce::PopupMenu& _menu, bool _enabled)