Umsci
Upmix Spatial Control Interface — OCA/OCP.1 spatial audio utility
Loading...
Searching...
No Matches
UmsciUpmixIndicatorPaintNControlComponent.h
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#pragma once
20
21#include <JuceHeader.h>
22
24
25#include <TwoDFieldBase.h>
26
94class UmsciUpmixIndicatorPaintNControlComponent : public UmsciPaintNControlComponentBase, public JUCEAppBasics::TwoDFieldBase, public juce::Timer
95{
96public:
99 static juce::String getShapeName(IndicatorShape shape)
100 {
101 switch (shape)
102 {
104 return "Rectangle";
106 default:
107 return "Circle";
108 }
109 }
110 static IndicatorShape getShapeForName(const juce::String& name)
111 {
112 if (name == "Rectangle")
114 else if (name == "Circle")
116
117 jassertfalse; // unknown string passed as name
119 }
120
123
124 //==============================================================================
125 void paint(Graphics&) override;
126 void resized() override;
127 void setControlsSize(ControlsSize size) override;
128 bool hitTest(int x, int y) override;
129 void mouseDown(const juce::MouseEvent&) override;
130 void mouseDrag(const juce::MouseEvent&) override;
131 void mouseUp(const juce::MouseEvent&) override;
132 void mouseDoubleClick(const juce::MouseEvent&) override;
133
134 //==============================================================================
135 void timerCallback() override;
136
137 //==============================================================================
138 bool setChannelConfiguration(const juce::AudioChannelSet& channelLayout) override;
139
140 //==============================================================================
148 void setSpeakersRealBoundingCube(const std::array<float, 6>& speakersRealBoundingCube);
149
154 void setSourcePositions(const std::map<std::int16_t, std::array<std::float_t, 3>>& sourcePositions);
156 void setSourcePosition(std::int16_t sourceId, const std::array<std::float_t, 3>& position);
157
158 //==============================================================================
166 void setSourceStartId(int startId);
167 int getSourceStartId() const;
168
169 //==============================================================================
174 void setLiveMode(bool liveMode);
175 bool getLiveMode() const;
176
177 //==============================================================================
180 IndicatorShape getShape() const;
181
182 //==============================================================================
184 void setUpmixTransform(float rot, float trans, float heightTrans, float angleStretch = 1.0f);
185 float getUpmixRot() const;
186 float getUpmixTrans() const;
187 float getUpmixHeightTrans() const;
188 float getUpmixAngleStretch() const;
189
190 //==============================================================================
192 void setUpmixOffset(float x, float y);
193 float getUpmixOffsetX() const;
194 float getUpmixOffsetY() const;
195
196 //==============================================================================
206
216 void triggerFlashCheck();
217
218 //==============================================================================
223 std::function<void(std::int16_t, std::array<std::float_t, 3>)> onSourcePositionChanged;
224
229 std::function<void()> onTransformChanged;
230
231private:
232 //==============================================================================
233 void onZoomChanged() override;
234
235 //==============================================================================
243 struct RenderedChannelPosition
244 {
245 std::int16_t sourceId = 0;
246 juce::Point<float> screenPos;
247 std::array<float, 3> realPos = { 0.0f, 0.0f, 0.0f };
248 juce::String label;
249 };
250
251 //==============================================================================
257 void PrerenderUpmixIndicatorInBounds();
259 void updateFlashState();
261 juce::Rectangle<int> getRefitButtonBounds() const;
262
263 //==============================================================================
264 int m_sourceStartId = 1;
265
266 //==============================================================================
267 std::array<float, 6> m_speakersRealBoundingCube;
268 std::map<std::int16_t, std::array<std::float_t, 3>> m_sourcePositions;
269
270 float m_boundingFitFactor = 0.15f;
271
272 // Prerendered juce::Path objects updated by PrerenderUpmixIndicatorInBounds().
273 juce::Path m_upmixIndicator;
274 juce::Path m_upmixHeightIndicator;
275 juce::Path m_centerHandlePath;
276 juce::Path m_stretchHandlePath;
277
278 float m_upmixRot = 0.0f;
279 float m_upmixTrans = 1.0f;
280 float m_upmixHeightTrans = 0.6f;
281
282 juce::Point<float> m_upmixCenter;
283 float m_subCircleRadius = 15.0f;
284 std::vector<RenderedChannelPosition> m_renderedFloorPositions;
285 std::vector<RenderedChannelPosition> m_renderedHeightPositions;
286
287 float m_upmixAngleStretch = 1.0f;
288 float m_naturalFloorMaxAngleDeg = 110.0f;
289 juce::Point<float> m_stretchHandlePos;
290 juce::Point<float> m_stretchHandleTangent;
291
292 float m_upmixOffsetX = 0.0f;
293 float m_upmixOffsetY = 0.0f;
294 float m_baseRadius = 100.0f;
295
296 // Drag state — values captured at mouseDown to allow incremental dragging.
297 bool m_draggingHeightRing = false;
298 bool m_draggingStretchHandle = false;
299 bool m_draggingCenterHandle = false;
300 float m_dragStartAngle = 0.0f;
301 float m_dragStartDist = 0.0f;
302 float m_dragStartRot = 0.0f;
303 float m_dragStartTrans = 0.0f;
304 float m_dragStartHeightTrans = 0.6f;
305 float m_dragStartStretch = 1.0f;
306 float m_dragStartOffsetX = 0.0f;
307 float m_dragStartOffsetY = 0.0f;
308 juce::Point<float> m_dragStartMousePos;
309
310 bool m_flashState = false;
311 bool m_liveMode = false;
316 int m_inhibitFlashCount = 0;
318
320};
321
Abstract base class for all three overlaid visualisation layers in UmsciControlComponent.
ControlsSize
Visual size of source/speaker icons. Multiplier accessible via getControlsSizeMultiplier().
The top layer of the UmsciControlComponent stack — renders an interactive upmix speaker ring and lets...
IndicatorShape
The geometric shape used to draw the upmix speaker ring.
void notifyTransformChanged()
Fires live-mode position callbacks and onTransformChanged after a programmatic transform change (e....
void setUpmixTransform(float rot, float trans, float heightTrans, float angleStretch=1.0f)
Applies all four transform parameters and triggers a prerender + repaint.
void triggerFlashCheck()
Checks whether the ideal ring positions diverge from the stored DS100 positions and starts the flash ...
std::function< void()> onTransformChanged
Fired whenever any transform parameter changes via an interactive drag, so UmsciControlComponent can ...
float getUpmixAngleStretch() const
Front/rear angular compression factor.
float getUpmixRot() const
Ring rotation (normalised 0–1 = 0–360°).
void setLiveMode(bool liveMode)
When true, actual DS100 positions for the upmix channels are overlaid on the ideal indicator ring so ...
void setSourcePosition(std::int16_t sourceId, const std::array< std::float_t, 3 > &position)
Updates a single source position (called on each OCP.1 notification).
void setControlsSize(ControlsSize size) override
Updates the icon size; derived classes may override to re-prerender.
void setSpeakersRealBoundingCube(const std::array< float, 6 > &speakersRealBoundingCube)
Provides the axis-aligned bounding cube of all loudspeaker positions.
float getUpmixHeightTrans() const
Height ring radius as a fraction of floor radius.
bool setChannelConfiguration(const juce::AudioChannelSet &channelLayout) override
void setSourcePositions(const std::map< std::int16_t, std::array< std::float_t, 3 > > &sourcePositions)
Provides live DS100 source positions for all upmix channels. Only rendered when m_liveMode is true.
static IndicatorShape getShapeForName(const juce::String &name)
void setSourceStartId(int startId)
Sets the first DS100 input channel (1-based) assigned to the upmix renderer.
void setUpmixOffset(float x, float y)
Sets the ring centre offset in units of base radius.
void setShape(IndicatorShape shape)
Sets the indicator ring geometry (circle or rectangle).
std::function< void(std::int16_t, std::array< std::float_t, 3 >)> onSourcePositionChanged
Fired when the user drags a source circle in live mode (pass-through from this component,...