Umsci
Upmix Spatial Control Interface — OCA/OCP.1 spatial audio utility
Loading...
Searching...
No Matches
MidiController.cpp
Go to the documentation of this file.
1/* Copyright (c) 2026, Christian Ahrens
2 *
3 * This file is part of Umsci <https://github.com/ChristianAhrens/Umsci>
4 *
5 * This tool is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU Lesser General Public License version 3.0 as published
7 * by the Free Software Foundation.
8 *
9 * This tool is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12 * details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this tool; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19#include "MidiController.h"
20
21
23
25{
26 if (m_midiInput)
27 {
28 m_midiInput->stop();
29 m_midiInput.reset();
30 }
31}
32
33void MidiController::openDevice(const juce::String& deviceIdentifier)
34{
35 if (m_deviceIdentifier == deviceIdentifier && m_midiInput != nullptr)
36 return;
37
38 if (m_midiInput)
39 {
40 m_midiInput->stop();
41 m_midiInput.reset();
42 }
43
44 m_deviceIdentifier = deviceIdentifier;
45
46 if (deviceIdentifier.isNotEmpty())
47 {
48 m_midiInput = juce::MidiInput::openDevice(deviceIdentifier, this);
49 if (m_midiInput)
50 m_midiInput->start();
51 }
52}
53
55 const JUCEAppBasics::MidiCommandRangeAssignment& assi)
56{
57 m_assignments[static_cast<int>(param)] = assi;
58}
59
60const JUCEAppBasics::MidiCommandRangeAssignment& MidiController::getAssignment(
62{
63 return m_assignments[static_cast<int>(param)];
64}
65
66void MidiController::handleIncomingMidiMessage(juce::MidiInput*, const juce::MidiMessage& message)
67{
68 // Called on the MIDI thread — copy the message and dispatch to the message thread.
69 auto msgCopy = message;
70 juce::MessageManager::callAsync([this, msgCopy]() {
72 {
73 auto& assi = m_assignments[i];
74 if (assi.getCommandType() == JUCEAppBasics::MidiCommandRangeAssignment::CT_Invalid)
75 continue;
76 if (!assi.isMatchingCommand(msgCopy) && !assi.isMatchingCommandRange(msgCopy))
77 continue;
78 if (!assi.isMatchingValueRange(msgCopy) && !assi.isMatchingCommandRange(msgCopy))
79 continue;
80
81 float normalised = 0.5f;
82 if (assi.isValueRangeAssignment())
83 {
84 auto range = assi.getValueRange();
85 auto val = JUCEAppBasics::MidiCommandRangeAssignment::getValue(msgCopy);
86 if (range.getLength() > 0)
87 normalised = juce::jlimit(0.0f, 1.0f,
88 float(val - range.getStart()) / float(range.getLength()));
89 }
90
91 auto [minVal, maxVal] = UmsciExternalControlComponent::s_paramRanges[i];
92 auto domainValue = minVal + normalised * (maxVal - minVal);
93
96 domainValue);
97 }
98 });
99}
void setAssignment(UmsciExternalControlComponent::UpmixMidiParam param, const JUCEAppBasics::MidiCommandRangeAssignment &assi)
void openDevice(const juce::String &deviceIdentifier)
std::function< void(UmsciExternalControlComponent::UpmixMidiParam, float)> onParamValueChanged
const JUCEAppBasics::MidiCommandRangeAssignment & getAssignment(UmsciExternalControlComponent::UpmixMidiParam param) const
~MidiController() override
static const std::array< std::pair< float, float >, UpmixMidiParam_COUNT > s_paramRanges
Natural parameter ranges for normalised MIDI→domain mapping. Indexed by UpmixMidiParam.
UpmixMidiParam
Identifies each controllable upmix transform parameter.