1 /* B.Choppr
2  * Step Sequencer Effect Plugin
3  *
4  * Copyright (C) 2018, 2019 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 "BChoppr_GUI.hpp"
22 #include "Ports.hpp"
23 #include "screen.h"
24 #include "BUtilities/stof.hpp"
25 #include "BUtilities/vsystem.hpp"
26 
27 
BChoppr_GUI(const char * bundle_path,const LV2_Feature * const * features,PuglNativeView parentWindow)28 BChoppr_GUI::BChoppr_GUI (const char *bundle_path, const LV2_Feature *const *features, PuglNativeView parentWindow) :
29 	Window (760, 560, "B.Choppr", parentWindow, true, PUGL_MODULE, 0),
30 	controller (NULL), write_function (NULL),
31 
32 	mContainer (0, 0, 760, 560, "main"),
33 	rContainer (260, 80, 480, 350, "rcontainer"),
34 	sContainer (3, 210, 474, 137, "scontainer"),
35 	monitorSwitch (600, 15, 40, 16, "switch", 0.0),
36 	monitorLabel (600, 35, 40, 20, "smlabel", BCHOPPR_LABEL_MONITOR),
37 	bypassButton (662, 15, 16, 16, "redbutton"),
38 	bypassLabel (650, 35, 40, 20, "smlabel", BCHOPPR_LABEL_BYPASS),
39 	drywetDial (703, 5, 33, 40, "dial", 1.0, 0.0, 1.0, 0.0, "%1.2f"),
40 	drywetLabel (690, 35, 60, 20, "smlabel", BCHOPPR_LABEL_DRY_WET),
41 	helpButton (20, 80, 24, 24, "halobutton", BCHOPPR_LABEL_HELP),
42 	ytButton (50, 80, 24, 24, "halobutton", BCHOPPR_LABEL_TUTORIAL),
43 	monitorDisplay (3, 3, 474, 207, "mmonitor"),
44 	blendControl (0, 0, 0, 0, "widget", 1, 1, 2, 1),
45 	rectButton (40, 240, 60, 40, "abutton"),
46 	sinButton (140, 240, 60, 40, "nbutton"),
47 	stepshapeDisplay (30, 290, 180, 140, "smonitor"),
48 	attackControl (40, 445, 50, 60, "dial", 0.2, 0.01, 1.0, 0.01, "%1.2f"),
49 	attackLabel (20, 500, 90, 20, "label", BCHOPPR_LABEL_ATTACK),
50 	releaseControl (150, 445, 50, 60, "dial", 0.2, 0.01, 1.0, -0.01, "%1.2f"),
51 	releaseLabel (130, 500, 90, 20, "label", BCHOPPR_LABEL_DECAY),
52 	sequencesperbarControl (260, 442, 120, 28, "slider", 1.0, 1.0, 8.0, 1.0, "%1.0f"),
53 	sequencesperbarLabel (260, 470, 120, 20, "label", BCHOPPR_LABEL_SEQUENCES_PER_BAR),
54 	ampSwingControl
55 	(
56 		400, 442, 110, 28, "slider", 1.0, 0.001, 1000.0, 0.0, "%4.1f",
57 		[] (const double val, const double min, const double max)
58 		{return (val >= 1.0 ? 1.0 - 0.5 / LIMIT (sqrt(val), sqrt(min), sqrt(max)) : 0.5 * LIMIT (sqrt(val), sqrt(min), sqrt(max)));},
59 		[] (const double frac, const double min, const double max)
__anonbeee13fc0202(const double frac, const double min, const double max) 60 		{return (frac >= 0.5 ? pow (0.5 / (1.0 - LIMIT (frac, 0, 1)), 2) : pow (2 * LIMIT (frac, 0, 1), 2));}
61 	),
62 	ampSwingLabel (400, 470, 110, 20, "label", BCHOPPR_LABEL_AMP_SWING),
63 	swingControl (525, 442, 110, 28, "slider", 1.0, 1.0 / 3.0, 3.0, 0.0),
64 	swingLabel (525, 470, 110, 20, "label", BCHOPPR_LABEL_STEPS_SWING),
65 	markersAutoButton (655, 450, 80, 20, "button", BCHOPPR_LABEL_AUTO),
66 	markersAutoLabel (655, 470, 80, 20, "label", BCHOPPR_LABEL_MARKER),
67 	nrStepsControl (260, 502, 480, 28, "slider", 1.0, 1.0, MAXSTEPS, 1.0, "%2.0f"),
68 	nrStepsLabel (260, 530, 480, 20, "label", BCHOPPR_LABEL_NUMBER_OF_STEPS),
69 	stepshapeLabel (33, 293, 120, 20, "llabel", BCHOPPR_LABEL_STEP_SHAPE),
70 	sequencemonitorLabel (263, 83, 120, 20, "llabel", BCHOPPR_LABEL_SEQUENCE_MONITOR),
71 	messageLabel (420, 83, 280, 20, "hilabel", ""),
72 	markerListBox (12, -68, 86, 66, "listbox", BItems::ItemList ({BCHOPPR_LABEL_MARKER, BCHOPPR_LABEL_MANUAL})),
73 	sharedDataSelection (28, 528, 194, 24, "widget", 0, 0, 4, 1),
74 
75 	surface (NULL), cr1 (NULL), cr2 (NULL), cr3 (NULL), cr4 (NULL), pat1 (NULL), pat2 (NULL), pat3 (NULL), pat4 (NULL), pat5 (NULL),
76 	pluginPath (bundle_path ? std::string (bundle_path) : std::string ("")),  sz (1.0), bgImageSurface (nullptr),
77 	scale (DB_CO(0.0)),
78 	map (NULL)
79 
80 {
81 	if (!init_mainMonitor () || !init_Stepshape ())
82 	{
83 		std::cerr << "BChoppr.lv2#GUI: Failed to init monitor." <<  std::endl;
84 		destroy_mainMonitor ();
85 		destroy_Stepshape ();
86 		throw std::bad_alloc ();
87 	}
88 
89 	//Initialialize and configure stepControllers
90 	double sw = sContainer.getEffectiveWidth();
91 	double sx = sContainer.getXOffset();
92 	for (int i = 0; i < MAXSTEPS; ++i)
93 	{
94 		stepControl[i] = BWidgets::VSlider ((i + 0.5) * sw / MAXSTEPS + sx - 7, 60, 14, 80, "slider", 1.0, 0.0, 1.0, 0.01);
95 		stepControl[i].setHardChangeable (false);
96 		stepControl[i].setScrollable (true);
97 		stepControl[i].applyTheme (theme, "slider");
98 		sContainer.add (stepControl[i]);
99 
100 		stepControlLabel[i] = BWidgets::Label ((i + 0.5) * sw / MAXSTEPS + sx - 14, 40, 28, 20, "mlabel", "1.00");
101 		stepControlLabel[i].applyTheme (theme, "mlabel");
102 		stepControlLabel[i].setState (BColors::ACTIVE);
103 		stepControlLabel[i].setEditable (true);
104 		stepControlLabel[i].setCallbackFunction(BEvents::EventType::MESSAGE_EVENT, stepControlLabelMessageCallback);
105 		sContainer.add (stepControlLabel[i]);
106 	}
107 
108 	//Initialialize and configure markers
109 	for (int i = 0; i < MAXSTEPS - 1; ++i)
110 	{
111 		markerWidgets[i] = Marker ((i + 1) * sw / MAXSTEPS + sx - 5, 10, 10, 16, "marker", (double(i) + 1.0) / MAXSTEPS, 0.0, 1.0, 0.0);
112 		markerWidgets[i].setHasValue (false);
113 		markerWidgets[i].setDraggable (true);
114 		markerWidgets[i].setCallbackFunction (BEvents::EventType::BUTTON_PRESS_EVENT, BChoppr_GUI::markerClickedCallback);
115 		markerWidgets[i].setCallbackFunction (BEvents::EventType::POINTER_DRAG_EVENT, BChoppr_GUI::markerDraggedCallback);
116 		markerWidgets[i].applyTheme (theme, "slider");
117 		sContainer.add (markerWidgets[i]);
118 	}
119 
120 	for (int i = 0; i < 4; ++i) sharedDataButtons[i] = HaloToggleButton
121 	(50 * i, 0, 44, 24, "halobutton", BCHOPPR_LABEL_SHARED_DATA " " + std::to_string (i + 1));
122 
123 	// Link controllers
124 	controllers[Bypass - Controllers] = &bypassButton;
125 	controllers[DryWet - Controllers] = &drywetDial;
126 	controllers[Blend - Controllers] = &blendControl;
127 	controllers[Attack - Controllers] = &attackControl;
128 	controllers[Release - Controllers] = &releaseControl;
129 	controllers[SequencesPerBar - Controllers] = &sequencesperbarControl;
130 	controllers[AmpSwing - Controllers] = &ampSwingControl;
131 	controllers[Swing - Controllers] = &swingControl;
132 	controllers[NrSteps - Controllers] = &nrStepsControl;
133 	for (int i = 0; i < MAXSTEPS - 1; ++i) controllers[StepPositions + i - Controllers] = &markerWidgets[i];
134 	for (int i = 0; i < MAXSTEPS; ++i) controllers[StepLevels + i - Controllers] = &stepControl[i];
135 
136 	// Set callbacks
137 	for (int i = 0; i < NrControllers; ++i) controllers[i]->setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BChoppr_GUI::valueChangedCallback);
138 	monitorSwitch.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BChoppr_GUI::valueChangedCallback);
139 	monitorDisplay.setCallbackFunction (BEvents::EventType::WHEEL_SCROLL_EVENT, BChoppr_GUI::monitorScrolledCallback);
140 	monitorDisplay.setCallbackFunction (BEvents::EventType::POINTER_DRAG_EVENT, BChoppr_GUI::monitorDraggedCallback);
141 	markerListBox.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BChoppr_GUI::listBoxChangedCallback);
142 	markersAutoButton.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BChoppr_GUI::markersAutoClickedCallback);
143 	rectButton.setCallbackFunction (BEvents::EventType::BUTTON_PRESS_EVENT, BChoppr_GUI::buttonClickedCallback);
144 	sinButton.setCallbackFunction (BEvents::EventType::BUTTON_PRESS_EVENT, BChoppr_GUI::buttonClickedCallback);
145 	helpButton.setCallbackFunction(BEvents::BUTTON_PRESS_EVENT, helpButtonClickedCallback);
146 	ytButton.setCallbackFunction(BEvents::BUTTON_PRESS_EVENT, ytButtonClickedCallback);
147 	for (HaloToggleButton& s: sharedDataButtons) s.setCallbackFunction (BEvents::EventType::BUTTON_PRESS_EVENT, BChoppr_GUI::sharedDataClickedCallback);
148 	sharedDataSelection.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BChoppr_GUI::valueChangedCallback);
149 
150 	// Configure widgets
151 	bgImageSurface = cairo_image_surface_create_from_png ((pluginPath + BG_FILE).c_str());
152 	widgetBg.loadFillFromCairoSurface (bgImageSurface);
153 	drywetDial.setScrollable (true);
154 	drywetDial.setHardChangeable (false);
155 	attackControl.setScrollable (true);
156 	attackControl.setHardChangeable (false);
157 	releaseControl.setScrollable (true);
158 	releaseControl.setHardChangeable (false);
159 	sequencesperbarControl.setScrollable (true);
160 	ampSwingControl.setHardChangeable (false);
161 	swingControl.setHardChangeable (false);
162 	nrStepsControl.setScrollable (true);
163 	monitorDisplay.setScrollable (true);
164 	monitorDisplay.setDraggable (true);
165 	markerListBox.setStacking (BWidgets::STACKING_OVERSIZE);
166 	applyTheme (theme);
167 
168 
169 	setAutoMarkers ();
170 	rearrange_controllers ();
171 	redrawMainMonitor ();
172 	redrawSContainer ();
173 	redrawButtons ();
174 
175 	// Pack widgets
176 	mContainer.add (rContainer);
177 	rContainer.add (monitorDisplay);
178 	rContainer.add (sContainer);
179 	mContainer.add (blendControl);
180 	mContainer.add (monitorSwitch);
181 	mContainer.add (monitorLabel);
182 	mContainer.add (bypassButton);
183 	mContainer.add (bypassLabel);
184 	mContainer.add (drywetDial);
185 	mContainer.add (drywetLabel);
186 	mContainer.add (helpButton);
187 	mContainer.add (ytButton);
188 	mContainer.add (rectButton);
189 	mContainer.add (sinButton);
190 	mContainer.add (stepshapeDisplay);
191 	mContainer.add (attackControl);
192 	mContainer.add (attackLabel);
193 	mContainer.add (releaseControl);
194 	mContainer.add (releaseLabel);
195 	mContainer.add (sequencesperbarControl);
196 	mContainer.add (sequencesperbarLabel);
197 	mContainer.add (ampSwingControl);
198 	mContainer.add (ampSwingLabel);
199 	mContainer.add (swingControl);
200 	mContainer.add (swingLabel);
201 	mContainer.add (markersAutoButton);
202 	mContainer.add (markersAutoLabel);
203 	mContainer.add (nrStepsControl);
204 	mContainer.add (nrStepsLabel);
205 	mContainer.add (stepshapeLabel);
206 	mContainer.add (sequencemonitorLabel);
207 	mContainer.add (messageLabel);
208 	for (HaloToggleButton& s : sharedDataButtons) sharedDataSelection.add (s);
209 	mContainer.add (sharedDataSelection);
210 	add (mContainer);
211 
212 	//Scan host features for URID map
213 	LV2_URID_Map* m = NULL;
214 	for (int i = 0; features[i]; ++i)
215 	{
216 		if (strcmp(features[i]->URI, LV2_URID__map) == 0) m = (LV2_URID_Map*) features[i]->data;
217 	}
218 	if (!m) throw std::invalid_argument ("Host does not support urid:map");
219 
220 	//Map URIS
221 	map = m;
222 	getURIs (map, &uris);
223 
224 	// Initialize forge
225 	lv2_atom_forge_init (&forge,map);
226 }
227 
~BChoppr_GUI()228 BChoppr_GUI::~BChoppr_GUI()
229 {
230 	send_record_off ();
231 	destroy_mainMonitor ();
232 	destroy_Stepshape ();
233 }
234 
portEvent(uint32_t port_index,uint32_t buffer_size,uint32_t format,const void * buffer)235 void BChoppr_GUI::portEvent(uint32_t port_index, uint32_t buffer_size, uint32_t format, const void* buffer)
236 {
237 	// Notify port
238 	if ((format == uris.atom_eventTransfer) && (port_index == Notify))
239 	{
240 		const LV2_Atom* atom = (const LV2_Atom*) buffer;
241 		if ((atom->type == uris.atom_Blank) || (atom->type == uris.atom_Object))
242 		{
243 			const LV2_Atom_Object* obj = (const LV2_Atom_Object*) atom;
244 
245 			// Linked / unlinked to shared data
246 			if (obj->body.otype == uris.notify_sharedDataLinkEvent)
247 			{
248 				LV2_Atom *oNr = NULL;
249 
250 				lv2_atom_object_get
251 				(
252 					obj,
253 					uris.notify_sharedDataNr, &oNr,
254 					NULL
255 				);
256 
257 				if (oNr && (oNr->type == uris.atom_Int))
258 				{
259 					const int nr = ((LV2_Atom_Int*)oNr)->body;
260 					if ((nr >= 0) && (nr <= 4) && (nr != sharedDataSelection.getValue()))
261 					{
262 						sharedDataSelection.setValueable (false);
263 						sharedDataSelection.setValue (nr);
264 						sharedDataSelection.setValueable (true);
265 
266 						for (int i = 0; i < 4; ++i)
267 						{
268 							sharedDataButtons[i].setValueable (false);
269 							sharedDataButtons[i].setValue (i == nr - 1 ? 1 : 0);
270 							sharedDataButtons[i].setValueable (true);
271 						}
272 
273 					}
274 				}
275 			}
276 
277 			// Controller changed
278 			else if (obj->body.otype == uris.notify_controllerEvent)
279 			{
280 				LV2_Atom *oNr = NULL, *oVal = NULL;
281 
282 				lv2_atom_object_get
283 				(
284 					obj,
285 					uris.notify_controllerNr, &oNr,
286 					uris.notify_controllerValue, &oVal,
287 					NULL
288 				);
289 
290 				if (oNr && (oNr->type == uris.atom_Int) && oVal && (oVal->type == uris.atom_Float))
291 				{
292 					const int nr =  ((LV2_Atom_Int*)oNr)->body;
293 					const float val = ((LV2_Atom_Float*)oVal)->body;
294 
295 					if ((nr >= StepPositions - Controllers) && (nr < StepPositions - Controllers + MAXSTEPS - 1))
296 					{
297 						setMarker (nr - (StepPositions - Controllers), val);
298 						setAutoMarkers ();
299 						rearrange_controllers ();
300 						redrawSContainer ();
301 						redrawMainMonitor ();
302 					}
303 
304 					else setController (nr, val);
305 				}
306 			}
307 
308 			// Monitor notification
309 			else if (obj->body.otype == uris.notify_event)
310 			{
311 				const LV2_Atom* data = NULL;
312 				lv2_atom_object_get(obj, uris.notify_key, &data, 0);
313 				if (data && (data->type == uris.atom_Vector))
314 				{
315 					const LV2_Atom_Vector* vec = (const LV2_Atom_Vector*) data;
316 					if (vec->body.child_type == uris.atom_Float)
317 					{
318 						uint32_t notificationsCount = (uint32_t) ((data->size - sizeof(LV2_Atom_Vector_Body)) / sizeof (BChopprNotifications));
319 						BChopprNotifications* notifications = (BChopprNotifications*) (&vec->body + 1);
320 						if (notificationsCount > 0)
321 						{
322 							add_monitor_data (notifications, notificationsCount, mainMonitor.horizonPos);
323 							redrawMainMonitor ();
324 						}
325 					}
326 				}
327 				else std::cerr << "BChoppr.lv2#GUI: Corrupt audio message." << std::endl;
328 			}
329 
330 			// Message notification
331 			else if (obj->body.otype == uris.notify_messageEvent)
332 			{
333 				const LV2_Atom* data = NULL;
334 				lv2_atom_object_get(obj, uris.notify_message, &data, 0);
335 				if (data && (data->type == uris.atom_Int))
336 				{
337 					const int messageNr = ((LV2_Atom_Int*)data)->body;
338 					std::string msg = ((messageNr >= NO_MSG) && (messageNr <= MAX_MSG) ? messageStrings[messageNr] : "");
339 					messageLabel.setText (msg);
340 				}
341 			}
342 		}
343 	}
344 
345 	// Scan remaining ports
346 	else if ((format == 0) && (port_index >= Controllers) && (port_index < Controllers + NrControllers) && (sharedDataSelection.getValue() == 0))
347 	{
348 		int nr = port_index - Controllers;
349 		float val = *(float*) buffer;
350 		if ((nr >= StepPositions - Controllers) && (nr < StepPositions - Controllers + MAXSTEPS - 1))
351 		{
352 			setMarker (nr - (StepPositions - Controllers), val);
353 			setAutoMarkers ();
354 			rearrange_controllers ();
355 			redrawSContainer ();
356 			redrawMainMonitor();
357 		}
358 
359 		else setController (nr, val);
360 	}
361 }
362 
resizeGUI()363 void BChoppr_GUI::resizeGUI()
364 {
365 	hide ();
366 
367 	// Resize Fonts
368 	defaultFont.setFontSize (12 * sz);
369 	leftFont.setFontSize (12 * sz);
370 	mdFont.setFontSize (10 * sz);
371 	smFont.setFontSize (8 * sz);
372 
373 	// Resize Background
374 	cairo_surface_t* surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 760 * sz, 560 * sz);
375 	cairo_t* cr = cairo_create (surface);
376 	cairo_scale (cr, sz, sz);
377 	cairo_set_source_surface(cr, bgImageSurface, 0, 0);
378 	cairo_paint(cr);
379 	widgetBg.loadFillFromCairoSurface(surface);
380 	cairo_destroy (cr);
381 	cairo_surface_destroy (surface);
382 
383 	// Resize widgets
384 	RESIZE (mContainer, 0, 0, 760, 560, sz);
385 	RESIZE (rContainer, 260, 80, 480, 350, sz);
386 	RESIZE (monitorSwitch, 600, 15, 40, 16, sz);
387 	RESIZE (monitorLabel, 600, 35, 40, 20, sz);
388 	RESIZE (bypassButton, 662, 15, 16, 16, sz);
389 	RESIZE (bypassLabel, 650, 35, 40, 20, sz);
390 	RESIZE (drywetDial, 703, 5, 33, 40, sz);
391 	RESIZE (drywetLabel, 690, 35, 60, 20, sz);
392 	RESIZE (helpButton, 20, 80, 24, 24, sz);
393 	RESIZE (ytButton, 50, 80, 24, 24, sz);
394 	RESIZE (monitorDisplay, 3, 3, 474, 207, sz);
395 	RESIZE (blendControl, 0, 0, 0, 0, sz);
396 	RESIZE (rectButton, 40, 240, 60, 40, sz);
397 	RESIZE (sinButton, 140, 240, 60, 40, sz);
398 	RESIZE (stepshapeDisplay, 30, 290, 180, 140, sz);
399 	RESIZE (attackControl, 40, 445, 50, 60, sz);
400 	RESIZE (attackLabel, 20, 500, 90, 20, sz);
401 	RESIZE (releaseControl, 150, 445, 50, 60, sz);
402 	RESIZE (releaseLabel, 130, 500, 90, 20, sz);
403 	RESIZE (sequencesperbarControl, 260, 442, 120, 28, sz);
404 	RESIZE (sequencesperbarLabel, 260, 470, 120, 20, sz);
405 	RESIZE (ampSwingControl, 400, 442, 110, 28, sz);
406 	RESIZE (ampSwingLabel, 400, 470, 110, 20, sz);
407 	RESIZE (swingControl, 525, 442, 110, 28, sz);
408 	RESIZE (swingLabel, 525, 470, 110, 20, sz);
409 	RESIZE (markersAutoButton, 655, 450, 80, 20, sz);
410 	RESIZE (markersAutoLabel, 655, 470, 80, 20, sz);
411 	RESIZE (nrStepsControl, 260, 502, 480, 28, sz);
412 	RESIZE (nrStepsLabel, 260, 530, 480, 20, sz);
413 	RESIZE (stepshapeLabel, 33, 293, 120, 20, sz);
414 	RESIZE (sequencemonitorLabel, 263, 83, 120, 20, sz);
415 	RESIZE (messageLabel, 420, 83, 280, 20,sz);
416 	RESIZE (sContainer, 3, 210, 474, 137, sz);
417 	RESIZE (markerListBox, 12, -68, 86, 66, sz);
418 	markerListBox.resizeItems (BUtilities::Point (80 * sz, 20 * sz));
419 	RESIZE (sharedDataSelection, 28, 528, 194, 24, sz);
420 	for (int i = 0; i < 4; ++i) {RESIZE (sharedDataButtons[i], 50 * i, 0, 44, 24, sz);}
421 
422 	// Update monitors
423 	destroy_Stepshape ();
424 	init_Stepshape ();
425 	redrawStepshape ();
426 	destroy_mainMonitor ();
427 	init_mainMonitor ();
428 	redrawMainMonitor ();
429 	redrawSContainer ();
430 	rearrange_controllers ();
431 	redrawButtons ();
432 
433 	// Apply changes
434 	applyTheme (theme);
435 	show ();
436 }
437 
applyTheme(BStyles::Theme & theme)438 void BChoppr_GUI::applyTheme (BStyles::Theme& theme)
439 {
440 	mContainer.applyTheme (theme);
441 	rContainer.applyTheme (theme);
442 	monitorSwitch.applyTheme (theme);
443 	monitorLabel.applyTheme (theme);
444 	bypassButton.applyTheme (theme);
445 	bypassLabel.applyTheme (theme);
446 	drywetDial.applyTheme (theme);
447 	drywetLabel.applyTheme (theme);
448 	helpButton.applyTheme (theme);
449 	ytButton.applyTheme (theme);
450 	monitorDisplay.applyTheme (theme);
451 	blendControl.applyTheme (theme);
452 	rectButton.applyTheme (theme);
453 	sinButton.applyTheme (theme);
454 	stepshapeDisplay.applyTheme (theme);
455 	attackControl.applyTheme (theme);
456 	attackLabel.applyTheme (theme);
457 	releaseControl.applyTheme (theme);
458 	releaseLabel.applyTheme (theme);
459 	sequencesperbarControl.applyTheme (theme);
460 	sequencesperbarLabel.applyTheme (theme);
461 	ampSwingControl.applyTheme (theme);
462 	ampSwingLabel.applyTheme (theme);
463 	swingControl.applyTheme (theme);
464 	swingLabel.applyTheme (theme);
465 	markersAutoButton.applyTheme (theme);
466 	markersAutoLabel.applyTheme (theme);
467 	nrStepsControl.applyTheme (theme);
468 	nrStepsLabel.applyTheme (theme);
469 	stepshapeLabel.applyTheme (theme);
470 	sequencemonitorLabel.applyTheme (theme);
471 	messageLabel.applyTheme (theme);
472 	sContainer.applyTheme (theme);
473 	markerListBox.applyTheme (theme);
474 	for (int i = 0; i < MAXSTEPS; ++i)
475 	{
476 		stepControl[i].applyTheme (theme);
477 		stepControlLabel[i].applyTheme (theme);
478 	}
479 	sharedDataSelection.applyTheme (theme);
480 	for (HaloToggleButton& s : sharedDataButtons) s.applyTheme (theme);
481 }
482 
onConfigureRequest(BEvents::ExposeEvent * event)483 void BChoppr_GUI::onConfigureRequest (BEvents::ExposeEvent* event)
484 {
485 	Window::onConfigureRequest (event);
486 
487 	sz = (getWidth() / 760 > getHeight() / 560 ? getHeight() / 560 : getWidth() / 760);
488 	resizeGUI ();
489 }
490 
send_record_on()491 void BChoppr_GUI::send_record_on ()
492 {
493 	uint8_t obj_buf[64];
494 	lv2_atom_forge_set_buffer(&forge, obj_buf, sizeof(obj_buf));
495 
496 	LV2_Atom_Forge_Frame frame;
497 	LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object(&forge, &frame, 0, uris.ui_on);
498 	lv2_atom_forge_pop(&forge, &frame);
499 	write_function(controller, Control_2, lv2_atom_total_size(msg), uris.atom_eventTransfer, msg);
500 	monitorSwitch.setValue (1.0);
501 }
502 
send_record_off()503 void BChoppr_GUI::send_record_off ()
504 {
505 	uint8_t obj_buf[64];
506 	lv2_atom_forge_set_buffer(&forge, obj_buf, sizeof(obj_buf));
507 
508 	LV2_Atom_Forge_Frame frame;
509 	LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object(&forge, &frame, 0, uris.ui_off);
510 	lv2_atom_forge_pop(&forge, &frame);
511 	write_function(controller, Control_2, lv2_atom_total_size(msg), uris.atom_eventTransfer, msg);
512 	monitorSwitch.setValue (0.0);
513 }
514 
sendSharedDataNr()515 void BChoppr_GUI::sendSharedDataNr ()
516 {
517 	uint8_t obj_buf[64];
518 	lv2_atom_forge_set_buffer(&forge, obj_buf, sizeof(obj_buf));
519 
520 	LV2_Atom_Forge_Frame frame;
521 	LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object(&forge, &frame, 0, uris.notify_sharedDataLinkEvent);
522 	lv2_atom_forge_key (&forge, uris.notify_sharedDataNr);
523 	lv2_atom_forge_int (&forge, sharedDataSelection.getValue());
524 	lv2_atom_forge_pop(&forge, &frame);
525 	write_function(controller, Control_2, lv2_atom_total_size(msg), uris.atom_eventTransfer, msg);
526 }
527 
sendController(const int nr,const float value)528 void BChoppr_GUI::sendController (const int nr, const float value)
529 {
530 	uint8_t obj_buf[64];
531 	lv2_atom_forge_set_buffer(&forge, obj_buf, sizeof(obj_buf));
532 
533 	LV2_Atom_Forge_Frame frame;
534 	LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object(&forge, &frame, 0, uris.notify_controllerEvent);
535 	lv2_atom_forge_key (&forge, uris.notify_controllerNr);
536 	lv2_atom_forge_int (&forge, nr);
537 	lv2_atom_forge_key (&forge, uris.notify_controllerValue);
538 	lv2_atom_forge_float (&forge, value);
539 	lv2_atom_forge_pop(&forge, &frame);
540 	write_function(controller, Control_2, lv2_atom_total_size(msg), uris.atom_eventTransfer, msg);
541 }
542 
setController(const int nr,const double value)543 float BChoppr_GUI::setController (const int nr, const double value)
544 {
545 	controllers[nr]->setValueable (false);
546 	controllers[nr]->setValue (value);
547 	controllers[nr]->setValueable (true);
548 
549 	if (nr == Blend - Controllers)
550 	{
551 		if (value == 1) {rectButton.rename ("abutton"); sinButton.rename ("nbutton");}
552 		else if (value == 2) {sinButton.rename ("abutton"); rectButton.rename ("nbutton");}
553 		rectButton.applyTheme (theme);
554 		sinButton.applyTheme (theme);
555 		redrawButtons ();
556 		redrawStepshape ();
557 	}
558 
559 	else if ((nr == Attack - Controllers) || (nr == Release - Controllers)) redrawStepshape ();
560 
561 	else if (nr == AmpSwing - Controllers) rearrange_controllers();
562 
563 	else if (nr == Swing - Controllers)
564 	{
565 		setAutoMarkers();
566 		rearrange_controllers();
567 		redrawSContainer();
568 		redrawMainMonitor();
569 	}
570 
571 	else if (nr == NrSteps - Controllers)
572 	{
573 		setAutoMarkers();
574 		rearrange_controllers();
575 		redrawSContainer();
576 		redrawMainMonitor();
577 	}
578 
579 	else if ((nr >= StepPositions - Controllers) and (nr < StepPositions - Controllers + MAXSTEPS - 1))
580 	{
581 		return (((Marker*)controllers[nr])->hasValue() ? value : 0.0f);
582 	}
583 
584 	else if ((nr >= StepLevels - Controllers) and (nr < StepLevels - Controllers + MAXSTEPS))
585 	{
586 		stepControlLabel[nr - (StepLevels - Controllers)].setText (BUtilities::to_string (value, "%1.2f"));
587 	}
588 
589 	return value;
590 }
591 
setMarker(const int markerNr,double value)592 void BChoppr_GUI::setMarker (const int markerNr, double value)
593 {
594 	if ((markerNr < 0) || (markerNr >= MAXSTEPS - 1)) return;
595 
596 	// Value 0.0: Automatic
597 	if (value == 0.0)
598 	{
599 		markerWidgets[markerNr].setHasValue (false);
600 	}
601 
602 	else
603 	{
604 		// Set value and switch off automatic
605 		value = LIMIT (value, MINMARKERVALUE, 1.0);
606 		markerWidgets[markerNr].setHasValue (true);
607 		markerWidgets[markerNr].setValue (value);
608 
609 		// Validate ancessors
610 		for (int i = markerNr - 1; i >= 0; --i)
611 		{
612 			if (markerWidgets[i].hasValue())
613 			{
614 				if (markerWidgets[i].getValue() > value) markerWidgets[i].setValue (value);
615 				else break;
616 			}
617 		}
618 
619 		// Validate successors
620 		for (int i = markerNr + 1; i < MAXSTEPS - 1; ++i)
621 		{
622 			if (markerWidgets[i].hasValue())
623 			{
624 				if (markerWidgets[i].getValue() < value) markerWidgets[i].setValue (value);
625 				else break;
626 			}
627 		}
628 	}
629 }
630 
setAutoMarkers()631 void BChoppr_GUI::setAutoMarkers ()
632 {
633 	int nrMarkers = nrStepsControl.getValue() - 1;
634 	int start = 0;
635 	for (int i = 0; i < nrMarkers; ++i)
636 	{
637 		if (!markerWidgets[i].hasValue())
638 		{
639 			if ((i == nrMarkers - 1) || (markerWidgets[i + 1].hasValue()))
640 			{
641 				double swing = 2.0 * swingControl.getValue() / (swingControl.getValue() + 1.0);
642 				double anc = (start == 0 ? 0 : markerWidgets[start - 1].getValue());
643 				double suc = (i == nrMarkers - 1 ? 1 : markerWidgets[i + 1].getValue());
644 				double diff = suc - anc;
645 				double dist = i - start + 1.0 + (int (i - start) & 1 ? ((start & 1) ? 2.0 - swing : swing) : 1.0);
646 				double step = (diff < 0 ? 0 : diff / dist);
647 				for (int j = start; j <= i; ++j)
648 				{
649 					double f = ((j & 1) ? 2.0 - swing : swing);
650 					anc += f * step;
651 					markerWidgets[j].setValue (anc);
652 				}
653 			}
654 		}
655 		else start = i + 1;
656 	}
657 }
658 
rearrange_controllers()659 void BChoppr_GUI::rearrange_controllers ()
660 {
661 	int nrStepsi = INT (nrStepsControl.getValue());
662 
663 	if ((nrStepsi < 1) || (nrStepsi > MAXSTEPS)) return;
664 
665 	double sw = sContainer.getEffectiveWidth();
666 	double sx = sContainer.getXOffset();
667 	const double oddf = (ampSwingControl.getValue() >= 1.0 ? 1.0 : ampSwingControl.getValue());
668 	const double evenf = (ampSwingControl.getValue() >= 1.0 ? 1.0 / ampSwingControl.getValue() : 1.0);
669 
670 	for (int i = 0; i < MAXSTEPS; ++i)
671 	{
672 		if (i < nrStepsi)
673 		{
674 			stepControl[i].resize (14 * sz, (14 + LIMIT (66 * ((i % 2) == 0 ? oddf : evenf), 0, 66 )) * sz);
675 			stepControl[i].moveTo ((i + 0.5) * sw / nrStepsi + sx - 7 * sz, 140 * sz - stepControl[i].getHeight());
676 			stepControl[i].show();
677 
678 			if (i < nrStepsi - 1) markerWidgets[i].resize (10 * sz, 16 * sz);
679 
680 			stepControlLabel[i].moveTo ((i + 0.5) * sw / nrStepsi + sx - 14 * sz, 40 * sz);
681 			stepControlLabel[i].resize (28 * sz, 20 * sz);
682 			stepControlLabel[i].show();
683 
684 		}
685 		else
686 		{
687 			stepControl[i].hide ();
688 			stepControlLabel[i].hide();
689 		}
690 	}
691 
692 	for (int i = 0; i < MAXSTEPS - 1; ++i)
693 	{
694 		if (i < nrStepsi - 1)
695 		{
696 			markerWidgets[i].moveTo (markerWidgets[i].getValue() * sw + sx - 5 * sz, 10 * sz);
697 			markerWidgets[i].show ();
698 		}
699 		else markerWidgets[i].hide ();
700 	}
701 }
702 
valueChangedCallback(BEvents::Event * event)703 void BChoppr_GUI::valueChangedCallback (BEvents::Event* event)
704 {
705 	if ((event) && (event->getWidget ()))
706 	{
707 		BWidgets::ValueWidget* widget = (BWidgets::ValueWidget*) event->getWidget ();
708 		const double value = widget->getValue();
709 
710 		if (widget->getMainWindow ())
711 		{
712 			BChoppr_GUI* ui = (BChoppr_GUI*) widget->getMainWindow ();
713 
714 			// Get controller nr
715 			int controllerNr = -1;
716 			for (int i = 0; i < NrControllers; ++i)
717 			{
718 				if (widget == ui->controllers[i])
719 				{
720 					controllerNr = i;
721 					break;
722 				}
723 			}
724 
725 			if (controllerNr >= 0)
726 			{
727 				const float v = ui->setController (controllerNr, value);
728 				if (ui->sharedDataSelection.getValue()) ui->sendController (controllerNr, v);
729 				else ui->write_function (ui->controller, Controllers + controllerNr, sizeof (float), 0, &v);
730 			}
731 
732 			else if (widget == &ui->sharedDataSelection)
733 			{
734 				const int val = ui->sharedDataSelection.getValue() - 1;
735 				for (int i = 0; i < 4; ++i)
736 				{
737 					ui->sharedDataButtons[i].setValueable (false);
738 					ui->sharedDataButtons[i].setValue (i == val ? 1 : 0);
739 					ui->sharedDataButtons[i].setValueable (true);
740 				}
741 
742 				ui->sendSharedDataNr();
743 			}
744 
745 			// monitor on/off changed
746 			else if (widget == &ui->monitorSwitch)
747 			{
748 				int value = INT (widget->getValue ());
749 				if (value == 1)
750 				{
751 					ui->mainMonitor.record_on = true;
752 					ui->send_record_on ();
753 				}
754 				else
755 				{
756 					ui->mainMonitor.record_on = false;
757 					ui->send_record_off ();
758 				}
759 				return;
760 			}
761 		}
762 	}
763 }
764 
markerClickedCallback(BEvents::Event * event)765 void BChoppr_GUI::markerClickedCallback (BEvents::Event* event)
766 {
767 	if (!event) return;
768 	BEvents::PointerEvent* pev = (BEvents::PointerEvent*) event;
769 	if (pev->getButton() != BDevices::RIGHT_BUTTON) return;
770 	Marker* marker = (Marker*)event->getWidget();
771 	if (!marker) return;
772 	marker->raiseToTop();
773 	BChoppr_GUI* ui = (BChoppr_GUI*)marker->getMainWindow();
774 	if (!ui) return;
775 
776 	const int nrSteps = ui->nrStepsControl.getValue();
777 
778 	for (int i = 0; i < nrSteps - 1; ++i)
779 	{
780 		if (marker == &ui->markerWidgets[i])
781 		{
782 			Marker* oldMarker = (Marker*) ui->markerListBox.getParent();
783 			ui->markerListBox.setValue (UNSELECTED);
784 
785 			if (oldMarker && (oldMarker == marker))
786 			{
787 				if (ui->markerListBox.isVisible()) ui->markerListBox.hide();
788 				else ui->markerListBox.show ();
789 			}
790 
791 			else if (oldMarker && (oldMarker != marker))
792 			{
793 				oldMarker->release (&ui->markerListBox);
794 				marker->add (ui->markerListBox);
795 				ui->markerListBox.show();
796 			}
797 
798 			else
799 			{
800 				marker->add (ui->markerListBox);
801 				ui->markerListBox.show();
802 			}
803 
804 		}
805 	}
806 }
807 
markerDraggedCallback(BEvents::Event * event)808 void BChoppr_GUI::markerDraggedCallback (BEvents::Event* event)
809 {
810 	if (!event) return;
811 	BEvents::PointerEvent* pev = (BEvents::PointerEvent*) event;
812 	if (pev->getButton() != BDevices::LEFT_BUTTON) return;
813 	Marker* marker = (Marker*)event->getWidget();
814 	if (!marker) return;
815 	marker->raiseToTop();
816 	BChoppr_GUI* ui = (BChoppr_GUI*)marker->getMainWindow();
817 	if (!ui) return;
818 
819 	const int nrSteps = ui->nrStepsControl.getValue();
820 
821 	for (int i = 0; i < nrSteps - 1; ++i)
822 	{
823 		if (marker == &ui->markerWidgets[i])
824 		{
825 			double x0 = ui->sContainer.getXOffset();
826 			double w = ui->sContainer. getEffectiveWidth();
827 			double frac = (w > 0 ? (pev->getPosition().x + marker->getPosition().x - x0) / w : MINMARKERVALUE);
828 			frac = LIMIT (frac, MINMARKERVALUE, 1.0);
829 
830 			// Limit to antecessors value
831 			for (int j = i - 1; j >= 0; --j)
832 			{
833 				if (ui->markerWidgets[j].hasValue())
834 				{
835 					if (frac < ui->markerWidgets[j].getValue()) frac = ui->markerWidgets[j].getValue();
836 					break;
837 				}
838 			}
839 
840 			// Limit to successors value
841 			for (int j = i + 1; j < nrSteps - 1; ++j)
842 			{
843 				if (ui->markerWidgets[j].hasValue())
844 				{
845 					if (frac > ui->markerWidgets[j].getValue()) frac = ui->markerWidgets[j].getValue();
846 					break;
847 				}
848 			}
849 
850 			ui->setMarker (i, frac);
851 			ui->setAutoMarkers();
852 			ui->rearrange_controllers();
853 			ui->redrawSContainer();
854 			ui->redrawMainMonitor();
855 			break;
856 		}
857 	}
858 }
859 
monitorScrolledCallback(BEvents::Event * event)860 void BChoppr_GUI::monitorScrolledCallback (BEvents::Event* event)
861 {
862 	if (!event) return;
863 	BEvents::WheelEvent* wev = (BEvents::WheelEvent*) event;
864 	BWidgets::Widget* widget = event->getWidget();
865 	if (!widget) return;
866 	BChoppr_GUI* ui = (BChoppr_GUI*)widget->getMainWindow();
867 	if (!ui) return;
868 
869 	ui->scale += 0.1 * wev->getDelta().y * ui->scale;
870 	if (ui->scale < 0.0001f) ui->scale = 0.0001f;
871 	ui->redrawMainMonitor ();
872 }
873 
monitorDraggedCallback(BEvents::Event * event)874 void BChoppr_GUI::monitorDraggedCallback (BEvents::Event* event)
875 {
876 	if (!event) return;
877 	BEvents::PointerEvent* wev = (BEvents::PointerEvent*) event;
878 	BWidgets::Widget* widget = event->getWidget();
879 	if (!widget) return;
880 	BChoppr_GUI* ui = (BChoppr_GUI*)widget->getMainWindow();
881 	if (!ui) return;
882 
883 	ui->scale += 0.01 * wev->getDelta().y * ui->scale;
884 	if (ui->scale < 0.0001f) ui->scale = 0.0001f;
885 	ui->redrawMainMonitor ();
886 }
887 
listBoxChangedCallback(BEvents::Event * event)888 void BChoppr_GUI::listBoxChangedCallback (BEvents::Event* event)
889 {
890 	if (!event) return;
891 	BEvents::ValueChangedEvent* vev = (BEvents::ValueChangedEvent*) event;
892 	BWidgets::ListBox* lb = (BWidgets::ListBox*) vev->getWidget();
893 	if (!lb) return;
894 	Marker* m = (Marker*) lb->getParent();
895 	if (!m) return;
896 	BChoppr_GUI* ui = (BChoppr_GUI*)m->getMainWindow();
897 	if (!ui) return;
898 
899 	double value = vev->getValue();
900 	if (value == 1.0) m->setHasValue (false);
901 	else if (value == 2.0) m->setHasValue (true);
902 	else return;
903 
904 	lb->hide();
905 	ui->setAutoMarkers();
906 	ui->rearrange_controllers();
907 	ui->redrawSContainer();
908 	ui->redrawMainMonitor();
909 }
910 
markersAutoClickedCallback(BEvents::Event * event)911 void BChoppr_GUI::markersAutoClickedCallback (BEvents::Event* event)
912 {
913 	if (!event) return;
914 	BEvents::ValueChangedEvent* vev = (BEvents::ValueChangedEvent*) event;
915 	if (vev->getValue() == 0.0) return;
916 	BWidgets::TextButton* tb = (BWidgets::TextButton*) vev->getWidget();
917 	if (!tb) return;
918 	BChoppr_GUI* ui = (BChoppr_GUI*)tb->getMainWindow();
919 	if (!ui) return;
920 
921 	for (Marker& m : ui->markerWidgets) m.setHasValue (false);
922 
923 	ui->setAutoMarkers();
924 	ui->rearrange_controllers();
925 	ui->redrawSContainer();
926 	ui->redrawMainMonitor();
927 }
928 
buttonClickedCallback(BEvents::Event * event)929 void BChoppr_GUI::buttonClickedCallback (BEvents::Event* event)
930 {
931 	if (!event) return;
932 	BWidgets::DrawingSurface* w = (BWidgets::DrawingSurface*) event->getWidget();
933 	if (!w) return;
934 	BChoppr_GUI* ui = (BChoppr_GUI*) w->getMainWindow();
935 	if (!ui) return;
936 
937 	if (w == &ui->rectButton) ui->blendControl.setValue (1);
938 	else if (w == &ui->sinButton) ui->blendControl.setValue (2);
939 }
940 
sharedDataClickedCallback(BEvents::Event * event)941 void BChoppr_GUI::sharedDataClickedCallback (BEvents::Event* event)
942 {
943 	if (!event) return;
944 	HaloToggleButton* widget = (HaloToggleButton*) event->getWidget ();
945 	if (!widget) return;
946 	double value = widget->getValue();
947 	BChoppr_GUI* ui = (BChoppr_GUI*) widget->getMainWindow();
948 	if (!ui) return;
949 
950 	if (value)
951 	{
952 		for (int i = 0; i < 4; ++i)
953 		{
954 			if (widget == &ui->sharedDataButtons[i])
955 			{
956 				ui->sharedDataSelection.setValue (i + 1);
957 				return;
958 			}
959 		}
960 	}
961 	ui->sharedDataSelection.setValue (0);
962 }
963 
helpButtonClickedCallback(BEvents::Event * event)964 void BChoppr_GUI::helpButtonClickedCallback (BEvents::Event* event)
965 {
966 	char cmd[] = WWW_BROWSER_CMD;
967 	char param[] = HELP_URL;
968 	char* argv[] = {cmd, param, NULL};
969 	std::cerr << "BChoppr.lv2#GUI: Call " << HELP_URL << " for help.\n";
970 	if (BUtilities::vsystem (argv) == -1) std::cerr << "BChoppr.lv2#GUI: Couldn't fork.\n";
971 }
972 
ytButtonClickedCallback(BEvents::Event * event)973 void BChoppr_GUI::ytButtonClickedCallback (BEvents::Event* event)
974 {
975 	char cmd[] = WWW_BROWSER_CMD;
976 	char param[] = YT_URL;
977 	char* argv[] = {cmd, param, NULL};
978 	std::cerr << "BChoppr.lv2#GUI: Call " << YT_URL << " for tutorial video.\n";
979 	if (BUtilities::vsystem (argv) == -1) std::cerr << "BChoppr.lv2#GUI: Couldn't fork.\n";
980 }
981 
stepControlLabelMessageCallback(BEvents::Event * event)982 void BChoppr_GUI::stepControlLabelMessageCallback (BEvents::Event* event)
983 {
984 	if (event && event->getWidget())
985 	{
986 		BWidgets::Label* l = (BWidgets::Label*)event->getWidget();
987 		BChoppr_GUI* ui = (BChoppr_GUI*)l->getMainWindow();
988 		if (ui)
989 		{
990 			for (int i = 0; i < MAXSTEPS; ++i)
991 			{
992 				if (l == &ui->stepControlLabel[i])
993 				{
994 					double val = ui->stepControl[i].getValue();
995 					try {val = BUtilities::stof (l->getText());}
996 					catch (std::invalid_argument &ia)
997 					{
998 						fprintf (stderr, "%s\n", ia.what());
999 						l->setText (BUtilities::to_string (val, "%1.2f"));
1000 						return;
1001 					}
1002 
1003 					ui->stepControl[i].setValue (val);
1004 					l->setText (BUtilities::to_string (ui->stepControl[i].getValue(), "%1.2f"));
1005 					break;
1006 				}
1007 			}
1008 		}
1009 	}
1010 }
1011 
init_Stepshape()1012 bool BChoppr_GUI::init_Stepshape ()
1013 {
1014 	double height = stepshapeDisplay.getEffectiveHeight ();
1015 	pat5 = cairo_pattern_create_linear (0, 0, 0, height);
1016 
1017 	return (pat5 && (cairo_pattern_status (pat5) == CAIRO_STATUS_SUCCESS));
1018 }
1019 
destroy_Stepshape()1020 void BChoppr_GUI::destroy_Stepshape ()
1021 {
1022 	//Destroy also mainMonitors cairo data
1023 	if (pat5 && (cairo_pattern_status (pat5) == CAIRO_STATUS_SUCCESS)) cairo_pattern_destroy (pat5);
1024 }
1025 
redrawStepshape()1026 void BChoppr_GUI::redrawStepshape ()
1027 {
1028 	double width = stepshapeDisplay.getEffectiveWidth ();
1029 	double height = stepshapeDisplay.getEffectiveHeight ();
1030 
1031 	cairo_t* cr = cairo_create (stepshapeDisplay.getDrawingSurface ());
1032 	if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) return;
1033 
1034 	// Draw background
1035 	cairo_set_source_rgba (cr, CAIRO_BG_COLOR);
1036 	cairo_rectangle (cr, 0.0, 0.0, width, height);
1037 	cairo_fill (cr);
1038 	cairo_set_source_rgba (cr, CAIRO_RGBA (BColors::grey));
1039 	cairo_set_line_width (cr, 1);
1040 	cairo_move_to (cr, 0, 0.2 * height);
1041 	cairo_line_to (cr, width, 0.2 * height);
1042 	cairo_move_to (cr, 0, 0.55 * height);
1043 	cairo_line_to (cr, width, 0.55 * height);
1044 	cairo_move_to (cr, 0, 0.9 * height);
1045 	cairo_line_to (cr, width, 0.9 * height);
1046 	cairo_move_to (cr, 0.25 * width, 0);
1047 	cairo_line_to (cr, 0.25 * width, height);
1048 	cairo_move_to (cr, 0.5 * width, 0);
1049 	cairo_line_to (cr, 0.5 * width, height);
1050 	cairo_move_to (cr, 0.75 * width, 0);
1051 	cairo_line_to (cr, 0.75 * width, height);
1052 	cairo_stroke (cr);
1053 
1054 	// Draw step shape
1055 	cairo_set_source_rgba (cr, CAIRO_INK1, 1.0);
1056 	cairo_set_line_width (cr, 3);
1057 
1058 	cairo_move_to (cr, 0, 0.9 * height);
1059 	cairo_line_to (cr, width * 0.25, 0.9 * height);
1060 
1061 	const float attack = attackControl.getValue();
1062 	const float release = releaseControl.getValue();
1063 
1064 	if (blendControl.getValue() == 1)
1065 	{
1066 		if ((attack + release) > 1)
1067 		{
1068 			float crosspointX = attack / (attack + release);
1069 			float crosspointY = crosspointX / attack - (crosspointX - (1 - release)) / release;
1070 			cairo_line_to (cr, width * 0.25 + crosspointX * width * 0.5, 0.9 * height - 0.7 * height * crosspointY);
1071 		}
1072 		else
1073 		{
1074 			cairo_line_to (cr, width * 0.25 + attack * width * 0.5, 0.2 * height);
1075 			cairo_line_to (cr, width * 0.75  - release * width * 0.5, 0.2 * height);
1076 
1077 		}
1078 	}
1079 
1080 	else if (blendControl.getValue() == 2)
1081 	{
1082 		for (double i = 0.0; i <= 1.0; i += 0.025)
1083 		{
1084 			double vol = 1.0;
1085 			if (i < attack) vol = sin (M_PI * (i / attack - 0.5));
1086 			if (i > (1 - release)) vol = vol * sin (M_PI * ((1 - i) / release - 0.5));
1087 			cairo_line_to (cr, width * (0.25 + 0.5 * i), height * (0.55 - 0.35 * vol));
1088 		}
1089 	}
1090 
1091 	cairo_line_to (cr, width * 0.75, 0.9 * height);
1092 	cairo_line_to (cr, width, 0.9 * height);
1093 
1094 	cairo_stroke_preserve (cr);
1095 
1096 	cairo_pattern_add_color_stop_rgba (pat5, 0.1, CAIRO_INK1, 1);
1097 	cairo_pattern_add_color_stop_rgba (pat5, 0.9, CAIRO_INK1, 0);
1098 	cairo_set_source (cr, pat5);
1099 	cairo_line_to(cr, 0, 0.9 * height);
1100 	cairo_set_line_width (cr, 0);
1101 	cairo_fill (cr);
1102 
1103 	cairo_destroy (cr);
1104 
1105 	stepshapeDisplay.update ();
1106 }
1107 
init_mainMonitor()1108 bool BChoppr_GUI::init_mainMonitor ()
1109 {
1110 	//Initialize mainMonitor
1111 	mainMonitor.record_on = true;
1112 	mainMonitor.width = 0;
1113 	mainMonitor.height = 0;
1114 	mainMonitor.data.fill (defaultNotification);
1115 	mainMonitor.horizonPos = 0;
1116 
1117 	//Initialize mainMonitors cairo data
1118 	double width = monitorDisplay.getEffectiveWidth ();
1119 	double height = monitorDisplay.getEffectiveHeight ();
1120 	surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
1121 	cr1 = cairo_create (surface);
1122 	cr2 = cairo_create (surface);
1123 	cr3 = cairo_create (surface);
1124 	cr4 = cairo_create (surface);
1125 	pat1 = cairo_pattern_create_linear (0, 0, 0, height);
1126 	cairo_pattern_add_color_stop_rgba (pat1, 0.1, CAIRO_INK1, 1);
1127 	cairo_pattern_add_color_stop_rgba (pat1, 0.6, CAIRO_INK1, 0);
1128 	pat2 = cairo_pattern_create_linear (0, 0, 0, height);
1129 	cairo_pattern_add_color_stop_rgba (pat2, 0.1, CAIRO_INK2, 1);
1130 	cairo_pattern_add_color_stop_rgba (pat2, 0.6, CAIRO_INK2, 0);
1131 	pat3 = cairo_pattern_create_linear (0, height, 0, 0);
1132 	cairo_pattern_add_color_stop_rgba (pat3, 0.1, CAIRO_INK1, 1);
1133 	cairo_pattern_add_color_stop_rgba (pat3, 0.6, CAIRO_INK1, 0);
1134 	pat4 = cairo_pattern_create_linear (0, height, 0, 0);
1135 	cairo_pattern_add_color_stop_rgba (pat4, 0.1, CAIRO_INK2, 1);
1136 	cairo_pattern_add_color_stop_rgba (pat4, 0.6, CAIRO_INK2, 0);
1137 
1138 	return (pat4 && (cairo_pattern_status (pat4) == CAIRO_STATUS_SUCCESS) &&
1139 			pat3 && (cairo_pattern_status (pat3) == CAIRO_STATUS_SUCCESS) &&
1140 			pat2 && (cairo_pattern_status (pat2) == CAIRO_STATUS_SUCCESS) &&
1141 			pat1 && (cairo_pattern_status (pat1) == CAIRO_STATUS_SUCCESS) &&
1142 			cr4 && (cairo_status (cr4) == CAIRO_STATUS_SUCCESS) &&
1143 			cr3 && (cairo_status (cr3) == CAIRO_STATUS_SUCCESS)&&
1144 			cr2 && (cairo_status (cr2) == CAIRO_STATUS_SUCCESS) &&
1145 			cr1 && (cairo_status (cr1) == CAIRO_STATUS_SUCCESS) &&
1146 			surface && (cairo_surface_status (surface) == CAIRO_STATUS_SUCCESS));
1147 }
1148 
destroy_mainMonitor()1149 void BChoppr_GUI::destroy_mainMonitor ()
1150 {
1151 	//Destroy also mainMonitors cairo data
1152 	if (pat4 && (cairo_pattern_status (pat4) == CAIRO_STATUS_SUCCESS)) cairo_pattern_destroy (pat4);
1153 	if (pat3 && (cairo_pattern_status (pat3) == CAIRO_STATUS_SUCCESS)) cairo_pattern_destroy (pat3);
1154 	if (pat2 && (cairo_pattern_status (pat2) == CAIRO_STATUS_SUCCESS)) cairo_pattern_destroy (pat2);
1155 	if (pat1 && (cairo_pattern_status (pat1) == CAIRO_STATUS_SUCCESS)) cairo_pattern_destroy (pat1);
1156 	if (cr4 && (cairo_status (cr4) == CAIRO_STATUS_SUCCESS)) cairo_destroy (cr4);
1157 	if (cr3 && (cairo_status (cr3) == CAIRO_STATUS_SUCCESS)) cairo_destroy (cr3);
1158 	if (cr2 && (cairo_status (cr2) == CAIRO_STATUS_SUCCESS)) cairo_destroy (cr2);
1159 	if (cr1 && (cairo_status (cr1) == CAIRO_STATUS_SUCCESS)) cairo_destroy (cr1);
1160 	if (surface && (cairo_surface_status (surface) == CAIRO_STATUS_SUCCESS)) cairo_surface_destroy (surface);
1161 }
1162 
add_monitor_data(BChopprNotifications * notifications,uint32_t notificationsCount,uint32_t & end)1163 void BChoppr_GUI::add_monitor_data (BChopprNotifications* notifications, uint32_t notificationsCount, uint32_t& end)
1164 {
1165 	for (uint32_t i = 0; i < notificationsCount; ++i)
1166 	{
1167 		int monitorpos = notifications[i].position;
1168 		if (monitorpos >= MONITORBUFFERSIZE) monitorpos = MONITORBUFFERSIZE;
1169 		if (monitorpos < 0) monitorpos = 0;
1170 
1171 		mainMonitor.data[monitorpos].inputMin = notifications[i].inputMin;
1172 		mainMonitor.data[monitorpos].inputMax = notifications[i].inputMax;
1173 		mainMonitor.data[monitorpos].outputMin = notifications[i].outputMin;
1174 		mainMonitor.data[monitorpos].outputMax = notifications[i].outputMax;
1175 		mainMonitor.horizonPos = monitorpos;
1176 	}
1177 }
1178 
redrawMainMonitor()1179 void BChoppr_GUI::redrawMainMonitor ()
1180 {
1181 	double width = monitorDisplay.getEffectiveWidth ();
1182 	double height = monitorDisplay.getEffectiveHeight ();
1183 
1184 	cairo_t* cr = cairo_create (monitorDisplay.getDrawingSurface ());
1185 	if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) return;
1186 
1187 	// Draw background
1188 	cairo_set_source_rgba (cr, CAIRO_BG_COLOR);
1189 	cairo_rectangle (cr, 0, 0, width, height);
1190 	cairo_fill (cr);
1191 
1192 	cairo_set_source_rgba (cr, CAIRO_RGBA (BColors::grey));
1193 	cairo_set_line_width (cr, 1);
1194 	cairo_move_to (cr, 0, 0.1 * height);
1195 	cairo_line_to (cr, width, 0.1 * height);
1196 	cairo_move_to (cr, 0, 0.5 * height);
1197 	cairo_line_to (cr, width, 0.5 * height);
1198 	cairo_move_to (cr, 0, 0.9 * height);
1199 	cairo_line_to (cr, width, 0.9 * height);
1200 
1201 	uint32_t steps = (uint32_t) nrStepsControl.getValue() - 1;
1202 	for (uint32_t i = 0; i < steps; ++i)
1203 	{
1204 		cairo_move_to (cr, markerWidgets[i].getValue() * width, 0);
1205 		cairo_rel_line_to (cr, 0, height);
1206 	}
1207 	cairo_stroke (cr);
1208 
1209 	if (mainMonitor.record_on)
1210 	{
1211 		cairo_surface_clear (surface);
1212 
1213 		// Draw input (cr, cr3) and output (cr2, cr4) curves
1214 		cairo_move_to (cr1, 0, height * (0.5  - (0.4 * LIM ((mainMonitor.data[0].inputMax / scale), 0.0f, 1.0f))));
1215 		cairo_move_to (cr2, 0, height * (0.5  - (0.4 * LIM ((mainMonitor.data[0].outputMax / scale), 0.0f, 1.0f))));
1216 		cairo_move_to (cr3, 0, height * (0.5  + (0.4 * LIM (-(mainMonitor.data[0].inputMin / scale), 0.0f, 1.0f))));
1217 		cairo_move_to (cr4, 0, height * (0.5  + (0.4 * LIM (-(mainMonitor.data[0].outputMin / scale), 0.0f, 1.0f))));
1218 
1219 		for (int i = 0; i < MONITORBUFFERSIZE; ++i)
1220 		{
1221 			double pos = ((double) i) / (MONITORBUFFERSIZE - 1.0f);
1222 			cairo_line_to (cr1, pos * width, height * (0.5  - (0.4 * LIM ((mainMonitor.data[i].inputMax / scale), 0.0f, 1.0f))));
1223 			cairo_line_to (cr2, pos * width, height * (0.5  - (0.4 * LIM ((mainMonitor.data[i].outputMax / scale), 0.0f, 1.0f))));
1224 			cairo_line_to (cr3, pos * width, height * (0.5  + (0.4 * LIM (-(mainMonitor.data[i].inputMin / scale), 0.0f, 1.0f))));
1225 			cairo_line_to (cr4, pos * width, height * (0.5  + (0.4 * LIM (-(mainMonitor.data[i].outputMin / scale), 0.0f, 1.0f))));
1226 		}
1227 
1228 		// Visualize input (cr, cr3) and output (cr2, cr4) curves
1229 		cairo_set_source_rgba (cr1, CAIRO_INK1, 1.0);
1230 		cairo_set_line_width (cr1, 3);
1231 		cairo_set_source_rgba (cr2, CAIRO_INK2, 1.0);
1232 		cairo_set_line_width (cr2, 3);
1233 		cairo_stroke_preserve (cr1);
1234 		cairo_stroke_preserve (cr2);
1235 		cairo_set_source_rgba (cr3, CAIRO_INK1, 1.0);
1236 		cairo_set_line_width (cr3, 3);
1237 		cairo_set_source_rgba (cr4, CAIRO_INK2, 1.0);
1238 		cairo_set_line_width (cr4, 3);
1239 		cairo_stroke_preserve (cr3);
1240 		cairo_stroke_preserve (cr4);
1241 
1242 		// Visualize input (cr, cr3) and output (cr2, cr4) areas under the curves
1243 		cairo_line_to (cr1, width, height * 0.5);
1244 		cairo_line_to (cr1, 0, height * 0.5);
1245 		cairo_close_path (cr1);
1246 		cairo_line_to (cr2, width, height * 0.5);
1247 		cairo_line_to (cr2, 0, height * 0.5);
1248 		cairo_close_path (cr2);
1249 		cairo_set_source (cr1, pat1);
1250 		cairo_set_line_width (cr1, 0);
1251 		cairo_set_source (cr2, pat2);
1252 		cairo_set_line_width (cr2, 0);
1253 		cairo_fill (cr1);
1254 		cairo_fill (cr2);
1255 		cairo_line_to (cr3, width, height * 0.5);
1256 		cairo_line_to (cr3, 0, height * 0.5);
1257 		cairo_close_path (cr3);
1258 		cairo_line_to (cr4, width, height * 0.5);
1259 		cairo_line_to (cr4, 0, height * 0.5);
1260 		cairo_close_path (cr4);
1261 		cairo_set_source (cr3, pat3);
1262 		cairo_set_line_width (cr3, 0);
1263 		cairo_set_source (cr4, pat4);
1264 		cairo_set_line_width (cr4, 0);
1265 		cairo_fill (cr3);
1266 		cairo_fill (cr4);
1267 
1268 		// Draw fade out
1269 		double horizon = ((double) mainMonitor.horizonPos) / (MONITORBUFFERSIZE - 1.0f);
1270 		cairo_pattern_t* pat6 = cairo_pattern_create_linear (horizon * width, 0, horizon * width + 63, 0);
1271 		if (cairo_pattern_status (pat6) == CAIRO_STATUS_SUCCESS)
1272 		{
1273 			cairo_pattern_add_color_stop_rgba (pat6, 0.0, CAIRO_BG_COLOR);
1274 			cairo_pattern_add_color_stop_rgba (pat6, 1.0, CAIRO_TRANSPARENT);
1275 			cairo_set_line_width (cr1, 0.0);
1276 			cairo_set_source (cr1, pat6);
1277 			cairo_rectangle (cr1, horizon * width, 0, 63, height);
1278 			cairo_fill (cr1);
1279 			cairo_pattern_destroy (pat6);
1280 		}
1281 
1282 		if (horizon * width > width - 63)
1283 		{
1284 			cairo_pattern_t* pat6 = cairo_pattern_create_linear ((horizon - 1) * width, 0, (horizon - 1) * width + 63, 0);
1285 			if (cairo_pattern_status (pat6) == CAIRO_STATUS_SUCCESS)
1286 			{
1287 				cairo_pattern_add_color_stop_rgba (pat6, 0.0, CAIRO_BG_COLOR);
1288 				cairo_pattern_add_color_stop_rgba (pat6, 1.0, CAIRO_TRANSPARENT);
1289 				cairo_set_line_width (cr1, 0.0);
1290 				cairo_set_source (cr1, pat6);
1291 				cairo_rectangle (cr1, (horizon - 1) * width, 0, 63, height);
1292 				cairo_fill (cr1);
1293 				cairo_pattern_destroy (pat6);
1294 			}
1295 		}
1296 
1297 		// Draw horizon line
1298 		cairo_set_source_rgba (cr1, CAIRO_FG_COLOR);
1299 		cairo_set_line_width (cr1, 1);
1300 		cairo_move_to (cr1, horizon * width, 0);
1301 		cairo_line_to (cr1, horizon * width, height);
1302 		cairo_stroke (cr1);
1303 	}
1304 
1305 	cairo_set_source_surface (cr, surface, 0, 0);
1306 	cairo_paint (cr);
1307 
1308 	cairo_destroy (cr);
1309 	monitorDisplay.update ();
1310 }
1311 
redrawSContainer()1312 void BChoppr_GUI::redrawSContainer ()
1313 {
1314 	double width = sContainer.getEffectiveWidth ();
1315 	double height = sContainer.getEffectiveHeight ();
1316 
1317 	cairo_surface_clear (sContainer.getDrawingSurface ());
1318 	cairo_t* cr = cairo_create (sContainer.getDrawingSurface ());
1319 	if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) return;
1320 
1321 	cairo_pattern_t* pat = cairo_pattern_create_linear (0, 0, 0, height);
1322 	cairo_pattern_add_color_stop_rgba (pat, 0.0, CAIRO_RGBA (BColors::black));
1323 	cairo_pattern_add_color_stop_rgba (pat, 1.0, 0.0, 0.0, 0.0, 0.5);
1324 	cairo_rectangle (cr, 0, 0, width, height);
1325 	cairo_set_source (cr, pat);
1326 	cairo_fill (cr);
1327 	cairo_pattern_destroy (pat);
1328 
1329 	for (int i = 0; i < nrStepsControl.getValue() - 1; ++i)
1330 	{
1331 		cairo_set_line_width (cr, 1.0);
1332 		cairo_set_source_rgba (cr, CAIRO_RGBA (BColors::grey));
1333 		cairo_move_to (cr, markerWidgets[i].getValue() * width, 0);
1334 		cairo_rel_line_to (cr, 0, 30 * sz);
1335 		cairo_line_to (cr, (i + 1) / nrStepsControl.getValue() * width, 40 * sz);
1336 		cairo_rel_line_to (cr, 0, 100 * sz);
1337 		cairo_stroke (cr);
1338 	}
1339 
1340 	cairo_destroy (cr);
1341 	sContainer.update();
1342 }
1343 
redrawButtons()1344 void BChoppr_GUI::redrawButtons ()
1345 {
1346 	// rectButton
1347 	double width = rectButton.getEffectiveWidth ();
1348 	double height = rectButton.getEffectiveHeight ();
1349 
1350 	cairo_surface_clear (rectButton.getDrawingSurface ());
1351 	cairo_t* cr = cairo_create (rectButton.getDrawingSurface ());
1352 	if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) return;
1353 
1354 	cairo_set_source_rgba (cr, CAIRO_RGBA (*rectButton.getBorder()->getLine()->getColor()));
1355 	cairo_set_line_width (cr, 2.0);
1356 
1357 	cairo_move_to (cr, 0.05 * width, 0.9 * height);
1358 	cairo_line_to (cr, 0.25 * width, 0.9 * height);
1359 	cairo_line_to (cr, 0.3 * width, 0.1 * height);
1360 	cairo_line_to (cr, 0.7 * width, 0.1 * height);
1361 	cairo_line_to (cr, 0.75 * width, 0.9 * height);
1362 	cairo_line_to (cr, 0.95 * width, 0.9 * height);
1363 	cairo_stroke (cr);
1364 
1365 	cairo_destroy (cr);
1366 
1367 	// sinButton
1368 	width = sinButton.getEffectiveWidth ();
1369 	height = sinButton.getEffectiveHeight ();
1370 
1371 	cairo_surface_clear (sinButton.getDrawingSurface ());
1372 	cr = cairo_create (sinButton.getDrawingSurface ());
1373 	if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) return;
1374 
1375 	cairo_set_source_rgba (cr, CAIRO_RGBA (*sinButton.getBorder()->getLine()->getColor()));
1376 	cairo_set_line_width (cr, 2.0);
1377 
1378 	cairo_move_to (cr, 0.05 * width, 0.9 * height);
1379 	cairo_line_to (cr, 0.15 * width, 0.9 * height);
1380 	for (int i = 0; i <= 10; ++i) cairo_line_to (cr, (0.15 + i * 0.03) * width, (0.5 - 0.4 * sin (double (i - 5) * M_PI / 10)) * height);
1381 	cairo_line_to (cr, 0.55 * width, 0.1 * height);
1382 	for (int i = 0; i <= 10; ++i) cairo_line_to (cr, (0.55 + i * 0.03) * width, (0.5 - 0.4 * sin (double (i + 5) * M_PI / 10)) * height);
1383 	cairo_line_to (cr, 0.95 * width, 0.9 * height);
1384 	cairo_stroke (cr);
1385 
1386 	cairo_destroy (cr);
1387 
1388 }
1389 
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)1390 static LV2UI_Handle instantiate (const LV2UI_Descriptor *descriptor, const char *plugin_uri, const char *bundle_path,
1391 						  LV2UI_Write_Function write_function, LV2UI_Controller controller, LV2UI_Widget *widget,
1392 						  const LV2_Feature *const *features)
1393 {
1394 	PuglNativeView parentWindow = 0;
1395 	LV2UI_Resize* resize = NULL;
1396 
1397 	if (strcmp(plugin_uri, BCHOPPR_URI) != 0)
1398 	{
1399 		std::cerr << "BChoppr.lv2#GUI: GUI does not support plugin with URI " << plugin_uri << std::endl;
1400 		return NULL;
1401 	}
1402 
1403 	for (int i = 0; features[i]; ++i)
1404 	{
1405 		if (!strcmp(features[i]->URI, LV2_UI__parent)) parentWindow = (PuglNativeView) features[i]->data;
1406 		else if (!strcmp(features[i]->URI, LV2_UI__resize)) resize = (LV2UI_Resize*)features[i]->data;
1407 	}
1408 	if (parentWindow == 0) std::cerr << "BChoppr.lv2#GUI: No parent window.\n";
1409 
1410 	// New instance
1411 	BChoppr_GUI* ui;
1412 	try {ui = new BChoppr_GUI (bundle_path, features, parentWindow);}
1413 	catch (std::exception& exc)
1414 	{
1415 		std::cerr << "BChoppr.lv2#GUI: Instantiation failed. " << exc.what () << std::endl;
1416 		return NULL;
1417 	}
1418 
1419 	ui->controller = controller;
1420 	ui->write_function = write_function;
1421 
1422 	// Reduce min GUI size for small displays
1423 	double sz = 1.0;
1424 	int screenWidth  = getScreenWidth ();
1425 	int screenHeight = getScreenHeight ();
1426 	if ((screenWidth < 820) || (screenHeight < 600)) sz = 0.66;
1427 	if (resize) resize->ui_resize(resize->handle, 760 * sz, 560 * sz);
1428 
1429 	*widget = (LV2UI_Widget) puglGetNativeWindow (ui->getPuglView ());
1430 	ui->send_record_on();
1431 	return (LV2UI_Handle) ui;
1432 }
1433 
cleanup(LV2UI_Handle ui)1434 static void cleanup(LV2UI_Handle ui)
1435 {
1436 	BChoppr_GUI* pluginGui = (BChoppr_GUI*) ui;
1437 	if (pluginGui) delete pluginGui;
1438 }
1439 
portEvent(LV2UI_Handle ui,uint32_t port_index,uint32_t buffer_size,uint32_t format,const void * buffer)1440 static void portEvent(LV2UI_Handle ui, uint32_t port_index, uint32_t buffer_size,
1441 	uint32_t format, const void* buffer)
1442 {
1443 	BChoppr_GUI* pluginGui = (BChoppr_GUI*) ui;
1444 	if (pluginGui) pluginGui->portEvent(port_index, buffer_size, format, buffer);
1445 }
1446 
callIdle(LV2UI_Handle ui)1447 static int callIdle (LV2UI_Handle ui)
1448 {
1449 	BChoppr_GUI* pluginGui = (BChoppr_GUI*) ui;
1450 	if (pluginGui) pluginGui->handleEvents ();
1451 	return 0;
1452 }
1453 
callResize(LV2UI_Handle ui,int width,int height)1454 static int callResize (LV2UI_Handle ui, int width, int height)
1455 {
1456 	BChoppr_GUI* self = (BChoppr_GUI*) ui;
1457 	if (!self) return 0;
1458 
1459 	BEvents::ExposeEvent* ev = new BEvents::ExposeEvent (self, self, BEvents::CONFIGURE_REQUEST_EVENT, self->getPosition().x, self->getPosition().y, width, height);
1460 	self->addEventToQueue (ev);
1461 	return 0;
1462 }
1463 
1464 static const LV2UI_Idle_Interface idle = {callIdle};
1465 static const LV2UI_Resize resize = {nullptr, callResize} ;
1466 
extensionData(const char * uri)1467 static const void* extensionData(const char* uri)
1468 {
1469 	if (!strcmp(uri, LV2_UI__idleInterface)) return &idle;
1470 	else if(!strcmp(uri, LV2_UI__resize)) return &resize;
1471 	else return NULL;
1472 }
1473 
1474 static const LV2UI_Descriptor guiDescriptor = {
1475 		BCHOPPR_GUI_URI,
1476 		instantiate,
1477 		cleanup,
1478 		portEvent,
1479 		extensionData
1480 };
1481 
1482 // LV2 Symbol Export
lv2ui_descriptor(uint32_t index)1483 LV2_SYMBOL_EXPORT const LV2UI_Descriptor *lv2ui_descriptor(uint32_t index)
1484 {
1485 	switch (index) {
1486 	case 0: return &guiDescriptor;
1487 	default:return NULL;
1488     }
1489 }
1490