1 /* B.Oops
2  * Glitch effect sequencer LV2 plugin
3  *
4  * Copyright (C) 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 <cstdio>
22 #include <string>
23 #include <stdexcept>
24 #include <algorithm>
25 #include "BOops.hpp"
26 #include "ControllerLimits.hpp"
27 #include "BUtilities/stof.hpp"
28 #include "BUtilities/Path.hpp"
29 #include "getURIs.hpp"
30 #include "to_shapes.hpp"
31 #include "bool2hstr.hpp"
32 
33 #ifndef SF_FORMAT_MP3
34 #ifndef MINIMP3_IMPLEMENTATION
35 #define MINIMP3_IMPLEMENTATION
36 #endif
37 #endif
38 #include "Sample.hpp"
39 
40 #ifndef LIMIT
41 #define LIMIT(g , min, max) ((g) > (max) ? (max) : ((g) < (min) ? (min) : (g)))
42 #endif /* LIMIT */
43 
floorfrac(const double value)44 inline double floorfrac (const double value) {return value - floor (value);}
45 
46 
BOops(double samplerate,const char * bundle_path,const LV2_Feature * const * features)47 BOops::BOops (double samplerate, const char* bundle_path, const LV2_Feature* const* features) :
48 	map(NULL), workerSchedule (NULL), pluginPath {0}, urids (),
49 	host {samplerate, 120.0f, 1.0f, 0ul, 0.0f, 4.0f},
50 	activated (false),
51 	positions {{0.0, -1, 0.0, 0, {samplerate, 120.0f, 1.0f, 0ul, 0.0f, 4.0f}, 1.0, true}, {0.0, -1, 0.0, 0, {0.0, 120.0f, 1.0f, 0ul, 0.0f, 4.0f}, 0.0, true}},
52 	transportGateKeys {false},
53 	pages {},
54 	pageNr (0),
55 	pageMax (0),
56 	midiLearn (false),
57 	midiLearned {0},
58 	editorPage (0),
59 	editorSlot (0),
60 	controlPort(NULL), notifyPort(NULL),
61 	audioInput1(NULL), audioInput2(NULL), audioOutput1(NULL), audioOutput2(NULL),
62 	new_controllers {NULL}, globalControllers {0},
63 	forge (), notify_frame (),
64 	sample (NULL), sampleAmp (1.0f),
65 	waveform {0}, waveformCounter (0), lastWaveformCounter (0),
66 	message (), ui_on(false), scheduleNotifyAllSlots (false),
67 	scheduleNotifyPageControls {false},
68 	scheduleNotifyStatus (false), scheduleResizeBuffers (false), scheduleSetFx {false},
69 	scheduleNotifyWaveformToGui (false), scheduleNotifyTransportGateKeys (false),
70 	scheduleNotifySamplePathToGui (false),
71 	scheduleNotifyMidiLearnedToGui (false),
72 	scheduleStateChanged (false),
73 	scheduleInit (false)
74 
75 {
76 	if (bundle_path) strncpy (pluginPath, bundle_path, 1023);
77 	if ((strlen (pluginPath) > 0) && (pluginPath[strlen (pluginPath) - 1] != BUTILITIES_PATH_SLASH[0])) strcat (pluginPath, BUTILITIES_PATH_SLASH);
78 
79 	//Scan host features for URID map
80 	LV2_URID_Map* m = NULL;
81 	for (int i = 0; features[i]; ++i)
82 	{
83 		if (strcmp(features[i]->URI, LV2_URID__map) == 0)
84 		{
85 			m = (LV2_URID_Map*) features[i]->data;
86 		}
87 
88 		else if (!strcmp(features[i]->URI, LV2_WORKER__schedule))
89 		{
90                         workerSchedule = (LV2_Worker_Schedule*)features[i]->data;
91 		}
92 	}
93 	if (!m) throw std::invalid_argument ("Host does not support urid:map");
94 	if (!workerSchedule) throw std::invalid_argument ("BJumblr.lv2: Host does not support work:schedule.");
95 
96 	//Map URIS
97 	map = m;
98 	getURIs (m, &urids);
99 
100 	// Initialize forge
101 	lv2_atom_forge_init (&forge, map);
102 
103 	// Initialize slots
104 	slots.fill (Slot (this, FX_NONE, nullptr, nullptr, 16, 1.0f, 0.25 * samplerate));
105 
106 	// Init pages
107 	for (Page& p : pages)
108 	{
109 		p.controls = {0, 0, 0, 0};
110 		for (std::array<Pad, NR_STEPS>& pp : p.pads) pp.fill (Pad());
111 		p.shapes.fill (Shape<SHAPE_MAXNODES>());
112 		for (std::array<bool, NR_PIANO_KEYS + 1>& pk : p.keys) pk.fill (false);
113 	}
114 }
115 
~BOops()116 BOops::~BOops ()
117 {
118 	if (sample) delete sample;
119 }
120 
connect_port(uint32_t port,void * data)121 void BOops::connect_port(uint32_t port, void *data)
122 {
123 	switch (port) {
124 	case CONTROL:
125 		controlPort = (LV2_Atom_Sequence*) data;
126 		break;
127 
128 	case NOTIFY:
129 		notifyPort = (LV2_Atom_Sequence*) data;
130 		break;
131 
132 	case AUDIO_IN_1:
133 		audioInput1 = (float*) data;
134 		break;
135 
136 	case AUDIO_IN_2:
137 		audioInput2 = (float*) data;
138 		break;
139 
140 	case AUDIO_OUT_1:
141 		audioOutput1 = (float*) data;
142 		break;
143 	case AUDIO_OUT_2:
144 		audioOutput2 = (float*) data;
145 		break;
146 
147 	default:
148 		if ((port >= CONTROLLERS) && (port < CONTROLLERS + NR_CONTROLLERS)) new_controllers[port - CONTROLLERS] = (float*) data;
149 	}
150 }
151 
getPositionFromBeats(const Transport & transport,const double beats)152 double BOops::getPositionFromBeats (const Transport& transport, const double beats)
153 {
154 	if (globalControllers[BASE_VALUE] == 0.0) return 0.0;
155 
156 	switch (int (globalControllers[BASE]))
157 	{
158 		case SECONDS: 	return (transport.bpm ? beats / (globalControllers[BASE_VALUE] * (transport.bpm / 60.0)) : 0.0);
159 		case BEATS:	return beats / globalControllers[BASE_VALUE];
160 		case BARS:	return (transport.beatsPerBar ? beats / (globalControllers[BASE_VALUE] * transport.beatsPerBar) : 0.0);
161 		default:	return 0.0;
162 	}
163 }
164 
getPositionFromFrames(const Transport & transport,const uint64_t frames)165 double BOops::getPositionFromFrames (const Transport& transport, const uint64_t frames)
166 {
167 	if ((globalControllers[BASE_VALUE] == 0.0) || (transport.rate == 0)) return 0.0;
168 
169 	switch (int (globalControllers[BASE]))
170 	{
171 		case SECONDS: 	return frames * (1.0 / transport.rate) / globalControllers[BASE_VALUE] ;
172 		case BEATS:	return (transport.bpm ? frames * (transport.speed / (transport.rate / (transport.bpm / 60))) / globalControllers[BASE_VALUE] : 0.0);
173 		case BARS:	return
174 				(
175 					transport.bpm && transport.beatsPerBar ?
176 					frames * (transport.speed / (transport.rate / (transport.bpm / 60))) / (globalControllers[BASE_VALUE] * transport.beatsPerBar) :
177 					0.0
178 				);
179 		default:	return 0.0;
180 	}
181 }
182 
getFramesFromPosition(const Transport & transport,const double position) const183 uint64_t BOops::getFramesFromPosition (const Transport& transport, const double position) const
184 {
185 	if (transport.bpm < 1.0) return 0;
186 
187 	switch (int (globalControllers[BASE]))
188 	{
189 		case SECONDS :	return position * transport.rate * globalControllers[BASE_VALUE];
190 		case BEATS:	return position * (60.0 / transport.bpm) * transport.rate * globalControllers[BASE_VALUE];
191 		case BARS:	return position * transport.beatsPerBar * (60.0 / transport.bpm) * transport.rate * globalControllers[BASE_VALUE];
192 		default:	return 0;
193 	}
194 }
195 
getPositionFromSeconds(const Transport & transport,const double seconds)196 double BOops::getPositionFromSeconds (const Transport& transport, const double seconds)
197 {
198 	if (globalControllers[BASE_VALUE] == 0.0) return 0.0;
199 
200 	switch (int (globalControllers[BASE]))
201 	{
202 		case SECONDS :	return seconds / globalControllers[BASE_VALUE];
203 		case BEATS:	return seconds * (transport.bpm / 60.0) / globalControllers[BASE_VALUE];
204 		case BARS:	return (transport.beatsPerBar ? seconds * (transport.bpm / 60.0 / transport.beatsPerBar) / globalControllers[BASE_VALUE] : 0.0);
205 		default:	return 0;
206 	}
207 }
208 
getFramesPerStep(const Transport & transport)209 double BOops::getFramesPerStep (const Transport& transport)
210 {
211 	double bps = (globalControllers[PLAY_MODE] == 0 ? globalControllers[AUTOPLAY_BPM] : transport.bpm) / 60.0;
212 	double bpB = (globalControllers[PLAY_MODE] == 0 ? globalControllers[AUTOPLAY_BPB] :transport. beatsPerBar);
213 	double s =
214 	(
215 		globalControllers[BASE] == 0 ?
216 		globalControllers[BASE_VALUE] :
217 		(
218 			globalControllers[BASE] == 1 ?
219 			globalControllers[BASE_VALUE] / bps :
220 			globalControllers[BASE_VALUE] * bpB / bps
221 		)
222 	);
223 	return transport.rate * s / globalControllers[STEPS];
224 }
225 
backPosition()226 Position& BOops::backPosition() {return (sizePosition() > 1 ? positions[1] : positions[0]);}
227 
sizePosition()228 size_t BOops::sizePosition() {return 1 + (positions[1].transport.rate != 0.0);}
229 
pushBackPosition(Position & p)230 void BOops::pushBackPosition (Position& p) {positions[1] = p;}
231 
popBackPosition()232 void BOops::popBackPosition() {positions[1].transport.rate = 0.0;}
233 
popFrontPosition()234 void BOops::popFrontPosition() {positions[0] = positions[1]; popBackPosition();}
235 
activate()236 void BOops::activate() {activated = true;}
237 
deactivate()238 void BOops::deactivate() {activated = false;}
239 
run(uint32_t n_samples)240 void BOops::run (uint32_t n_samples)
241 {
242 	// Check ports
243 	if ((!controlPort) || (!notifyPort) || (!audioInput1) || (!audioInput2) || (!audioOutput1) || (!audioOutput2)) return;
244 
245 	for (int i = 0; i < NR_CONTROLLERS; ++i) if (!new_controllers[i]) return;
246 
247 	// Prepare forge buffer and initialize atom sequence
248 	const uint32_t space = notifyPort->atom.size;
249 	lv2_atom_forge_set_buffer(&forge, (uint8_t*) notifyPort, space);
250 	lv2_atom_forge_sequence_head(&forge, &notify_frame, 0);
251 
252 	// Update controller values
253 	for (int i = 0; i < SLOTS; ++i)
254 	{
255 		if (globalControllers[i] != *new_controllers[i])
256 		{
257 			float newValue = controllerLimits[i].validate (*new_controllers[i]);
258 			float oldValue = globalControllers[i];
259 			globalControllers[i] = newValue;
260 
261 			if (i == PLAY_MODE)
262 			{
263 				Position np = backPosition();
264 
265 				switch (int (newValue))
266 				{
267 					case AUTOPLAY:
268 						np.playing = true;
269 						np.transport.bpm = globalControllers[AUTOPLAY_BPM];
270 						np.transport.speed = 1.0;
271 						np.transport.beatsPerBar = globalControllers[AUTOPLAY_BPB];
272 						break;
273 
274 					case HOST_CONTROLLED:
275 						np.playing = true;
276 						np.transport = host;
277 						break;
278 
279 					default:
280 						np.playing = false;
281 						np.transport = host;
282 				}
283 
284 				pushBackPosition (np);
285 
286 				resizeSteps ();
287 			}
288 
289 			else if (i == STEPS)
290 			{
291 				for (Slot& s : slots) s.size = newValue;
292 				resizeSteps ();
293 			}
294 
295 			else if (i == AUTOPLAY_BPM)
296 			{
297 				if (globalControllers[PLAY_MODE] == AUTOPLAY) backPosition().transport.bpm = globalControllers[AUTOPLAY_BPM];
298 				resizeSteps ();
299 			}
300 
301 			else if (i == AUTOPLAY_BPB)
302 			{
303 				if (globalControllers[PLAY_MODE] == AUTOPLAY) backPosition().transport.beatsPerBar = globalControllers[AUTOPLAY_BPB];
304 				resizeSteps ();
305 			}
306 
307 			else if (i == AUTOPLAY_POSITION)
308 			{
309 				Position np = backPosition();
310 				np.sequence = floorfrac (np.sequence + 1.0 + newValue - oldValue);
311 				np.refFrame = 0;
312 				pushBackPosition (np);
313 				scheduleNotifyStatus = true;
314 			}
315 
316 			else if
317 			((i == BASE) || (i == BASE_VALUE)) resizeSteps ();
318 		}
319 	}
320 
321 	for (int slotNr = 0; slotNr < NR_SLOTS; ++slotNr)
322 	{
323 		if (!scheduleSetFx[slotNr])
324 		{
325 			if (slots[slotNr].effect != *new_controllers[SLOTS + slotNr * (SLOTS_PARAMS + NR_PARAMS)])
326 			{
327 				LV2_Atom_Int msg = {{sizeof (int), urids.bOops_allocateFx}, slotNr};
328 				scheduleSetFx[slotNr] = true;
329 				workerSchedule->schedule_work (workerSchedule->handle, sizeof (msg), &msg);
330 				continue;
331 			}
332 
333 			for (int params = 0; params < NR_PARAMS; ++params)
334 			{
335 				int controllerNr = SLOTS + slotNr * (SLOTS_PARAMS + NR_PARAMS) + SLOTS_PARAMS + params;
336 				if (slots[slotNr].params[params] != *new_controllers[controllerNr])
337 				{
338 					float newValue = controllerLimits[controllerNr].validate (*new_controllers[controllerNr]);
339 					slots[slotNr].params[params] = newValue;
340 				}
341 			}
342 		}
343 	}
344 
345 
346 
347 	// Control and MIDI messages
348 	uint32_t last_t = 0;
349 	LV2_ATOM_SEQUENCE_FOREACH(controlPort, ev)
350 	{
351 		// Read host & GUI events
352 		if ((ev->body.type == urids.atom_Object) || (ev->body.type == urids.atom_Blank))
353 		{
354 			const LV2_Atom_Object* obj = (const LV2_Atom_Object*)&ev->body;
355 
356 			// Process GUI on status data
357 			if (obj->body.otype == urids.bOops_uiOn)
358 			{
359 				ui_on = true;
360 				scheduleNotifyAllSlots = true;
361 				std::fill (scheduleNotifyPageControls, scheduleNotifyPageControls + NR_PAGES, true);
362 				std::fill (scheduleNotifyShape, scheduleNotifyShape + NR_SLOTS, true);
363 				scheduleNotifyTransportGateKeys = true;
364 				scheduleNotifySamplePathToGui = true;
365 				scheduleNotifyStatus = true;
366 			}
367 
368 			// Process GUI off status data
369 			else if (obj->body.otype == urids.bOops_uiOff) ui_on = false;
370 
371 
372 			// Process page properties
373 			else if (obj->body.otype == urids.bOops_pagePropertiesEvent)
374 			{
375 				LV2_Atom *oId = NULL, *oStatus = NULL, *oChannel = NULL, *oMsg = NULL, *oValue = NULL;
376 				int id = -1;
377 				lv2_atom_object_get (obj,
378 						     urids.bOops_pageID, &oId,
379 		     				     urids.bOops_pageStatus, &oStatus,
380 		     				     urids.bOops_pageChannel, &oChannel,
381 		     				     urids.bOops_pageMessage, &oMsg,
382 		     				     urids.bOops_pageValue, &oValue,
383 						     NULL);
384 
385 				if (oId && (oId->type == urids.atom_Int) && (((LV2_Atom_Int*)oId)->body >= 0) && (((LV2_Atom_Int*)oId)->body < NR_PAGES))
386      				{
387      					id = ((LV2_Atom_Int*)oId)->body;
388 
389 					if (oStatus && (oStatus->type == urids.atom_Int)) pages[id].controls.status = LIMIT (((LV2_Atom_Int*)oStatus)->body, 0, 15);
390      					if (oChannel && (oChannel->type == urids.atom_Int)) pages[id].controls.channel = LIMIT (((LV2_Atom_Int*)oChannel)->body, 0, 16);
391      					if (oMsg && (oMsg->type == urids.atom_Int)) pages[id].controls.message = LIMIT (((LV2_Atom_Int*)oMsg)->body, 0, 128);
392      					if (oValue && (oValue->type == urids.atom_Int)) pages[id].controls.value = LIMIT (((LV2_Atom_Int*)oValue)->body, 0, 128);
393      				}
394 
395 				scheduleStateChanged = true;
396 			}
397 
398 
399 			// Process page selection
400 			else if (obj->body.otype == urids.bOops_statusEvent)
401 			{
402 				LV2_Atom * oMl = NULL, *oId = NULL, *oMax = NULL, *oEdPg = NULL, *oEdSl = NULL;
403 				lv2_atom_object_get (obj,
404 						     urids.bOops_requestMidiLearn, &oMl,
405 						     urids.bOops_pageID, &oId,
406 						     urids.bOops_pageMax, &oMax,
407 						     urids.bOops_editorPage, &oEdPg,
408 						     urids.bOops_editorSlot, &oEdSl,
409 						     NULL);
410 
411 				// Midi learn request notification
412 				if (oMl && (oMl->type == urids.atom_Bool)) midiLearn = ((LV2_Atom_Bool*)oMl)->body;
413 
414 				if (oId && (oId->type == urids.atom_Int) && (((LV2_Atom_Int*)oId)->body >= 0) && (((LV2_Atom_Int*)oId)->body < NR_PAGES))
415      				{
416      					const int id = ((LV2_Atom_Int*)oId)->body;
417 
418 					// Schedule fader for page change
419 					if (id != pageNr)
420 					{
421 						Position np = backPosition();
422 						pushBackPosition (np);
423 						pageNr = id;
424 					}
425 
426 					if (pageMax < pageNr) pageMax = pageNr;
427      				}
428 
429 				if (oMax && (oMax->type == urids.atom_Int) && (((LV2_Atom_Int*)oMax)->body >= 0) && (((LV2_Atom_Int*)oMax)->body < NR_PAGES))
430      				{
431      					pageMax = ((LV2_Atom_Int*)oMax)->body;
432 
433 					if (pageNr > pageMax)
434 					{
435 						// Limit pageNr to pageMax
436 						pageNr = pageMax;
437 
438 						// Schedule fader for page change
439 						Position np = backPosition();
440 						pushBackPosition (np);
441 					}
442      				}
443 
444 				if (oEdPg && (oEdPg->type == urids.atom_Int)) editorPage = LIMIT (((LV2_Atom_Int*)oEdPg)->body, 0, NR_PAGES - 1);
445 
446 				if (oEdSl && (oEdSl->type == urids.atom_Int)) editorSlot = LIMIT (((LV2_Atom_Int*)oEdSl)->body, 0, NR_SLOTS - 1);
447 
448 				scheduleStateChanged = true;
449 			}
450 
451 
452 			// Process transportGateKey data
453 			else if (obj->body.otype == urids.bOops_transportGateKeyEvent)
454 			{
455 				LV2_Atom *oKeys = NULL;
456 				lv2_atom_object_get (obj,
457 						     urids.bOops_transportGateKeys, &oKeys,
458 						     NULL);
459 
460 				if (oKeys && (oKeys->type == urids.atom_Vector))
461 				{
462 					const LV2_Atom_Vector* vec = (const LV2_Atom_Vector*) oKeys;
463 					if (vec->body.child_type == urids.atom_Int)
464 					{
465 						const int keysize = LIMIT ((int) ((oKeys->size - sizeof(LV2_Atom_Vector_Body)) / sizeof (int)), 0, NR_PIANO_KEYS);
466 						const int* keys = (int*) (&vec->body + 1);
467 						std::fill (transportGateKeys, transportGateKeys + NR_PIANO_KEYS, false);
468 						for (int i = 0; i < keysize; ++i)
469 						{
470 							int keyNr = keys[i];
471 							if ((keyNr >=0) && (keyNr < NR_PIANO_KEYS)) transportGateKeys[keyNr] = true;
472 						}
473 						scheduleNotifyTransportGateKeys = true;
474 						scheduleStateChanged = true;
475 					}
476 				}
477 			}
478 
479 			// Process slot pads or shape or keys data
480 			else if (obj->body.otype == urids.bOops_slotEvent)
481 			{
482 				LV2_Atom *oPg = NULL, *oSl = NULL, *oPd = NULL, *oSh = NULL, *oKy = NULL;
483 				int pg = 0;
484 				int slot = -1;
485 				lv2_atom_object_get (obj,
486 					 	     urids.bOops_pageID, &oPg,
487 					 	     urids.bOops_slot, &oSl,
488 						     urids.bOops_pads, &oPd,
489 							 urids.bOops_shapeData, &oSh,
490 							 urids.bOops_keysData, &oKy,
491 						     NULL);
492 
493 				// Page nr notification
494      				if (oPg && (oPg->type == urids.atom_Int) && (((LV2_Atom_Int*)oPg)->body >= 0) && (((LV2_Atom_Int*)oPg)->body < NR_PAGES))
495      				{
496      					pg = ((LV2_Atom_Int*)oPg)->body;
497      				}
498 
499 				// Slot nr notification
500 				if (oSl && (oSl->type == urids.atom_Int) && (((LV2_Atom_Int*)oSl)->body >= 0) && (((LV2_Atom_Int*)oSl)->body < NR_SLOTS))
501 				{
502 					slot = ((LV2_Atom_Int*)oSl)->body;
503 				}
504 
505 				// Pad notification
506 				if (oPd && (oPd->type == urids.atom_Vector) && (slot >= 0))
507 				{
508 					const LV2_Atom_Vector* vec = (const LV2_Atom_Vector*) oPd;
509 					if (vec->body.child_type == urids.atom_Float)
510 					{
511 						const uint32_t size = (uint32_t) ((oPd->size - sizeof(LV2_Atom_Vector_Body)) / sizeof (Pad));
512 						Pad* pad = (Pad*) (&vec->body + 1);
513 						for (unsigned int i = 0; (i < size) && (i < NR_STEPS); ++i) pages[pg].pads[slot][i] = pad[i];
514 						if (pg == pageNr)
515 						{
516 							for (unsigned int i = 0; (i < size) && (i < NR_STEPS); ++i) slots[slot].setPad (i, pad[i]);
517 						}
518 
519 						scheduleStateChanged = true;
520 					}
521 				}
522 
523 				// Shape notification
524 				if (oSh && (oSh->type == urids.atom_Vector) && (slot >= 0))
525 				{
526 					const LV2_Atom_Vector* vec = (const LV2_Atom_Vector*) oSh;
527 					if (vec->body.child_type == urids.atom_Float)
528 					{
529 						Shape<SHAPE_MAXNODES> shape = Shape<SHAPE_MAXNODES>();
530 						const uint32_t vecSize = (uint32_t) ((oSh->size - sizeof(LV2_Atom_Vector_Body)) / (7 * sizeof (float)));
531 						float* data = (float*) (&vec->body + 1);
532 						for (unsigned int i = 0; (i < vecSize) && (i < SHAPE_MAXNODES); ++i)
533 						{
534 							Node node;
535 							node.nodeType = NodeType (int (data[i * 7]));
536 							node.point.x = data[i * 7 + 1];
537 							node.point.y = data[i * 7 + 2];
538 							node.handle1.x = data[i * 7 + 3];
539 							node.handle1.y = data[i * 7 + 4];
540 							node.handle2.x = data[i * 7 + 5];
541 							node.handle2.y = data[i * 7 + 6];
542 							shape.appendNode (node);
543 						}
544 						if (shape != Shape<SHAPE_MAXNODES>()) shape.validateShape();
545 						pages[pg].shapes[slot] = shape;
546 						if (pg == pageNr) slots[slot].setSlotShape (shape);
547 
548 						scheduleStateChanged = true;
549 					}
550 				}
551 
552 				// Keys notification
553 				if (oKy && (oKy->type == urids.atom_String) && (slot >= 0))
554 				{
555 					const char* kstr = (const char*) (oKy + 1);
556 					hstr2bool<std::array<bool, NR_PIANO_KEYS + 1>> (kstr, pages[pg].keys[slot]);
557 					if (pg == pageNr) slots[slot].setSlotKeys (pages[pg].keys[slot]);
558 					scheduleStateChanged = true;
559 				}
560 			}
561 
562 			// Process single pad data
563 			else if (obj->body.otype == urids.bOops_padEvent)
564 			{
565 				LV2_Atom *oPg = NULL, *oSl = NULL, *oSt = NULL, *oPd = NULL;
566 				int pg = 0;
567 				int slot = -1;
568 				int step = -1;
569 				lv2_atom_object_get (obj,
570 					 	     urids.bOops_pageID, &oPg,
571 					 	     urids.bOops_slot, &oSl,
572 						     urids.bOops_step, &oSt,
573 						     urids.bOops_pads, &oPd,
574 						     NULL);
575 
576 				// Page nr notification
577   				if (oPg && (oPg->type == urids.atom_Int) && (((LV2_Atom_Int*)oPg)->body >= 0) && (((LV2_Atom_Int*)oPg)->body < NR_PAGES))
578   				{
579   					pg = ((LV2_Atom_Int*)oPg)->body;
580   				}
581 
582 		     		// Slot nr notification
583 				if (oSl && (oSl->type == urids.atom_Int) && (((LV2_Atom_Int*)oSl)->body >= 0) && (((LV2_Atom_Int*)oSl)->body < NR_SLOTS))
584 				{
585 					slot = ((LV2_Atom_Int*)oSl)->body;
586 				}
587 
588 				// Step nr notification
589 				if (oSt && (oSt->type == urids.atom_Int) && (((LV2_Atom_Int*)oSt)->body >= 0) && (((LV2_Atom_Int*)oSt)->body < NR_STEPS))
590 				{
591 					step = ((LV2_Atom_Int*)oSt)->body;
592 				}
593 
594 				// Pad notification
595 				if (oPd && (oPd->type == urids.atom_Vector) && (slot >= 0) && (step >= 0))
596 				{
597 					const LV2_Atom_Vector* vec = (const LV2_Atom_Vector*) oPd;
598 					if (vec->body.child_type == urids.atom_Float)
599 					{
600 						const uint32_t size = (uint32_t) ((oPd->size - sizeof(LV2_Atom_Vector_Body)) / sizeof (Pad));
601 						if (size == 1)
602 						{
603 							Pad* pad = (Pad*) (&vec->body + 1);
604 							pages[pg].pads[slot][step] = *pad;
605 							if (pg == pageNr) slots[slot].setPad (step, *pad);
606 							scheduleStateChanged = true;
607 						}
608 					}
609 				}
610 			}
611 
612 			// Process param shape data
613 			else if (obj->body.otype == urids.bOops_shapeEvent)
614 			{
615 				LV2_Atom *oSl = NULL, *oSh = NULL;
616 				int slot = -1;
617 				lv2_atom_object_get (obj,
618 						     urids.bOops_slot, &oSl,
619 						     urids.bOops_shapeData, &oSh,
620 						     NULL);
621 
622 				// Slot nr notification
623 				if (oSl && (oSl->type == urids.atom_Int) && (((LV2_Atom_Int*)oSl)->body >= 0) && (((LV2_Atom_Int*)oSl)->body < NR_SLOTS))
624 				{
625 					slot = ((LV2_Atom_Int*)oSl)->body;
626 				}
627 
628 				// Shape notification
629 				if (oSh && (oSh->type == urids.atom_Vector) && (slot >= 0))
630 				{
631 					const LV2_Atom_Vector* vec = (const LV2_Atom_Vector*) oSh;
632 					if (vec->body.child_type == urids.atom_Float)
633 					{
634 						slots[slot].shape.clearShape ();
635 						const uint32_t vecSize = (uint32_t) ((oSh->size - sizeof(LV2_Atom_Vector_Body)) / (7 * sizeof (float)));
636 						float* data = (float*) (&vec->body + 1);
637 						for (unsigned int i = 0; (i < vecSize) && (i < SHAPE_MAXNODES); ++i)
638 						{
639 							Node node;
640 							node.nodeType = NodeType (int (data[i * 7]));
641 							node.point.x = data[i * 7 + 1];
642 							node.point.y = data[i * 7 + 2];
643 							node.handle1.x = data[i * 7 + 3];
644 							node.handle1.y = data[i * 7 + 4];
645 							node.handle2.x = data[i * 7 + 5];
646 							node.handle2.y = data[i * 7 + 6];
647 							slots[slot].shape.appendNode (node);
648 						}
649 						slots[slot].shape.validateShape();
650 						scheduleStateChanged = true;
651 					}
652 				}
653 			}
654 
655 			// Sample path notification -> forward to worker
656 			else if (obj->body.otype ==urids.bOops_samplePathEvent)
657 			{
658 				const LV2_Atom* oPath = NULL, *oStart = NULL, *oEnd = NULL, *oAmp = NULL, *oLoop = NULL;
659 				lv2_atom_object_get
660 				(
661 					obj,
662 					urids.bOops_samplePath, &oPath,
663 					urids.bOops_sampleStart, &oStart,
664 					urids.bOops_sampleEnd, &oEnd,
665 					urids.bOops_sampleAmp, &oAmp,
666 					urids.bOops_sampleLoop, &oLoop,
667 					0
668 				);
669 
670 				// New sample
671 				if (oPath && (oPath->type == urids.atom_Path))
672 				{
673 					workerSchedule->schedule_work (workerSchedule->handle, lv2_atom_total_size((LV2_Atom*)obj), obj);
674 				}
675 
676 				// Only start / end /amp / loop changed
677 				else if (sample)
678 				{
679 					if (oStart && (oStart->type == urids.atom_Long)) sample->start = LIMIT (((LV2_Atom_Long*)oStart)->body, 0, sample->info.frames - 1);
680 					if (oEnd && (oEnd->type == urids.atom_Long)) sample->end = LIMIT (((LV2_Atom_Long*)oEnd)->body, 0, sample->info.frames);
681 					if (oAmp && (oAmp->type == urids.atom_Float)) sampleAmp = LIMIT (((LV2_Atom_Float*)oAmp)->body, 0.0f, 1.0f);
682 					if (oLoop && (oLoop->type == urids.atom_Bool)) sample->loop = bool (((LV2_Atom_Bool*)oLoop)->body);
683 				}
684 			}
685 
686 			// Process time / position data
687 			else if (obj->body.otype == urids.time_Position)
688 			{
689 				bool scheduleUpdatePosition = false;
690 				bool scheduleResizeSteps = false;
691 
692 				// Update bpm, speed, position
693 				LV2_Atom *oBbeat = NULL, *oBpm = NULL, *oSpeed = NULL, *oBpb = NULL, *oBu = NULL, *oBar = NULL;
694 				const LV2_Atom_Object* obj = (const LV2_Atom_Object*)&ev->body;
695 				lv2_atom_object_get
696 				(
697 					obj,
698 					urids.time_bar, &oBar,
699 					urids.time_barBeat, &oBbeat,
700 					urids.time_beatsPerMinute,  &oBpm,
701 					urids.time_beatsPerBar,  &oBpb,
702 					urids.time_beatUnit,  &oBu,
703 					urids.time_speed, &oSpeed,
704 					NULL
705 				);
706 
707 				// BPM changed?
708 				if (oBpm && (oBpm->type == urids.atom_Float))
709 				{
710 					float nbpm = ((LV2_Atom_Float*)oBpm)->body;
711 
712 					if (nbpm != host.bpm)
713 					{
714 						host.bpm = nbpm;
715 						if (nbpm < 1.0) message.setMessage (JACK_STOP_MSG);
716 						else message.deleteMessage (JACK_STOP_MSG);
717 
718 						scheduleResizeSteps = true;
719 					}
720 				}
721 
722 				// Beats per bar changed?
723 				if (oBpb && (oBpb->type == urids.atom_Float) && (((LV2_Atom_Float*)oBpb)->body > 0) && (((LV2_Atom_Float*)oBpb)->body != host.beatsPerBar))
724 				{
725 					host.beatsPerBar = ((LV2_Atom_Float*)oBpb)->body;
726 					scheduleNotifyStatus = true;
727 					scheduleResizeSteps = true;
728 				}
729 
730 				// Speed changed?
731 				if (oSpeed && (oSpeed->type == urids.atom_Float))
732 				{
733 					float nspeed = ((LV2_Atom_Float*)oSpeed)->body;
734 
735 					if (nspeed != host.speed)
736 					{
737 
738 						if (globalControllers[BASE] != SECONDS)
739 						{
740 
741 							// Started ?
742 							// TODO Clear all audio buffers
743 							// if (speed == 0)
744 							// {
745 							//
746 							// }
747 
748 							// Stopped ?
749 							if (nspeed == 0)
750 							{
751 								message.setMessage (JACK_STOP_MSG);
752 							}
753 
754 							// Not stopped ?
755 							else message.deleteMessage (JACK_STOP_MSG);
756 						}
757 
758 						host.speed = nspeed;
759 					}
760 				}
761 
762 				// Bar position changed
763 				if (oBar && (oBar->type == urids.atom_Long) && (host.bar != ((uint64_t)((LV2_Atom_Long*)oBar)->body)))
764 				{
765 					host.bar = ((LV2_Atom_Long*)oBar)->body;
766 					scheduleUpdatePosition = true;
767 				}
768 
769 				// Beat position changed (during playing) ?
770 				if (oBbeat && (oBbeat->type == urids.atom_Float) && (((LV2_Atom_Float*)oBbeat)->body != host.barBeat))
771 				{
772 					host.barBeat = ((LV2_Atom_Float*)oBbeat)->body;
773 					scheduleUpdatePosition = true;
774 				}
775 
776 				// Bar or beat position data changed in host or midi controlled mode: fade
777 				if (scheduleUpdatePosition)
778 				{
779 					if (globalControllers[PLAY_MODE] != AUTOPLAY)
780 					{
781 						Position np = backPosition();
782 						double pos = getPositionFromBeats (host, host.barBeat + host.beatsPerBar * host.bar);
783 						double npos = floorfrac (pos - np.offset);
784 
785 						// Fade only if jump > 1 ms
786 						if (fabs (npos - np.sequence) > getPositionFromSeconds (host, 0.001))
787 						{
788 							np.fader = 0.0;
789 							np.transport = host;
790 							np.sequence = npos;
791 							// keep np.step
792 							np.refFrame = ev->time.frames;
793 							scheduleNotifyStatus = true;
794 
795 							pushBackPosition (np);
796 						}
797 
798 						// Otherwise update at least the transport data
799 						else backPosition().transport = host;
800 					}
801 				}
802 
803 				// Other data changed in host or midi controlled mode: copy
804 				else if (globalControllers[PLAY_MODE] != AUTOPLAY) backPosition().transport = host;
805 
806 				if (scheduleResizeSteps && (globalControllers[PLAY_MODE] != AUTOPLAY)) resizeSteps();
807 			}
808 		}
809 
810 		// Read incoming MIDI events
811 		if (ev->body.type == urids.midi_Event)
812 		{
813 			const uint8_t* const msg = (const uint8_t*)(ev + 1);
814 			const uint8_t status = (msg[0] >> 4);
815 			const uint8_t channel = msg[0] & 0x0F;
816 			const uint8_t note = ((status == 8) || (status == 9) || (status == 11) ? msg[1] : 0);
817 			const uint8_t value = ((status == 8) || (status == 9) || (status == 11) ? msg[2] : 0);
818 
819 			// MidiLearn
820 			if (midiLearn)
821 			{
822 				midiLearned[0] = status;
823 				midiLearned[1] = channel;
824 				midiLearned[2] = note;
825 				midiLearned[3] = value;
826 				midiLearn = false;
827 				scheduleNotifyMidiLearnedToGui = true;
828 			}
829 
830 			// Analyze MIDI event
831 			else
832 			{
833 				// Store into keys
834 				// NOTE_ON and NOTE_OFF
835 				if (((status == 8) || (status == 9)) && (note < NR_PIANO_KEYS))
836 				{
837 					// Note on
838 					if (status == 9)
839 					{
840 						for (Slot& s : slots)
841 						{
842 							MidiKey old = s.findMidiKey (note);
843 							const double v0 = old.value;
844 							s.addMidiKey ({9, channel, note, value, 0.0, v0});
845 						}
846 					}
847 
848 					// Note off
849 					else if (status == 8)
850 					{
851 						for (Slot& s : slots)
852 						{
853 							MidiKey old = s.findMidiKey (note);
854 							if (old.status != 0) s.addMidiKey ({8, channel, note, value, 0.0, old.value});
855 						}
856 					}
857 				}
858 
859 				// LV2_MIDI_CTL_ALL_NOTES_OFF, LV2_MIDI_CTL_ALL_SOUNDS_OFF
860 				{
861 					if ((status == 11) && ((note == LV2_MIDI_CTL_ALL_NOTES_OFF) || (note ==LV2_MIDI_CTL_ALL_SOUNDS_OFF)))
862 					{
863 						for (Slot& s : slots) s.allKeysOff();
864 					}
865 				}
866 
867 				// MIDI-controlled pages
868 				for (int p = 0; p <= pageMax; ++p)
869 				{
870 					if
871 					(
872 						pages[p].controls.status &&
873 						(pages[p].controls.status == status) &&
874 						(
875 							(pages[p].controls.channel == 0) ||
876 							(pages[p].controls.channel - 1 == channel)
877 						) &&
878 						(
879 							(pages[p].controls.message == 128) ||
880 							(pages[p].controls.message == note)
881 						) &&
882 						(
883 							(pages[p].controls.value == 128) ||
884 							(pages[p].controls.value == value)
885 						)
886 					)
887 					{
888 						if (p != pageNr)
889 						{
890 							Position np = backPosition();
891 							pushBackPosition (np);
892 							pageNr = p;
893 							scheduleNotifyStatus = true;
894 						}
895 
896 						break;
897 					}
898 				}
899 
900 				// MIDI-controlled playback
901 				if (globalControllers[PLAY_MODE] == MIDI_CONTROLLED)
902 				{
903 					const uint8_t typ = lv2_midi_message_type(msg);
904 					// uint8_t chn = msg[0] & 0x0F;
905 					const uint8_t note = msg[1];
906 					const bool isTransportGateKey = ((note < NR_PIANO_KEYS) && transportGateKeys[note]);
907 
908 
909 					switch (typ)
910 					{
911 						case LV2_MIDI_MSG_NOTE_ON:
912 						{
913 							if (isTransportGateKey)
914 							{
915 								Position p = backPosition();
916 
917 								switch (int (globalControllers[ON_MIDI]))
918 								{
919 									case 0:	// Restart
920 										p.offset = floorfrac (p.sequence + p.offset);
921 										p.sequence = 0;
922 										p.refFrame = ev->time.frames;
923 										break;
924 
925 									case 2: // Restart & sync
926 										{
927 											double steppos = fmod (p.sequence, 1.0 / double (globalControllers[STEPS]));
928 											p.offset = floorfrac (1.0 + p.sequence + p.offset - steppos);
929 											p.sequence = steppos;
930 											p.refFrame = ev->time.frames;
931 										}
932 										break;
933 
934 									default:// Continue
935 										break;
936 								}
937 
938 								p.playing = true;
939 								pushBackPosition (p);
940 								scheduleNotifyStatus = true;
941 							}
942 						}
943 						break;
944 
945 						case LV2_MIDI_MSG_NOTE_OFF:
946 						{
947 							if (isTransportGateKey)
948 							{
949 								Position p = backPosition();
950 								p.playing = false;
951 								pushBackPosition (p);
952 								scheduleNotifyStatus = true;
953 							}
954 						}
955 						break;
956 
957 						case LV2_MIDI_MSG_CONTROLLER:
958 						{
959 							if ((note == LV2_MIDI_CTL_ALL_NOTES_OFF) ||
960 							    (note == LV2_MIDI_CTL_ALL_SOUNDS_OFF))
961 							{
962 								Position p = backPosition();
963 								p.playing = false;
964 								pushBackPosition (p);
965 								scheduleNotifyStatus = true;
966 							}
967 						}
968 						break;
969 
970 						default: break;
971 					}
972 				}
973 			}
974 		}
975 
976 		uint32_t next_t = (ev->time.frames < n_samples ? ev->time.frames : n_samples);
977 		play (last_t, next_t);
978 		last_t = next_t;
979 	}
980 
981 	// Play remaining samples
982 	if (last_t < n_samples) play (last_t, n_samples);
983 
984 	// Update position in case of no new barBeat submitted on next call
985 	for (unsigned int i = 0; i < sizePosition(); ++i)
986 	{
987 		const uint64_t diff = n_samples - positions[i].refFrame;
988 		const double relpos = getPositionFromFrames (positions[i].transport, diff);	// Position relative to reference frame
989 		const double npos = floorfrac (positions[i].sequence + relpos);
990 		const int nstep = LIMIT (npos * globalControllers[STEPS], 0, globalControllers[STEPS] - 1);
991 		if (nstep != int (positions[i].sequence * globalControllers[STEPS])) scheduleNotifyStatus = true;
992 		positions[i].sequence = npos;
993 		positions[i].refFrame = 0;
994 	}
995 
996 	// Send collected data to GUI
997 	if (waveformCounter != lastWaveformCounter) scheduleNotifyWaveformToGui = true;
998 	if (ui_on)
999 	{
1000 		if (message.isScheduled ()) notifyMessageToGui ();
1001 		if (scheduleNotifyStatus) notifyStatusToGui ();
1002 		if (scheduleNotifyAllSlots) notifyAllSlotsToGui();
1003 		for (int i = 0; i < NR_PAGES; ++i) {if (scheduleNotifyPageControls[i]) notifyPageControls (i);}
1004 		for (int i = 0; i < NR_SLOTS; ++i) {if (scheduleNotifyShape[i]) notifyShapeToGui (i);}
1005 		if (scheduleNotifyTransportGateKeys) notifyTransportGateKeysToGui();
1006 		if (scheduleNotifyWaveformToGui) notifyWaveformToGui (lastWaveformCounter, waveformCounter);
1007 		if (scheduleNotifySamplePathToGui) notifySamplePathToGui();
1008 		if (scheduleNotifyMidiLearnedToGui) notifyMidiLearnedToGui ();
1009 	}
1010 	if (scheduleStateChanged) notifyStateChanged();
1011 	lv2_atom_forge_pop (&forge, &notify_frame);
1012 }
1013 
resizeSteps()1014 void BOops::resizeSteps ()
1015 {
1016 	double fpst = getFramesPerStep (backPosition().transport);
1017 	for (Slot& s : slots) s.framesPerStep = fpst;
1018 
1019 	if (!scheduleResizeBuffers)
1020 	{
1021 		scheduleResizeBuffers = true;
1022 		LV2_Atom msg = {0, urids.bOops_allocateBuffers};
1023 		workerSchedule->schedule_work (workerSchedule->handle, sizeof (msg), &msg);
1024 	}
1025 }
1026 
notifyAllSlotsToGui()1027 void BOops::notifyAllSlotsToGui ()
1028 {
1029 	for (int page = 0; page <= pageMax; ++page)
1030 	{
1031 		for (int slot = 0; slot < NR_SLOTS; ++slot)
1032 		{
1033 			LV2_Atom_Forge_Frame frame;
1034 			lv2_atom_forge_frame_time(&forge, 0);
1035 			forgePads (&forge, &frame, page, slot, NR_STEPS);
1036 			forgeShapeData (&forge, &frame, &pages[page].shapes[slot]);
1037 			char hstr[40];
1038 			bool2hstr<std::array<bool, NR_PIANO_KEYS + 1>> (pages[page].keys[slot], hstr);
1039 			lv2_atom_forge_key(&forge, urids.bOops_keysData);
1040 			lv2_atom_forge_string (&forge, hstr, strlen (hstr) + 1);
1041 			lv2_atom_forge_pop(&forge, &frame);
1042 		}
1043 	}
1044 
1045 	scheduleNotifyAllSlots = false;
1046 }
1047 
notifyShapeToGui(const int slot)1048 void BOops::notifyShapeToGui (const int slot)
1049 {
1050 	LV2_Atom_Forge_Frame frame;
1051 	lv2_atom_forge_frame_time(&forge, 0);
1052 	forgeShape (&forge, &frame, slot, &slots[slot].shape);
1053 	lv2_atom_forge_pop(&forge, &frame);
1054 
1055 	scheduleNotifyShape[slot] = false;
1056 }
1057 
notifyMessageToGui()1058 void BOops::notifyMessageToGui()
1059 {
1060 	uint32_t messageNr = message.loadMessage ();
1061 
1062 	// Send notifications
1063 	LV2_Atom_Forge_Frame frame;
1064 	lv2_atom_forge_frame_time(&forge, 0);
1065 	lv2_atom_forge_object(&forge, &frame, 0, urids.bOops_messageEvent);
1066 	lv2_atom_forge_key(&forge, urids.bOops_message);
1067 	lv2_atom_forge_int(&forge, messageNr);
1068 	lv2_atom_forge_pop(&forge, &frame);
1069 }
1070 
notifyStatusToGui()1071 void BOops::notifyStatusToGui()
1072 {
1073 	Position& p = backPosition();
1074 	double pos =
1075 	(
1076 		(globalControllers[PLAY] != PLAY_OFF) && p.playing && ((p.transport.speed != 0.0f) || (globalControllers[BASE] == SECONDS)) && (p.transport.bpm >= 1.0f)?
1077 		floorfrac (p.sequence) * globalControllers[STEPS] :
1078 		-1
1079 	);
1080 	// Send notifications
1081 	LV2_Atom_Forge_Frame frame;
1082 	lv2_atom_forge_frame_time(&forge, 0);
1083 	lv2_atom_forge_object(&forge, &frame, 0, urids.bOops_statusEvent);
1084 	lv2_atom_forge_key(&forge, urids.bOops_position);
1085 	lv2_atom_forge_double(&forge, pos);
1086 	lv2_atom_forge_key(&forge, urids.bOops_pageID);
1087 	lv2_atom_forge_int(&forge, pageNr);
1088 	lv2_atom_forge_key(&forge, urids.bOops_pageMax);
1089 	lv2_atom_forge_int(&forge, pageMax);
1090 	lv2_atom_forge_key(&forge, urids.bOops_editorPage);
1091 	lv2_atom_forge_int(&forge, editorPage);
1092 	lv2_atom_forge_key(&forge, urids.bOops_editorSlot);
1093 	lv2_atom_forge_int(&forge, editorSlot);
1094 	lv2_atom_forge_pop(&forge, &frame);
1095 
1096 	scheduleNotifyStatus = false;
1097 }
1098 
notifyWaveformToGui(const int start,const int end)1099 void BOops::notifyWaveformToGui (const int start, const int end)
1100 {
1101 	int p1 = (start <= end ? end : WAVEFORMSIZE - 1);
1102 
1103 	// Notify shapeBuffer (position to end)
1104 	LV2_Atom_Forge_Frame frame;
1105 	lv2_atom_forge_frame_time(&forge, 0);
1106 	lv2_atom_forge_object(&forge, &frame, 0, urids.bOops_waveformEvent);
1107 	lv2_atom_forge_key(&forge, urids.bOops_waveformStart);
1108 	lv2_atom_forge_int(&forge, start);
1109 	lv2_atom_forge_key(&forge, urids.bOops_waveformData);
1110 	lv2_atom_forge_vector(&forge, sizeof(float), urids.atom_Float, (uint32_t) (p1 + 1 - start), &waveform[start]);
1111 	lv2_atom_forge_pop(&forge, &frame);
1112 
1113 	// Additional notification if position exceeds end
1114 	if (start > waveformCounter)
1115 	{
1116 		LV2_Atom_Forge_Frame frame;
1117 		lv2_atom_forge_frame_time(&forge, 0);
1118 		lv2_atom_forge_object(&forge, &frame, 0, urids.bOops_waveformEvent);
1119 		lv2_atom_forge_key(&forge, urids.bOops_waveformStart);
1120 		lv2_atom_forge_int(&forge, 0);
1121 		lv2_atom_forge_key(&forge, urids.bOops_waveformData);
1122 		lv2_atom_forge_vector(&forge, sizeof(float), urids.atom_Float, (uint32_t) (end), &waveform[0]);
1123 		lv2_atom_forge_pop(&forge, &frame);
1124 	}
1125 
1126 	scheduleNotifyWaveformToGui = false;
1127 	lastWaveformCounter = end;
1128 }
1129 
notifyTransportGateKeysToGui()1130 void BOops::notifyTransportGateKeysToGui()
1131 {
1132 	// Create buffer
1133 	int keys[NR_PIANO_KEYS];
1134 	int keysize = 0;
1135 	std::fill (keys, keys + NR_PIANO_KEYS, 0);
1136 	for (int i = 0; i < NR_PIANO_KEYS; ++i)
1137 	{
1138 		if (transportGateKeys[i])
1139 		{
1140 			keys[keysize] = i;
1141 			++keysize;
1142 		}
1143 	}
1144 
1145 	// Send notifications
1146 	LV2_Atom_Forge_Frame frame;
1147 	lv2_atom_forge_frame_time (&forge, 0);
1148 	forgeTransportGateKeys (&forge, &frame, keys, keysize);
1149 	lv2_atom_forge_pop(&forge, &frame);
1150 
1151 	scheduleNotifyTransportGateKeys = false;
1152 }
1153 
notifySamplePathToGui()1154 void BOops::notifySamplePathToGui ()
1155 {
1156 	LV2_Atom_Forge_Frame frame;
1157 	lv2_atom_forge_frame_time(&forge, 0);
1158 
1159 	if (sample && sample->path && (sample->path[0] != 0) && (strlen (sample->path) < PATH_MAX))
1160 	{
1161 		forgeSamplePath (&forge, &frame, sample->path, sample->start, sample->end, sampleAmp, int32_t (sample->loop));
1162 	}
1163 
1164 	else
1165 	{
1166 		const char* path = ".";
1167 		forgeSamplePath (&forge, &frame, path, 0, 0, sampleAmp, false);
1168 	}
1169 
1170 	lv2_atom_forge_pop(&forge, &frame);
1171 	scheduleNotifySamplePathToGui = false;
1172 }
1173 
notifyStateChanged()1174 void BOops::notifyStateChanged()
1175 {
1176 	LV2_Atom_Forge_Frame frame;
1177 	lv2_atom_forge_frame_time(&forge, 0);
1178 	lv2_atom_forge_object(&forge, &frame, 0, urids.state_StateChanged);
1179 	lv2_atom_forge_pop(&forge, &frame);
1180 	scheduleStateChanged = false;
1181 }
1182 
notifyPageControls(const int pageId)1183 void BOops::notifyPageControls (const int pageId)
1184 {
1185 	LV2_Atom_Forge_Frame frame;
1186 	lv2_atom_forge_frame_time (&forge, 0);
1187 	forgePageControls (&forge, &frame, pageId);
1188 	lv2_atom_forge_pop(&forge, &frame);
1189 	scheduleNotifyPageControls[pageId] = false;
1190 }
1191 
notifyMidiLearnedToGui()1192 void BOops::notifyMidiLearnedToGui ()
1193 {
1194 	uint32_t ml = midiLearned[0] * 0x1000000 + midiLearned[1] * 0x10000 + midiLearned[2] * 0x100 + midiLearned[3];
1195 	LV2_Atom_Forge_Frame frame;
1196 	lv2_atom_forge_frame_time(&forge, 0);
1197 	lv2_atom_forge_object(&forge, &frame, 0, urids.bOops_statusEvent);
1198 	lv2_atom_forge_key(&forge, urids.bOops_midiLearned);
1199 	lv2_atom_forge_int(&forge, ml);
1200 	lv2_atom_forge_pop(&forge, &frame);
1201 	scheduleNotifyMidiLearnedToGui = false;
1202 }
1203 
forgeSamplePath(LV2_Atom_Forge * forge,LV2_Atom_Forge_Frame * frame,const char * path,const int64_t start,const int64_t end,const float amp,const int32_t loop)1204 LV2_Atom_Forge_Ref BOops::forgeSamplePath (LV2_Atom_Forge* forge, LV2_Atom_Forge_Frame* frame, const char* path, const int64_t start, const int64_t end, const float amp, const int32_t loop)
1205 {
1206 	const LV2_Atom_Forge_Ref msg = lv2_atom_forge_object (forge, frame, 0, urids.bOops_samplePathEvent);
1207 	if (msg)
1208 	{
1209 		lv2_atom_forge_key (forge, urids.bOops_samplePath);
1210 		lv2_atom_forge_path (forge, path, strlen (path) + 1);
1211 		lv2_atom_forge_key (forge, urids.bOops_sampleStart);
1212 		lv2_atom_forge_long (forge, start);
1213 		lv2_atom_forge_key (forge, urids.bOops_sampleEnd);
1214 		lv2_atom_forge_long (forge, end);
1215 		lv2_atom_forge_key (forge, urids.bOops_sampleAmp);
1216 		lv2_atom_forge_float (forge, amp);
1217 		lv2_atom_forge_key (forge, urids.bOops_sampleLoop);
1218 		lv2_atom_forge_bool (forge, loop);
1219 	}
1220 	return msg;
1221 }
1222 
forgeTransportGateKeys(LV2_Atom_Forge * forge,LV2_Atom_Forge_Frame * frame,const int * keys,const size_t size)1223 LV2_Atom_Forge_Ref BOops::forgeTransportGateKeys (LV2_Atom_Forge* forge, LV2_Atom_Forge_Frame* frame, const int* keys, const size_t size)
1224 {
1225 	const LV2_Atom_Forge_Ref msg = lv2_atom_forge_object (forge, frame, 0, urids.bOops_transportGateKeyEvent);
1226 	if (msg)
1227 	{
1228 		lv2_atom_forge_key (forge, urids.bOops_transportGateKeys);
1229 		lv2_atom_forge_vector (forge, sizeof(int), urids.atom_Int, size, (void*) keys);
1230 	}
1231 	return msg;
1232 }
1233 
forgeShape(LV2_Atom_Forge * forge,LV2_Atom_Forge_Frame * frame,const int slot,const Shape<SHAPE_MAXNODES> * shape)1234 LV2_Atom_Forge_Ref BOops::forgeShape (LV2_Atom_Forge* forge, LV2_Atom_Forge_Frame* frame, const int slot, const Shape<SHAPE_MAXNODES>* shape)
1235 {
1236 	const LV2_Atom_Forge_Ref msg = lv2_atom_forge_object (forge, frame, 0, urids.bOops_shapeEvent);
1237 	if (msg)
1238 	{
1239 		lv2_atom_forge_key(forge, urids.bOops_slot);
1240 		lv2_atom_forge_int(forge, slot);
1241 		forgeShapeData (forge, frame, shape);
1242 	}
1243 	return msg;
1244 }
1245 
forgeShapeData(LV2_Atom_Forge * forge,LV2_Atom_Forge_Frame * frame,const Shape<SHAPE_MAXNODES> * shape)1246 LV2_Atom_Forge_Ref BOops::forgeShapeData (LV2_Atom_Forge* forge, LV2_Atom_Forge_Frame* frame, const Shape<SHAPE_MAXNODES>* shape)
1247 {
1248 	float nodes[SHAPE_MAXNODES][7];
1249 	for (unsigned int i = 0; i < shape->size(); ++i)
1250 	{
1251 		Node n = shape->getNode (i);
1252 		nodes[i][0] = n.nodeType;
1253 		nodes[i][1] = n.point.x;
1254 		nodes[i][2] = n.point.y;
1255 		nodes[i][3] = n.handle1.x;
1256 		nodes[i][4] = n.handle1.y;
1257 		nodes[i][5] = n.handle2.x;
1258 		nodes[i][6] = n.handle2.y;
1259 	}
1260 
1261 	lv2_atom_forge_key(forge, urids.bOops_shapeData);
1262 	return lv2_atom_forge_vector(forge, sizeof(float), urids.atom_Float, 7 * shape->size(), nodes);
1263 }
1264 
forgePads(LV2_Atom_Forge * forge,LV2_Atom_Forge_Frame * frame,const int page,const int slot,const size_t size)1265 LV2_Atom_Forge_Ref BOops::forgePads (LV2_Atom_Forge* forge, LV2_Atom_Forge_Frame* frame, const int page, const int slot, const size_t size)
1266 {
1267 	const LV2_Atom_Forge_Ref msg = lv2_atom_forge_object(forge, frame, 0, urids.bOops_slotEvent);
1268 	if (msg)
1269 	{
1270 		lv2_atom_forge_key(forge, urids.bOops_pageID);
1271 		lv2_atom_forge_int(forge, page);
1272 		lv2_atom_forge_key(forge, urids.bOops_slot);
1273 		lv2_atom_forge_int(forge, slot);
1274 		lv2_atom_forge_key(forge, urids.bOops_pads);
1275 		lv2_atom_forge_vector(forge, sizeof(float), urids.atom_Float, sizeof(Pad) / sizeof(float) * NR_STEPS, (void*) &(pages[page].pads[slot][0]));
1276 	}
1277 	return msg;
1278 }
1279 
forgePageControls(LV2_Atom_Forge * forge,LV2_Atom_Forge_Frame * frame,const int pageId)1280 LV2_Atom_Forge_Ref BOops::forgePageControls (LV2_Atom_Forge* forge, LV2_Atom_Forge_Frame* frame, const int pageId)
1281 {
1282 	const LV2_Atom_Forge_Ref msg = lv2_atom_forge_object(forge, frame, 0, urids.bOops_pagePropertiesEvent);
1283 	if (msg)
1284 	{
1285 		const PageControls& controls = pages[pageId].controls;
1286 		lv2_atom_forge_key(forge, urids.bOops_pageID);
1287 		lv2_atom_forge_int(forge, pageId);
1288 		lv2_atom_forge_key(forge, urids.bOops_pageStatus);
1289 		lv2_atom_forge_int(forge, controls.status);
1290 		lv2_atom_forge_key(forge, urids.bOops_pageChannel);
1291 		lv2_atom_forge_int(forge, controls.channel);
1292 		lv2_atom_forge_key(forge, urids.bOops_pageMessage);
1293 		lv2_atom_forge_int(forge, controls.message);
1294 		lv2_atom_forge_key(forge, urids.bOops_pageValue);
1295 		lv2_atom_forge_int(forge, controls.value);
1296 	}
1297 	return msg;
1298 }
1299 
getSample(const Position & p,const double pos)1300 Stereo BOops::getSample (const Position& p, const double pos)
1301 {
1302 	if (sample && (sample->end > sample->start))
1303 	{
1304 		const uint64_t f0 = getFramesFromPosition (p.transport, pos);
1305 		const int64_t frame =
1306 		(
1307 			sample->loop ?
1308 			(f0  % (sample->end - sample->start)) + sample->start :
1309 			f0 + sample->start
1310 		);
1311 
1312 		if (frame < sample->end) return Stereo (sample->get (frame, 0, host.rate), sample->get (frame, 1, host.rate)) * sampleAmp;
1313 		else return Stereo();
1314 	}
1315 
1316 	else return Stereo();
1317 }
1318 
play(uint32_t start,uint32_t end)1319 void BOops::play (uint32_t start, uint32_t end)
1320 {
1321 	if (end < start) return;
1322 
1323 	if (globalControllers[PLAY] == PLAY_OFF)
1324 	{
1325 		for (uint32_t i = start; i < end; ++i)
1326 		{
1327 			for (Slot& s : slots) s.buffer->push_front (Stereo {audioInput1[i], audioInput2[i]});
1328 		}
1329 		memset(&audioOutput1[start], 0, (end - start) * sizeof(float));
1330 		memset(&audioOutput2[start], 0, (end - start) * sizeof(float));
1331 		return;
1332 
1333 		// TODO fader
1334 	}
1335 
1336 	if (globalControllers[PLAY] == PLAY_BYPASS)
1337 	{
1338 		for (uint32_t i = start; i < end; ++i)
1339 		{
1340 			Position& p = backPosition();
1341 			double relpos = getPositionFromFrames (p.transport, i - p.refFrame);	// Position relative to reference frame
1342 			double pos = floorfrac (p.sequence + relpos);				// 0..1 position sequence
1343 
1344 			// Input signal
1345 			Stereo input = (globalControllers[SOURCE] == SOURCE_SAMPLE) ? getSample (p, pos) : Stereo (audioInput1[i], audioInput2[i]);
1346 
1347 			// Load samples to buffer
1348 			for (Slot& s : slots) s.buffer->push_front (input);
1349 
1350 			// Waveform
1351 			waveformCounter = int (pos * WAVEFORMSIZE) % WAVEFORMSIZE;
1352 			waveform[waveformCounter] = (input.left + input.right) / 2;
1353 
1354 			// Bypass to output
1355 			audioOutput1[i] = input.left;
1356 			audioOutput2[i] = input.right;
1357 		}
1358 
1359 		// TODO fader
1360 
1361 		return;
1362 	}
1363 
1364 
1365 	for (uint32_t i = start; i < end; ++i)
1366 	{
1367 		Position& p = positions[0];
1368 		p.fader = p.fader + (1.0 - 2.0 * (sizePosition() > 1)) / (FADINGTIME * p.transport.rate);
1369 		p.fader = LIMIT (p.fader, 0.0, 1.0);
1370 
1371 		// Interpolate position within the loop
1372 		double relpos = getPositionFromFrames (p.transport, i - p.refFrame);	// Position relative to reference frame
1373 		double pos = floorfrac (p.sequence + relpos);							// 0..1 position sequence
1374 
1375 		// Input
1376 		const Stereo input = (globalControllers[SOURCE] == SOURCE_SAMPLE) ? getSample (p, pos) : Stereo (audioInput1[i], audioInput2[i]);
1377 		Stereo output = input;
1378 
1379 		// Waveform
1380 		waveformCounter = int (pos * WAVEFORMSIZE) % WAVEFORMSIZE;
1381 		waveform[waveformCounter] = (input.left + input.right) / 2;
1382 
1383 		if
1384 		(
1385 			(p.playing) &&
1386 			((p.transport.speed != 0.0f) || (globalControllers[BASE] == SECONDS)) &&
1387 			(p.transport.bpm >= 1.0f)
1388 		)
1389 		{
1390 			double step = pos * globalControllers[STEPS];
1391 			int iStep = LIMIT (step, 0, globalControllers[STEPS] - 1);
1392 
1393 			// Init step ?
1394 			if (scheduleInit || (p.step != iStep))
1395 			{
1396 				for (Slot& s : slots)
1397 				{
1398 					if ((s.effect == FX_INVALID) || (s.effect == FX_NONE)) break;
1399 
1400 					// Old pad ended?
1401 					const int iStart = s.startPos[iStep];
1402 					if (((p.step < 0) || (s.startPos[p.step] != iStart)) && (s.getMode() == MODE_PATTERN))
1403 					{
1404 						// Stop old pad
1405 						s.end ();
1406 
1407 						// Start new pad (if set)
1408 						if (iStart >= 0) s.init (iStart);
1409 					}
1410 
1411 					else if (scheduleInit)
1412 					{
1413 						s.end();
1414 						s.init (LIMIT (step, 0, globalControllers[STEPS] - 1));
1415 					}
1416 				}
1417 				scheduleInit = false;
1418 			}
1419 
1420 			// Play slots
1421 			const double dsteps = getPositionFromFrames (p.transport, 1) * globalControllers[STEPS];
1422 			for (Slot& s : slots)
1423 			{
1424 				// Store last output
1425 				s.buffer->push_front (output);
1426 
1427 				if ((s.effect == FX_INVALID) || (s.effect == FX_NONE)) break;
1428 
1429 				// Play music :-)
1430 				if (s.params[SLOTS_PLAY])
1431 				{
1432 					if (s.getMode() == MODE_KEYS)
1433 					{
1434 						float mx = 0;
1435 						for (MidiKey** iit = s.midis.begin(); iit < s.midis.end(); ++iit)
1436 						{
1437 							if (((**iit).status != 0) && s.isKey ((**iit).note)) mx = std::max (float ((**iit).velocity) * float ((**iit).value) / 127.0f, mx);
1438 						}
1439 						output = s.play (step, mx);
1440 					}
1441 
1442 					else output = s.play (step);
1443 				}
1444 
1445 				s.mixf = 1.0f;
1446 
1447 				// Update MidiKeys
1448 				for (MidiKey** iit = s.midis.begin(); iit < s.midis.end(); )
1449 				{
1450 					// Update position;
1451 					(**iit).count +=dsteps;
1452 
1453 					// Use ADSR envelope
1454 					double adr = s.params[SLOTS_ATTACK] + s.params[SLOTS_DECAY] + s.params[SLOTS_RELEASE];
1455 					if (adr < 1.0f) adr = 1.0f;
1456 					const double a = s.params[SLOTS_ATTACK] / adr;
1457 					const double d = s.params[SLOTS_DECAY] / adr;
1458 					const double r = s.params[SLOTS_RELEASE] / adr;
1459 
1460 					// Recalculate value
1461 					// NOTE_ON
1462 					if ((**iit).status == 9)
1463 					{
1464 						if ((**iit).count < a) (**iit).value = std::min ((**iit).value + dsteps / a, 1.0);
1465 						else if ((**iit).count < a + d) (**iit).value = std::max ((**iit).value - dsteps / d, double (s.params[SLOTS_SUSTAIN]));
1466 						else (**iit).value = s.params[SLOTS_SUSTAIN];
1467 					}
1468 
1469 					// NOTE_OFF
1470 					else if ((**iit).status == 8)
1471 					{
1472 						if (r == 0) (**iit).value = 0.0;
1473 						else (**iit).value -= dsteps / r;
1474 					}
1475 
1476 					else (**iit).value = 0.0;
1477 
1478 					// Cleanup
1479 					if (((**iit).value <= 0.0) || ((**iit).status == 0)) iit = s.midis.erase (iit);
1480 					else ++iit;
1481 				}
1482 			}
1483 
1484 			p.step = iStep;
1485 		}
1486 
1487 		audioOutput1[i] = (1.0 - p.fader) * input.left + p.fader * output.left;
1488 		audioOutput2[i] = (1.0 - p.fader) * input.right + p.fader * output.right;
1489 
1490 		// Just faded out ?
1491 		if ((p.fader <= 0) && (sizePosition() > 1))
1492 		{
1493 			// Switch to new position data to fade in
1494 			popFrontPosition();
1495 
1496 			// Copy pads
1497 			for (int i = 0; i < NR_SLOTS; ++i)
1498 			{
1499 				for (int j = 0; j < NR_STEPS; ++j) slots[i].setPad (j, pages[pageNr].pads[i][j]);
1500 				slots[i].setSlotShape (pages[pageNr].shapes[i]);
1501 				slots[i].setSlotKeys (pages[pageNr].keys[i]);
1502 			}
1503 
1504 			scheduleInit = true;
1505 		}
1506 	}
1507 }
1508 
state_save(LV2_State_Store_Function store,LV2_State_Handle handle,uint32_t flags,const LV2_Feature * const * features)1509 LV2_State_Status BOops::state_save (LV2_State_Store_Function store, LV2_State_Handle handle, uint32_t flags,
1510 			const LV2_Feature* const* features)
1511 {
1512 	// Store sample path
1513 	if (sample && sample->path && (sample->path[0] != 0) && (globalControllers[SOURCE] == SOURCE_SAMPLE))
1514 	{
1515 		LV2_State_Map_Path* mapPath = NULL;
1516 #ifdef LV2_STATE__freePath
1517 		LV2_State_Free_Path* freePath = NULL;
1518 #endif
1519 
1520 		for (int i = 0; features[i]; ++i)
1521 		{
1522 			if (strcmp(features[i]->URI, LV2_STATE__mapPath) == 0)
1523 			{
1524 				mapPath = (LV2_State_Map_Path*) features[i]->data;
1525 				break;
1526 			}
1527 		}
1528 
1529 #ifdef LV2_STATE__freePath
1530 		for (int i = 0; features[i]; ++i)
1531 		{
1532 			if (strcmp(features[i]->URI, LV2_STATE__freePath) == 0)
1533 			{
1534 				freePath = (LV2_State_Free_Path*) features[i]->data;
1535 				break;
1536 			}
1537 		}
1538 #endif
1539 
1540 		if (mapPath)
1541 		{
1542 			char* abstrPath = mapPath->abstract_path(mapPath->handle, sample->path);
1543 
1544 			if (abstrPath)
1545 			{
1546 				fprintf(stderr, "BOops.lv2: Save abstr_path:%s\n", abstrPath);
1547 
1548 				store(handle, urids.bOops_samplePath, abstrPath, strlen (abstrPath) + 1, urids.atom_Path, LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
1549 				store(handle, urids.bOops_sampleStart, &sample->start, sizeof (sample->start), urids.atom_Long, LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
1550 				store(handle, urids.bOops_sampleEnd, &sample->end, sizeof (sample->end), urids.atom_Long, LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
1551 				store(handle, urids.bOops_sampleAmp, &sampleAmp, sizeof (sampleAmp), urids.atom_Float, LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
1552 				const int32_t sloop = int32_t (sample->loop);
1553 				store(handle, urids.bOops_sampleLoop, &sloop, sizeof (sloop), urids.atom_Bool, LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
1554 
1555 #ifdef LV2_STATE__freePath
1556 				if (freePath) freePath->free_path (freePath->handle, abstrPath);
1557 				else
1558 #endif
1559 				{
1560 					free (abstrPath);
1561 				}
1562 			}
1563 
1564 			else fprintf(stderr, "BOops.lv2: Can't generate abstr_path from %s\n", sample->path);
1565 		}
1566 		else
1567 		{
1568 			fprintf (stderr, "BOops.lv2: Feature map_path not available! Can't save sample!\n" );
1569 			return LV2_STATE_ERR_NO_FEATURE;
1570 		}
1571 	}
1572 
1573 	// Store transportGateKeys
1574 	{
1575 		// Create atom:Vector
1576 
1577 		AtomKeys atom;
1578 		int keysize = 0;
1579 		std::fill (atom.keys, atom.keys + NR_PIANO_KEYS, 0);
1580 		for (int i = 0; i < NR_PIANO_KEYS; ++i)
1581 		{
1582 			if (transportGateKeys[i])
1583 			{
1584 				atom.keys[keysize] = i;
1585 				++keysize;
1586 			}
1587 		}
1588 		atom.body.child_type = urids.atom_Int;
1589 		atom.body.child_size = sizeof(int);
1590 
1591 		store (handle, urids.bOops_transportGateKeys, &atom, keysize * sizeof (int) + sizeof(LV2_Atom_Vector_Body), urids.atom_Vector, LV2_STATE_IS_POD);
1592 	}
1593 
1594 	// Store pageNr
1595 	store (handle, urids.bOops_pageID, &pageNr, sizeof (int), urids.atom_Int, LV2_STATE_IS_POD);
1596 
1597 	// Store pageMax
1598 	store (handle, urids.bOops_pageMax, &pageMax, sizeof (int), urids.atom_Int, LV2_STATE_IS_POD);
1599 
1600 	// Store editor data
1601 	store (handle, urids.bOops_editorPage, &editorPage, sizeof (int), urids.atom_Int, LV2_STATE_IS_POD);
1602 	store (handle, urids.bOops_editorSlot, &editorSlot, sizeof (int), urids.atom_Int, LV2_STATE_IS_POD);
1603 
1604 	// Store page control properties
1605 	{
1606 		AtomPageControls atom;
1607 		for (int i = 0; i <= pageMax; ++i) atom.data[i] = pages[i].controls;
1608 		atom.body.child_type = urids.atom_Int;
1609 		atom.body.child_size = sizeof(int);
1610 
1611 		store (handle, urids.bOops_pageControls, &atom, (pageMax + 1) * sizeof (PageControls) + sizeof(LV2_Atom_Vector_Body), urids.atom_Vector, LV2_STATE_IS_POD);
1612 	}
1613 
1614 	// Store pads
1615 	{
1616 		char padDataString[0x8010] = "\nMatrix data:\n";
1617 
1618 		for (int pgNr = 0; pgNr <= pageMax; ++pgNr)
1619 		{
1620 			for (int slotNr = 0; slotNr < NR_SLOTS; ++slotNr)
1621 			{
1622 				if ((slots[slotNr].effect == FX_NONE) || (slots[slotNr].effect == FX_INVALID)) continue;
1623 
1624 				for (int stepNr = 0; stepNr < NR_STEPS; ++stepNr)
1625 				{
1626 					Pad p = pages[pgNr].pads[slotNr][stepNr];
1627 					if ((p.gate > 0) && (p.size > 0) && (p.mix > 0))
1628 					{
1629 						char valueString[64];
1630 						snprintf (valueString, 62, "pg:%d; sl:%d; st:%d; gt:%1.3f; sz:%d; mx:%1.3f", pgNr, slotNr, stepNr, p.gate, int (p.size), p.mix);
1631 						if ((slotNr < NR_SLOTS - 1) || (stepNr < NR_STEPS)) strcat (valueString, ";\n");
1632 						else strcat(valueString, "\n");
1633 						strcat (padDataString, valueString);
1634 					}
1635 
1636 				}
1637 			}
1638 		}
1639 		store (handle, urids.bOops_statePad, padDataString, strlen (padDataString) + 1, urids.atom_String, LV2_STATE_IS_POD);
1640 	}
1641 
1642 	// Store Keys
1643 	{
1644 		char keysDataString[8192] = "";
1645 
1646 		for (int pageNr = 0; pageNr <= pageMax; ++pageNr)
1647 		{
1648 			strcat (keysDataString, "\nKeys data slots page ");
1649 			char pageString[16];
1650 			snprintf (pageString, 12, "%d", pageNr);
1651 			strcat (keysDataString, pageString);
1652 			strcat (keysDataString, ":\n");
1653 			for (int slotNr = 0; slotNr < NR_SLOTS; ++slotNr)
1654 			{
1655 				if (pages[pageNr].keys[slotNr][NR_PIANO_KEYS])
1656 				{
1657 					char slotString[16];
1658 					snprintf (slotString, 12, "slo: %d", slotNr);
1659 					char keysString[40];
1660 					bool2hstr<std::array<bool, NR_PIANO_KEYS + 1>> (pages[pageNr].keys[slotNr], keysString);
1661 
1662 					strcat (keysDataString, slotString);
1663 					strcat (keysDataString, " key: 0x");
1664 					strcat (keysDataString, keysString);
1665 					strcat (keysDataString, ";\n");
1666 				}
1667 			}
1668 		}
1669 
1670 		store (handle, urids.bOops_keysData, keysDataString, strlen (keysDataString) + 1, urids.atom_String, LV2_STATE_IS_POD);
1671 	}
1672 
1673 	// Store shapes
1674 	{
1675 		char shapesDataString[0x110000] = "";
1676 
1677 		// Slot shapes
1678 		for (int pageNr = 0; pageNr <= pageMax; ++pageNr)
1679 		{
1680 			strcat (shapesDataString, "\nShape data slots page ");
1681 			char pageString[16];
1682 			snprintf (pageString, 12, "%d", pageNr);
1683 			strcat (shapesDataString, pageString);
1684 			strcat (shapesDataString, ":\n");
1685 			for (int slotNr = 0; slotNr < NR_SLOTS; ++slotNr)
1686 			{
1687 				if (pages[pageNr].shapes[slotNr] != Shape<SHAPE_MAXNODES>())
1688 				{
1689 					for (unsigned int nodeNr = 0; nodeNr < pages[pageNr].shapes[slotNr].size(); ++nodeNr)
1690 					{
1691 						char valueString[160];
1692 						Node node = pages[pageNr].shapes[slotNr].getNode (nodeNr);
1693 						snprintf
1694 						(
1695 							valueString,
1696 							126,
1697 							"slo:%d; typ:%d; ptx:%f; pty:%f; h1x:%f; h1y:%f; h2x:%f; h2y:%f",
1698 							slotNr,
1699 							int (node.nodeType),
1700 							node.point.x,
1701 							node.point.y,
1702 							node.handle1.x,
1703 							node.handle1.y,
1704 							node.handle2.x,
1705 							node.handle2.y
1706 						);
1707 						if ((slotNr < NR_SLOTS - 1) || (nodeNr < pages[pageNr].shapes[slotNr].size ())) strcat (valueString, ";\n");
1708 						else strcat(valueString, "\n");
1709 						strcat (shapesDataString, valueString);
1710 					}
1711 				}
1712 			}
1713 			strcat(shapesDataString, "\n");
1714 		}
1715 
1716 
1717 		// Param shapes
1718 		strcat (shapesDataString, "\nShape data param:\n");
1719 		for (int slotNr = 0; slotNr < NR_SLOTS; ++slotNr)
1720 		{
1721 			if (!slots[slotNr].shape.isDefault())
1722 			{
1723 				for (unsigned int nodeNr = 0; nodeNr < slots[slotNr].shape.size (); ++nodeNr)
1724 				{
1725 					char valueString[160];
1726 					Node node = slots[slotNr].shape.getNode (nodeNr);
1727 					snprintf
1728 					(
1729 						valueString,
1730 						126,
1731 						"slo:%d; typ:%d; ptx:%f; pty:%f; h1x:%f; h1y:%f; h2x:%f; h2y:%f",
1732 						slotNr,
1733 						int (node.nodeType),
1734 						node.point.x,
1735 						node.point.y,
1736 						node.handle1.x,
1737 						node.handle1.y,
1738 						node.handle2.x,
1739 						node.handle2.y
1740 					);
1741 					if ((slotNr < NR_SLOTS - 1) || (nodeNr < slots[slotNr].shape.size ())) strcat (valueString, ";\n");
1742 					else strcat(valueString, "\n");
1743 					strcat (shapesDataString, valueString);
1744 				}
1745 			}
1746 		}
1747 		store (handle, urids.bOops_shapeData, shapesDataString, strlen (shapesDataString) + 1, urids.atom_String, LV2_STATE_IS_POD);
1748 	}
1749 
1750 	return LV2_STATE_SUCCESS;
1751 }
1752 
state_restore(LV2_State_Retrieve_Function retrieve,LV2_State_Handle handle,uint32_t flags,const LV2_Feature * const * features)1753 LV2_State_Status BOops::state_restore (LV2_State_Retrieve_Function retrieve, LV2_State_Handle handle, uint32_t flags,
1754 			const LV2_Feature* const* features)
1755 {
1756 	// Get host features
1757 	LV2_Worker_Schedule* schedule = nullptr;
1758 	LV2_State_Map_Path* mapPath = nullptr;
1759 #ifdef LV2_STATE__freePath
1760 	LV2_State_Free_Path* freePath = nullptr;
1761 #endif
1762 
1763 	for (int i = 0; features[i]; ++i)
1764 	{
1765 		if (strcmp(features[i]->URI, LV2_STATE__mapPath) == 0)
1766 		{
1767 			mapPath = (LV2_State_Map_Path*) features[i]->data;
1768 			break;
1769 		}
1770 	}
1771 
1772 	for (int i = 0; features[i]; ++i)
1773 	{
1774 		if (strcmp(features[i]->URI, LV2_WORKER__schedule) == 0)
1775 		{
1776 			schedule = (LV2_Worker_Schedule*) features[i]->data;
1777 			break;
1778 		}
1779 	}
1780 
1781 #ifdef LV2_STATE__freePath
1782 	for (int i = 0; features[i]; ++i)
1783 	{
1784 		if (strcmp(features[i]->URI, LV2_STATE__freePath) == 0)
1785 		{
1786 			freePath = (LV2_State_Free_Path*) features[i]->data;
1787 			break;
1788 		}
1789 	}
1790 #endif
1791 
1792 	if (!mapPath)
1793 	{
1794 		fprintf (stderr, "BOops.lv2: Feature map_path not available! Can't restore sample!\n");
1795 		return LV2_STATE_ERR_NO_FEATURE;
1796 	}
1797 
1798 	size_t   size;
1799 	uint32_t type;
1800 	uint32_t valflags;
1801 
1802 	// Retireve sample data
1803 	char samplePath[PATH_MAX] = {0};
1804 	int64_t sampleStart = 0;
1805 	int64_t sampleEnd = 0;
1806 	float sampleAmp = 1.0;
1807 	int32_t sampleLoop = false;
1808 
1809 	const void* pathData = retrieve (handle, urids.bOops_samplePath, &size, &type, &valflags);
1810 	if (pathData)
1811 	{
1812 		char* absPath  = mapPath->absolute_path (mapPath->handle, (char*)pathData);
1813 	        if (absPath)
1814 		{
1815 			if (strlen (absPath) < PATH_MAX) strcpy (samplePath, absPath);
1816 			else
1817 			{
1818 				fprintf (stderr, "BOops.lv2: Sample path too long.\n");
1819 				message.setMessage (CANT_OPEN_SAMPLE);
1820 			}
1821 
1822 			fprintf(stderr, "BOops.lv2: Restore abs_path:%s\n", absPath);
1823 
1824 #ifdef LV2_STATE__freePath
1825 			if (freePath) freePath->free_path (freePath->handle, absPath);
1826 			else
1827 #endif
1828 			{
1829 				free (absPath);
1830 			}
1831 	        }
1832 	}
1833 
1834 	const void* startData = retrieve (handle, urids.bOops_sampleStart, &size, &type, &valflags);
1835         if (startData && (type == urids.atom_Long)) sampleStart = *(int64_t*)startData;
1836 	const void* endData = retrieve (handle, urids.bOops_sampleEnd, &size, &type, &valflags);
1837         if (endData && (type == urids.atom_Long)) sampleEnd = *(int64_t*)endData;
1838 	const void* ampData = retrieve (handle, urids.bOops_sampleAmp, &size, &type, &valflags);
1839         if (ampData && (type == urids.atom_Float)) sampleAmp = *(float*)ampData;
1840 	const void* loopData = retrieve (handle, urids.bOops_sampleLoop, &size, &type, &valflags);
1841         if (loopData && (type == urids.atom_Bool)) sampleLoop = *(int32_t*)loopData;
1842 
1843 	if (activated && schedule)
1844 	{
1845 		LV2_Atom_Forge forge;
1846 		lv2_atom_forge_init(&forge, map);
1847 		uint8_t buf[1200];
1848 		lv2_atom_forge_set_buffer(&forge, buf, sizeof(buf));
1849 		LV2_Atom_Forge_Frame frame;
1850 		LV2_Atom* msg = (LV2_Atom*)forgeSamplePath (&forge, &frame, samplePath, sampleStart, sampleEnd, sampleAmp, sampleLoop);
1851 		lv2_atom_forge_pop(&forge, &frame);
1852 		if (msg) schedule->schedule_work(schedule->handle, lv2_atom_total_size(msg), msg);
1853 	}
1854 
1855 	else
1856 	{
1857 		// Free old sample
1858 		if (sample)
1859 		{
1860 			delete sample;
1861 			sample = nullptr;
1862 			sampleAmp = 1.0;
1863 		}
1864 
1865 		// Load new sample
1866 		message.deleteMessage (CANT_OPEN_SAMPLE);
1867 		try {sample = new Sample (samplePath);}
1868 		catch (std::bad_alloc &ba)
1869 		{
1870 			fprintf (stderr, "BOops.lv2: Can't allocate enoug memory to open sample file.\n");
1871 			message.setMessage (CANT_OPEN_SAMPLE);
1872 		}
1873 		catch (std::invalid_argument &ia)
1874 		{
1875 			fprintf (stderr, "%s\n", ia.what());
1876 			message.setMessage (CANT_OPEN_SAMPLE);
1877 		}
1878 
1879 		// Set new sample properties
1880 		if  (sample)
1881 		{
1882 			sample->start = sampleStart;
1883 			sample->end = sampleEnd;
1884 			sample->loop = bool (sampleLoop);
1885 			this->sampleAmp = sampleAmp;
1886 		}
1887 
1888 		scheduleNotifySamplePathToGui = true;
1889 	}
1890 
1891 	// Retrieve transportGateKeys
1892 	const void* transportGateKeysData = retrieve(handle, urids.bOops_transportGateKeys, &size, &type, &valflags);
1893 	if (transportGateKeysData && (type == urids.atom_Vector))
1894 	{
1895 		const AtomKeys* atom = (const AtomKeys*) transportGateKeysData;
1896 		const int nr = LIMIT ((size - sizeof (LV2_Atom_Vector_Body)) / sizeof(int), 0, NR_PIANO_KEYS);
1897 
1898 		std::fill (transportGateKeys, transportGateKeys + NR_PIANO_KEYS, false);
1899 		for (int i = 0; i < nr; ++i)
1900 		{
1901 			const int keyNr = atom->keys[i];
1902 			if ((keyNr >= 0) && (keyNr < NR_PIANO_KEYS)) transportGateKeys[keyNr] = true;
1903 		}
1904 		scheduleNotifyTransportGateKeys = true;
1905         }
1906 
1907 	// Retrieve pageNr
1908 	pageNr = 0;
1909 	const void* pageNrData = retrieve(handle, urids.bOops_pageID, &size, &type, &valflags);
1910 	if (pageNrData && (type == urids.atom_Int))
1911 	{
1912 		const int pgNr = LIMIT (*(const int*)pageNrData, 0, NR_PAGES - 1);
1913 
1914 		if (pgNr != pageNr)
1915 		{
1916 			Position np = backPosition();
1917 			pushBackPosition (np);
1918 		}
1919 
1920 		pageNr = pgNr;
1921 		if (pageMax < pageNr) pageMax = pageNr;
1922         }
1923 
1924 	// Retrieve pageMax
1925 	pageMax = 0;
1926 	const void* pageMaxData = retrieve(handle, urids.bOops_pageMax, &size, &type, &valflags);
1927 	if (pageMaxData && (type == urids.atom_Int))
1928 	{
1929 		pageMax = LIMIT (*(const int*)pageMaxData, 0, NR_PAGES - 1);
1930 
1931 		if (pageNr > pageMax)
1932 		{
1933 			// Limit pageNr to pageMax
1934 			pageNr = pageMax;
1935 
1936 			// Schedule fader for page change
1937 			Position np = backPosition();
1938 			pushBackPosition (np);
1939 		}
1940         }
1941 
1942 	// Retrieve editor data
1943 	editorPage = 0;
1944 	editorSlot = 0;
1945 
1946 	const void* editorPageData = retrieve(handle, urids.bOops_editorPage, &size, &type, &valflags);
1947 	if (editorPageData && (type == urids.atom_Int)) editorPage = LIMIT (*(const int*)editorPageData, 0, NR_PAGES - 1);
1948 
1949 	const void* editorSlotData = retrieve(handle, urids.bOops_editorSlot, &size, &type, &valflags);
1950 	if (editorSlotData && (type == urids.atom_Int)) editorSlot = LIMIT (*(const int*)editorSlotData, 0, NR_SLOTS - 1);
1951 
1952 	scheduleNotifyStatus = true;
1953 
1954 	// Retrieve page control properties
1955 	const void* pageControlsData = retrieve(handle, urids.bOops_pageControls, &size, &type, &valflags);
1956 	if (pageControlsData && (type == urids.atom_Vector))
1957 	{
1958 		const AtomPageControls* atom = (const AtomPageControls*) pageControlsData;
1959 		const int nr = LIMIT ((size - sizeof (LV2_Atom_Vector_Body)) / sizeof(PageControls), 0, NR_PAGES - 1);
1960 
1961 		for (Page& page : pages) page.controls = {0, 0, 0, 0};
1962 		for (int i = 0; i < nr; ++i) pages[i].controls = atom->data[i];
1963 		for (int i = 0; i < NR_PAGES; ++i) scheduleNotifyPageControls[i] = true;
1964         }
1965 
1966 	// Retrieve pattern
1967 	const void* padData = retrieve(handle, urids.bOops_statePad, &size, &type, &valflags);
1968 	if (padData && (type == urids.atom_String))
1969 	{
1970 		// Clear pads
1971 		for (int pg = 0; pg < NR_PAGES; ++pg)
1972 		{
1973 			for (std::array<Pad, NR_STEPS>& row : pages[pg].pads) row.fill (Pad());
1974 		}
1975 
1976 		// Also clear pads stored in slots
1977 		for (Slot& s : slots)
1978 		{
1979 			for (unsigned int i = 0; i < NR_STEPS; ++i) s.setPad (i, Pad());
1980 		}
1981 
1982 		std::string padDataString = (char*) padData;
1983 		const std::string keywords[6] = {"pg:", "sl:", "st:", "gt:", "sz:", "mx:"};
1984 
1985 		// Restore pads
1986 		// Parse retrieved data
1987 		while (!padDataString.empty())
1988 		{
1989 			// Look for optional "pg:"
1990 			int pgNr = 0;
1991 			size_t strPos = padDataString.find (keywords[0]);
1992 			size_t nextPos = 0;
1993 			if (strPos != std::string::npos)
1994 			{
1995 				if (strPos + 3 > padDataString.length()) break;	// Nothing more after pg => end
1996 				padDataString.erase (0, strPos + 3);
1997 				try {pgNr = BUtilities::stof (padDataString, &nextPos);}
1998 				catch  (const std::exception& e)
1999 				{
2000 					fprintf (stderr, "BOops.lv2: Restore pad state incomplete. Can't parse page nr from \"%s...\"\n", padDataString.substr (0, 63).c_str());
2001 					break;
2002 				}
2003 
2004 				if (nextPos > 0) padDataString.erase (0, nextPos);
2005 				if ((pgNr < 0) || (pgNr >= NR_PAGES))
2006 				{
2007 					fprintf (stderr, "BOops.lv2: Restore pad state incomplete. Invalid page nr %i.\n", pgNr);
2008 					break;
2009 				}
2010 			}
2011 
2012 			// Look for mandatory "sl:"
2013 			int slotNr = -1;
2014 			strPos = padDataString.find (keywords[1]);
2015 			nextPos = 0;
2016 			if (strPos == std::string::npos) break;	// No "sl:" found => end
2017 			if (strPos + 3 > padDataString.length()) break;	// Nothing more after sl => end
2018 			padDataString.erase (0, strPos + 3);
2019 			try {slotNr = BUtilities::stof (padDataString, &nextPos);}
2020 			catch  (const std::exception& e)
2021 			{
2022 				fprintf (stderr, "BOops.lv2: Restore pad state incomplete. Can't parse slot nr from \"%s...\"\n", padDataString.substr (0, 63).c_str());
2023 				break;
2024 			}
2025 
2026 			if (nextPos > 0) padDataString.erase (0, nextPos);
2027 			if ((slotNr < 0) || (slotNr >= NR_SLOTS))
2028 			{
2029 				fprintf (stderr, "BOops.lv2: Restore pad state incomplete. Invalid slot nr %i.\n", slotNr);
2030 				break;
2031 			}
2032 
2033 			// Look for mandatory "st:"
2034 			int stepNr = -1;
2035 			strPos = padDataString.find (keywords[2]);
2036 			nextPos = 0;
2037 			if (strPos == std::string::npos) break;	// No "st:" found => end
2038 			if (strPos + 3 > padDataString.length()) break;	// Nothing more after st => end
2039 			padDataString.erase (0, strPos + 3);
2040 			try {stepNr = BUtilities::stof (padDataString, &nextPos);}
2041 			catch  (const std::exception& e)
2042 			{
2043 				fprintf (stderr, "BOops.lv2: Restore pad state incomplete. Can't parse step nr from \"%s...\"\n", padDataString.substr (0, 63).c_str());
2044 				break;
2045 			}
2046 
2047 			if (nextPos > 0) padDataString.erase (0, nextPos);
2048 			if ((stepNr < 0) || (stepNr >= NR_STEPS))
2049 			{
2050 				fprintf (stderr, "BOops.lv2: Restore pad state incomplete. Invalid step nr %i.\n", slotNr);
2051 				break;
2052 			}
2053 
2054 			// Look for pad data
2055 			for (int i = 3; i < 6; ++i)
2056 			{
2057 				nextPos = 0;
2058 				strPos = padDataString.find (keywords[i]);
2059 				if (strPos == std::string::npos) continue;	// Keyword not found => next keyword
2060 				if (strPos + 3 >= padDataString.length())	// Nothing more after keyword => end
2061 				{
2062 					padDataString ="";
2063 					break;
2064 				}
2065 				if (strPos > 0) padDataString.erase (0, strPos + 3);
2066 				float val;
2067 				try {val = BUtilities::stof (padDataString, &nextPos);}
2068 				catch  (const std::exception& e)
2069 				{
2070 					fprintf (stderr, "BOops.lv2: Restore pad state incomplete. Can't parse %s from \"%s...\"\n",
2071 							 keywords[i].substr(0,2).c_str(), padDataString.substr (0, 63).c_str());
2072 					break;
2073 				}
2074 
2075 				if (nextPos > 0) padDataString.erase (0, nextPos);
2076 
2077 				Pad& p = pages[pgNr].pads[slotNr][stepNr];
2078 				switch (i)
2079 				{
2080 					case 3:	p.gate = LIMIT (val, 0, 1);
2081 						break;
2082 
2083 					case 4:	p.size = LIMIT (val, 1, NR_STEPS - stepNr);
2084 						break;
2085 
2086 					case 5:	p.mix = LIMIT (val, 0, 1);
2087 						break;
2088 
2089 					default:break;
2090 				}
2091 				if (pageNr == pgNr) slots[slotNr].setPad (stepNr, p);
2092 			}
2093 		}
2094 
2095 		// Schedule notify GUI
2096 		scheduleNotifyAllSlots = true;
2097 	}
2098 
2099 	// Retrieve keys
2100 	for (Page& p : pages) for (std::array<bool, NR_PIANO_KEYS + 1>& k : p.keys) k.fill (false);
2101 	const void* keysData = retrieve(handle, urids.bOops_keysData, &size, &type, &valflags);
2102 	if (keysData && (type == urids.atom_String))
2103 	{
2104 		// Parse retrieved data
2105 		std::string s = (char*) keysData;
2106 
2107 		while (!s.empty())
2108 		{
2109 			// Check for slots page
2110 			size_t pos = s.find ("Keys data slots page");
2111 			if ((pos == std::string::npos) || (pos + 20 >= s.length())) break;
2112 			s.erase (0, pos + 20);
2113 
2114 			// Parse page number
2115 			int pageNr = 0;
2116 			try {pageNr = BUtilities::stof (s, &pos);}
2117 			catch  (const std::exception& e)
2118 			{
2119 				fprintf (stderr, "BOops.lv2: Restore keys state incomplete. Can't parse page number from \"%s...\"", s.substr (0, 63).c_str());
2120 				break;
2121 			}
2122 
2123 			if (pos > 0) s.erase (0, pos);
2124 			if ((pageNr < 0) || (pageNr >= NR_PAGES))
2125 			{
2126 				fprintf (stderr, "BOops.lv2: Restore keys state incomplete. Invalid matrix data block loaded for page %i.\n", pageNr);
2127 				break;
2128 			}
2129 
2130 			while (!s.empty())
2131 			{
2132 				pos = s.find ("slo:");
2133 				if (pos == std::string::npos) break;
2134 				if (pos + 4 >= s.length())
2135 				{
2136 						fprintf (stderr, "BOops.lv2: Restore keys state incomplete. Can't parse slot number from \"%s...\"", s.substr (0, 63).c_str());
2137 						break;
2138 				}
2139 
2140 				s.erase (0, pos + 4);
2141 
2142 				int sl;
2143 				try {sl = BUtilities::stof (s, &pos);}
2144 				catch  (const std::exception& e)
2145 				{
2146 					fprintf (stderr, "BOops.lv2: Restore keys state incomplete. Can't parse slot number from \"%s...\"", s.substr (0, 63).c_str());
2147 					break;
2148 				}
2149 
2150 				if (pos > 0) s.erase (0, pos);
2151 				if ((sl < 0) || (sl >= NR_SLOTS))
2152 				{
2153 					fprintf (stderr, "BOops.lv2: Restore keys state incomplete. Invalid matrix data block loaded for slot %i.\n", sl);
2154 					break;
2155 				}
2156 
2157 				size_t kPos = s.find ("key: 0x");
2158 				size_t ePos = s.find (";");
2159 				if ((kPos == std::string::npos) || (kPos + 7 >= s.length()) || (kPos == std::string::npos) || (kPos + 47 < ePos))
2160 				{
2161 					fprintf (stderr, "BOops.lv2: Restore keys state incomplete. Invalid matrix data block loaded for slot %i.\n", sl);
2162 					break;
2163 				}
2164 
2165 				hstr2bool<std::array<bool, NR_PIANO_KEYS + 1>> (s.substr (kPos + 7, ePos - kPos - 7).c_str(), pages[pageNr].keys[sl]);
2166 				s.erase (0, ePos + 1);
2167 			}
2168 		}
2169 
2170 		scheduleNotifyAllSlots = true;
2171 	}
2172 	for (int i = 0; i < NR_SLOTS; ++i) slots[i].setSlotKeys (pages[pageNr].keys[i]);
2173 
2174 	// Retrieve shapes
2175 	for (Page& p : pages) for (Shape<SHAPE_MAXNODES>& s : p.shapes) s = Shape<SHAPE_MAXNODES>();
2176 	const void* shapesData = retrieve(handle, urids.bOops_shapeData, &size, &type, &valflags);
2177 	if (shapesData && (type == urids.atom_String))
2178 	{
2179 		std::array<Shape<SHAPE_MAXNODES>, NR_SLOTS> paramShapes;
2180 		std::array<std::array<Shape<SHAPE_MAXNODES>, NR_SLOTS>, NR_PAGES> pageShapes;
2181 		for (int sl = 0; sl < NR_SLOTS; ++sl) paramShapes[sl].clearShape();
2182 		for (int pg = 0; pg < NR_PAGES; ++pg)
2183 		{
2184 			for (int sl = 0; sl < NR_SLOTS; ++sl) pageShapes[pg][sl].clearShape();
2185 		}
2186 
2187 		// Parse retrieved data
2188 		std::string shapesDataString = (char*) shapesData;
2189 		const std::string keywords[8] = {"slo:", "typ:", "ptx:", "pty:", "h1x:", "h1y:", "h2x:", "h2y:"};
2190 
2191 		size_t startPos = shapesDataString.find ("Shape data");
2192 		while (startPos != std::string::npos)
2193 		{
2194 			shapesDataString.erase (0, startPos + 10);
2195 
2196 			size_t nextPos = shapesDataString.find ("Shape data");
2197 			std::string s = shapesDataString.substr (0, nextPos);
2198 
2199 			// Check for slots page
2200 			size_t slotspagePos = s.find ("slots page");
2201 			if ((slotspagePos != std::string::npos) && (slotspagePos < 10))
2202 			{
2203 				s.erase (0, slotspagePos + 10);
2204 
2205 				// Parse page number
2206 				size_t np;
2207 				int pageNr = 0;
2208 				try {pageNr = BUtilities::stof (s, &np);}
2209 				catch  (const std::exception& e)
2210 				{
2211 					fprintf (stderr, "BOops.lv2: Restore shape state incomplete. Can't parse page number from \"%s...\"", s.substr (0, 63).c_str());
2212 					break;
2213 				}
2214 
2215 				if (np > 0) s.erase (0, np);
2216 				if ((pageNr < 0) || (pageNr >= NR_PAGES))
2217 				{
2218 					fprintf (stderr, "BOops.lv2: Restore shape state incomplete. Invalid matrix data block loaded for page %i.\n", pageNr);
2219 					break;
2220 				}
2221 
2222 				to_shapes (s, pageShapes[pageNr]);
2223 				for (int pg = 0; pg < NR_PAGES; ++pg)
2224 				{
2225 					for (int sl = 0; sl < NR_SLOTS; ++sl)
2226 					{
2227 						if (pageShapes[pg][sl] != Shape<SHAPE_MAXNODES>())
2228 						{
2229 							if (!pageShapes[pg][sl].validateShape ()) pageShapes[pg][sl].setDefaultShape ();
2230 						}
2231 						pages[pg].shapes[sl] = pageShapes[pg][sl];
2232 					}
2233 				}
2234 				scheduleNotifyAllSlots = true;
2235 			}
2236 
2237 			// Param shapes
2238 			else
2239 			{
2240 				to_shapes (s, paramShapes);
2241 				for (int sl = 0; sl < NR_SLOTS; ++sl)
2242 				{
2243 					if (paramShapes[sl].size () < 2) paramShapes[sl].setDefaultShape ();
2244 					else
2245 					{
2246 						if (!paramShapes[sl].validateShape ()) paramShapes[sl].setDefaultShape ();
2247 					}
2248 					slots[sl].shape = paramShapes[sl];
2249 					scheduleNotifyShape[sl] = true;
2250 				}
2251 			}
2252 
2253 			startPos = nextPos;
2254 		}
2255 	}
2256 	for (int i = 0; i < NR_SLOTS; ++i) slots[i].setSlotShape (pages[pageNr].shapes[i]);
2257 
2258 	return LV2_STATE_SUCCESS;
2259 }
2260 
work(LV2_Worker_Respond_Function respond,LV2_Worker_Respond_Handle handle,uint32_t size,const void * data)2261 LV2_Worker_Status BOops::work (LV2_Worker_Respond_Function respond, LV2_Worker_Respond_Handle handle, uint32_t size, const void* data)
2262 {
2263 	const LV2_Atom* atom = (const LV2_Atom*)data;
2264 	if (!atom) return LV2_WORKER_ERR_UNKNOWN;
2265 
2266 	// Free old buffers
2267         else if (atom->type == urids.bOops_freeBuffers)
2268 	{
2269 		const Atom_BufferList* bAtom = (const Atom_BufferList*) data;
2270 		for (int i = 0; i < NR_SLOTS; ++i)
2271 		{
2272 			if (bAtom->buffers[i]) delete (bAtom->buffers[i]);
2273 		}
2274         }
2275 
2276 	// Free old Fx
2277         else if (atom->type == urids.bOops_freeFx)
2278 	{
2279 		const Atom_Fx* fAtom = (const Atom_Fx*) data;
2280 		if (fAtom->fx) delete (fAtom->fx);
2281         }
2282 
2283 	// Free old sample
2284         else if (atom->type == urids.bOops_sampleFreeEvent)
2285 	{
2286 		const AtomSample* sAtom = (AtomSample*) atom;
2287 		if (sAtom->sample) delete sAtom->sample;
2288         }
2289 
2290 	// Load sample
2291 	else if ((atom->type == urids.atom_Object) && (((LV2_Atom_Object*)atom)->body.otype == urids.bOops_samplePathEvent))
2292 	{
2293                 const LV2_Atom_Object* obj = (const LV2_Atom_Object*)data;
2294 
2295 		const LV2_Atom* oPath = NULL, *oStart = NULL, *oEnd = NULL, *oAmp = NULL, *oLoop = NULL;
2296 		lv2_atom_object_get
2297 		(
2298 			obj,
2299 			urids.bOops_samplePath, &oPath,
2300 			urids.bOops_sampleStart, &oStart,
2301 			urids.bOops_sampleEnd, &oEnd,
2302 			urids.bOops_sampleAmp, &oAmp,
2303 			urids.bOops_sampleLoop, &oLoop,
2304 			0
2305 		);
2306 
2307 		// New sample
2308 		if (oPath && (oPath->type == urids.atom_Path))
2309 		{
2310 			message.deleteMessage (CANT_OPEN_SAMPLE);
2311 			Sample* s = nullptr;
2312 
2313 			const char* pathName = (const char*)LV2_ATOM_BODY_CONST(oPath);
2314 			if (pathName && (pathName[0] != 0))
2315 			{
2316 				try {s = new Sample (pathName);}
2317 				catch (std::bad_alloc &ba)
2318 				{
2319 					fprintf (stderr, "BOops.lv2: Can't allocate enough memory to open sample file.\n");
2320 					message.setMessage (CANT_OPEN_SAMPLE);
2321 					return LV2_WORKER_ERR_NO_SPACE;
2322 				}
2323 				catch (std::invalid_argument &ia)
2324 				{
2325 					fprintf (stderr, "%s\n", ia.what());
2326 					message.setMessage (CANT_OPEN_SAMPLE);
2327 					return LV2_WORKER_ERR_UNKNOWN;
2328 				}
2329 			}
2330 
2331 			AtomSample sAtom;
2332 			sAtom.atom = {sizeof (s), urids.bOops_installSample};
2333 			sAtom.sample = s;
2334 			sAtom.start = (oStart && (oStart->type == urids.atom_Long) && s ? ((LV2_Atom_Long*)oStart)->body : 0);
2335 			sAtom.end = (s ? (oEnd && (oEnd->type == urids.atom_Long) ? ((LV2_Atom_Long*)oEnd)->body : s->info.frames) : 0);
2336 			sAtom.amp = (oAmp && (oAmp->type == urids.atom_Float) ? ((LV2_Atom_Float*)oAmp)->body : 1.0f);
2337 			sAtom.loop = (oLoop && (oLoop->type == urids.atom_Bool && s) ? ((LV2_Atom_Bool*)oLoop)->body : 0);
2338 			respond (handle, sizeof(sAtom), &sAtom);
2339 		}
2340 
2341 		else return LV2_WORKER_ERR_UNKNOWN;
2342         }
2343 
2344 	// Allocate new buffers
2345 	else if (atom->type == urids.bOops_allocateBuffers)
2346 	{
2347 		//Required buffer size
2348 		double fpst = getFramesPerStep (backPosition().transport);
2349 		size_t bSize = slots[0].buffer->size();
2350 
2351 		if ((bSize < globalControllers[STEPS] * fpst) || (bSize > 2.0 * globalControllers[STEPS] * fpst))
2352 		{
2353 			Atom_BufferList bAtom;
2354 			bAtom.atom = {sizeof (bAtom.buffers), urids.bOops_installBuffers};
2355 			size_t nSize = 1.5 * globalControllers[STEPS] * fpst;
2356 
2357 			for (int i = 0; i < NR_SLOTS; ++i)
2358 			{
2359 				try
2360 				{
2361 					RingBuffer<Stereo>* b = new RingBuffer<Stereo> (*slots[i].buffer);
2362 					bAtom.buffers[i] = b;
2363 					bAtom.buffers[i]->resize (nSize);
2364 				}
2365 		                catch (std::bad_alloc& ba)
2366 				{
2367 					fprintf (stderr, "BOops.lv2: Can't allocate enough memory to resize audio buffers.\n");
2368 					//message.setMessage (MEMORY_ERR);
2369 					return LV2_WORKER_ERR_NO_SPACE;
2370 				}
2371 			}
2372 
2373 			respond (handle, sizeof (bAtom) , &bAtom);
2374 		}
2375 
2376 		// Resize not needed
2377 		else scheduleResizeBuffers = false;
2378 	}
2379 
2380 	else if (atom->type == urids.bOops_allocateFx)
2381 	{
2382 		const LV2_Atom_Int* iAtom = (const LV2_Atom_Int*)data;
2383 		int slotNr = iAtom->body;
2384 
2385 		BOopsEffectsIndex effect = (BOopsEffectsIndex) *new_controllers[SLOTS + slotNr * (SLOTS_PARAMS + NR_PARAMS)];
2386 		Fx* fx = slots[slotNr].newFx (effect);
2387 		Atom_Fx fAtom = {{sizeof (int) + sizeof (BOopsEffectsIndex) + sizeof (Fx*), urids.bOops_installFx}, slotNr, effect, fx};
2388 		respond (handle, sizeof (fAtom) , &fAtom);
2389 	}
2390 
2391 	else return LV2_WORKER_ERR_UNKNOWN;
2392 
2393 	return LV2_WORKER_SUCCESS;
2394 }
2395 
work_response(uint32_t size,const void * data)2396 LV2_Worker_Status BOops::work_response (uint32_t size, const void* data)
2397 {
2398 	const LV2_Atom* atom = (const LV2_Atom*)data;
2399 	if (!atom) return LV2_WORKER_ERR_UNKNOWN;
2400 
2401 	// Install slot audio buffers
2402 	if (atom->type == urids.bOops_installBuffers)
2403 	{
2404 		// Schedule worker to free old buffers
2405 		Atom_BufferList bAtom;
2406 		bAtom.atom = {sizeof (bAtom.buffers), urids.bOops_freeBuffers};
2407 		for (int i = 0; i < NR_SLOTS; ++i) bAtom.buffers[i] = slots[i].buffer;
2408 		workerSchedule->schedule_work (workerSchedule->handle, sizeof (bAtom), &bAtom);
2409 
2410 		// Install new buffer
2411 		const Atom_BufferList* nAtom = (const Atom_BufferList*) data;
2412 		for (int i = 0; i < NR_SLOTS; ++i) slots[i].buffer = nAtom->buffers[i];
2413 		scheduleResizeBuffers = false;
2414 	}
2415 
2416 	// Install Fx
2417 	else if (atom->type == urids.bOops_installFx)
2418 	{
2419 		const Atom_Fx* nAtom = (const Atom_Fx*) data;
2420 
2421 		// Schedule worker to free old Fx
2422 		Atom_Fx fAtom;
2423 		fAtom = {{sizeof (int) + sizeof (BOopsEffectsIndex) + sizeof (Fx*), urids.bOops_freeFx}, nAtom->index, slots[nAtom->index].effect, slots[nAtom->index].fx};
2424 		workerSchedule->schedule_work (workerSchedule->handle, sizeof (fAtom), &fAtom);
2425 
2426 		// Install new Fx
2427 		slots[nAtom->index].fx = nAtom->fx;
2428 		slots[nAtom->index].effect = BOopsEffectsIndex (nAtom->effect);
2429 		scheduleSetFx[nAtom->index] = false;
2430 	}
2431 
2432 	// Install sample
2433 	else if (atom->type == urids.bOops_installSample)
2434 	{
2435 		const AtomSample* nAtom = (const AtomSample*)data;
2436 		// Schedule worker to free old sample
2437 		AtomSample sAtom = {{sizeof (Sample*), urids.bOops_sampleFreeEvent}, sample};
2438 		workerSchedule->schedule_work (workerSchedule->handle, sizeof (sAtom), &sAtom);
2439 
2440 		// Install new sample from data
2441 		sample = nAtom->sample;
2442 		if (sample)
2443 		{
2444 			sample->start = LIMIT (nAtom->start, 0, sample->info.frames - 1);
2445 			sample->end = LIMIT (nAtom->end, sample->start, sample->info.frames);
2446 			sampleAmp = LIMIT (nAtom->amp, 0.0f, 1.0f);
2447 			sample->loop = bool (nAtom->loop);
2448 		}
2449 		scheduleNotifySamplePathToGui = true;
2450 		scheduleStateChanged = true;
2451 	}
2452 
2453 	return LV2_WORKER_SUCCESS;
2454 }
2455 
instantiate(const LV2_Descriptor * descriptor,double samplerate,const char * bundle_path,const LV2_Feature * const * features)2456 static LV2_Handle instantiate (const LV2_Descriptor* descriptor, double samplerate, const char* bundle_path, const LV2_Feature* const* features)
2457 {
2458 	// New instance
2459 	BOops* instance;
2460 	try {instance = new BOops(samplerate, bundle_path, features);}
2461 	catch (std::exception& exc)
2462 	{
2463 		fprintf (stderr, "BOops.lv2: Plugin instantiation failed. %s\n", exc.what ());
2464 		return NULL;
2465 	}
2466 
2467 	if (!instance)
2468 	{
2469 		fprintf(stderr, "BOops.lv2: Plugin instantiation failed.\n");
2470 		return NULL;
2471 	}
2472 
2473 	if (!instance->map)
2474 	{
2475 		fprintf(stderr, "BOops.lv2: Host does not support urid:map.\n");
2476 		delete (instance);
2477 		return NULL;
2478 	}
2479 
2480 	return (LV2_Handle)instance;
2481 }
2482 
connect_port(LV2_Handle instance,uint32_t port,void * data)2483 static void connect_port (LV2_Handle instance, uint32_t port, void *data)
2484 {
2485 	BOops* inst = (BOops*) instance;
2486 	if (inst) inst->connect_port (port, data);
2487 }
2488 
activate(LV2_Handle instance)2489 static void activate (LV2_Handle instance)
2490 {
2491 	BOops* inst = (BOops*) instance;
2492 	if (inst) inst->activate();
2493 }
2494 
run(LV2_Handle instance,uint32_t n_samples)2495 static void run (LV2_Handle instance, uint32_t n_samples)
2496 {
2497 	BOops* inst = (BOops*) instance;
2498 	if (inst) inst->run (n_samples);
2499 }
2500 
deactivate(LV2_Handle instance)2501 static void deactivate (LV2_Handle instance)
2502 {
2503 	BOops* inst = (BOops*) instance;
2504 	if (inst) inst->deactivate();
2505 }
2506 
cleanup(LV2_Handle instance)2507 static void cleanup (LV2_Handle instance)
2508 {
2509 	BOops* inst = (BOops*) instance;
2510 	if (inst) delete inst;
2511 }
2512 
state_save(LV2_Handle instance,LV2_State_Store_Function store,LV2_State_Handle handle,uint32_t flags,const LV2_Feature * const * features)2513 static LV2_State_Status state_save(LV2_Handle instance, LV2_State_Store_Function store, LV2_State_Handle handle, uint32_t flags,
2514            const LV2_Feature* const* features)
2515 {
2516 	BOops* inst = (BOops*)instance;
2517 	if (!inst) return LV2_STATE_SUCCESS;
2518 
2519 	inst->state_save (store, handle, flags, features);
2520 	return LV2_STATE_SUCCESS;
2521 }
2522 
state_restore(LV2_Handle instance,LV2_State_Retrieve_Function retrieve,LV2_State_Handle handle,uint32_t flags,const LV2_Feature * const * features)2523 static LV2_State_Status state_restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve, LV2_State_Handle handle, uint32_t flags,
2524            const LV2_Feature* const* features)
2525 {
2526 	BOops* inst = (BOops*)instance;
2527 	if (inst) inst->state_restore (retrieve, handle, flags, features);
2528 	return LV2_STATE_SUCCESS;
2529 }
2530 
work(LV2_Handle instance,LV2_Worker_Respond_Function respond,LV2_Worker_Respond_Handle handle,uint32_t size,const void * data)2531 static LV2_Worker_Status work (LV2_Handle instance, LV2_Worker_Respond_Function respond, LV2_Worker_Respond_Handle handle,
2532 	uint32_t size, const void* data)
2533 {
2534 	BOops* inst = (BOops*)instance;
2535 	if (!inst) return LV2_WORKER_SUCCESS;
2536 
2537 	return inst->work (respond, handle, size, data);
2538 }
2539 
work_response(LV2_Handle instance,uint32_t size,const void * data)2540 static LV2_Worker_Status work_response (LV2_Handle instance, uint32_t size,  const void* data)
2541 {
2542 	BOops* inst = (BOops*)instance;
2543 	if (!inst) return LV2_WORKER_SUCCESS;
2544 
2545 	return inst->work_response (size, data);
2546 }
2547 
extension_data(const char * uri)2548 static const void* extension_data(const char* uri)
2549 {
2550 	static const LV2_State_Interface  state  = {state_save, state_restore};
2551 	static const LV2_Worker_Interface worker = {work, work_response, NULL};
2552 	if (!strcmp(uri, LV2_STATE__interface)) return &state;
2553 	if (!strcmp(uri, LV2_WORKER__interface)) return &worker;
2554 	return NULL;
2555 }
2556 
2557 static const LV2_Descriptor descriptor =
2558 {
2559 	BOOPS_URI,
2560 	instantiate,
2561 	connect_port,
2562 	activate,
2563 	run,
2564 	deactivate,
2565 	cleanup,
2566 	extension_data
2567 };
2568 
2569 // LV2 Symbol Export
lv2_descriptor(uint32_t index)2570 LV2_SYMBOL_EXPORT const LV2_Descriptor* lv2_descriptor(uint32_t index)
2571 {
2572 	switch (index)
2573 	{
2574 	case 0: return &descriptor;
2575 	default: return NULL;
2576 	}
2577 }
2578