1 /* B.Schaffl
2 * MIDI Pattern Delay Plugin
3 *
4 * Copyright (C) 2018 - 2020 by Sven Jähnichen
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21 #include "BSchafflGUI.hpp"
22 #include "Ports.hpp"
23 #include "screen.h"
24 #include "BUtilities/vsystem.hpp"
25
26
BSchafflGUI(const char * bundle_path,const LV2_Feature * const * features,PuglNativeView parentWindow)27 BSchafflGUI::BSchafflGUI (const char *bundle_path, const LV2_Feature *const *features, PuglNativeView parentWindow) :
28 Window (1020, 480, "B.Schaffl", parentWindow, true, PUGL_MODULE, 0),
29 controller (NULL), write_function (NULL),
30 pluginPath (bundle_path ? std::string (bundle_path) : std::string ("")),
31
32 mContainer (0, 0, 1020, 480, "main"),
33
34 helpButton (950, 60, 24, 24, "halobutton", BSCHAFFL_LABEL_HELP),
35 ytButton (980, 60, 24, 24, "halobutton", BSCHAFFL_LABEL_TUTORIAL),
36
37 toolbox (380, 330, 620, 30, "scontainer"),
38 toolIcon (4, 2 , 40, 26, "widget", pluginPath + "inc/tools.png"),
39 convertToShapeIcon (50, 5, 50, 20, "widget", pluginPath + "inc/convert_to_linear_shape.png"),
40 convertToStepsIcon (50, 5, 50, 20, "widget", pluginPath + "inc/convert_to_steps.png"),
41 convertToShapeButton (48, 3, 54, 24, "halobutton", BSCHAFFL_LABEL_CONVERT_TO_SHAPE),
42 convertToStepsButton (48, 3, 54, 24, "halobutton", BSCHAFFL_LABEL_CONVERT_TO_STEPS),
43 markersToolbox (120, 5, 50, 20, "widget", pluginPath + "inc/markers_tb.png"),
44 shapeToolbox (190, 5, 140, 20, "widget", pluginPath + "inc/shape_tools_tb.png"),
45 editToolbox (360, 5, 80, 20, "widget", pluginPath + "inc/edit_tb.png"),
46 historyToolbox (460, 5, 80, 20, "widget", pluginPath + "inc/history_tb.png"),
47 gridToolbox (560, 5, 50, 20, "widget", pluginPath + "inc/grid_tb.png"),
48 markersAutoButton (118, 3, 24, 24, "halobutton", BSCHAFFL_LABEL_ALL_MARKERS_AUTO),
49 markersManualButton (148, 3, 24, 24, "halobutton", BSCHAFFL_LABEL_ALL_MARKERS_MANUAL),
50 shapeToolButtons
51 {
52 HaloToggleButton (188, 3, 24, 24, "halobutton", BSCHAFFL_LABEL_SELECT),
53 HaloToggleButton (218, 3, 24, 24, "halobutton", BSCHAFFL_LABEL_POINT_NODE),
54 HaloToggleButton (248, 3, 24, 24, "halobutton", BSCHAFFL_LABEL_AUTO_NODE),
55 HaloToggleButton (278, 3, 24, 24, "halobutton", BSCHAFFL_LABEL_SYMMETRIC_NODE),
56 HaloToggleButton (308, 3, 24, 24, "halobutton", BSCHAFFL_LABEL_ASYMMETRIC_NODE)
57 },
58 editToolButtons
59 {
60 HaloButton (358, 3, 24, 24, "halobutton", BSCHAFFL_LABEL_CUT),
61 HaloButton (388, 3, 24, 24, "halobutton", BSCHAFFL_LABEL_COPY),
62 HaloButton (418, 3, 24, 24, "halobutton", BSCHAFFL_LABEL_PASTE)
63 },
64 historyToolButtons
65 {
66 HaloButton (458, 3, 24, 24, "halobutton", BSCHAFFL_LABEL_RESET),
67 HaloButton (488, 3, 24, 24, "halobutton", BSCHAFFL_LABEL_UNDO),
68 HaloButton (518, 3, 24, 24, "halobutton", BSCHAFFL_LABEL_REDO)
69 },
70 gridShowButton (558, 3, 24, 24, "halobutton", BSCHAFFL_LABEL_SHOW_GRID),
71 gridSnapButton (588, 3, 24, 24, "halobutton", BSCHAFFL_LABEL_SNAP_GRID),
72
73 convertToShapeMessage
74 (
75 560, 100, 300, 150, "menu",
76 BSCHAFFL_LABEL_CONVERT_TO_SHAPE_TITLE,
77 BSCHAFFL_LABEL_CONVERT_TO_SHAPE_TEXT,
78 std::vector<std::string>{BSCHAFFL_LABEL_OK, BSCHAFFL_LABEL_CANCEL}
79 ),
80 convertToShapeToLinearButton (20, 70, 12, 12, "slider", 0.0),
81 convertToShapeToLinearText (60, 70, 200, 20, "menu/text", BSCHAFFL_LABEL_CONVERT_TO_SHAPE_LINEAR_TEXT),
82 convertToShapeToConstButton (20, 90, 12, 12, "slider", 0.0),
83 convertToShapeToConstText (60, 90, 200, 20, "menu/text", BSCHAFFL_LABEL_CONVERT_TO_SHAPE_CONST_TEXT),
84
85 convertToStepsMessage
86 (
87 560, 100, 300, 110, "menu",
88 BSCHAFFL_LABEL_CONVERT_TO_STEPS_TITLE,
89 BSCHAFFL_LABEL_CONVERT_TO_STEPS_TEXT,
90 std::vector<std::string>{BSCHAFFL_LABEL_OK, BSCHAFFL_LABEL_CANCEL}
91 ),
92
93 midiChFilterIcon (0, 0, 300, 20, "widget", pluginPath + BSCHAFFL_FILENAME_MIDI_CH_FILTER),
94 midiChFilterContainer (0, 0, 340, 140, "screen"),
95 midiChFilterText (10, 10, 320, 50, "text", BSCHAFFL_LABEL_MIDI_CH),
96 midiChFilterAllSwitch (10, 36, 28, 14, "slider", 1),
97 midiChFilterAllLabel (44, 33, 120, 20, "lflabel", BSCHAFFL_LABEL_ALL),
98
99 midiMsgFilterIcon (0, 0, 300, 20, "widget", pluginPath + BSCHAFFL_FILENAME_MIDI_MSG_FILTER),
100 midiMsgFilterContainer (0, 0, 340, 200, "screen"),
101 midiMsgFilterText (10, 10, 320, 20, "text", BSCHAFFL_LABEL_MIDI_MSG),
102 midiMsgFilterAllSwitch (10, 36, 28, 14, "slider", 1),
103 midiMsgFilterAllLabel (50, 33, 120, 20, "lflabel", BSCHAFFL_LABEL_ALL),
104
105 midiNoteOptionsIcon (0, 0, 300, 20, "widget", pluginPath + BSCHAFFL_FILENAME_MIDI_NOTE_OPTIONS),
106 midiNoteOptionsContainer (0, 0, 340, 210, "screen"),
107 midiNoteText (10, 10, 320, 50, "text", BSCHAFFL_LABEL_NOTE_TEXT),
108 midiNotePositionSwitch (10, 68, 28, 14, "slider", 0.0),
109 midiNotePositionLabel (50, 65, 240, 20, "lflabel", BSCHAFFL_LABEL_NOTE_KEEP_POSITION),
110 midiNoteValueSwitch (10, 88, 28, 14, "slider", 0.0),
111 midiNoteValueLabel (50, 85, 180, 20, "lflabel", BSCHAFFL_LABEL_NOTE_KEEP_DURATION),
112 midiNoteOverlapListbox
113 (
114 160, 110, 100, 20, 0, 20, 100, 80, "menu",
115 BItems::ItemList ({{0, BSCHAFFL_LABEL_DO_NOTHING}, {1, BSCHAFFL_LABEL_SPLIT}, {2, BSCHAFFL_LABEL_MERGE}}),
116 0
117 ),
118 midiNoteOverlapLabel (10, 110, 150, 20, "lflabel", BSCHAFFL_LABEL_IF_NOTES_OVERLAP_TITLE),
119 midiNoteText2 (10, 140, 320, 30, "text", BSCHAFFL_LABEL_IF_NOTES_OVERLAP_TEXT),
120 midiNoteOffAmpLabel (10, 180, 110, 20, "lflabel", BSCHAFFL_LABEL_NOTE_OFF_AMP),
121 midiNoteOffAmpListbox
122 (
123 120, 180, 220, 20, 0, 20, 220, 60, "menu",
124 BItems::ItemList ({{0, BSCHAFFL_LABEL_USE_NOTE_ON_AMP}, {1, BSCHAFFL_LABEL_CALCULATE_FROM_END}}),
125 0
126 ),
127
128 smartQuantizationIcon (0, 0, 300, 20, "widget", pluginPath + BSCHAFFL_FILENAME_SMART_QUANTIZATION),
129 smartQuantizationContainer (0, 0, 340, 200, "screen"),
130 smartQuantizationRangeSlider (10, 80, 110, 28, "slider", 0.25, 0.0, 0.5, 0.0, "%1.2f"),
131 smartQuantizationMappingSwitch (10, 156, 28, 14, "slider", 1.0),
132 smartQuantizationPositioningSwitch (10, 176, 28, 14, "slider", 0.0),
133 smartQuantizationText1 (10, 10, 320, 70, "text", BSCHAFFL_LABEL_SMART_QUANTIZATION_TEXT_1),
134 smartQuantizationRangeLabel (130, 90, 150, 20, "lflabel", BSCHAFFL_LABEL_RANGE_STEPS),
135 smartQuantizationText2 (10, 120, 320, 30, "text", BSCHAFFL_LABEL_SMART_QUANTIZATION_TEXT_2),
136 smartQuantizationMappingLabel (50, 153, 180, 20, "lflabel", BSCHAFFL_LABEL_ASSIGN_TO_STEP),
137 smartQuantizationPositionLabel (50, 173, 180, 20, "lflabel", BSCHAFFL_LABEL_FIT_TO_STEP),
138
139 userLatencyIcon (0, 0, 300, 20, "widget", pluginPath + BSCHAFFL_FILENAME_LATENCY),
140 userLatencyContainer (0, 0, 340, 180, "screen"),
141 timeCompensText (10, 10, 320, 30, "text", BSCHAFFL_LABEL_LATENCY_COMPENSATION_TEXT),
142 timeCompensLabel (50, 45, 230, 20, "lflabel", BSCHAFFL_LABEL_LATENCY_COMPENSATION_TITLE),
143 timeCompensSwitch (10, 48, 28, 14, "slider", 0.0),
144 userLatencyText (10, 80, 320, 30, "text", BSCHAFFL_LABEL_LATENCY_USER_TEXT),
145 userLatencySwitch (10, 118, 28, 14, "slider", 0.0),
146 userLatencyLabel (50, 115, 180, 20, "lflabel", BSCHAFFL_LABEL_LATENCY_USER_TITLE),
147 userLatencyValue (0, 0, 0, 0, "widget", 0.0, 0.0, 192000, 1.0),
148 userLatencySlider (10, 140, 160, 28, "slider", 0, 0, 192000, 1, "%6.0f"),
149 userLatencyUnitListbox
150 (
151 180, 150, 90, 20, 0, 20, 90, 60, "menu",
152 BItems::ItemList ({{1, BSCHAFFL_LABEL_FRAMES}, {2, BSCHAFFL_LABEL_MS}}),
153 1
154 ),
155
156 selectMenu
157 (
158 20, 90, 340, 350, "selectmenu",
159 std::list<std::pair<Widget*, Widget*>>
160 ({
161 {&midiChFilterIcon, &midiChFilterContainer},
162 {&midiMsgFilterIcon, &midiMsgFilterContainer},
163 {&midiNoteOptionsIcon, &midiNoteOptionsContainer},
164 {&smartQuantizationIcon, &smartQuantizationContainer},
165 {&userLatencyIcon, &userLatencyContainer}
166 })
167 ),
168
169 sharedDataSelection (58, 448, 304, 24, "widget", 0, 0, 4, 1),
170
171 sContainer (380, 90, 620, 240, "scontainer"),
172
173 modeSwitch (426, 71, 28, 14, "slider", 0.0),
174 seqLenValueListbox
175 (
176 380, 380, 50, 20, 0, -220, 50, 220, "menu",
177 BItems::ItemList
178 ({
179 {0.125, "1/8"}, {0.25, "1/4"}, {0.333333, "1/3"}, {0.5, "1/2"},
180 {0.666667, "2/3"}, {0.75, "3/4"}, {1, "1"}, {2, "2"}, {3, "3"}, {4, "4"},
181 {6, "6"}, {8, "8"}, {12, "12"}, {16, "16"}
182 }), 1.0
183 ),
184 seqLenBaseListbox
185 (
186 440, 380, 90, 20, 0, -80, 90, 80, "menu",
187 BItems::ItemList
188 ({{0, BSCHAFFL_LABEL_SECONDS}, {1, BSCHAFFL_LABEL_BEATS}, {2, BSCHAFFL_LABEL_BARS}}), 2.0
189 ),
190 ampSwingControl
191 (
192 565, 372, 120, 28, "slider", 1.0, 0.0078125, 128.0, 0.0, "%3.1f",
193 [] (const double val, const double min, const double max)
__anon2ccd2c280102(const double val, const double min, const double max) 194 {return (val >= 1.0 ? 1.0 - 0.5 / LIMIT (val, min, max) : 0.5 * LIMIT (val, min, max));},
195 [] (const double frac, const double min, const double max)
__anon2ccd2c280202(const double frac, const double min, const double max) 196 {return (frac >= 0.5 ? 0.5 / (1.0 - LIMIT (frac, 0, 1)) : 2 * LIMIT (frac, 0, 1));}
197 ),
198 ampRandomControl (720, 372, 120, 28, "slider", 0.0, 0.0, 1.0, 0.0, "%1.2f"),
199 ampProcessControl (875, 372, 120, 28, "procslider", 1.0, -1.0, 2.0, 0.0, "%1.2f"),
200 swingControl (565, 422, 120, 28, "slider", 1.0, 1.0 / 3.0, 3.0, 0.0),
201 swingRandomControl (720, 422, 120, 28, "slider", 0.0, 0.0, 1.0, 0.0, "%1.2f"),
202 swingProcessControl (875, 422, 120, 28, "procslider", 0.0, 0.0, 1.0, 0.0, "%1.2f"),
203 nrStepsControl (380, 422, 155, 28, "slider", 1.0, 1.0, MAXSTEPS, 1.0, "%2.0f"),
204 seqLenIcon (385, 405, 140, 12, "widget", pluginPath + BSCHAFFL_FILENAME_SEQUENCE_SIZE),
205 ampSwingIcon (555, 405, 140, 12, "widget", pluginPath + BSCHAFFL_FILENAME_AMP_SWING),
206 ampRandomIcon (710, 405, 140, 12, "widget", pluginPath + BSCHAFFL_FILENAME_AMP_RANDOM),
207 ampProcessIcon (865, 405, 140, 12, "widget", pluginPath + BSCHAFFL_FILENAME_AMP_PROCESS),
208 nrStepsIcon (385, 455, 140, 12, "widget", pluginPath + BSCHAFFL_FILENAME_NR_OF_STEPS),
209 swingIcon (555, 455, 140, 12, "widget", pluginPath + BSCHAFFL_FILENAME_STEPS_SWING),
210 swingRandomIcon (710, 455, 140, 12, "widget", pluginPath + BSCHAFFL_FILENAME_STEPS_RANDOM),
211 swingProcessIcon (865, 455, 140, 12, "widget", pluginPath + BSCHAFFL_FILENAME_STEPS_PROCESS),
212
213 stepControlContainer (40, 40, 580, 130, "widget", 0.0),
214 shapeWidget (40, 40, 580, 130, "shape"),
215 markerListBox (12, -68, 86, 66, "listbox", BItems::ItemList ({BSCHAFFL_LABEL_AUTO, BSCHAFFL_LABEL_MANUAL})),
216
217 latencyValue (0, 0, 0, 0, "widget", 0),
218 latencyDisplay (900, 10, 120, 10, "smlabel", ""),
219 controllers{nullptr},
220 messageLabel (480, 63, 465, 20, "hilabel", ""),
221 inIcon (4, 14, 32, 12, "widget", pluginPath + BSCHAFFL_FILENAME_IN),
222 ampIcon (4, 100, 32, 20, "widget", pluginPath + BSCHAFFL_FILENAME_AMP),
223 delIcon (2, 185, 36, 12, "widget", pluginPath + BSCHAFFL_FILENAME_STR),
224 outIcon (4, 214, 32, 12, "widget", pluginPath + BSCHAFFL_FILENAME_OUT),
225
226 clipboard (),
227
228 sz (1.0), bgImageSurface (nullptr),
229 map (NULL), rate (48000.0)
230
231 {
232 // Init
233 for (unsigned int i = 0; i < midiMsgFilterSwitches.size(); ++i)
234 {
235 midiMsgFilterSwitches[i] = BWidgets::HSwitch (10, 56 + i * 20, 28, 14, "slider", 1);
236 midiMsgFilterLabels[i] = BWidgets::Label (50, 53 + i * 20, 180, 20, "lflabel", midiMsgGroupTexts[i]);
237 }
238
239 for (unsigned int i = 0; i < midiChFilterSwitches.size(); ++i)
240 {
241 midiChFilterSwitches[i] = BWidgets::HSwitch (10 + 80.0 * int (i / 4), 56 + int (i % 4) * 20, 28, 14, "slider", 1);
242 midiChFilterLabels[i] = BWidgets::Label (44 + 80.0 * int (i / 4), 53 + int (i % 4) * 20, 36, 20, "lflabel", "#" + std::to_string (i + 1));
243 }
244
245 for (int i = 0; i < 4; ++i) sharedDataButtons[i] = HaloToggleButton (80 * i, 0, 64, 24, "halobutton", BSCHAFFL_LABEL_SHARED_DATA " " + std::to_string (i + 1));
246
247 // Link widgets to controllers
248 controllers[SEQ_LEN_VALUE] = &seqLenValueListbox;
249 controllers[SEQ_LEN_BASE] = &seqLenBaseListbox;
250 controllers[AMP_SWING] = &SwingControl;
251 controllers[AMP_RANDOM] = &RandomControl;
252 controllers[AMP_PROCESS] = &ProcessControl;
253 controllers[SWING] = &swingControl;
254 controllers[SWING_RANDOM] = &swingRandomControl;
255 controllers[SWING_PROCESS] = &swingProcessControl;
256 controllers[NR_OF_STEPS] = &nrStepsControl;
257 controllers[AMP_MODE] = &modeSwitch;
258 controllers[NOTE_POSITION_STR] = &midiNotePositionSwitch;
259 controllers[NOTE_VALUE_STR] = &midiNoteValueSwitch;
260 controllers[NOTE_OVERLAP] = &midiNoteOverlapListbox;
261 controllers[NOTE_OFF_AMP] = &midiNoteOffAmpListbox;
262 controllers[QUANT_RANGE] = &smartQuantizationRangeSlider;
263 controllers[QUANT_MAP] = &smartQuantizationMappingSwitch;
264 controllers[QUANT_POS] = &smartQuantizationPositioningSwitch;
265 controllers[TIME_COMPENS] = &timeCompensSwitch;
266 controllers[USR_LATENCY] = &userLatencySwitch;
267 controllers[USR_LATENCY_FR] = &userLatencyValue;
268
269 for (unsigned int i = 0; i < midiChFilterSwitches.size(); ++i) controllers[MIDI_CH_FILTER + i] = &midiChFilterSwitches[i];
270 for (unsigned int i = 0; i < midiMsgFilterSwitches.size(); ++i) controllers[MSG_FILTER_NOTE + i] = &midiMsgFilterSwitches[i];
271 for (int i = 0; i < MAXSTEPS - 1; ++i) controllers[STEP_POS + i] = &markerWidgets[i];
272 for (int i = 0; i < MAXSTEPS; ++i) controllers[STEP_LEV + i] = &stepControl[i];
273 controllers[LATENCY] = &latencyValue;
274
275 // Set callbacks
276 for (BWidgets::ValueWidget* v : controllers) v->setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BSchafflGUI::valueChangedCallback);
277 midiChFilterAllSwitch.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BSchafflGUI::valueChangedCallback);
278 midiMsgFilterAllSwitch.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BSchafflGUI::valueChangedCallback);
279 userLatencySlider.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BSchafflGUI::valueChangedCallback);
280 userLatencyUnitListbox.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BSchafflGUI::valueChangedCallback);
281 for (HaloToggleButton& s: sharedDataButtons) s.setCallbackFunction (BEvents::EventType::BUTTON_PRESS_EVENT, BSchafflGUI::sharedDataClickedCallback);
282 sharedDataSelection.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BSchafflGUI::valueChangedCallback);
283 markerListBox.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BSchafflGUI::listBoxChangedCallback);
284 convertToShapeButton.setCallbackFunction (BEvents::EventType::BUTTON_PRESS_EVENT, BSchafflGUI::convertButtonClickedCallback);
285 convertToStepsButton.setCallbackFunction (BEvents::EventType::BUTTON_PRESS_EVENT, BSchafflGUI::convertButtonClickedCallback);
286 convertToShapeToLinearButton.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BSchafflGUI::lightButtonClickedCallback);
287 convertToShapeToConstButton.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BSchafflGUI::lightButtonClickedCallback);
288 markersAutoButton.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BSchafflGUI::markersAutoClickedCallback);
289 markersManualButton.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BSchafflGUI::markersAutoClickedCallback);
290 for (HaloToggleButton& s: shapeToolButtons) s.setCallbackFunction (BEvents::EventType::BUTTON_PRESS_EVENT, BSchafflGUI::shapeToolClickedCallback);
291 for (HaloButton& e: editToolButtons) e.setCallbackFunction (BEvents::EventType::BUTTON_PRESS_EVENT, BSchafflGUI::editToolClickedCallback);
292 for (HaloButton& h: historyToolButtons) h.setCallbackFunction (BEvents::EventType::BUTTON_PRESS_EVENT, BSchafflGUI::historyToolClickedCallback);
293 gridShowButton.setCallbackFunction (BEvents::EventType::BUTTON_PRESS_EVENT, BSchafflGUI::gridToolClickedCallback);
294 gridSnapButton.setCallbackFunction (BEvents::EventType::BUTTON_PRESS_EVENT, BSchafflGUI::gridToolClickedCallback);
295 helpButton.setCallbackFunction(BEvents::BUTTON_PRESS_EVENT, helpButtonClickedCallback);
296 ytButton.setCallbackFunction(BEvents::BUTTON_PRESS_EVENT, ytButtonClickedCallback);
297 shapeWidget.setCallbackFunction (BEvents::VALUE_CHANGED_EVENT, shapeChangedCallback);
298 stepControlContainer.setCallbackFunction (BEvents::VALUE_CHANGED_EVENT, valueChangedCallback);
299
300 // Configure widgets
301 bgImageSurface = cairo_image_surface_create_from_png ((pluginPath + BSCHAFFL_FILENAME_BG).c_str());
302 widgetBg.loadFillFromCairoSurface (bgImageSurface);
303 userLatencySlider.hide();
304 userLatencyUnitListbox.hide();
305 nrStepsControl.setScrollable (true);
306 nrStepsControl.getDisplayLabel ()->setState (BColors::ACTIVE);
307 swingControl.getDisplayLabel ()->setState (BColors::ACTIVE);
308 markerListBox.setStacking (BWidgets::STACKING_OVERSIZE);
309
310 shapeWidget.hide();
311 shapeWidget.setMergeable (BEvents::POINTER_DRAG_EVENT, false);
312 shapeWidget.setTool (ToolType::POINT_NODE_TOOL);
313 shapeWidget.setDefaultShape ();
314 shapeWidget.setScaleParameters (0.05, 0, 1.1);
315 shapeWidget.setMajorXSteps (1.0);
316 shapeWidget.setMinorXSteps (1.0/16.0);
317 shapeWidget.setLowerLimit (0.0);
318 shapeWidget.setHigherLimit (1.0);
319
320 shapeToolButtons[1].setValue (1.0);
321 gridSnapButton.setValue (1.0);
322 shapeToolbox.hide();
323 editToolbox.hide();
324 //historyToolbox.hide();
325 gridToolbox.hide();
326 for (HaloToggleButton& s : shapeToolButtons) s.hide();
327 for (HaloButton& e : editToolButtons) e.hide();
328 //for (HaloButton& h : historyToolButtons) h.hide();
329 gridShowButton.hide();
330 gridSnapButton.hide();
331 convertToShapeIcon.hide();
332
333 convertToShapeMessage.setStacking (BWidgets::STACKING_OVERSIZE);
334
335 //Initialialize and configure stepControllers
336 double sw = sContainer.getEffectiveWidth() - 40;
337 double sx = sContainer.getXOffset() + 40;
338 for (int i = 0; i < MAXSTEPS; ++i)
339 {
340 stepControl[i] = BWidgets::VSlider ((i + 0.5) * sw / MAXSTEPS + sx - 7, 20, 14, 80, "slider", 1.0, 0.0, 1.0, 0.01);
341 stepControl[i].setHardChangeable (false);
342 stepControl[i].setScrollable (true);
343 stepControl[i].setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BSchafflGUI::valueChangedCallback);
344 stepControl[i].applyTheme (theme, "slider");
345 stepControlContainer.add (stepControl[i]);
346
347 stepControlLabel[i] = BWidgets::Label ((i + 0.5) * sw / MAXSTEPS + sx - 14, 0, 28, 20, "mlabel", "1.00");
348 stepControlLabel[i].applyTheme (theme, "mlabel");
349 stepControlLabel[i].setState (BColors::ACTIVE);
350 stepControlLabel[i].setEditable (true);
351 stepControlLabel[i].setCallbackFunction(BEvents::EventType::MESSAGE_EVENT, stepControlLabelMessageCallback);
352 stepControlContainer.add (stepControlLabel[i]);
353
354 inputStepLabel[i] = BWidgets::Label (sx + (i + 0.1) * sw / MAXSTEPS, 10, 0.8 * sw / MAXSTEPS, 20, "steplabel", "#" + std::to_string (i + 1));
355 sContainer.add (inputStepLabel[i]);
356
357 outputStepLabel[i] = BWidgets::Label (sx + (i + 0.1) * sw / MAXSTEPS, 180, 0.8 * sw / MAXSTEPS, 20, "steplabel", "#" + std::to_string (i + 1));
358 sContainer.add (outputStepLabel[i]);
359 }
360
361 //Initialialize and configure markers
362 for (int i = 0; i < MAXSTEPS - 1; ++i)
363 {
364 markerWidgets[i] = Marker ((i + 1) * sw / MAXSTEPS + sx - 5, 154, 10, 16, "marker", (double(i) + 1.0) / MAXSTEPS, 0.0, 1.0, 0.0);
365 markerWidgets[i].setHasValue (false);
366 markerWidgets[i].setDraggable (true);
367 markerWidgets[i].setCallbackFunction (BEvents::EventType::BUTTON_PRESS_EVENT, BSchafflGUI::markerClickedCallback);
368 markerWidgets[i].setCallbackFunction (BEvents::EventType::POINTER_DRAG_EVENT, BSchafflGUI::markerDraggedCallback);
369 markerWidgets[i].setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BSchafflGUI::valueChangedCallback);
370 markerWidgets[i].applyTheme (theme, "slider");
371 sContainer.add (markerWidgets[i]);
372 }
373
374 setAutoMarkers ();
375 rearrange_controllers ();
376 redrawSContainer ();
377 applyTheme (theme);
378
379 // Pack widgets
380 midiChFilterContainer.add (midiChFilterText);
381 midiChFilterContainer.add (midiChFilterAllSwitch);
382 midiChFilterContainer.add (midiChFilterAllLabel);
383 for (unsigned int i = 0; i < midiChFilterSwitches.size(); ++i)
384 {
385 midiChFilterContainer.add (midiChFilterSwitches[i]);
386 midiChFilterContainer.add (midiChFilterLabels[i]);
387 }
388
389 midiMsgFilterContainer.add (midiMsgFilterText);
390 midiMsgFilterContainer.add (midiMsgFilterAllSwitch);
391 midiMsgFilterContainer.add (midiMsgFilterAllLabel);
392 for (unsigned int i = 0; i < midiMsgFilterSwitches.size(); ++i)
393 {
394 midiMsgFilterContainer.add (midiMsgFilterSwitches[i]);
395 midiMsgFilterContainer.add (midiMsgFilterLabels[i]);
396 }
397
398 midiNoteOptionsContainer.add (midiNoteText);
399 midiNoteOptionsContainer.add (midiNotePositionSwitch);
400 midiNoteOptionsContainer.add (midiNotePositionLabel);
401 midiNoteOptionsContainer.add (midiNoteValueSwitch);
402 midiNoteOptionsContainer.add (midiNoteValueLabel);
403 midiNoteOptionsContainer.add (midiNoteOverlapListbox);
404 midiNoteOptionsContainer.add (midiNoteOverlapLabel);
405 midiNoteOptionsContainer.add (midiNoteText2);
406 midiNoteOptionsContainer.add (midiNoteOffAmpLabel);
407 midiNoteOptionsContainer.add (midiNoteOffAmpListbox);
408
409 smartQuantizationContainer.add (smartQuantizationRangeSlider);
410 smartQuantizationContainer.add (smartQuantizationMappingSwitch);
411 smartQuantizationContainer.add (smartQuantizationPositioningSwitch);
412 smartQuantizationContainer.add (smartQuantizationText1);
413 smartQuantizationContainer.add (smartQuantizationRangeLabel);
414 smartQuantizationContainer.add (smartQuantizationText2);
415 smartQuantizationContainer.add (smartQuantizationMappingLabel);
416 smartQuantizationContainer.add (smartQuantizationPositionLabel);
417
418 userLatencyContainer.add (timeCompensText);
419 userLatencyContainer.add (timeCompensLabel);
420 userLatencyContainer.add (timeCompensSwitch);
421 userLatencyContainer.add (userLatencyText);
422 userLatencyContainer.add (userLatencySwitch);
423 userLatencyContainer.add (userLatencyLabel);
424 userLatencyContainer.add (userLatencyValue);
425 userLatencyContainer.add (userLatencySlider);
426 userLatencyContainer.add (userLatencyUnitListbox);
427
428 for (HaloToggleButton& s : sharedDataButtons) sharedDataSelection.add (s);
429 mContainer.add (sharedDataSelection);
430
431 sContainer.add (inIcon);
432 sContainer.add (ampIcon);
433 sContainer.add (delIcon);
434 sContainer.add (outIcon);
435 sContainer.add (stepControlContainer);
436 sContainer.add (shapeWidget);
437
438 mContainer.add (selectMenu);
439 mContainer.add (sContainer);
440 mContainer.add (helpButton);
441 mContainer.add (ytButton);
442
443 toolbox.add (toolIcon);
444 toolbox.add (convertToShapeIcon);
445 toolbox.add (convertToStepsIcon);
446 toolbox.add (convertToShapeButton);
447 toolbox.add (convertToStepsButton);
448 toolbox.add (markersToolbox);
449 toolbox.add (shapeToolbox);
450 toolbox.add (editToolbox);
451 toolbox.add (historyToolbox);
452 toolbox.add (gridToolbox);
453 toolbox.add (markersAutoButton);
454 toolbox.add (markersManualButton);
455 for (HaloToggleButton& s : shapeToolButtons) toolbox.add (s);
456 for (HaloButton& e : editToolButtons) toolbox.add (e);
457 for (HaloButton& h : historyToolButtons) toolbox.add (h);
458 toolbox.add (gridShowButton);
459 toolbox.add (gridSnapButton);
460 mContainer.add (toolbox);
461
462 mContainer.add (modeSwitch);
463 mContainer.add (seqLenValueListbox);
464 mContainer.add (seqLenBaseListbox);
465 mContainer.add (ampSwingControl);
466 mContainer.add (ampRandomControl);
467 mContainer.add (ampProcessControl);
468 mContainer.add (swingControl);
469 mContainer.add (swingRandomControl);
470 mContainer.add (swingProcessControl);
471 mContainer.add (nrStepsControl);
472 mContainer.add (latencyValue);
473 mContainer.add (latencyDisplay);
474 mContainer.add (messageLabel);
475
476 mContainer.add (seqLenIcon);
477 mContainer.add (ampSwingIcon);
478 mContainer.add (ampRandomIcon);
479 mContainer.add (ampProcessIcon);
480 mContainer.add (nrStepsIcon);
481 mContainer.add (swingIcon);
482 mContainer.add (swingRandomIcon);
483 mContainer.add (swingProcessIcon);
484
485 convertToShapeMessage.add (convertToShapeToLinearButton);
486 convertToShapeMessage.add (convertToShapeToLinearText);
487 convertToShapeMessage.add (convertToShapeToConstButton);
488 convertToShapeMessage.add (convertToShapeToConstText);
489
490 add (mContainer);
491
492 std::array<double, MAXSTEPS> s;
493 s.fill (1.0);
494 sliderHistory.setDefault (s);
495 sliderHistory.clear();
496
497 //Scan host features for URID map
498 LV2_URID_Map* m = NULL;
499 for (int i = 0; features[i]; ++i)
500 {
501 if (strcmp(features[i]->URI, LV2_URID__map) == 0) m = (LV2_URID_Map*) features[i]->data;
502 }
503 if (!m) throw std::invalid_argument ("Host does not support urid:map");
504
505 //Map URIS
506 map = m;
507 getURIs (map, &uris);
508
509 // Initialize forge
510 lv2_atom_forge_init (&forge,map);
511 }
512
~BSchafflGUI()513 BSchafflGUI::~BSchafflGUI() {}
514
portEvent(uint32_t port_index,uint32_t buffer_size,uint32_t format,const void * buffer)515 void BSchafflGUI::portEvent(uint32_t port_index, uint32_t buffer_size, uint32_t format, const void* buffer)
516 {
517 // Notify port
518 if ((format == uris.atom_eventTransfer) && (port_index == OUTPUT))
519 {
520 const LV2_Atom* atom = (const LV2_Atom*) buffer;
521 if ((atom->type == uris.atom_Blank) || (atom->type == uris.atom_Object))
522 {
523 const LV2_Atom_Object* obj = (const LV2_Atom_Object*) atom;
524
525 // Linked / unlinked to shared data
526 if (obj->body.otype == uris.bschaffl_sharedDataLinkEvent)
527 {
528 LV2_Atom *oNr = NULL;
529
530 lv2_atom_object_get
531 (
532 obj,
533 uris.bschaffl_sharedDataNr, &oNr,
534 NULL
535 );
536
537 if (oNr && (oNr->type == uris.atom_Int))
538 {
539 const int nr = ((LV2_Atom_Int*)oNr)->body;
540 if ((nr >= 0) && (nr <= 4) && (nr != sharedDataSelection.getValue()))
541 {
542 sharedDataSelection.setValueable (false);
543 sharedDataSelection.setValue (nr);
544 sharedDataSelection.setValueable (true);
545
546 for (int i = 0; i < 4; ++i)
547 {
548 sharedDataButtons[i].setValueable (false);
549 sharedDataButtons[i].setValue (i == nr - 1 ? 1 : 0);
550 sharedDataButtons[i].setValueable (true);
551 }
552
553 }
554 }
555 }
556
557 // Controller changed
558 else if (obj->body.otype == uris.bschaffl_controllerEvent)
559 {
560 LV2_Atom *oNr = NULL, *oVal = NULL;
561
562 lv2_atom_object_get
563 (
564 obj,
565 uris.bschaffl_controllerNr, &oNr,
566 uris.bschaffl_controllerValue, &oVal,
567 NULL
568 );
569
570 if (oNr && (oNr->type == uris.atom_Int) && oVal && (oVal->type == uris.atom_Float))
571 {
572 const int nr = ((LV2_Atom_Int*)oNr)->body;
573 const float val = ((LV2_Atom_Float*)oVal)->body;
574
575 if ((nr >= STEP_POS) && (nr < STEP_POS + MAXSTEPS - 1))
576 {
577 setMarker (nr - STEP_POS, val);
578 setAutoMarkers ();
579 rearrange_controllers ();
580 redrawSContainer ();
581 }
582
583 else setController (nr, val);
584 }
585 }
586
587 // Status notification
588 if (obj->body.otype == uris.bschaffl_statusEvent)
589 {
590 const LV2_Atom *oPos = NULL, *oLat = NULL, *oRate = NULL;
591 lv2_atom_object_get
592 (
593 obj,
594 uris.bschaffl_step, &oPos,
595 uris.bschaffl_latency, &oLat,
596 uris.bschaffl_rate, &oRate,
597 0
598 );
599 if (oPos && (oPos->type == uris.atom_Int))
600 {
601 const int step = LIMIT (((LV2_Atom_Int*)oPos)->body, 0, MAXSTEPS - 1);
602 if (inputStepLabel[step].getName() != "actsteplabel")
603 {
604 for (int i = 0; i < MAXSTEPS; ++i)
605 {
606 if (i == step)
607 {
608 inputStepLabel[i].rename ("actsteplabel");
609 outputStepLabel[i].rename ("actsteplabel");
610 }
611
612 else
613 {
614 inputStepLabel[i].rename ("steplabel");
615 outputStepLabel[i].rename ("steplabel");
616 }
617
618 inputStepLabel[i].applyTheme (theme);
619 outputStepLabel[i].applyTheme (theme);
620 }
621 }
622 }
623
624 if (oLat && (oLat->type == uris.atom_Float))
625 {
626 const float latencyMs = ((LV2_Atom_Float*)oLat)->body;
627 latencyDisplay.setText ((latencyMs > 0) ? BSCHAFFL_LABEL_LATENCY ": " + BUtilities::to_string (latencyMs, "%5.1f") + " " BSCHAFFL_LABEL_MS : "");
628 }
629
630 if (oRate && (oRate->type == uris.atom_Double))
631 {
632 rate = ((LV2_Atom_Double*)oRate)->body;
633
634 const float latencyFr =
635 (
636 userLatencyUnitListbox.getValue() == 2.0 ?
637 userLatencySlider.getValue() * rate / 1000.0 :
638 userLatencySlider.getValue()
639
640 );
641 userLatencyValue.setValue (latencyFr);
642 }
643 }
644
645 // Shape notification
646 else if (obj->body.otype == uris.bschaffl_shapeEvent)
647 {
648 LV2_Atom *oData = NULL;
649 lv2_atom_object_get
650 (
651 obj,
652 uris.bschaffl_shapeData, &oData,
653 NULL
654 );
655
656 if (oData && (oData->type == uris.atom_Vector))
657 {
658
659 const LV2_Atom_Vector* vec = (const LV2_Atom_Vector*) oData;
660 if (vec->body.child_type == uris.atom_Float)
661 {
662 int32_t size = (int32_t) ((oData->size - sizeof(LV2_Atom_Vector_Body)) / (7 * sizeof (float)));
663 float* data = (float*) (&vec->body + 1);
664
665 shapeWidget.setValueEnabled (false);
666 shapeWidget.clearShape ();
667 for (int i = 0; (i < size) && (i < MAXNODES); ++i)
668 {
669 Node node;
670 node.nodeType = NodeType (int (data[i * 7]));
671 node.point.x = data[i * 7 + 1];
672 node.point.y = data[i * 7 + 2];
673 node.handle1.x = data[i * 7 + 3];
674 node.handle1.y = data[i * 7 + 4];
675 node.handle2.x = data[i * 7 + 5];
676 node.handle2.y = data[i * 7 + 6];
677 shapeWidget.appendRawNode (node);
678 }
679 shapeWidget.validateShape();
680 shapeWidget.pushToSnapshots ();
681 shapeWidget.update ();
682 shapeWidget.setValueEnabled (true);
683 }
684 }
685 }
686
687 // Message notification
688 if (obj->body.otype == uris.notify_messageEvent)
689 {
690 const LV2_Atom* data = NULL;
691 lv2_atom_object_get(obj, uris.notify_message, &data, 0);
692 if (data && (data->type == uris.atom_Int))
693 {
694 const int messageNr = ((LV2_Atom_Int*)data)->body;
695 std::string msg = ((messageNr >= NO_MSG) && (messageNr <= MAX_MSG) ? messageStrings[messageNr] : "");
696 messageLabel.setText (msg);
697 }
698 }
699 }
700 }
701
702 // Scan controller ports
703 else if ((format == 0) && (port_index >= CONTROLLERS) && (port_index < CONTROLLERS + NR_CONTROLLERS) && (sharedDataSelection.getValue() == 0))
704 {
705 float* pval = (float*) buffer;
706 const int controllerNr = port_index - CONTROLLERS;
707
708 if ((controllerNr >= STEP_POS) && (controllerNr < STEP_POS + MAXSTEPS - 1))
709 {
710 setMarker (controllerNr - STEP_POS, *pval);
711 setAutoMarkers ();
712 rearrange_controllers ();
713 redrawSContainer ();
714 }
715
716 else setController (controllerNr, *pval);
717 }
718 }
719
resizeGUI()720 void BSchafflGUI::resizeGUI()
721 {
722 hide ();
723
724 // Resize Fonts
725 defaultFont.setFontSize (12 * sz);
726 lfFont.setFontSize (12 * sz);
727 txFont.setFontSize (12 * sz);
728 mdFont.setFontSize (10 * sz);
729 smFont.setFontSize (8 * sz);
730
731 // Resize Background
732 cairo_surface_t* surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1020 * sz, 480 * sz);
733 cairo_t* cr = cairo_create (surface);
734 cairo_scale (cr, sz, sz);
735 cairo_set_source_surface(cr, bgImageSurface, 0, 0);
736 cairo_paint(cr);
737 widgetBg.loadFillFromCairoSurface(surface);
738 cairo_destroy (cr);
739 cairo_surface_destroy (surface);
740
741 // Resize widgets
742 RESIZE (mContainer, 0, 0, 1020, 480, sz);
743
744 RESIZE (helpButton, 950, 60, 24, 24, sz);
745 RESIZE (ytButton, 980, 60, 24, 24, sz);
746
747 RESIZE (toolbox, 380, 330, 620, 40, sz);
748 RESIZE (toolIcon, 4, 2, 40, 26, sz);
749 RESIZE (convertToShapeIcon, 50, 5, 50, 20, sz);
750 RESIZE (convertToStepsIcon, 50, 5, 50, 20, sz);
751 RESIZE (convertToShapeButton, 48, 3, 54, 24, sz);
752 RESIZE (convertToStepsButton, 48, 3, 54, 24, sz);
753 RESIZE (markersToolbox, 120, 5, 50, 20, sz);
754 RESIZE (shapeToolbox, 190, 5, 140, 20, sz);
755 RESIZE (editToolbox, 360, 5, 80, 20, sz);
756 RESIZE (historyToolbox, 460, 5, 80, 20, sz);
757 RESIZE (gridToolbox, 560, 5, 50, 20, sz);
758 RESIZE (markersAutoButton, 118, 3, 24, 24, sz);
759 RESIZE (markersManualButton, 148, 3, 24, 24, sz);
760 for (size_t i = 0; i < shapeToolButtons.size(); ++i) {RESIZE (shapeToolButtons[i], 188 + i * 30, 3, 24, 24, sz);}
761 for (size_t i = 0; i < editToolButtons.size(); ++i) {RESIZE (editToolButtons[i], 358 + i * 30, 3, 24, 24, sz);}
762 for (size_t i = 0; i < historyToolButtons.size(); ++i) {RESIZE (historyToolButtons[i], 458 + i * 30, 3, 24, 24, sz);}
763 RESIZE (gridShowButton, 588, 3, 24, 24, sz);
764 RESIZE (gridSnapButton, 588, 3, 24, 24, sz);
765
766 RESIZE (midiChFilterIcon, 0, 0, 300, 20, sz);
767 RESIZE (midiChFilterContainer, 0, 0, 340, 140, sz);
768 RESIZE (midiChFilterText, 10, 10, 320, 50, sz);
769 RESIZE (midiChFilterAllSwitch, 10, 36, 28, 14, sz);
770 RESIZE (midiChFilterAllLabel, 44, 33, 120, 20, sz);
771 for (unsigned int i = 0; i < midiChFilterSwitches.size(); ++i)
772 {
773 RESIZE (midiChFilterSwitches[i], 10 + 80.0 * int (i / 4), 56 + int (i % 4) * 20, 28, 14, sz);
774 RESIZE (midiChFilterLabels[i], 44 + 80.0 * int (i / 4), 53 + int (i % 4) * 20, 36, 20, sz);
775 }
776
777 RESIZE (midiMsgFilterIcon, 0, 0, 300, 20, sz);
778 RESIZE (midiMsgFilterContainer, 0, 0, 340, 200, sz);
779 RESIZE (midiMsgFilterText, 10, 10, 320, 20, sz);
780 RESIZE (midiMsgFilterAllSwitch, 10, 36, 28, 14, sz);
781 RESIZE (midiMsgFilterAllLabel, 50, 33, 120, 20, sz);
782 for (unsigned int i = 0; i < midiMsgFilterSwitches.size(); ++i)
783 {
784 RESIZE (midiMsgFilterSwitches[i], 10, 56 + i * 20, 28, 14, sz);
785 RESIZE (midiMsgFilterLabels[i], 50, 53 + i * 20, 180, 20, sz);
786 }
787
788 RESIZE (midiNoteOptionsIcon, 0, 0, 300, 20, sz);
789 RESIZE (midiNoteOptionsContainer, 0, 0, 340, 210, sz);
790 RESIZE (midiNoteText, 10, 10, 320, 50, sz);
791 RESIZE (midiNotePositionSwitch, 10, 68, 28, 14, sz);
792 RESIZE (midiNotePositionLabel, 50, 65, 240, 20, sz);
793 RESIZE (midiNoteValueSwitch, 10, 88, 28, 14, sz);
794 RESIZE (midiNoteValueLabel, 50, 85, 180, 20, sz);
795 RESIZE (midiNoteOverlapListbox, 160, 110, 100, 20, sz);
796 midiNoteOverlapListbox.resizeListBox (BUtilities::Point (100 * sz, 80 * sz));
797 midiNoteOverlapListbox.moveListBox (BUtilities::Point (0, 20 * sz));
798 midiNoteOverlapListbox.resizeListBoxItems (BUtilities::Point (100 * sz, 20 * sz));
799 RESIZE (midiNoteOverlapLabel, 10, 110, 150, 20, sz);
800 RESIZE (midiNoteText2, 10, 140, 320, 30, sz);
801 RESIZE (midiNoteOffAmpLabel, 10, 180, 110, 20, sz);
802 RESIZE (midiNoteOffAmpListbox, 120, 180, 220, 20, sz);
803 midiNoteOffAmpListbox.resizeListBox (BUtilities::Point (220 * sz, 60 * sz));
804 midiNoteOffAmpListbox.moveListBox (BUtilities::Point (0, 20 * sz));
805 midiNoteOffAmpListbox.resizeListBoxItems (BUtilities::Point (220 * sz, 20 * sz));
806
807 RESIZE (smartQuantizationIcon, 0, 0, 300, 20, sz);
808 RESIZE (smartQuantizationContainer, 0, 0, 340, 200, sz);
809 RESIZE (smartQuantizationRangeSlider, 10, 80, 110, 28, sz);
810 RESIZE (smartQuantizationMappingSwitch, 10, 156, 28, 14, sz);
811 RESIZE (smartQuantizationPositioningSwitch, 10, 176, 28, 14, sz);
812 RESIZE (smartQuantizationText1, 10, 10, 320, 70, sz);
813 RESIZE (smartQuantizationRangeLabel, 130, 90, 150, 20, sz);
814 RESIZE (smartQuantizationText2, 10, 120, 320, 30, sz);
815 RESIZE (smartQuantizationMappingLabel, 50, 153, 180, 20, sz);
816 RESIZE (smartQuantizationPositionLabel, 50, 173, 180, 20, sz);
817
818 RESIZE (userLatencyIcon, 0, 0, 300, 20, sz);
819 RESIZE (userLatencyContainer, 0, 0, 340, 180, sz);
820 RESIZE (timeCompensText, 10, 10, 320, 30, sz);
821 RESIZE (timeCompensLabel, 50, 45, 230, 20, sz);
822 RESIZE (timeCompensSwitch, 10, 48, 28, 14, sz);
823 RESIZE (userLatencyText, 10, 80, 320, 30, sz);
824 RESIZE (userLatencySwitch, 10, 118, 28, 14, sz);
825 RESIZE (userLatencyLabel, 50, 115, 180, 20, sz);
826 RESIZE (userLatencySlider, 10, 140, 160, 28, sz);
827 RESIZE (userLatencyUnitListbox, 180, 150, 90, 20, sz);
828 userLatencyUnitListbox.resizeListBox (BUtilities::Point (90 * sz, 60 * sz));
829 userLatencyUnitListbox.moveListBox (BUtilities::Point (0, 20 * sz));
830 userLatencyUnitListbox.resizeListBoxItems (BUtilities::Point (40 * sz, 20 * sz));
831
832 RESIZE (selectMenu, 20, 90, 340, 350, sz);
833
834 RESIZE (sharedDataSelection, 58, 448, 304, 24, sz);
835 for (int i = 0; i < 4; ++i) {RESIZE (sharedDataButtons[i], 80 * i, 0, 64, 24, sz);}
836
837 RESIZE (sContainer, 380, 90, 620, 240, sz);
838
839 RESIZE (modeSwitch, 426, 71, 28, 14, sz);
840 RESIZE (seqLenValueListbox, 380, 380, 50, 20, sz);
841 seqLenValueListbox.resizeListBox (BUtilities::Point (50 * sz, 220 * sz));
842 seqLenValueListbox.moveListBox (BUtilities::Point (0, -220 * sz));
843 seqLenValueListbox.resizeListBoxItems (BUtilities::Point (50 * sz, 20 * sz));
844 RESIZE (seqLenBaseListbox, 440, 380, 90, 20, sz);
845 seqLenBaseListbox.resizeListBox (BUtilities::Point (90 * sz, 80 * sz));
846 seqLenBaseListbox.moveListBox (BUtilities::Point (0, -80 * sz));
847 seqLenBaseListbox.resizeListBoxItems (BUtilities::Point (90 * sz, 20 * sz));
848 RESIZE (ampSwingControl, 565, 372, 120, 28, sz);
849 RESIZE (ampRandomControl, 720, 372, 120, 28, sz);
850 RESIZE (ampProcessControl, 875, 372, 120, 28, sz);
851 RESIZE (swingControl, 565, 422, 120, 28, sz);
852 RESIZE (swingRandomControl, 720, 422, 120, 28, sz);
853 RESIZE (swingProcessControl, 875, 422, 120, 28, sz);
854 RESIZE (nrStepsControl, 380, 422, 155, 28, sz);
855 RESIZE (stepControlContainer, 40, 40, 580, 130, sz);
856 RESIZE (shapeWidget, 40, 40, 580, 130, sz);
857 RESIZE (markerListBox, 12, -68, 86, 66, sz);
858 markerListBox.resizeItems (BUtilities::Point (80 * sz, 20 * sz));
859
860 RESIZE (seqLenIcon, 385, 405, 140, 12, sz);
861 RESIZE (ampSwingIcon, 555, 405, 140, 12, sz);
862 RESIZE (ampRandomIcon, 710, 405, 140, 12, sz);
863 RESIZE (ampProcessIcon, 865, 405, 140, 12, sz);
864 RESIZE (nrStepsIcon, 385, 455, 140, 12, sz);
865 RESIZE (swingIcon, 555, 455, 140, 12, sz);
866 RESIZE (swingRandomIcon, 710, 455, 140, 12, sz);
867 RESIZE (swingProcessIcon, 865, 455, 140, 12, sz);
868
869 RESIZE (messageLabel, 480, 63, 465, 20, sz);
870 RESIZE (latencyDisplay, 900, 10, 120, 10, sz);
871
872 RESIZE (inIcon, 4, 14, 32, 12, sz);
873 RESIZE (ampIcon, 4, 100, 32, 20, sz);
874 RESIZE (delIcon, 2, 185, 36, 12, sz);
875 RESIZE (outIcon, 4, 214, 32, 12, sz);
876
877 // Update monitors
878 rearrange_controllers ();
879 redrawSContainer ();
880
881 // Apply changes
882 applyTheme (theme);
883 show ();
884 }
885
applyTheme(BStyles::Theme & theme)886 void BSchafflGUI::applyTheme (BStyles::Theme& theme)
887 {
888 mContainer.applyTheme (theme);
889
890 midiChFilterIcon.applyTheme (theme);
891 midiChFilterContainer.applyTheme (theme);
892 midiChFilterText.applyTheme (theme);
893 midiChFilterAllSwitch.applyTheme (theme);
894 midiChFilterAllLabel.applyTheme (theme);
895 for (unsigned int i = 0; i < midiChFilterSwitches.size(); ++i)
896 {
897 midiChFilterSwitches[i].applyTheme (theme);
898 midiChFilterLabels[i].applyTheme (theme);
899 }
900
901 midiMsgFilterIcon.applyTheme (theme);
902 midiMsgFilterContainer.applyTheme (theme);
903 midiMsgFilterText.applyTheme (theme);
904 midiMsgFilterAllSwitch.applyTheme (theme);
905 midiMsgFilterAllLabel.applyTheme (theme);
906 for (unsigned int i = 0; i < midiMsgFilterSwitches.size(); ++i)
907 {
908 midiMsgFilterSwitches[i].applyTheme (theme);
909 midiMsgFilterLabels[i].applyTheme (theme);
910 }
911
912 midiNoteOptionsIcon.applyTheme (theme);
913 midiNoteOptionsContainer.applyTheme (theme);
914 midiNoteText.applyTheme (theme);
915 midiNotePositionSwitch.applyTheme (theme);
916 midiNotePositionLabel.applyTheme (theme);
917 midiNoteValueSwitch.applyTheme (theme);
918 midiNoteValueLabel.applyTheme (theme);
919 midiNoteOverlapListbox.applyTheme (theme);
920 midiNoteOverlapLabel.applyTheme (theme);
921 midiNoteText2.applyTheme (theme);
922 midiNoteOffAmpLabel.applyTheme (theme);
923 midiNoteOffAmpListbox.applyTheme (theme);
924
925 smartQuantizationIcon.applyTheme (theme);
926 smartQuantizationContainer.applyTheme (theme);
927 smartQuantizationRangeSlider.applyTheme (theme);
928 smartQuantizationMappingSwitch.applyTheme (theme);
929 smartQuantizationPositioningSwitch.applyTheme (theme);
930 smartQuantizationText1.applyTheme (theme);
931 smartQuantizationRangeLabel.applyTheme (theme);
932 smartQuantizationText2.applyTheme (theme);
933 smartQuantizationMappingLabel.applyTheme (theme);
934 smartQuantizationPositionLabel.applyTheme (theme);
935
936 userLatencyIcon.applyTheme (theme);
937 userLatencyContainer.applyTheme (theme);
938 timeCompensText.applyTheme (theme);
939 timeCompensLabel.applyTheme (theme);
940 timeCompensSwitch.applyTheme (theme);
941 userLatencyText.applyTheme (theme);
942 userLatencySwitch.applyTheme (theme);
943 userLatencyLabel.applyTheme (theme);
944 userLatencyValue.applyTheme (theme);
945 userLatencySlider.applyTheme (theme);
946 userLatencyUnitListbox.applyTheme (theme);
947
948 selectMenu.applyTheme (theme);
949
950 sharedDataSelection.applyTheme (theme);
951 for (HaloToggleButton& s : sharedDataButtons) s.applyTheme (theme);
952 sContainer.applyTheme (theme);
953 helpButton.applyTheme (theme);
954 ytButton.applyTheme (theme);
955
956 toolbox.applyTheme (theme);
957 toolIcon.applyTheme (theme);
958 convertToShapeIcon.applyTheme (theme);
959 convertToStepsIcon.applyTheme (theme);
960 convertToShapeButton.applyTheme (theme);
961 convertToStepsButton.applyTheme (theme);
962 markersToolbox.applyTheme (theme);
963 shapeToolbox.applyTheme (theme);
964 editToolbox.applyTheme (theme);
965 historyToolbox.applyTheme (theme);
966 gridToolbox.applyTheme (theme);
967 markersAutoButton.applyTheme (theme);
968 markersManualButton.applyTheme (theme);
969 for (HaloToggleButton& s : shapeToolButtons) s.applyTheme (theme);
970 for (HaloButton& e : editToolButtons) e.applyTheme (theme);
971 for (HaloButton& h : historyToolButtons) h.applyTheme (theme);
972 gridShowButton.applyTheme (theme);
973 gridSnapButton.applyTheme (theme);
974
975 convertToShapeMessage.applyTheme (theme);
976 convertToShapeToLinearButton.applyTheme (theme);
977 convertToShapeToLinearText.applyTheme (theme);
978 convertToShapeToConstButton.applyTheme (theme);
979 convertToShapeToConstText.applyTheme (theme);
980
981 convertToStepsMessage.applyTheme (theme);
982
983 seqLenIcon.applyTheme (theme);
984 ampSwingIcon.applyTheme (theme);
985 ampRandomIcon.applyTheme (theme);
986 ampProcessIcon.applyTheme (theme);
987 nrStepsIcon.applyTheme (theme);
988 swingIcon.applyTheme (theme);
989 swingRandomIcon.applyTheme (theme);
990 swingProcessIcon.applyTheme (theme);
991
992 modeSwitch.applyTheme (theme);
993 seqLenValueListbox.applyTheme (theme);
994 seqLenBaseListbox.applyTheme (theme);
995 ampSwingControl.applyTheme (theme);
996 ampRandomControl.applyTheme (theme);
997 ampProcessControl.applyTheme (theme);
998 swingControl.applyTheme (theme);
999 swingRandomControl.applyTheme (theme);
1000 swingProcessControl.applyTheme (theme);
1001 stepControlContainer.applyTheme (theme);
1002 shapeWidget.applyTheme (theme);
1003 nrStepsControl.applyTheme (theme);
1004 latencyValue.applyTheme (theme);
1005 latencyDisplay.applyTheme (theme);
1006 messageLabel.applyTheme (theme);
1007 sContainer.applyTheme (theme);
1008 markerListBox.applyTheme (theme);
1009 inIcon.applyTheme (theme);
1010 ampIcon.applyTheme (theme);
1011 delIcon.applyTheme (theme);
1012 outIcon.applyTheme (theme);
1013 for (int i = 0; i < MAXSTEPS; ++i)
1014 {
1015 stepControl[i].applyTheme (theme);
1016 stepControlLabel[i].applyTheme (theme);
1017 inputStepLabel[i].applyTheme (theme);
1018 outputStepLabel[i].applyTheme (theme);
1019 }
1020 }
1021
onConfigureRequest(BEvents::ExposeEvent * event)1022 void BSchafflGUI::onConfigureRequest (BEvents::ExposeEvent* event)
1023 {
1024 Window::onConfigureRequest (event);
1025
1026 sz = (getWidth() / 1020 > getHeight() / 480 ? getHeight() / 480 : getWidth() / 1020);
1027 resizeGUI ();
1028 }
1029
onCloseRequest(BEvents::WidgetEvent * event)1030 void BSchafflGUI::onCloseRequest (BEvents::WidgetEvent* event)
1031 {
1032 if (event)
1033 {
1034 Widget* requestWidget = event->getRequestWidget ();
1035 if (requestWidget)
1036 {
1037 if (requestWidget == (Widget*) &convertToShapeMessage)
1038 {
1039 if (convertToShapeMessage.getValue() == 1.0)
1040 {
1041 if (convertToShapeToLinearButton.getValue() != 0.0)
1042 {
1043 int nrSteps = nrStepsControl.getValue();
1044 shapeWidget.setValueEnabled (false);
1045 shapeWidget.clearShape ();
1046
1047 shapeWidget.appendRawNode
1048 (
1049 Node
1050 (
1051 END_NODE,
1052 {0.0, (getStepValue (0) + getStepValue (nrSteps - 1)) /2},
1053 {0.0, 0.0},
1054 {0.0, 0.0}
1055 )
1056 );
1057
1058 for (int i = 0; i < nrSteps; ++i)
1059 {
1060 shapeWidget.appendRawNode
1061 (
1062 Node
1063 (
1064 POINT_NODE,
1065 {(double (i) + 0.5) / double (nrSteps), getStepValue (i)},
1066 {0.0, 0.0},
1067 {0.0, 0.0}
1068 )
1069 );
1070 }
1071
1072 shapeWidget.appendRawNode
1073 (
1074 Node
1075 (
1076 END_NODE,
1077 {1.0, (getStepValue (0) + getStepValue (nrSteps - 1)) /2},
1078 {0.0, 0.0},
1079 {0.0, 0.0}
1080 )
1081 );
1082
1083 shapeWidget.validateShape();
1084 shapeWidget.pushToSnapshots ();
1085 shapeWidget.update ();
1086 shapeWidget.setValueEnabled (true);
1087 shapeWidget.setValue (1.0);
1088 }
1089
1090 else if (convertToShapeToConstButton.getValue() != 0.0)
1091 {
1092 int nrSteps = nrStepsControl.getValue();
1093 shapeWidget.setValueEnabled (false);
1094 shapeWidget.clearShape ();
1095
1096 shapeWidget.appendRawNode (Node (END_NODE, {0.0, (getStepValue (0))}, {0.0, 0.0}, {0.0, 0.0}));
1097
1098 for (int i = 0; i < nrSteps; ++i)
1099 {
1100 if (i != 0)
1101 {
1102 shapeWidget.appendRawNode
1103 (
1104 Node
1105 (
1106 POINT_NODE,
1107 {double (i) / double (nrSteps), getStepValue (i)},
1108 {0.0, 0.0},
1109 {0.0, 0.0}
1110 )
1111 );
1112 }
1113
1114 shapeWidget.appendRawNode
1115 (
1116 Node
1117 (
1118 POINT_NODE,
1119 {double (i + 1) / double (nrSteps) - 1.0 / double (MAPRES), getStepValue (i)},
1120 {0.0, 0.0},
1121 {0.0, 0.0}
1122 )
1123 );
1124 }
1125
1126 shapeWidget.appendRawNode (Node (END_NODE, {1.0, (getStepValue (0))}, {0.0, 0.0}, {0.0, 0.0}));
1127
1128 shapeWidget.validateShape();
1129 shapeWidget.pushToSnapshots ();
1130 shapeWidget.update ();
1131 shapeWidget.setValueEnabled (true);
1132 shapeWidget.setValue (1.0);
1133 }
1134 }
1135
1136
1137 if (requestWidget->getMainWindow()) release (requestWidget);
1138 }
1139
1140 else if (requestWidget == (Widget*) &convertToStepsMessage)
1141 {
1142 if (convertToStepsMessage.getValue() == 1.0)
1143 {
1144 // Convert to sliders
1145 int nrSteps = nrStepsControl.getValue();
1146 for (int i = 0; i < nrSteps; ++i)
1147 {
1148 stepControl[i].setValue (shapeWidget.getMapValue ((double (i) + 0.5) / double (nrSteps)));
1149 }
1150 }
1151
1152 if (requestWidget->getMainWindow()) release (requestWidget);
1153 }
1154
1155 else Window::onCloseRequest (event);
1156 }
1157 }
1158 }
1159
getStepValue(const int stepNr) const1160 double BSchafflGUI::getStepValue (const int stepNr) const
1161 {
1162 const float aswing = ((stepNr % 2) == 0 ? ampSwingControl.getValue() : 1.0 / ampSwingControl.getValue());
1163 return stepControl[stepNr].getValue() * LIM (aswing, 0, 1);
1164 }
1165
sendUiStatus(const bool on)1166 void BSchafflGUI::sendUiStatus (const bool on)
1167 {
1168 uint8_t obj_buf[64];
1169 lv2_atom_forge_set_buffer(&forge, obj_buf, sizeof(obj_buf));
1170
1171 LV2_Atom_Forge_Frame frame;
1172 LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object(&forge, &frame, 0, (on ? uris.bschaffl_uiOn : uris.bschaffl_uiOff));
1173 lv2_atom_forge_pop(&forge, &frame);
1174 write_function(controller, INPUT, lv2_atom_total_size(msg), uris.atom_eventTransfer, msg);
1175 }
1176
sendShape()1177 void BSchafflGUI::sendShape ()
1178 {
1179 size_t size = shapeWidget.size ();
1180
1181 uint8_t obj_buf[4096];
1182 lv2_atom_forge_set_buffer(&forge, obj_buf, sizeof(obj_buf));
1183
1184 // Load shapeBuffer
1185 float shapeBuffer[MAXNODES * 7];
1186 for (unsigned int i = 0; i < size; ++i)
1187 {
1188 Node node = shapeWidget.getRawNode (i);
1189 shapeBuffer[i * 7 + 0] = (float)node.nodeType;
1190 shapeBuffer[i * 7 + 1] = (float)node.point.x;
1191 shapeBuffer[i * 7 + 2] = (float)node.point.y;
1192 shapeBuffer[i * 7 + 3] = (float)node.handle1.x;
1193 shapeBuffer[i * 7 + 4] = (float)node.handle1.y;
1194 shapeBuffer[i * 7 + 5] = (float)node.handle2.x;
1195 shapeBuffer[i * 7 + 6] = (float)node.handle2.y;
1196 }
1197
1198 // Notify shapeBuffer
1199 LV2_Atom_Forge_Frame frame;
1200 LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object (&forge, &frame, 0, uris.bschaffl_shapeEvent);
1201 lv2_atom_forge_key(&forge, uris.bschaffl_shapeData);
1202 lv2_atom_forge_vector(&forge, sizeof(float), uris.atom_Float, (uint32_t) (7 * size), &shapeBuffer);
1203 lv2_atom_forge_pop(&forge, &frame);
1204 write_function (controller, INPUT, lv2_atom_total_size(msg), uris.atom_eventTransfer, msg);
1205 }
1206
sendSharedDataNr()1207 void BSchafflGUI::sendSharedDataNr ()
1208 {
1209 uint8_t obj_buf[64];
1210 lv2_atom_forge_set_buffer(&forge, obj_buf, sizeof(obj_buf));
1211
1212 LV2_Atom_Forge_Frame frame;
1213 LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object(&forge, &frame, 0, uris.bschaffl_sharedDataLinkEvent);
1214 lv2_atom_forge_key (&forge, uris.bschaffl_sharedDataNr);
1215 lv2_atom_forge_int (&forge, sharedDataSelection.getValue());
1216 lv2_atom_forge_pop(&forge, &frame);
1217 write_function(controller, INPUT, lv2_atom_total_size(msg), uris.atom_eventTransfer, msg);
1218 }
1219
sendController(const int nr,const float value)1220 void BSchafflGUI::sendController (const int nr, const float value)
1221 {
1222 uint8_t obj_buf[64];
1223 lv2_atom_forge_set_buffer(&forge, obj_buf, sizeof(obj_buf));
1224
1225 LV2_Atom_Forge_Frame frame;
1226 LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object(&forge, &frame, 0, uris.bschaffl_controllerEvent);
1227 lv2_atom_forge_key (&forge, uris.bschaffl_controllerNr);
1228 lv2_atom_forge_int (&forge, nr);
1229 lv2_atom_forge_key (&forge, uris.bschaffl_controllerValue);
1230 lv2_atom_forge_float (&forge, value);
1231 lv2_atom_forge_pop(&forge, &frame);
1232 write_function(controller, INPUT, lv2_atom_total_size(msg), uris.atom_eventTransfer, msg);
1233 }
1234
setController(const int nr,const double value)1235 float BSchafflGUI::setController (const int nr, const double value)
1236 {
1237 controllers[nr]->setValueable (false);
1238 controllers[nr]->setValue (value);
1239 controllers[nr]->setValueable (true);
1240
1241 if (nr == AMP_MODE)
1242 {
1243 if (value == 0.0f)
1244 {
1245 stepControlContainer.show();
1246 shapeWidget.hide();
1247 shapeToolbox.hide();
1248 editToolbox.hide();
1249 gridToolbox.hide();
1250 for (HaloToggleButton& s : shapeToolButtons) s.hide();
1251 for (HaloButton& e : editToolButtons) e.hide();
1252 gridShowButton.hide();
1253 gridSnapButton.hide();
1254 ampSwingControl.setState (BColors::NORMAL);
1255 convertToShapeIcon.hide();
1256 convertToStepsIcon.show();
1257 convertToShapeButton.hide();
1258 convertToStepsButton.show();
1259 if (convertToShapeMessage.getParent()) release (&convertToShapeMessage);
1260 }
1261 else
1262 {
1263 stepControlContainer.hide();
1264 shapeWidget.show();
1265 shapeToolbox.show();
1266 editToolbox.show();
1267 gridToolbox.show();
1268 for (HaloToggleButton& s : shapeToolButtons) s.show();
1269 for (HaloButton& e : editToolButtons) e.show();
1270 gridShowButton.show();
1271 gridSnapButton.show();
1272 ampSwingControl.setState (BColors::INACTIVE);
1273 convertToShapeIcon.show();
1274 convertToStepsIcon.hide();
1275 convertToShapeButton.show();
1276 convertToStepsButton.hide();
1277 if (convertToStepsMessage.getParent()) release (&convertToStepsMessage);
1278 }
1279 }
1280
1281 else if ((nr >= MIDI_CH_FILTER) && (nr < MIDI_CH_FILTER + NR_MIDI_CHS))
1282 {
1283 int count = 0;
1284 for (BWidgets::HSwitch& s : midiChFilterSwitches)
1285 {
1286 if (s.getValue() != 0.0) ++count;
1287 }
1288
1289 if (count == 0)
1290 {
1291 midiChFilterAllSwitch.setState (BColors::NORMAL);
1292 midiChFilterAllLabel.setState (BColors::NORMAL);
1293 midiChFilterAllSwitch.setValue (0.0);
1294 }
1295
1296 else if (count == NR_MIDI_CHS)
1297 {
1298 midiChFilterAllSwitch.setState (BColors::NORMAL);
1299 midiChFilterAllLabel.setState (BColors::NORMAL);
1300 midiChFilterAllSwitch.setValue (1.0);
1301 }
1302
1303 else
1304 {
1305 midiChFilterAllSwitch.setState (BColors::INACTIVE);
1306 midiChFilterAllLabel.setState (BColors::INACTIVE);
1307 }
1308 }
1309
1310 else if ((nr >= MSG_FILTER_NOTE) && (nr < MSG_FILTER_NOTE + NR_MIDI_MSG_FILTERS))
1311 {
1312 int count = 0;
1313 for (BWidgets::HSwitch& s : midiMsgFilterSwitches)
1314 {
1315 if (s.getValue() != 0.0) ++count;
1316 }
1317
1318 if (count == 0)
1319 {
1320 midiMsgFilterAllSwitch.setState (BColors::NORMAL);
1321 midiMsgFilterAllLabel.setState (BColors::NORMAL);
1322 midiMsgFilterAllSwitch.setValue (0.0);
1323 }
1324
1325 else if (count == NR_MIDI_MSG_FILTERS)
1326 {
1327 midiMsgFilterAllSwitch.setState (BColors::NORMAL);
1328 midiMsgFilterAllLabel.setState (BColors::NORMAL);
1329 midiMsgFilterAllSwitch.setValue (1.0);
1330 }
1331
1332 else
1333 {
1334 midiMsgFilterAllSwitch.setState (BColors::INACTIVE);
1335 midiMsgFilterAllLabel.setState (BColors::INACTIVE);
1336 }
1337 }
1338
1339 else if (nr == USR_LATENCY)
1340 {
1341 if (value == 0.0)
1342 {
1343 userLatencySlider.hide();
1344 userLatencyUnitListbox.hide();
1345 }
1346 else
1347 {
1348 userLatencySlider.show();
1349 userLatencyUnitListbox.show();
1350 }
1351 }
1352
1353 else if ((nr >= STEP_POS) && (nr < STEP_POS + MAXSTEPS - 1)) return (((Marker*)controllers[nr])->hasValue() ? value : 0.0f);
1354
1355 else if ((nr >= STEP_LEV) && (nr < STEP_LEV + MAXSTEPS))
1356 {
1357 int stepNr = nr - STEP_LEV;
1358 stepControlLabel[stepNr].setText (BUtilities::to_string (value, "%1.2f"));
1359
1360 std::array<double, MAXSTEPS> u = sliderHistory.undo();
1361 for (int i = 0; i < MAXSTEPS; ++i)
1362 {
1363 if ((i != stepNr) && (float (u[i]) != float (stepControl[i].getValue())))
1364 {
1365 sliderHistory.redo();
1366 break;
1367 }
1368 }
1369 stepControlContainer.setValue (1.0);
1370 }
1371
1372 else if (nr == AMP_SWING) rearrange_controllers();
1373
1374 else if (nr == AMP_PROCESS)
1375 {
1376 if ((value >= 0.0) && (value <= 1.0)) ampProcessControl.setState (BColors::NORMAL);
1377 else ampProcessControl.setState (BColors::ACTIVE);
1378 }
1379
1380 else if (nr == SWING)
1381 {
1382 setAutoMarkers();
1383 rearrange_controllers();
1384 redrawSContainer();
1385 }
1386
1387 else if (nr == NR_OF_STEPS)
1388 {
1389 shapeWidget.setMinorXSteps (1.0 / value);
1390 setAutoMarkers();
1391 rearrange_controllers();
1392 redrawSContainer();
1393 }
1394
1395 return value;
1396 }
1397
setMarker(const int markerNr,double value)1398 void BSchafflGUI::setMarker (const int markerNr, double value)
1399 {
1400 if ((markerNr < 0) || (markerNr >= MAXSTEPS - 1)) return;
1401
1402 // Value 0.0: Automatic
1403 if (value == 0.0)
1404 {
1405 markerWidgets[markerNr].setHasValue (false);
1406 }
1407
1408 else
1409 {
1410 // Set value and switch off automatic
1411 value = LIMIT (value, MINMARKERVALUE, 1.0);
1412 markerWidgets[markerNr].setHasValue (true);
1413 markerWidgets[markerNr].setValue (value);
1414
1415 // Validate ancessors
1416 for (int i = markerNr - 1; i >= 0; --i)
1417 {
1418 if (markerWidgets[i].hasValue())
1419 {
1420 if (markerWidgets[i].getValue() > value) markerWidgets[i].setValue (value);
1421 else break;
1422 }
1423 }
1424
1425 // Validate successors
1426 for (int i = markerNr + 1; i < MAXSTEPS - 1; ++i)
1427 {
1428 if (markerWidgets[i].hasValue())
1429 {
1430 if (markerWidgets[i].getValue() < value) markerWidgets[i].setValue (value);
1431 else break;
1432 }
1433 }
1434 }
1435 }
1436
setAutoMarkers()1437 void BSchafflGUI::setAutoMarkers ()
1438 {
1439 int nrMarkers = controllers[NR_OF_STEPS]->getValue() - 1;
1440 int start = 0;
1441 for (int i = 0; i < nrMarkers; ++i)
1442 {
1443 if (!markerWidgets[i].hasValue())
1444 {
1445 if ((i == nrMarkers - 1) || (markerWidgets[i + 1].hasValue()))
1446 {
1447 double swing = 2.0 * swingControl.getValue() / (swingControl.getValue() + 1.0);
1448 double anc = (start == 0 ? 0 : markerWidgets[start - 1].getValue());
1449 double suc = (i == nrMarkers - 1 ? 1 : markerWidgets[i + 1].getValue());
1450 double diff = suc - anc;
1451 double dist = i - start + 1.0 + (int (i - start) & 1 ? ((start & 1) ? 2.0 - swing : swing) : 1.0);
1452 double step = (diff < 0 ? 0 : diff / dist);
1453 for (int j = start; j <= i; ++j)
1454 {
1455 double f = ((j & 1) ? 2.0 - swing : swing);
1456 anc += f * step;
1457 markerWidgets[j].setValue (anc);
1458 }
1459 }
1460 }
1461 else start = i + 1;
1462 }
1463 }
1464
rearrange_controllers()1465 void BSchafflGUI::rearrange_controllers ()
1466 {
1467 const int nrStepsi = controllers[NR_OF_STEPS]->getValue();
1468
1469 if ((nrStepsi < 1) || (nrStepsi > MAXSTEPS)) return;
1470
1471 const double sw = sContainer.getWidth() - 40 * sz;
1472 const double sx = 40 * sz;
1473 const double sccw = stepControlContainer.getWidth();
1474 const double oddf = (ampSwingControl.getValue() >= 1.0 ? 1.0 : ampSwingControl.getValue());
1475 const double evenf = (ampSwingControl.getValue() >= 1.0 ? 1.0 / ampSwingControl.getValue() : 1.0);
1476
1477 for (int i = 0; i < MAXSTEPS; ++i)
1478 {
1479 if (i < nrStepsi)
1480 {
1481 stepControl[i].resize (14 * sz, (14 + LIMIT (96 * ((i % 2) == 0 ? oddf : evenf), 0, 96 )) * sz);
1482 stepControl[i].moveTo ((i + 0.5) * sccw / nrStepsi - 7 * sz, 130 * sz - stepControl[i].getHeight());
1483 stepControl[i].show();
1484
1485 if (i < nrStepsi - 1) markerWidgets[i].resize (10 * sz, 16 * sz);
1486
1487 stepControlLabel[i].moveTo ((i + 0.5) * sccw / nrStepsi - 14 * sz, 0);
1488 stepControlLabel[i].resize (28 * sz, 20 * sz);
1489 stepControlLabel[i].show();
1490
1491 inputStepLabel[i].moveTo (sx + (i + 0.1) * sw / nrStepsi, 10 * sz);
1492 inputStepLabel[i].resize (0.8 * (sw / nrStepsi), 20 * sz);
1493 inputStepLabel[i].show();
1494
1495 const double outx = (i == 0 ? 0.0 : markerWidgets[i - 1].getValue() * sw);
1496 const double outw =
1497 (
1498 i == 0 ?
1499 markerWidgets[i].getValue() * sw :
1500 (
1501 i < nrStepsi - 1 ?
1502 (markerWidgets[i].getValue() - markerWidgets[i - 1].getValue()) * sw :
1503 (1 - markerWidgets[i - 1].getValue()) * sw
1504 )
1505 );
1506 outputStepLabel[i].moveTo (sx + outx + 0.1 * outw, 210 * sz);
1507 outputStepLabel[i].resize (0.8 * outw, 20 * sz);
1508 outputStepLabel[i].show();
1509
1510 }
1511 else
1512 {
1513 stepControl[i].hide ();
1514 stepControlLabel[i].hide();
1515 inputStepLabel[i].hide();
1516 outputStepLabel[i].hide();
1517 }
1518 }
1519
1520 for (int i = 0; i < MAXSTEPS - 1; ++i)
1521 {
1522 if (i < nrStepsi - 1)
1523 {
1524 markerWidgets[i].moveTo (markerWidgets[i].getValue() * sw + sx - 5 * sz, 184 * sz);
1525 markerWidgets[i].show ();
1526 }
1527 else markerWidgets[i].hide ();
1528 }
1529 }
1530
valueChangedCallback(BEvents::Event * event)1531 void BSchafflGUI::valueChangedCallback (BEvents::Event* event)
1532 {
1533 if ((event) && (event->getWidget ()))
1534 {
1535 BWidgets::ValueWidget* widget = (BWidgets::ValueWidget*) event->getWidget ();
1536 const double value = widget->getValue();
1537
1538 if (widget->getMainWindow ())
1539 {
1540 BSchafflGUI* ui = (BSchafflGUI*) widget->getMainWindow ();
1541
1542 // Get controller nr
1543 int controllerNr = -1;
1544 for (int i = 0; i < NR_CONTROLLERS; ++i)
1545 {
1546 if (widget == ui->controllers[i])
1547 {
1548 controllerNr = i;
1549 break;
1550 }
1551 }
1552
1553 if (controllerNr >= 0)
1554 {
1555 if (controllerNr != LATENCY)
1556 {
1557 const float v = ui->setController (controllerNr, value);
1558 if (ui->sharedDataSelection.getValue()) ui->sendController (controllerNr, v);
1559 else ui->write_function (ui->controller, CONTROLLERS + controllerNr, sizeof (float), 0, &v);
1560 }
1561 }
1562
1563 else if (widget == &ui->stepControlContainer)
1564 {
1565 if (value != 0.0)
1566 {
1567 std::array<double, MAXSTEPS> steps;
1568 for (int i = 0; i < MAXSTEPS; ++i) steps[i] = ui->stepControl[i].getValue();
1569 ui->sliderHistory.push (steps);
1570 ui->stepControlContainer.setValue (0.0);
1571 }
1572 }
1573
1574 else if (widget == &ui->midiChFilterAllSwitch)
1575 {
1576 for (BWidgets::HSwitch& s : ui->midiChFilterSwitches) s.setValue (value);
1577 }
1578
1579 else if (widget == &ui->midiMsgFilterAllSwitch)
1580 {
1581 for (BWidgets::HSwitch& s : ui->midiMsgFilterSwitches) s.setValue (value);
1582 }
1583
1584 else if (widget == &ui->userLatencySlider)
1585 {
1586 const double latencyFr =
1587 (
1588 ui->userLatencyUnitListbox.getValue() == 2.0 ?
1589 ui->userLatencySlider.getValue() * ui->rate / 1000.0 :
1590 ui->userLatencySlider.getValue()
1591
1592 );
1593 ui->userLatencyValue.setValue (latencyFr);
1594 }
1595
1596 else if (widget == &ui->userLatencyUnitListbox)
1597 {
1598 // Translate slider value
1599 const double val =
1600 (
1601 ui->userLatencyUnitListbox.getValue() == 2.0 ?
1602 ui->userLatencySlider.getValue() * 1000.0 / ui->rate :
1603 ui->userLatencySlider.getValue() * ui->rate / 1000.0
1604
1605 );
1606
1607 // Set new slider limits
1608 const double max = (ui->userLatencyUnitListbox.getValue() == 2.0 ? 192000000.0 / ui->rate : 192000.0);
1609 ui->userLatencySlider.setValueable (false);
1610 ui->userLatencySlider.setMax (max);
1611 ui->userLatencySlider.setValueable (true);
1612 ui->userLatencySlider.setValue (val);
1613 }
1614
1615 else if (widget == &ui->sharedDataSelection)
1616 {
1617 const int val = ui->sharedDataSelection.getValue() - 1;
1618 for (int i = 0; i < 4; ++i)
1619 {
1620 ui->sharedDataButtons[i].setValueable (false);
1621 ui->sharedDataButtons[i].setValue (i == val ? 1 : 0);
1622 ui->sharedDataButtons[i].setValueable (true);
1623 }
1624
1625 ui->sendSharedDataNr();
1626 }
1627 }
1628 }
1629 }
1630
shapeChangedCallback(BEvents::Event * event)1631 void BSchafflGUI::shapeChangedCallback (BEvents::Event* event)
1632 {
1633 if (!event) return;
1634 ShapeWidget* widget = (ShapeWidget*) event->getWidget ();
1635 if (!widget) return;
1636 float value = widget->getValue();
1637 if (value != 1.0) return;
1638 BSchafflGUI* ui = (BSchafflGUI*) widget->getMainWindow();
1639 if (!ui) return;
1640
1641 ui->sendShape ();
1642 }
1643
markerClickedCallback(BEvents::Event * event)1644 void BSchafflGUI::markerClickedCallback (BEvents::Event* event)
1645 {
1646 if (!event) return;
1647 BEvents::PointerEvent* pev = (BEvents::PointerEvent*) event;
1648 if (pev->getButton() != BDevices::RIGHT_BUTTON) return;
1649 Marker* marker = (Marker*)event->getWidget();
1650 if (!marker) return;
1651 marker->raiseToTop();
1652 BSchafflGUI* ui = (BSchafflGUI*)marker->getMainWindow();
1653 if (!ui) return;
1654
1655 int nrSteps = ui->controllers[NR_OF_STEPS]->getValue();
1656
1657 for (int i = 0; i < nrSteps - 1; ++i)
1658 {
1659 if (marker == &ui->markerWidgets[i])
1660 {
1661 Marker* oldMarker = (Marker*) ui->markerListBox.getParent();
1662 ui->markerListBox.setValue (UNSELECTED);
1663
1664 if (oldMarker && (oldMarker == marker))
1665 {
1666 if (ui->markerListBox.isVisible()) ui->markerListBox.hide();
1667 else ui->markerListBox.show ();
1668 }
1669
1670 else if (oldMarker && (oldMarker != marker))
1671 {
1672 oldMarker->release (&ui->markerListBox);
1673 marker->add (ui->markerListBox);
1674 ui->markerListBox.show();
1675 }
1676
1677 else
1678 {
1679 marker->add (ui->markerListBox);
1680 ui->markerListBox.show();
1681 }
1682
1683 }
1684 }
1685 }
1686
markerDraggedCallback(BEvents::Event * event)1687 void BSchafflGUI::markerDraggedCallback (BEvents::Event* event)
1688 {
1689 if (!event) return;
1690 BEvents::PointerEvent* pev = (BEvents::PointerEvent*) event;
1691 if (pev->getButton() != BDevices::LEFT_BUTTON) return;
1692 Marker* marker = (Marker*)event->getWidget();
1693 if (!marker) return;
1694 marker->raiseToTop();
1695 BSchafflGUI* ui = (BSchafflGUI*)marker->getMainWindow();
1696 if (!ui) return;
1697
1698 int nrSteps = ui->controllers[NR_OF_STEPS]->getValue();
1699
1700 for (int i = 0; i < nrSteps - 1; ++i)
1701 {
1702 if (marker == &ui->markerWidgets[i])
1703 {
1704 double x0 = ui->sContainer.getXOffset() + 40 * ui->sz;
1705 double w = ui->sContainer. getEffectiveWidth() - 40 * ui->sz;
1706 double frac = (w > 0 ? (pev->getPosition().x + marker->getPosition().x - x0) / w : MINMARKERVALUE);
1707 frac = LIMIT (frac, MINMARKERVALUE, 1.0);
1708
1709 // Limit to antecessors value
1710 for (int j = i - 1; j >= 0; --j)
1711 {
1712 if (ui->markerWidgets[j].hasValue())
1713 {
1714 if (frac < ui->markerWidgets[j].getValue()) frac = ui->markerWidgets[j].getValue();
1715 break;
1716 }
1717 }
1718
1719 // Limit to successors value
1720 for (int j = i + 1; j < nrSteps - 1; ++j)
1721 {
1722 if (ui->markerWidgets[j].hasValue())
1723 {
1724 if (frac > ui->markerWidgets[j].getValue()) frac = ui->markerWidgets[j].getValue();
1725 break;
1726 }
1727 }
1728
1729 ui->setMarker (i, frac);
1730 ui->setAutoMarkers();
1731 ui->rearrange_controllers();
1732 ui->redrawSContainer();
1733 break;
1734 }
1735 }
1736 }
1737
listBoxChangedCallback(BEvents::Event * event)1738 void BSchafflGUI::listBoxChangedCallback (BEvents::Event* event)
1739 {
1740 if (!event) return;
1741 BEvents::ValueChangedEvent* vev = (BEvents::ValueChangedEvent*) event;
1742 BWidgets::ListBox* lb = (BWidgets::ListBox*) vev->getWidget();
1743 if (!lb) return;
1744 Marker* m = (Marker*) lb->getParent();
1745 if (!m) return;
1746 BSchafflGUI* ui = (BSchafflGUI*)m->getMainWindow();
1747 if (!ui) return;
1748
1749 double value = vev->getValue();
1750 if (value == 1.0) m->setHasValue (false);
1751 else if (value == 2.0) m->setHasValue (true);
1752 else return;
1753
1754 lb->hide();
1755 ui->setAutoMarkers();
1756 ui->rearrange_controllers();
1757 ui->redrawSContainer();
1758 }
1759
markersAutoClickedCallback(BEvents::Event * event)1760 void BSchafflGUI::markersAutoClickedCallback (BEvents::Event* event)
1761 {
1762 if (!event) return;
1763 BEvents::ValueChangedEvent* vev = (BEvents::ValueChangedEvent*) event;
1764 if (vev->getValue() == 0.0) return;
1765 HaloButton* hb = (HaloButton*) vev->getWidget();
1766 if (!hb) return;
1767 BSchafflGUI* ui = (BSchafflGUI*)hb->getMainWindow();
1768 if (!ui) return;
1769
1770 if (hb == &ui->markersAutoButton)
1771 {
1772 for (int i = 0; i < MAXSTEPS - 1; ++i)
1773 {
1774 const float v = 0;
1775 ui->markerWidgets[i].setHasValue (false);
1776 if (ui->sharedDataSelection.getValue()) ui->sendController (STEP_POS + i, v);
1777 else ui->write_function (ui->controller, CONTROLLERS + STEP_POS + i, sizeof (float), 0, &v);
1778 }
1779 }
1780
1781 else if (hb == &ui->markersManualButton)
1782 {
1783 for (int i = 0; i < MAXSTEPS - 1; ++i)
1784 {
1785 const float v = ui->markerWidgets[i].getValue();
1786 ui->markerWidgets[i].setHasValue (true);
1787 if (ui->sharedDataSelection.getValue()) ui->sendController (STEP_POS + i, v);
1788 else ui->write_function (ui->controller, CONTROLLERS + STEP_POS + i, sizeof (float), 0, &v);
1789 }
1790 }
1791
1792 ui->setAutoMarkers();
1793 ui->rearrange_controllers();
1794 ui->redrawSContainer();
1795 }
1796
shapeToolClickedCallback(BEvents::Event * event)1797 void BSchafflGUI::shapeToolClickedCallback(BEvents::Event* event)
1798 {
1799 if (!event) return;
1800 HaloToggleButton* widget = (HaloToggleButton*) event->getWidget ();
1801 if (!widget) return;
1802 float value = widget->getValue();
1803 BSchafflGUI* ui = (BSchafflGUI*) widget->getMainWindow();
1804 if (!ui) return;
1805
1806 // Identify tool
1807 int widgetNr = 0;
1808 if (value)
1809 {
1810 for (int i = 1; i < NR_TOOLS; ++i)
1811 {
1812 if (widget == &ui->shapeToolButtons[i - 1])
1813 {
1814 widgetNr = i;
1815 break;
1816 }
1817 }
1818 }
1819
1820 ui->shapeWidget.setTool (ToolType (widgetNr));
1821
1822 // Allow only one button pressed
1823 for (HaloToggleButton& s : ui->shapeToolButtons)
1824 {
1825 if (&s != widget) s.setValue (0.0);
1826 }
1827 }
1828
editToolClickedCallback(BEvents::Event * event)1829 void BSchafflGUI::editToolClickedCallback(BEvents::Event* event)
1830 {
1831 if (!event) return;
1832 HaloButton* widget = (HaloButton*) event->getWidget ();
1833 if (!widget) return;
1834 float value = widget->getValue();
1835 if (value != 1.0) return;
1836 BSchafflGUI* ui = (BSchafflGUI*) widget->getMainWindow();
1837 if (!ui) return;
1838
1839 // Identify editButtons
1840 int widgetNr = -1;
1841 for (size_t i = 0; i < ui->editToolButtons.size(); ++i)
1842 {
1843 if (widget == &ui->editToolButtons[i])
1844 {
1845 widgetNr = i;
1846 break;
1847 }
1848 }
1849
1850 // Action
1851 switch (widgetNr)
1852 {
1853 case 0: ui->clipboard = ui->shapeWidget.cutSelection();
1854 break;
1855
1856 case 1: ui->clipboard = ui->shapeWidget.copySelection();
1857 break;
1858
1859 case 2: ui->shapeWidget.pasteSelection (ui->clipboard);
1860 break;
1861
1862 default: break;
1863 }
1864 }
1865
historyToolClickedCallback(BEvents::Event * event)1866 void BSchafflGUI::historyToolClickedCallback(BEvents::Event* event)
1867 {
1868 if (!event) return;
1869 HaloButton* widget = (HaloButton*) event->getWidget ();
1870 if (!widget) return;
1871 float value = widget->getValue();
1872 if (value != 1.0) return;
1873 BSchafflGUI* ui = (BSchafflGUI*) widget->getMainWindow();
1874 if (!ui) return;
1875
1876 // Identify editButtons
1877 int widgetNr = -1;
1878 for (size_t i = 0; i < ui->historyToolButtons.size(); ++i)
1879 {
1880 if (widget == &ui->historyToolButtons[i])
1881 {
1882 widgetNr = i;
1883 break;
1884 }
1885 }
1886
1887 // Action
1888 if (ui->modeSwitch.getValue() == 0.0)
1889 {
1890 std::array<double, MAXSTEPS> values;
1891
1892 switch (widgetNr)
1893 {
1894 case 0: values.fill (1.0);
1895 ui->sliderHistory.push (values);
1896 break;
1897
1898 case 1: values = ui->sliderHistory.undo();
1899 break;
1900
1901 case 2: values = ui->sliderHistory.redo();
1902 break;
1903
1904 default: break;
1905 }
1906
1907 for (int i = 0; i < MAXSTEPS; ++i)
1908 {
1909 float value = values[i];
1910 ui->stepControl[i].setValueable (false);
1911 ui->stepControl[i].setValue (value);
1912 ui->stepControl[i].setValueable (true);
1913 ui->stepControlLabel[i].setText (BUtilities::to_string (value, "%1.2f"));
1914 if (ui->sharedDataSelection.getValue()) ui->sendController (STEP_LEV + i, value);
1915 else ui->write_function (ui->controller, CONTROLLERS + STEP_LEV + i, sizeof (float), 0, &value);
1916 }
1917 }
1918
1919 else
1920 {
1921 switch (widgetNr)
1922 {
1923 case 0: ui->shapeWidget.reset();
1924 break;
1925
1926 case 1: ui->shapeWidget.undo();
1927 break;
1928
1929 case 2: ui->shapeWidget.redo();
1930 break;
1931
1932 default: break;
1933 }
1934 }
1935 }
1936
gridToolClickedCallback(BEvents::Event * event)1937 void BSchafflGUI::gridToolClickedCallback (BEvents::Event* event)
1938 {
1939 if (!event) return;
1940 HaloToggleButton* widget = (HaloToggleButton*) event->getWidget ();
1941 if (!widget) return;
1942 float value = widget->getValue();
1943 BSchafflGUI* ui = (BSchafflGUI*) widget->getMainWindow();
1944 if (!ui) return;
1945
1946 if (widget == &ui->gridShowButton)
1947 {
1948 if (value) ui->shapeWidget.showGrid();
1949 else ui->shapeWidget.hideGrid();
1950 ui->shapeWidget.setSnap (false);
1951 ui->gridSnapButton.setValue (0.0);
1952 }
1953
1954 else if (widget == &ui->gridSnapButton)
1955 {
1956 if (value)
1957 {
1958 ui->shapeWidget.showGrid();
1959 ui->shapeWidget.setSnap (true);
1960 }
1961 else
1962 {
1963 ui->shapeWidget.hideGrid();
1964 ui->shapeWidget.setSnap (false);
1965 }
1966 ui->gridShowButton.setValue (0.0);
1967 }
1968 }
1969
convertButtonClickedCallback(BEvents::Event * event)1970 void BSchafflGUI::convertButtonClickedCallback (BEvents::Event* event)
1971 {
1972 if (!event) return;
1973 HaloButton* widget = (HaloButton*) event->getWidget ();
1974 if (!widget) return;
1975 BSchafflGUI* ui = (BSchafflGUI*) widget->getMainWindow();
1976 if (!ui) return;
1977
1978 if (widget == &ui->convertToShapeButton)
1979 {
1980 if (!ui->convertToShapeMessage.getParent())
1981 {
1982 ui->add (ui->convertToShapeMessage);
1983 ui->convertToShapeToLinearButton.setValue (1.0);
1984 }
1985 }
1986
1987 else if (widget == &ui->convertToStepsButton)
1988 {
1989 if (!ui->convertToStepsMessage.getParent()) ui->add (ui->convertToStepsMessage);
1990 }
1991 }
1992
lightButtonClickedCallback(BEvents::Event * event)1993 void BSchafflGUI::lightButtonClickedCallback (BEvents::Event* event)
1994 {
1995 if (!event) return;
1996 LightButton* widget = (LightButton*) event->getWidget ();
1997 if (!widget) return;
1998 double value = widget->getValue();
1999 if (!value) return;
2000 BWidgets::Widget* parent = widget->getParent();
2001 if (!parent) return;
2002 std::vector<BWidgets::Widget*> children = parent->getChildren();
2003 BSchafflGUI* ui = (BSchafflGUI*) widget->getMainWindow();
2004 if (!ui) return;
2005
2006 // Un-toggle all other LightButtons
2007 for (BWidgets::Widget* w : children)
2008 {
2009 LightButton* l = dynamic_cast<LightButton*> (w);
2010 if ((l) && (l != widget)) l->setValue (0.0);
2011 }
2012 }
2013
sharedDataClickedCallback(BEvents::Event * event)2014 void BSchafflGUI::sharedDataClickedCallback (BEvents::Event* event)
2015 {
2016 if (!event) return;
2017 HaloToggleButton* widget = (HaloToggleButton*) event->getWidget ();
2018 if (!widget) return;
2019 double value = widget->getValue();
2020 BSchafflGUI* ui = (BSchafflGUI*) widget->getMainWindow();
2021 if (!ui) return;
2022
2023 if (value)
2024 {
2025 for (int i = 0; i < 4; ++i)
2026 {
2027 if (widget == &ui->sharedDataButtons[i])
2028 {
2029 ui->sharedDataSelection.setValue (i + 1);
2030 return;
2031 }
2032 }
2033 }
2034 ui->sharedDataSelection.setValue (0);
2035 }
2036
helpButtonClickedCallback(BEvents::Event * event)2037 void BSchafflGUI::helpButtonClickedCallback (BEvents::Event* event)
2038 {
2039 char cmd[] = WWW_BROWSER_CMD;
2040 char param[] = HELP_URL;
2041 char* argv[] = {cmd, param, NULL};
2042 std::cerr << "BSchaffl.lv2#GUI: Call " << HELP_URL << " for help.\n";
2043 if (BUtilities::vsystem (argv) == -1) std::cerr << "BSchaffl.lv2#GUI: Couldn't fork.\n";
2044 }
2045
ytButtonClickedCallback(BEvents::Event * event)2046 void BSchafflGUI::ytButtonClickedCallback (BEvents::Event* event)
2047 {
2048 char cmd[] = WWW_BROWSER_CMD;
2049 char param[] = YT_URL;
2050 char* argv[] = {cmd, param, NULL};
2051 std::cerr << "BSchaffl.lv2#GUI: Call " << YT_URL << " for tutorial video.\n";
2052 if (BUtilities::vsystem (argv) == -1) std::cerr << "BSchaffl.lv2#GUI: Couldn't fork.\n";
2053 }
2054
stepControlLabelMessageCallback(BEvents::Event * event)2055 void BSchafflGUI::stepControlLabelMessageCallback (BEvents::Event* event)
2056 {
2057 if (event && event->getWidget())
2058 {
2059 BWidgets::Label* l = (BWidgets::Label*)event->getWidget();
2060 BSchafflGUI* ui = (BSchafflGUI*)l->getMainWindow();
2061 if (ui)
2062 {
2063 for (int i = 0; i < MAXSTEPS; ++i)
2064 {
2065 if (l == &ui->stepControlLabel[i])
2066 {
2067 double val = ui->stepControl[i].getValue();
2068 try {val = BUtilities::stof (l->getText());}
2069 catch (std::invalid_argument &ia)
2070 {
2071 fprintf (stderr, "%s\n", ia.what());
2072 l->setText (BUtilities::to_string (val, "%1.2f"));
2073 return;
2074 }
2075
2076 ui->stepControl[i].setValue (val);
2077 l->setText (BUtilities::to_string (ui->stepControl[i].getValue(), "%1.2f"));
2078 break;
2079 }
2080 }
2081 }
2082 }
2083 }
2084
redrawSContainer()2085 void BSchafflGUI::redrawSContainer ()
2086 {
2087 double width = sContainer.getWidth ();
2088 double x0 = sContainer.getXOffset();
2089 double y0 = sContainer.getYOffset();
2090 double height = sContainer.getHeight ();
2091
2092 cairo_surface_clear (sContainer.getDrawingSurface ());
2093 cairo_t* cr = cairo_create (sContainer.getDrawingSurface ());
2094 if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) return;
2095
2096 cairo_pattern_t* pat = cairo_pattern_create_linear (0, 0, 0, height);
2097 cairo_pattern_add_color_stop_rgba (pat, 0.0, CAIRO_RGBA (BColors::black));
2098 cairo_pattern_add_color_stop_rgba (pat, 1.0, 0.0, 0.0, 0.0, 0.5);
2099 cairo_rectangle (cr, 0, 0, width, height);
2100 cairo_set_source (cr, pat);
2101 cairo_fill (cr);
2102 cairo_pattern_destroy (pat);
2103
2104 int nrSteps = controllers[NR_OF_STEPS]->getValue();
2105
2106 // Step lines
2107 cairo_set_line_width (cr, 1.0);
2108 cairo_set_source_rgba (cr, CAIRO_RGBA (BColors::grey));
2109 cairo_move_to (cr, 40 * sz - x0, -y0);
2110 cairo_rel_line_to (cr, 0, 240 * sz);
2111
2112 for (int i = 0; i < nrSteps - 1; ++i)
2113 {
2114 cairo_move_to (cr, double (i + 1) / double (nrSteps) * (width - 40 * sz) + 40 * sz - x0, -y0);
2115 cairo_rel_line_to (cr, 0, 170 * sz);
2116 cairo_line_to (cr, markerWidgets[i].getValue() * (width - 40 * sz) + 40 * sz - x0, 180 * sz - y0);
2117 cairo_rel_line_to (cr, 0, 60 * sz);
2118 cairo_stroke (cr);
2119 }
2120
2121 cairo_destroy (cr);
2122 sContainer.update();
2123 }
2124
instantiate(const LV2UI_Descriptor * descriptor,const char * plugin_uri,const char * bundle_path,LV2UI_Write_Function write_function,LV2UI_Controller controller,LV2UI_Widget * widget,const LV2_Feature * const * features)2125 static LV2UI_Handle instantiate (const LV2UI_Descriptor *descriptor, const char *plugin_uri, const char *bundle_path,
2126 LV2UI_Write_Function write_function, LV2UI_Controller controller, LV2UI_Widget *widget,
2127 const LV2_Feature *const *features)
2128 {
2129 PuglNativeView parentWindow = 0;
2130 LV2UI_Resize* resize = NULL;
2131
2132 if (strcmp(plugin_uri, BSCHAFFL_URI) != 0)
2133 {
2134 std::cerr << "BSchaffl.lv2#GUI: GUI does not support plugin with URI " << plugin_uri << std::endl;
2135 return NULL;
2136 }
2137
2138 for (int i = 0; features[i]; ++i)
2139 {
2140 if (!strcmp(features[i]->URI, LV2_UI__parent)) parentWindow = (PuglNativeView) features[i]->data;
2141 else if (!strcmp(features[i]->URI, LV2_UI__resize)) resize = (LV2UI_Resize*)features[i]->data;
2142 }
2143 if (parentWindow == 0) std::cerr << "BSchaffl.lv2#GUI: No parent window.\n";
2144
2145 // New instance
2146 BSchafflGUI* ui;
2147 try {ui = new BSchafflGUI (bundle_path, features, parentWindow);}
2148 catch (std::exception& exc)
2149 {
2150 std::cerr << "BSchaffl.lv2#GUI: Instantiation failed. " << exc.what () << std::endl;
2151 return NULL;
2152 }
2153
2154 ui->controller = controller;
2155 ui->write_function = write_function;
2156
2157 // Reduce min GUI size for small displays
2158 double sz = 1.0;
2159 int screenWidth = getScreenWidth ();
2160 int screenHeight = getScreenHeight ();
2161 if ((screenWidth < 1060) || (screenHeight < 520)) sz = 0.66;
2162
2163 if (resize) resize->ui_resize(resize->handle, 1020 * sz, 480 * sz);
2164
2165 *widget = (LV2UI_Widget) puglGetNativeWindow (ui->getPuglView ());
2166
2167 ui->sendUiStatus (true);
2168 return (LV2UI_Handle) ui;
2169 }
2170
cleanup(LV2UI_Handle ui)2171 static void cleanup(LV2UI_Handle ui)
2172 {
2173 BSchafflGUI* pluginGui = (BSchafflGUI*) ui;
2174 if (pluginGui) delete pluginGui;
2175 }
2176
portEvent(LV2UI_Handle ui,uint32_t port_index,uint32_t buffer_size,uint32_t format,const void * buffer)2177 static void portEvent(LV2UI_Handle ui, uint32_t port_index, uint32_t buffer_size,
2178 uint32_t format, const void* buffer)
2179 {
2180 BSchafflGUI* pluginGui = (BSchafflGUI*) ui;
2181 if (pluginGui) pluginGui->portEvent(port_index, buffer_size, format, buffer);
2182 }
2183
callIdle(LV2UI_Handle ui)2184 static int callIdle (LV2UI_Handle ui)
2185 {
2186 BSchafflGUI* pluginGui = (BSchafflGUI*) ui;
2187 if (pluginGui) pluginGui->handleEvents ();
2188 return 0;
2189 }
2190
callResize(LV2UI_Handle ui,int width,int height)2191 static int callResize (LV2UI_Handle ui, int width, int height)
2192 {
2193 BSchafflGUI* self = (BSchafflGUI*) ui;
2194 if (!self) return 0;
2195
2196 BEvents::ExposeEvent* ev = new BEvents::ExposeEvent (self, self, BEvents::CONFIGURE_REQUEST_EVENT, self->getPosition().x, self->getPosition().y, width, height);
2197 self->addEventToQueue (ev);
2198 return 0;
2199 }
2200
2201 static const LV2UI_Idle_Interface idle = {callIdle};
2202 static const LV2UI_Resize resize = {nullptr, callResize};
2203
extensionData(const char * uri)2204 static const void* extensionData(const char* uri)
2205 {
2206 if (!strcmp(uri, LV2_UI__idleInterface)) return &idle;
2207 else if(!strcmp(uri, LV2_UI__resize)) return &resize;
2208 else return NULL;
2209 }
2210
2211 static const LV2UI_Descriptor guiDescriptor = {
2212 BSCHAFFLGUI_URI,
2213 instantiate,
2214 cleanup,
2215 portEvent,
2216 extensionData
2217 };
2218
2219 // LV2 Symbol Export
lv2ui_descriptor(uint32_t index)2220 LV2_SYMBOL_EXPORT const LV2UI_Descriptor *lv2ui_descriptor(uint32_t index)
2221 {
2222 switch (index) {
2223 case 0: return &guiDescriptor;
2224 default:return NULL;
2225 }
2226 }
2227