26 "Translation (scale)",
35 { -juce::MathConstants<float>::pi, juce::MathConstants<float>::pi },
44 "/umsci/indicator/rot",
45 "/umsci/indicator/trans",
46 "/umsci/indicator/heighttrans",
47 "/umsci/indicator/anglestretch",
48 "/umsci/indicator/offsetx",
49 "/umsci/indicator/offsety"
56 public juce::ComboBox::Listener
61 m_midiDeviceLabel = std::make_unique<juce::Label>();
62 m_midiDeviceLabel->setText(
"MIDI input device:", juce::dontSendNotification);
63 addAndMakeVisible(m_midiDeviceLabel.get());
65 m_midiDeviceCombo = std::make_unique<juce::ComboBox>();
66 m_midiDeviceCombo->addListener(
this);
67 addAndMakeVisible(m_midiDeviceCombo.get());
69 updateAvailableMidiInputDevices();
73 m_paramLabels[i] = std::make_unique<juce::Label>();
75 juce::dontSendNotification);
76 addAndMakeVisible(m_paramLabels[i].get());
78 m_learners[i] = std::make_unique<JUCEAppBasics::MidiLearnerComponent>(
79 static_cast<std::int16_t
>(i),
80 JUCEAppBasics::MidiLearnerComponent::AT_ValueRange | JUCEAppBasics::MidiLearnerComponent::AT_CommandRange);
82 m_learners[i]->onMidiAssiSet = [
this, i](juce::Component*,
const JUCEAppBasics::MidiCommandRangeAssignment& assi) {
87 addAndMakeVisible(m_learners[i].get());
93 constexpr int margin = 10;
94 constexpr int rowHeight = 28;
95 constexpr int rowGap = 4;
96 constexpr int labelWidth = 140;
98 auto bounds = getLocalBounds().reduced(margin);
100 auto deviceRow = bounds.removeFromTop(rowHeight);
101 m_midiDeviceLabel->setBounds(deviceRow.removeFromLeft(labelWidth));
102 m_midiDeviceCombo->setBounds(deviceRow);
104 bounds.removeFromTop(rowGap + 4);
108 if (i > 0) bounds.removeFromTop(rowGap);
109 auto row = bounds.removeFromTop(rowHeight);
110 m_paramLabels[i]->setBounds(row.removeFromLeft(labelWidth));
111 m_learners[i]->setBounds(row);
117 if (cb != m_midiDeviceCombo.get())
120 auto it = m_midiInputDeviceIdentifiers.find(m_midiDeviceCombo->getSelectedId());
121 if (it == m_midiInputDeviceIdentifiers.end())
124 m_currentDeviceIdentifier = it->second;
127 m_learners[i]->setSelectedDeviceIdentifier(m_currentDeviceIdentifier);
135 m_currentDeviceIdentifier = identifier;
137 for (
auto& [
id, devId] : m_midiInputDeviceIdentifiers)
139 if (devId == identifier)
141 m_midiDeviceCombo->setSelectedId(
id, juce::dontSendNotification);
147 m_learners[i]->setSelectedDeviceIdentifier(identifier);
152 return m_currentDeviceIdentifier;
155 void setMidiAssi(
int param,
const JUCEAppBasics::MidiCommandRangeAssignment& assi)
157 m_learners[param]->setCurrentMidiAssi(assi);
160 const JUCEAppBasics::MidiCommandRangeAssignment&
getMidiAssi(
int param)
const
162 return m_learners[param]->getCurrentMidiAssi();
166 void updateAvailableMidiInputDevices()
168 m_midiInputDeviceIdentifiers.clear();
169 m_midiDeviceCombo->clear(juce::dontSendNotification);
172 m_midiDeviceCombo->addItem(
"None", itemId);
173 m_midiInputDeviceIdentifiers[itemId] = {};
176 for (
auto& device : juce::MidiInput::getAvailableDevices())
178 m_midiDeviceCombo->addItem(device.name, itemId);
179 m_midiInputDeviceIdentifiers[itemId] = device.identifier;
183 m_midiDeviceCombo->setSelectedId(1, juce::dontSendNotification);
188 std::unique_ptr<juce::Label> m_midiDeviceLabel;
189 std::unique_ptr<juce::ComboBox> m_midiDeviceCombo;
190 std::map<int, juce::String> m_midiInputDeviceIdentifiers;
195 juce::String m_currentDeviceIdentifier;
206 m_oscPortLabel = std::make_unique<juce::Label>();
207 m_oscPortLabel->setText(
"OSC listen port:", juce::dontSendNotification);
208 addAndMakeVisible(m_oscPortLabel.get());
210 m_oscPortEditor = std::make_unique<juce::TextEditor>();
211 m_oscPortEditor->setText(
"0", juce::dontSendNotification);
212 m_oscPortEditor->setInputRestrictions(5,
"0123456789");
213 m_oscPortEditor->onReturnKey = [
this] { notifyPortChanged(); };
214 m_oscPortEditor->onFocusLost = [
this] { notifyPortChanged(); };
215 addAndMakeVisible(m_oscPortEditor.get());
219 m_oscParamLabels[i] = std::make_unique<juce::Label>();
221 juce::dontSendNotification);
222 addAndMakeVisible(m_oscParamLabels[i].get());
224 m_oscAddrEditors[i] = std::make_unique<juce::TextEditor>();
226 juce::dontSendNotification);
228 m_oscAddrEditors[i]->onReturnKey = [
this, idx] { notifyAddrChanged(idx); };
229 m_oscAddrEditors[i]->onFocusLost = [
this, idx] { notifyAddrChanged(idx); };
230 addAndMakeVisible(m_oscAddrEditors[i].get());
236 constexpr int margin = 10;
237 constexpr int rowHeight = 28;
238 constexpr int rowGap = 4;
239 constexpr int labelWidth = 140;
241 auto bounds = getLocalBounds().reduced(margin);
243 auto portRow = bounds.removeFromTop(rowHeight);
244 m_oscPortLabel->setBounds(portRow.removeFromLeft(labelWidth));
245 m_oscPortEditor->setBounds(portRow);
247 bounds.removeFromTop(rowGap + 4);
251 if (i > 0) bounds.removeFromTop(rowGap);
252 auto row = bounds.removeFromTop(rowHeight);
253 m_oscParamLabels[i]->setBounds(row.removeFromLeft(labelWidth));
254 m_oscAddrEditors[i]->setBounds(row);
260 m_oscPortEditor->setText(juce::String(port), juce::dontSendNotification);
265 return m_oscPortEditor->getText().getIntValue();
270 m_oscAddrEditors[param]->setText(address, juce::dontSendNotification);
275 return m_oscAddrEditors[param]->getText();
279 void notifyPortChanged()
285 void notifyAddrChanged(
int idx)
290 m_oscAddrEditors[idx]->getText());
295 std::unique_ptr<juce::Label> m_oscPortLabel;
296 std::unique_ptr<juce::TextEditor> m_oscPortEditor;
307 m_tabs = std::make_unique<juce::TabbedComponent>(juce::TabbedButtonBar::TabsAtTop);
309 auto midiTabOwned = std::make_unique<MidiTab>(*
this);
310 m_midiTab = midiTabOwned.get();
312 auto oscTabOwned = std::make_unique<OscTab>(*
this);
313 m_oscTab = oscTabOwned.get();
315 auto bgColour = getLookAndFeel().findColour(juce::ResizableWindow::backgroundColourId);
316 m_tabs->addTab(
"MIDI", bgColour, midiTabOwned.release(),
true);
317 m_tabs->addTab(
"OSC", bgColour, oscTabOwned.release(),
true);
319 addAndMakeVisible(m_tabs.get());
330 m_tabs->setBounds(getLocalBounds());
346 const JUCEAppBasics::MidiCommandRangeAssignment& assi)
348 m_midiTab->
setMidiAssi(
static_cast<int>(param), assi);
353 return m_midiTab->
getMidiAssi(
static_cast<int>(param));
370 m_oscTab->
setOscAddr(
static_cast<int>(param), address);
375 return m_oscTab->
getOscAddr(
static_cast<int>(param));
MidiTab(UmsciExternalControlComponent &owner)
const JUCEAppBasics::MidiCommandRangeAssignment & getMidiAssi(int param) const
void setMidiInputDeviceIdentifier(const juce::String &identifier)
void setMidiAssi(int param, const JUCEAppBasics::MidiCommandRangeAssignment &assi)
void comboBoxChanged(juce::ComboBox *cb) override
const juce::String & getMidiInputDeviceIdentifier() const
void setOscAddr(int param, const juce::String &address)
OscTab(UmsciExternalControlComponent &owner)
int getOscInputPort() const
juce::String getOscAddr(int param) const
void setOscInputPort(int port)
Settings panel for MIDI- and OSC-based external control of the six upmix transform parameters (rotati...
~UmsciExternalControlComponent() override
std::function< void(UpmixMidiParam, JUCEAppBasics::MidiCommandRangeAssignment)> onMidiAssiChanged
std::function< void(int)> onOscInputPortChanged
static const juce::String s_oscDefaultAddresses[UpmixMidiParam_COUNT]
Default OSC address for each parameter, indexed by UpmixMidiParam.
void setOscInputPort(int port)
void setMidiAssi(UpmixMidiParam param, const JUCEAppBasics::MidiCommandRangeAssignment &assi)
static const juce::String s_paramLabels[UpmixMidiParam_COUNT]
Human-readable parameter labels shared by both tabs.
static const std::array< std::pair< float, float >, UpmixMidiParam_COUNT > s_paramRanges
Natural parameter ranges for normalised MIDI→domain mapping. Indexed by UpmixMidiParam.
const juce::String & getMidiInputDeviceIdentifier() const
const JUCEAppBasics::MidiCommandRangeAssignment & getMidiAssi(UpmixMidiParam param) const
UpmixMidiParam
Identifies each controllable upmix transform parameter.
int getOscInputPort() const
juce::String getOscAddr(UpmixMidiParam param) const
void setOscAddr(UpmixMidiParam param, const juce::String &address)
std::function< void(const juce::String &)> onMidiInputDeviceChanged
UmsciExternalControlComponent()
std::function< void(UpmixMidiParam, juce::String)> onOscAddrChanged
void setMidiInputDeviceIdentifier(const juce::String &identifier)