1 /* B.Jumblr
2  * Pattern-controlled audio stream / sample re-sequencer LV2 plugin
3  *
4  * Copyright (C) 2018 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 "BJumblr.hpp"
22 
23 #ifndef SF_FORMAT_MP3
24 #ifndef MINIMP3_IMPLEMENTATION
25 #define MINIMP3_IMPLEMENTATION
26 #endif
27 #endif
28 #include "Sample.hpp"
29 
floorfrac(const double value)30 inline double floorfrac (const double value) {return value - floor (value);}
floormod(const double numer,const double denom)31 inline double floormod (const double numer, const double denom) {return numer - floor(numer / denom) * denom;}
32 
BJumblr(double samplerate,const LV2_Feature * const * features)33 BJumblr::BJumblr (double samplerate, const LV2_Feature* const* features) :
34 	map (NULL), unmap (NULL), workerSchedule (NULL),
35 	controlPort (nullptr), notifyPort (nullptr),
36 	audioInput1 (nullptr), audioInput2 (nullptr),
37 	audioOutput1 (nullptr), audioOutput2 (nullptr),
38 	notifyForge (), notifyFrame (),
39 	waveform {0.0f}, waveformCounter (0), lastWaveformCounter (0),
40 	new_controllers {nullptr}, controllers {0},
41 	editMode (0), midiLearn (false), nrPages (1),
42 	schedulePage (0), playPage (0), lastPage (0),
43 	pads {Pad()}, patternFlipped (false),
44 	sample (nullptr), sampleAmp (1.0f),
45 	rate (samplerate), bpm (120.0f), beatsPerBar (4.0f), beatUnit (0),
46 	speed (0.0f), bar (0), barBeat (0.0f),
47 	outCapacity (0), position (0.0), cursor (0.0f), offset (0.0), refFrame (0),
48 	progressionDelay (0), progressionDelayFrac (0),
49 	maxBufferSize (samplerate * 24 * 32),
50 	audioBuffer1 (maxBufferSize, 0.0f),
51 	audioBuffer2 (maxBufferSize, 0.0f),
52 	audioBufferCounter (0), audioBufferSize (samplerate * 8),
53 	activated (false),
54 	ui_on (false), scheduleNotifyPadsToGui (false),
55 	scheduleNotifyFullPatternToGui {false},
56 	scheduleNotifySchedulePageToGui (false),
57 	scheduleNotifyPlaybackPageToGui (false),
58 	scheduleNotifyStatusToGui (false),
59 	scheduleNotifyWaveformToGui (false), scheduleNotifySamplePathToGui (false),
60 	scheduleNotifyMidiLearnedToGui (false),
61 	scheduleNotifyStateChanged (false),
62 	message ()
63 
64 {
65 	// Inits
66 	for (std::array <PadMessage, MAXSTEPS * MAXSTEPS>& p : padMessageBuffer)
67 	{
68 		p.fill ({PadMessage()});
69 		p[0] = PadMessage (ENDPADMESSAGE);
70 	};
71 
72 	//Scan host features for URID map
73 	LV2_URID_Map* m = NULL;
74 	LV2_URID_Unmap* u = NULL;
75 	for (int i = 0; features[i]; ++i)
76 	{
77 		if (strcmp (features[i]->URI, LV2_URID__map) == 0)
78 		{
79 			m = (LV2_URID_Map*) features[i]->data;
80 		}
81 
82 		else if (strcmp (features[i]->URI, LV2_URID__unmap) == 0)
83 		{
84 			u = (LV2_URID_Unmap*) features[i]->data;
85 		}
86 
87 		else if (!strcmp(features[i]->URI, LV2_WORKER__schedule))
88 		{
89                         workerSchedule = (LV2_Worker_Schedule*)features[i]->data;
90 		}
91 	}
92 
93 	if (!m) throw std::invalid_argument ("BJumblr.lv2: 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 	unmap = u;
99 	getURIs (m, &uris);
100 
101 	// Initialize notify
102 	lv2_atom_forge_init (&notifyForge, map);
103 
104 	// Initialize pads
105 	for (int p = 0; p < MAXPAGES; ++p)
106 	{
107 		for (int i = 0; i < MAXSTEPS; ++i) pads[p][i][i].level = 1.0;
108 	}
109 
110 	// Initialize controllers
111 	// Controllers are zero initialized and will get data from host, only
112 	// NR_OF_STEPS need to be set to prevent div by zero.
113 	controllers[NR_OF_STEPS] = 32;
114 
115 	ui_on = false;
116 
117 }
118 
~BJumblr()119 BJumblr::~BJumblr()
120 {
121 	if (sample) delete sample;
122 }
123 
connect_port(uint32_t port,void * data)124 void BJumblr::connect_port (uint32_t port, void *data)
125 {
126 	switch (port)
127 	{
128 		case CONTROL:
129 			controlPort = (LV2_Atom_Sequence*) data;
130 			break;
131 		case NOTIFY:
132 			notifyPort = (LV2_Atom_Sequence*) data;
133 			break;
134 		case AUDIO_IN_1:
135 			audioInput1 = (float*) data;
136 			break;
137 		case AUDIO_IN_2:
138 			audioInput2 = (float*) data;
139 			break;
140 		case AUDIO_OUT_1:
141 			audioOutput1 = (float*) data;
142 			break;
143 		case AUDIO_OUT_2:
144 			audioOutput2 = (float*) data;
145 			break;
146 		default:
147 			// Connect controllers
148 			if ((port >= CONTROLLERS) && (port < CONTROLLERS + MAXCONTROLLERS)) new_controllers[port - CONTROLLERS] = (float*) data;
149 	}
150 }
151 
runSequencer(const int start,const int end)152 void BJumblr::runSequencer (const int start, const int end)
153 {
154 	int iNrOfSteps = controllers[NR_OF_STEPS];
155 	double delay = progressionDelay + controllers[MANUAL_PROGRSSION_DELAY];
156 
157 	// Calculate start position data
158 	double relpos = getPositionFromFrames (start - refFrame);	// Position relative to reference frame
159 	double pos = floorfrac (position + relpos);			// 0..1 position
160 	double step = floormod (pos * controllers[NR_OF_STEPS] + controllers[STEP_OFFSET] + delay, controllers[NR_OF_STEPS]);	// 0..NR_OF_STEPS position
161 
162 
163 	for (int i = start; i < end; ++i)
164 	{
165 		int iStep = step;
166 
167 		float input1 = 0;
168 		float input2 = 0;
169 
170 		// Store audio input signal to buffer
171 		if (controllers[SOURCE] == 0)	// Audio stream
172 		{
173 			input1 = audioInput1[i];
174 			input2 = audioInput2[i];
175 		}
176 		else	// Sample
177 		{
178 			input1 = 0;
179 			input2 = 0;
180 
181 			if (sample)
182 			{
183 				if (sample->end > sample->start)
184 				{
185 					const uint64_t f0 = getFramesFromValue (pos * controllers[NR_OF_STEPS] * controllers[STEP_SIZE]);
186 					const int64_t frame = (sample->loop ? (f0 % (sample->end - sample->start)) + sample->start : f0 + sample->start);
187 
188 					if (frame < sample->end)
189 					{
190 						input1 = sampleAmp * sample->get (frame, 0, rate);
191 						input2 = sampleAmp * sample->get (frame, 1, rate);
192 					}
193 				}
194 			}
195 		}
196 
197 		audioBuffer1[audioBufferCounter] = input1;
198 		audioBuffer2[audioBufferCounter] = input2;
199 
200 		if (controllers[PLAY] == 1.0f)	// Play
201 		{
202 			double fracTime = 0;					// Time from start of step
203 			switch (int (controllers[STEP_BASE]))
204 			{
205 				case SECONDS:	fracTime = (step - iStep) * controllers[STEP_SIZE];
206 						break;
207 
208 				case BEATS:	fracTime = (step - iStep) * controllers[STEP_SIZE] / (bpm / 60);
209 						break;
210 
211 				case BARS:	fracTime = (step - iStep) * controllers[STEP_SIZE] / (bpm / (60 * beatsPerBar));
212 						break;
213 
214 				default:	break;
215 
216 			}
217 
218 			double fade = (fracTime < FADETIME ? fracTime / FADETIME : 1.0);
219 
220 			double prevAudio1 = 0;
221 			double prevAudio2 = 0;
222 			double audio1 = 0;
223 			double audio2 = 0;
224 
225 			// Fade out: Extrapolate audio using previous step data
226 			if (fade < 1.0)
227 			{
228 				// Begin of step: Page change scheduled ?
229 				if ((fade < 0.1) && (schedulePage != playPage))
230 				{
231 					playPage = schedulePage;
232 					scheduleNotifyPlaybackPageToGui = true;
233 					scheduleNotifyStateChanged = true;
234 				}
235 
236 				int iPrevStep = (fade < 1.0 ? (iStep + iNrOfSteps - 1) % iNrOfSteps : iStep);	// Previous step
237 				for (int r = 0; r < iNrOfSteps; ++r)
238 				{
239 					float factor = pads[lastPage][r][iPrevStep].level;
240 					if (factor != 0.0)
241 					{
242 						int stepDiff = floormod (iPrevStep - r - delay, iNrOfSteps);
243 						size_t frame = size_t (maxBufferSize + audioBufferCounter - audioBufferSize * (double (stepDiff) / double (iNrOfSteps))) % maxBufferSize;
244 						prevAudio1 += factor * audioBuffer1[frame];
245 						prevAudio2 += factor * audioBuffer2[frame];
246 
247 						if (editMode == 1) break;	// Only one active pad allowed in REPLACE mode
248 					}
249 				}
250 
251 			}
252 
253 			else lastPage = playPage;
254 
255 			// Calculate audio for this step
256 			for (int r = 0; r < iNrOfSteps; ++r)
257 			{
258 				float factor = pads[playPage][r][iStep].level;
259 				if (factor != 0.0)
260 				{
261 					int stepDiff = floormod (iStep - r - delay, iNrOfSteps);
262 					size_t frame = size_t (maxBufferSize + audioBufferCounter - audioBufferSize * (double (stepDiff) / double (iNrOfSteps))) % maxBufferSize;
263 					audio1 += factor * audioBuffer1[frame];
264 					audio2 += factor * audioBuffer2[frame];
265 
266 					if (editMode == 1) break;	// Only one active pad allowed in REPLACE mode
267 				}
268 			}
269 
270 			// Mix audio and store into output
271 			audioOutput1[i] = fade * audio1 + (1 - fade) * prevAudio1;
272 			audioOutput2[i] = fade * audio2 + (1 - fade) * prevAudio2;
273 
274 			waveformCounter = int ((pos + controllers[STEP_OFFSET] / controllers[NR_OF_STEPS]) * WAVEFORMSIZE) % WAVEFORMSIZE;
275 			waveform[waveformCounter] = (input1 + input2) / 2;
276 		}
277 
278 		else if (controllers[PLAY] == 2.0f)	// Bypass
279 		{
280 			audioOutput1[i] = input1;
281 			audioOutput2[i] = input2;
282 
283 			waveformCounter = int ((pos + controllers[STEP_OFFSET] / controllers[NR_OF_STEPS]) * WAVEFORMSIZE) % WAVEFORMSIZE;
284 			waveform[waveformCounter] = (input1 + input2) / 2;
285 		}
286 
287 		else	// Stop
288 		{
289 			audioOutput1[i] = 0;
290 			audioOutput2[i] = 0;
291 		}
292 
293 		// Calculate next position
294 		relpos = getPositionFromFrames (i + 1 - refFrame);
295 		pos = floorfrac (position + relpos);
296 		step = floormod (pos * controllers[NR_OF_STEPS] + controllers[STEP_OFFSET] + delay, controllers[NR_OF_STEPS]);
297 
298 		// Change step ? Update delaySteps
299 		int nextiStep = step;
300 		if (nextiStep != iStep)
301 		{
302 			progressionDelayFrac += controllers[SPEED] - 1;
303 			double floorDelayFrac = floor (progressionDelayFrac);
304 			progressionDelay += floorDelayFrac;
305 			progressionDelayFrac -= floorDelayFrac;
306 			scheduleNotifyStatusToGui = true;
307 		}
308 
309 		// Increment counter
310 		audioBufferCounter = (audioBufferCounter + 1) % maxBufferSize;
311 	}
312 }
313 
getPositionFromBeats(const double beats) const314 double BJumblr::getPositionFromBeats (const double beats) const
315 {
316 	if (controllers[STEP_SIZE] == 0.0) return 0.0;
317 
318 	switch (int (controllers[STEP_BASE]))
319 	{
320 		case SECONDS: 	return (bpm ? beats / (controllers[STEP_SIZE] * controllers[NR_OF_STEPS] * (bpm / 60.0)) : 0.0);
321 		case BEATS:	return beats / (controllers[STEP_SIZE] * controllers[NR_OF_STEPS]);
322 		case BARS:	return (beatsPerBar ? beats / (controllers[STEP_SIZE] * controllers[NR_OF_STEPS] * beatsPerBar) : 0.0);
323 		default:	return 0.0;
324 	}
325 }
326 
getPositionFromFrames(const uint64_t frames) const327 double BJumblr::getPositionFromFrames (const uint64_t frames) const
328 {
329 	if ((controllers[STEP_SIZE] == 0.0) || (rate == 0)) return 0.0;
330 
331 	switch (int (controllers[STEP_BASE]))
332 	{
333 		case SECONDS: 	return frames * (1.0 / rate) / (controllers[STEP_SIZE] * controllers[NR_OF_STEPS]);
334 		case BEATS:	return (bpm ? frames * (speed / (rate / (bpm / 60))) / (controllers[STEP_SIZE] * controllers[NR_OF_STEPS]) : 0.0);
335 		case BARS:	return (bpm && beatsPerBar ? frames * (speed / (rate / (bpm / 60))) / (controllers[STEP_SIZE] * controllers[NR_OF_STEPS] * beatsPerBar) : 0.0);
336 		default:	return 0.0;
337 	}
338 }
339 
getPositionFromSeconds(const double seconds) const340 double BJumblr::getPositionFromSeconds (const double seconds) const
341 {
342 	if (controllers[STEP_SIZE] == 0.0) return 0.0;
343 
344 	switch (int (controllers[STEP_BASE]))
345 	{
346 		case SECONDS :	return seconds / (controllers[STEP_SIZE] * controllers[NR_OF_STEPS]);
347 		case BEATS:	return seconds * (bpm / 60.0) / (controllers[STEP_SIZE] * controllers[NR_OF_STEPS]);
348 		case BARS:	return (beatsPerBar ? seconds * (bpm / 60.0 / beatsPerBar) / (controllers[STEP_SIZE] * controllers[NR_OF_STEPS]) : 0.0);
349 		default:	return 0;
350 	}
351 }
352 
getFramesFromValue(const double value) const353 uint64_t BJumblr::getFramesFromValue (const double value) const
354 {
355 	if (bpm < 1.0) return 0;
356 
357 	switch (int (controllers[STEP_BASE]))
358 	{
359 		case SECONDS :	return value * rate;
360 		case BEATS:	return value * (60.0 / bpm) * rate;
361 		case BARS:	return value * beatsPerBar * (60.0 / bpm) * rate;
362 		default:	return 0;
363 	}
364 }
365 
activate()366 void BJumblr::activate() {activated = true;}
367 
deactivate()368 void BJumblr::deactivate() {activated = false;}
369 
run(uint32_t n_samples)370 void BJumblr::run (uint32_t n_samples)
371 {
372 	uint32_t last_t = 0;
373 
374 	if ((!controlPort) || (!notifyPort) || (!audioInput1) || (!audioInput2) || (!audioOutput1) || (!audioOutput2)) return;
375 
376 	// Init notify port
377 	uint32_t space = notifyPort->atom.size;
378 	lv2_atom_forge_set_buffer(&notifyForge, (uint8_t*) notifyPort, space);
379 	lv2_atom_forge_sequence_head(&notifyForge, &notifyFrame, 0);
380 
381 	// Validate controllers
382 	for (int i = 0; i < MAXCONTROLLERS; ++i)
383 	{
384 		if (new_controllers[i])
385 		{
386 			float val = validateValue (*(new_controllers[i]), controllerLimits[i]);
387 			if (val != *(new_controllers[i]))
388 			{
389 				fprintf (stderr, "BJumblr.lv2: Value out of range in run (): Controller#%i\n", i);
390 				*(new_controllers[i]) = val;
391 				// TODO update GUI controller
392 			}
393 
394 			if (controllers[i] != val)
395 			{
396 				if (i == SOURCE)
397 				{
398 					if (val == 0.0) message.deleteMessage (CANT_OPEN_SAMPLE);
399 				}
400 
401 				else if (i == STEP_BASE)
402 				{
403 					if (val == SECONDS)
404 					{
405 						if (bpm < 1.0) message.setMessage (JACK_STOP_MSG);
406 						else message.deleteMessage (JACK_STOP_MSG);
407 					}
408 					else
409 					{
410 						if ((speed == 0) || (bpm < 1.0)) message.setMessage (JACK_STOP_MSG);
411 						else message.deleteMessage (JACK_STOP_MSG);
412 					}
413 				}
414 
415 				else if (i == PAGE)
416 				{
417 					schedulePage = val;
418 					scheduleNotifySchedulePageToGui = true;
419 				}
420 
421 				controllers[i] = val;
422 				uint64_t size = getFramesFromValue (controllers[STEP_SIZE] * controllers[NR_OF_STEPS]);
423 				audioBufferSize = LIMIT (size, 0, maxBufferSize);
424 
425 				// Also re-calculate waveform buffer for GUI
426 				if ((i == SOURCE) || (i == NR_OF_STEPS) || (i == STEP_BASE) || (i == STEP_SIZE) || (i == STEP_OFFSET))
427 				{
428 					for (size_t i = 0; i < WAVEFORMSIZE; ++i)
429 					{
430 						double di = double (i) / WAVEFORMSIZE;
431 						int wcount = size_t ((position + di + controllers[STEP_OFFSET] / controllers[NR_OF_STEPS]) * WAVEFORMSIZE) % WAVEFORMSIZE;
432 						size_t acount = (maxBufferSize + audioBufferCounter - audioBufferSize + (i * audioBufferSize) / WAVEFORMSIZE) % maxBufferSize;
433 						waveform[wcount] = (audioBuffer1[acount] + (audioBuffer2[acount])) / 2;
434 					}
435 					if (ui_on) notifyWaveformToGui ((waveformCounter + 1) % WAVEFORMSIZE, waveformCounter);
436 				}
437 			}
438 		}
439 	}
440 
441 	// Read CONTROL port (notifications from GUI and host)
442 	LV2_ATOM_SEQUENCE_FOREACH (controlPort, ev)
443 	{
444 		if ((ev->body.type == uris.atom_Object) || (ev->body.type == uris.atom_Blank))
445 		{
446 			const LV2_Atom_Object* obj = (const LV2_Atom_Object*)&ev->body;
447 
448 			// GUI on
449 			if (obj->body.otype == uris.ui_on)
450 			{
451 				ui_on = true;
452 				for (int i = 0; i < nrPages; ++i) scheduleNotifyFullPatternToGui[i] = true;
453 				scheduleNotifyPadsToGui = true;
454 				scheduleNotifyStatusToGui = true;
455 				scheduleNotifySamplePathToGui = true;
456 			}
457 
458 			// GUI off
459 			else if (obj->body.otype == uris.ui_off)
460 			{
461 				ui_on = false;
462 			}
463 
464 			// GUI pad changed notifications
465 			else if (obj->body.otype == uris.notify_padEvent)
466 			{
467 				LV2_Atom *oEd = NULL, *oPg = NULL, *oPd = NULL, *oPat = NULL;
468 				int page = -1;
469 				lv2_atom_object_get (obj,
470 					 	     uris.notify_editMode, &oEd,
471 						     uris.notify_padPage, &oPg,
472 						     uris.notify_pad, &oPd,
473 						     uris.notify_padFullPattern, &oPat,
474 						     NULL);
475 
476 				// EditMode notification
477 				if (oEd && (oEd->type == uris.atom_Int)) editMode = ((LV2_Atom_Int*)oEd)->body;
478 
479 				// padPage notification
480 				if (oPg && (oPg->type == uris.atom_Int))
481 				{
482 					page = ((LV2_Atom_Int*)oPg)->body;
483 					if (page >= nrPages)
484 					{
485 						nrPages = LIMIT (page + 1, 1, MAXPAGES);
486 						if (playPage >= nrPages)
487 						{
488 							schedulePage = nrPages - 1;
489 							scheduleNotifySchedulePageToGui = true;
490 						}
491 					}
492 				}
493 
494 				// Pad notification
495 				if (oPd && (oPd->type == uris.atom_Vector) && (page >= 0) && (page < MAXPAGES))
496 				{
497 					const LV2_Atom_Vector* vec = (const LV2_Atom_Vector*) oPd;
498 					if (vec->body.child_type == uris.atom_Float)
499 					{
500 						const uint32_t size = (uint32_t) ((oPd->size - sizeof(LV2_Atom_Vector_Body)) / sizeof (PadMessage));
501 						PadMessage* pMes = (PadMessage*) (&vec->body + 1);
502 
503 						for (unsigned int i = 0; i < size; ++i)
504 						{
505 							int row = pMes[i].row;
506 							int step = pMes[i].step;
507 
508 							// Copy PadMessages to pads
509 							if ((row >= 0) && (row < MAXSTEPS) && (step >= 0) && (step < MAXSTEPS))
510 							{
511 								Pad pd (pMes[i].level);
512 								Pad valPad = validatePad (pd);
513 								pads[page][row][step] = valPad;
514 								if (valPad != pd)
515 								{
516 									fprintf (stderr, "BJumblr.lv2: Pad out of range in run (): pads[%i][%i][%i].\n", page, row, step);
517 									padMessageBufferAppendPad (page, row, step, valPad);
518 									scheduleNotifyPadsToGui = true;
519 								}
520 								scheduleNotifyStateChanged = true;
521 							}
522 						}
523 					}
524 				}
525 
526 				// Full pattern notification
527 				if (oPat && (oPat->type == uris.atom_Vector) && (page >= 0) && (page < MAXPAGES))
528 				{
529 					const LV2_Atom_Vector* vec = (const LV2_Atom_Vector*) oPat;
530 					if (vec->body.child_type == uris.atom_Float)
531 					{
532 						const uint32_t size = (uint32_t) ((oPat->size - sizeof(LV2_Atom_Vector_Body)) / sizeof (Pad));
533 						Pad* data = (Pad*) (&vec->body + 1);
534 
535 						if (size == MAXSTEPS * MAXSTEPS)
536 						{
537 							// Copy pattern data
538 							for (int r = 0; r < MAXSTEPS; ++r)
539 							{
540 								for (int s = 0; s < MAXSTEPS; ++s)
541 								{
542 									pads[page][r][s] = data[r * MAXSTEPS + s];
543 								}
544 							}
545 
546 							scheduleNotifyStateChanged = true;
547 						}
548 
549 						else fprintf (stderr, "BJumblr.lv2: Corrupt pattern size of %i for page %i.\n", size, page);
550 					}
551 				}
552 			}
553 
554 			// Status notifications
555 			else if (obj->body.otype == uris.notify_statusEvent)
556 			{
557 				LV2_Atom *oMx = NULL, *oPp = NULL, *oMl = NULL, *oFlip = NULL;
558 				lv2_atom_object_get (obj,
559 					 	     uris.notify_maxPage, &oMx,
560 						     uris.notify_playbackPage, &oPp,
561 						     uris.notify_requestMidiLearn, &oMl,
562 						     uris.notify_padFlipped, &oFlip,
563 						     NULL);
564 
565 				// padMaxPage notification
566 				if (oMx && (oMx->type == uris.atom_Int))
567 				{
568 					int newPages = ((LV2_Atom_Int*)oMx)->body;
569 					if (newPages != nrPages)
570 					{
571 						nrPages = LIMIT (newPages, 1, MAXPAGES);
572 						if (playPage >= nrPages)
573 						{
574 							schedulePage = nrPages - 1;
575 							scheduleNotifyPlaybackPageToGui = true;
576 						}
577 					}
578 				}
579 
580 				// playbackPage notification
581 				if (oPp && (oPp->type == uris.atom_Int))
582 				{
583 					int newPp = ((LV2_Atom_Int*)oPp)->body;
584 					if (newPp != playPage)
585 					{
586 						playPage = LIMIT (newPp, 0, MAXPAGES - 1);
587 						scheduleNotifyStateChanged = true;
588 					}
589 				}
590 
591 				// Midi learn request notification
592 				if (oMl && (oMl->type == uris.atom_Bool)) midiLearn = ((LV2_Atom_Bool*)oMl)->body;
593 
594 				// Pattern orientation
595 				if (oFlip && (oFlip->type == uris.atom_Bool))
596 				{
597 					patternFlipped = ((LV2_Atom_Bool*)oFlip)->body;
598 					scheduleNotifyStateChanged = true;
599 				}
600 			}
601 
602 			// Sample path notification -> forward to worker
603 			else if (obj->body.otype ==uris.notify_pathEvent)
604 			{
605 				LV2_Atom* oPath = NULL, *oStart = NULL, *oEnd = NULL, *oAmp = NULL, *oLoop = NULL;
606 				lv2_atom_object_get
607 				(
608 					obj,
609 					uris.notify_samplePath, &oPath,
610 					uris.notify_sampleStart, &oStart,
611 					uris.notify_sampleEnd, &oEnd,
612 					uris.notify_sampleAmp, &oAmp,
613 					uris.notify_sampleLoop, &oLoop,
614 					NULL
615 				);
616 
617 				// New sample
618 				if (oPath && (oPath->type == uris.atom_Path))
619 				{
620 					workerSchedule->schedule_work (workerSchedule->handle, lv2_atom_total_size(&ev->body), &ev->body);
621 				}
622 
623 				// Only start / end /amp / loop changed
624 				else if (sample)
625 				{
626 					if (oStart && (oStart->type == uris.atom_Long)) sample->start = LIMIT (((LV2_Atom_Long*)oStart)->body, 0, sample->info.frames - 1);
627 					if (oEnd && (oEnd->type == uris.atom_Long)) sample->end = LIMIT (((LV2_Atom_Long*)oEnd)->body, 0, sample->info.frames);
628 					if (oAmp && (oAmp->type == uris.atom_Float)) sampleAmp = LIMIT (((LV2_Atom_Float*)oAmp)->body, 0.0f, 1.0f);
629 					if (oLoop && (oLoop->type == uris.atom_Bool)) sample->loop = bool(((LV2_Atom_Bool*)oLoop)->body);
630 					scheduleNotifyStateChanged = true;
631 				}
632 			}
633 
634 			// Process time / position data
635 			else if (obj->body.otype == uris.time_Position)
636 			{
637 				bool scheduleUpdatePosition = false;
638 
639 				// Update bpm, speed, position
640 				LV2_Atom *oBbeat = NULL, *oBpm = NULL, *oSpeed = NULL, *oBpb = NULL, *oBu = NULL, *oBar = NULL;
641 				const LV2_Atom_Object* obj = (const LV2_Atom_Object*)&ev->body;
642 				lv2_atom_object_get
643 				(
644 					obj, uris.time_bar, &oBar,
645 					uris.time_barBeat, &oBbeat,
646 					uris.time_beatsPerMinute,  &oBpm,
647 					uris.time_beatsPerBar,  &oBpb,
648 					uris.time_beatUnit,  &oBu,
649 					uris.time_speed, &oSpeed,
650 					NULL
651 				);
652 
653 				// BPM changed?
654 				if (oBpm && (oBpm->type == uris.atom_Float) && (bpm != ((LV2_Atom_Float*)oBpm)->body))
655 				{
656 					bpm = ((LV2_Atom_Float*)oBpm)->body;
657 					scheduleUpdatePosition = true;
658 				}
659 
660 				// Beats per bar changed?
661 				if (oBpb && (oBpb->type == uris.atom_Float) && (beatsPerBar != ((LV2_Atom_Float*)oBpb)->body))
662 				{
663 					beatsPerBar = ((LV2_Atom_Float*)oBpb)->body;
664 					scheduleUpdatePosition = true;
665 				}
666 
667 				// BeatUnit changed?
668 				if (oBu && (oBu->type == uris.atom_Int) && (beatUnit != ((LV2_Atom_Int*)oBu)->body))
669 				{
670 					beatUnit = ((LV2_Atom_Int*)oBu)->body;
671 					scheduleUpdatePosition = true;
672 				}
673 
674 				// Speed changed?
675 				if (oSpeed && (oSpeed->type == uris.atom_Float) && (speed != ((LV2_Atom_Float*)oSpeed)->body))
676 				{
677 					speed = ((LV2_Atom_Float*)oSpeed)->body;
678 					scheduleUpdatePosition = true;
679 				}
680 
681 				// Bar position changed
682 				if (oBar && (oBar->type == uris.atom_Long) && (bar != ((long)((LV2_Atom_Long*)oBar)->body)))
683 				{
684 					bar = ((LV2_Atom_Long*)oBar)->body;
685 					scheduleUpdatePosition = true;
686 				}
687 
688 				// Beat position changed (during playing) ?
689 				if (oBbeat && (oBbeat->type == uris.atom_Float) && (barBeat != ((LV2_Atom_Float*)oBbeat)->body))
690 				{
691 					barBeat = ((LV2_Atom_Float*)oBbeat)->body;
692 					scheduleUpdatePosition = true;
693 				}
694 
695 				if (scheduleUpdatePosition)
696 				{
697 					// Hard set new position if new data received
698 					double pos = getPositionFromBeats (barBeat + beatsPerBar * bar);
699 					position = floorfrac (pos - offset);
700 					refFrame = ev->time.frames;
701 					uint64_t size = getFramesFromValue (controllers[STEP_SIZE] * controllers[NR_OF_STEPS]);
702 					audioBufferSize = LIMIT (size, 0, maxBufferSize);
703 
704 					// Store message
705 					if (((bpm < 1.0) || (speed == 0.0)) && (controllers[STEP_BASE] != SECONDS)) message.setMessage (JACK_STOP_MSG);
706 					else message.deleteMessage (JACK_STOP_MSG);
707 				}
708 			}
709 		}
710 
711 		// Read incoming MIDI events
712 		else if (ev->body.type == uris.midi_Event)
713 		{
714 			const uint8_t* const msg = (const uint8_t*)(ev + 1);
715 			const uint8_t status = (msg[0] >> 4);
716 			const uint8_t channel = msg[0] & 0x0F;
717 			const uint8_t note = ((status == 8) || (status == 9) || (status == 11) ? msg[1] : 0);
718 			const uint8_t value = ((status == 8) || (status == 9) || (status == 11) ? msg[2] : 0);
719 
720 			if (midiLearn)
721 			{
722 				midiLearned[0] = status;
723 				midiLearned[1] = channel;
724 				midiLearned[2] = note;
725 				midiLearned[3] = value;
726 				midiLearn = false;
727 				scheduleNotifyMidiLearnedToGui = true;
728 			}
729 
730 			else
731 			{
732 
733 				for (int p = 0; p < nrPages; ++p)
734 				{
735 					if
736 					(
737 						controllers[MIDI + p * NR_MIDI_CTRLS + STATUS] &&
738 						(controllers[MIDI + p * NR_MIDI_CTRLS + STATUS] == status) &&
739 						(
740 							(controllers[MIDI + p * NR_MIDI_CTRLS + CHANNEL] == 0) ||
741 							(controllers[MIDI + p * NR_MIDI_CTRLS + CHANNEL] - 1 == channel)
742 						) &&
743 						(
744 							(controllers[MIDI + p * NR_MIDI_CTRLS + NOTE] == 128) ||
745 							(controllers[MIDI + p * NR_MIDI_CTRLS + NOTE] == note)
746 						) &&
747 						(
748 							(controllers[MIDI + p * NR_MIDI_CTRLS + VALUE] == 128) ||
749 							(controllers[MIDI + p * NR_MIDI_CTRLS + VALUE] == value)
750 						)
751 					)
752 					{
753 						schedulePage = p;
754 						scheduleNotifySchedulePageToGui = true;
755 						break;
756 					}
757 				}
758 			}
759 		}
760 
761 		// Update for this iteration
762 		uint32_t next_t = (ev->time.frames < n_samples ? ev->time.frames : n_samples);
763 		runSequencer (last_t, next_t);
764 		last_t = next_t;
765 	}
766 
767 	// Update for the remainder of the cycle
768 	if (last_t < n_samples) runSequencer (last_t, n_samples);
769 
770 	// Update position in case of no new barBeat submitted on next call
771 	double relpos = getPositionFromFrames (n_samples - refFrame);	// Position relative to reference frame
772 	position = floorfrac (position + relpos);
773 	refFrame = 0;
774 
775 	if (controllers[PLAY])
776 	{
777 
778 		cursor = floormod
779 		(
780 			position * controllers[NR_OF_STEPS] + controllers[STEP_OFFSET] + progressionDelay + controllers[MANUAL_PROGRSSION_DELAY],
781 			controllers[NR_OF_STEPS]
782 		);
783 		scheduleNotifyStatusToGui = true;
784 	}
785 
786 	if (waveformCounter != lastWaveformCounter) scheduleNotifyWaveformToGui = true;
787 
788 	if (ui_on)
789 	{
790 		if (scheduleNotifyStatusToGui) notifyStatusToGui();
791 		if (scheduleNotifyPadsToGui) notifyPadsToGui();
792 		if (scheduleNotifyWaveformToGui) notifyWaveformToGui (lastWaveformCounter, waveformCounter);
793 		if (scheduleNotifySamplePathToGui) notifySamplePathToGui ();
794 		if (scheduleNotifySchedulePageToGui) notifySchedulePageToGui ();
795 		if (scheduleNotifyPlaybackPageToGui) notifyPlaybackPageToGui ();
796 		if (scheduleNotifyMidiLearnedToGui) notifyMidiLearnedToGui ();
797 		if (message.isScheduled ()) notifyMessageToGui();
798 	}
799 
800 	if (scheduleNotifyStateChanged) notifyStateChanged();
801 	lv2_atom_forge_pop(&notifyForge, &notifyFrame);
802 }
803 
state_save(LV2_State_Store_Function store,LV2_State_Handle handle,uint32_t flags,const LV2_Feature * const * features)804 LV2_State_Status BJumblr::state_save (LV2_State_Store_Function store, LV2_State_Handle handle, uint32_t flags,
805 			const LV2_Feature* const* features)
806 {
807 	// Store sample path
808 	if (sample && sample->path && (sample->path[0] != 0) && (controllers[SOURCE] == 1.0))
809 	{
810 		LV2_State_Map_Path* mapPath = NULL;
811 #ifdef LV2_STATE__freePath
812 		LV2_State_Free_Path* freePath = NULL;
813 #endif
814 
815 		for (int i = 0; features[i]; ++i)
816 		{
817 			if (strcmp(features[i]->URI, LV2_STATE__mapPath) == 0)
818 			{
819 				mapPath = (LV2_State_Map_Path*) features[i]->data;
820 				break;
821 			}
822 		}
823 
824 #ifdef LV2_STATE__freePath
825 		for (int i = 0; features[i]; ++i)
826 		{
827 			if (strcmp(features[i]->URI, LV2_STATE__freePath) == 0)
828 			{
829 				freePath = (LV2_State_Free_Path*) features[i]->data;
830 				break;
831 			}
832 		}
833 #endif
834 
835 		if (mapPath)
836 		{
837 			char* abstrPath = mapPath->abstract_path(mapPath->handle, sample->path);
838 
839 			if (abstrPath)
840 			{
841 				fprintf(stderr, "BJumblr.lv2: Save abstr_path:%s\n", abstrPath);
842 				store(handle, uris.notify_samplePath, abstrPath, strlen (abstrPath) + 1, uris.atom_Path, LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
843 				store(handle, uris.notify_sampleStart, &sample->start, sizeof (sample->start), uris.atom_Long, LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
844 				store(handle, uris.notify_sampleEnd, &sample->end, sizeof (sample->end), uris.atom_Long, LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
845 				store(handle, uris.notify_sampleAmp, &sampleAmp, sizeof (sampleAmp), uris.atom_Float, LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
846 				const int32_t sloop = int32_t (sample->loop);
847 				store(handle, uris.notify_sampleLoop, &sloop, sizeof (sloop), uris.atom_Bool, LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
848 
849 #ifdef LV2_STATE__freePath
850 				if (freePath) freePath->free_path (freePath->handle, abstrPath);
851 				else
852 #endif
853 				{
854 					free (abstrPath);
855 				}
856 			}
857 
858 			else fprintf(stderr, "BJumblr.lv2: Can't generate abstr_path from %s\n", sample->path);
859 		}
860 		else
861 		{
862 			fprintf (stderr, "BJumblr.lv2: Feature map_path not available! Can't save sample!\n" );
863 			return LV2_STATE_ERR_NO_FEATURE;
864 		}
865 	}
866 
867 	// Store pattern orientation
868 	store(handle, uris.notify_padFlipped, &patternFlipped, sizeof (patternFlipped), uris.atom_Bool, LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
869 
870 	// Store playbackPage
871 	uint32_t pp = playPage;
872 	store (handle, uris.notify_playbackPage, &pp, sizeof(uint32_t), uris.atom_Int, LV2_STATE_IS_POD);
873 
874 	// Store edit mode
875 	uint32_t em = editMode;
876 	store (handle, uris.notify_editMode, &em, sizeof(uint32_t), uris.atom_Int, LV2_STATE_IS_POD);
877 
878 	// Store pads
879 	char padDataString[0x80100] = "\nMatrix data:\n";
880 
881 	for (int page = 0; page < nrPages; ++page)
882 	{
883 		for (int step = 0; step < MAXSTEPS; ++step)
884 		{
885 			for (int row = 0; row < MAXSTEPS; ++row)
886 			{
887 				Pad* pd = &pads[page][row][step];
888 				if (*pd != Pad())
889 				{
890 					char valueString[64];
891 					int id = step * MAXSTEPS + row;
892 					snprintf (valueString, 62, "pg:%d; id:%d; lv:%f", page, id, pd->level);
893 					if ((step < MAXSTEPS - 1) || (row < MAXSTEPS)) strcat (valueString, ";\n");
894 					else strcat(valueString, "\n");
895 					strcat (padDataString, valueString);
896 				}
897 			}
898 		}
899 	}
900 	store (handle, uris.state_pad, padDataString, strlen (padDataString) + 1, uris.atom_String, LV2_STATE_IS_POD);
901 
902 	return LV2_STATE_SUCCESS;
903 }
904 
state_restore(LV2_State_Retrieve_Function retrieve,LV2_State_Handle handle,uint32_t flags,const LV2_Feature * const * features)905 LV2_State_Status BJumblr::state_restore (LV2_State_Retrieve_Function retrieve, LV2_State_Handle handle, uint32_t flags,
906 			const LV2_Feature* const* features)
907 {
908 	// Get host features
909 	LV2_Worker_Schedule* schedule = nullptr;
910 	LV2_State_Map_Path* mapPath = nullptr;
911 #ifdef LV2_STATE__freePath
912 	LV2_State_Free_Path* freePath = NULL;
913 #endif
914 
915 	for (int i = 0; features[i]; ++i)
916 	{
917 		if (strcmp(features[i]->URI, LV2_STATE__mapPath) == 0)
918 		{
919 			mapPath = (LV2_State_Map_Path*) features[i]->data;
920 			break;
921 		}
922 	}
923 
924 	for (int i = 0; features[i]; ++i)
925 	{
926 		if (strcmp(features[i]->URI, LV2_WORKER__schedule) == 0)
927 		{
928 			schedule = (LV2_Worker_Schedule*) features[i]->data;
929 			break;
930 		}
931 	}
932 
933 #ifdef LV2_STATE__freePath
934 	for (int i = 0; features[i]; ++i)
935 	{
936 		if (strcmp(features[i]->URI, LV2_STATE__freePath) == 0)
937 		{
938 			freePath = (LV2_State_Free_Path*) features[i]->data;
939 			break;
940 		}
941 	}
942 #endif
943 
944 	if (!mapPath)
945 	{
946 		fprintf (stderr, "BJumblr.lv2: Host doesn't support required features.\n");
947 		return LV2_STATE_ERR_NO_FEATURE;
948 	}
949 
950 	size_t   size;
951 	uint32_t type;
952 	uint32_t valflags;
953 
954 	// Retireve sample data
955 	{
956 		char samplePath[PATH_MAX] = {0};
957 		int64_t sampleStart = 0;
958 		int64_t sampleEnd = 0;
959 		float sampleAmp = 1.0;
960 		int32_t sampleLoop = false;
961 
962 		const void* pathData = retrieve (handle, uris.notify_samplePath, &size, &type, &valflags);
963 		if (pathData)
964 		{
965 			char* absPath  = mapPath->absolute_path (mapPath->handle, (char*)pathData);
966 
967 		        if (absPath)
968 			{
969 				if (strlen (absPath) < PATH_MAX) strcpy (samplePath, absPath);
970 				else
971 				{
972 					fprintf (stderr, "BJumblr.lv2: Sample path too long.\n");
973 					message.setMessage (CANT_OPEN_SAMPLE);
974 				}
975 
976 				fprintf(stderr, "BJumblr.lv2: Restore abs_path:%s\n", absPath);
977 
978 #ifdef LV2_STATE__freePath
979 				if (freePath) freePath->free_path (freePath->handle, absPath);
980 				else
981 #endif
982 				{
983 					free (absPath);
984 				}
985 		        }
986 		}
987 
988 		const void* startData = retrieve (handle, uris.notify_sampleStart, &size, &type, &valflags);
989 	        if (startData && (type == uris.atom_Long)) sampleStart = *(int64_t*)startData;
990 		const void* endData = retrieve (handle, uris.notify_sampleEnd, &size, &type, &valflags);
991 	        if (endData && (type == uris.atom_Long)) sampleEnd = *(int64_t*)endData;
992 		const void* ampData = retrieve (handle, uris.notify_sampleAmp, &size, &type, &valflags);
993 	        if (ampData && (type == uris.atom_Float)) sampleAmp = *(float*)ampData;
994 		const void* loopData = retrieve (handle, uris.notify_sampleLoop, &size, &type, &valflags);
995 	        if (loopData && (type == uris.atom_Bool)) sampleLoop = *(int32_t*)loopData;
996 
997 		if (activated && schedule)
998 		{
999 			LV2_Atom_Forge forge;
1000 			lv2_atom_forge_init(&forge, map);
1001 			uint8_t buf[1200];
1002 			lv2_atom_forge_set_buffer(&forge, buf, sizeof(buf));
1003 			LV2_Atom_Forge_Frame frame;
1004 			LV2_Atom* msg = (LV2_Atom*)forgeSamplePath (&forge, &frame, samplePath, sampleStart, sampleEnd, sampleAmp, sampleLoop);
1005 			lv2_atom_forge_pop(&forge, &frame);
1006 			if (msg) schedule->schedule_work(schedule->handle, lv2_atom_total_size(msg), msg);
1007 		}
1008 
1009 		else
1010 		{
1011 			// Free old sample
1012 			if (sample)
1013 			{
1014 				delete sample;
1015 				sample = nullptr;
1016 				sampleAmp = 1.0;
1017 			}
1018 
1019 			// Load new sample
1020 			message.deleteMessage (CANT_OPEN_SAMPLE);
1021 			try {sample = new Sample (samplePath);}
1022 			catch (std::bad_alloc &ba)
1023 			{
1024 				fprintf (stderr, "Jumblr.lv2: Can't allocate enoug memory to open sample file.\n");
1025 				message.setMessage (CANT_OPEN_SAMPLE);
1026 			}
1027 			catch (std::invalid_argument &ia)
1028 			{
1029 				fprintf (stderr, "%s\n", ia.what());
1030 				message.setMessage (CANT_OPEN_SAMPLE);
1031 			}
1032 
1033 			// Set new sample properties
1034 			if  (sample)
1035 			{
1036 				sample->start = sampleStart;
1037 				sample->end = sampleEnd;
1038 				sample->loop = bool (sampleLoop);
1039 				this->sampleAmp = sampleAmp;
1040 			}
1041 
1042 			scheduleNotifySamplePathToGui = true;
1043 		}
1044 	}
1045 
1046 	// Retrieve pattern orientation
1047 	const void* flipData = retrieve (handle, uris.notify_padFlipped, &size, &type, &valflags);
1048         if (flipData && (type == uris.atom_Bool))
1049 	{
1050 		patternFlipped = *(bool*) flipData;
1051 		scheduleNotifyStatusToGui = true;
1052         }
1053 
1054 	// Retrieve playbackPage
1055 	const void* ppData = retrieve (handle, uris.notify_playbackPage, &size, &type, &valflags);
1056         if (ppData && (size == sizeof (uint32_t)) && (type == uris.atom_Int))
1057 	{
1058 		const uint32_t pp = *(const uint32_t*) ppData;
1059 		if ((pp < 0) || (pp >= MAXPAGES)) fprintf (stderr, "BJumblr.lv2: Invalid playbackPage data\n");
1060 		else playPage = pp;
1061 		scheduleNotifyPlaybackPageToGui = true;
1062         }
1063 
1064 	// Retrieve edit mode
1065 	const void* modeData = retrieve (handle, uris.notify_editMode, &size, &type, &valflags);
1066         if (modeData && (size == sizeof (uint32_t)) && (type == uris.atom_Int))
1067 	{
1068 		const uint32_t mode = *(const uint32_t*) modeData;
1069 		if ((mode < 0) || (mode > 1)) fprintf (stderr, "BJumblr.lv2: Invalid editMode data\n");
1070 		else editMode = mode;
1071         }
1072 
1073 	// Retrieve pad data
1074 	const void* padData = retrieve(handle, uris.state_pad, &size, &type, &valflags);
1075 
1076 	if (padData && (type == uris.atom_String))
1077 	{
1078 		nrPages = 1;
1079 		for (int i = 0; i < MAXPAGES; ++i)
1080 		{
1081 			for (int j = 0; j < MAXSTEPS; ++j)
1082 			{
1083 				for (int k = 0; k < MAXSTEPS; ++k)
1084 				{
1085 					pads[i][j][k] = Pad();
1086 				}
1087 			}
1088 		}
1089 
1090 		std::string padDataString = (char*) padData;
1091 		const std::string keywords[3] = {"pg:", "id:", "lv:"};
1092 
1093 		// Restore pads
1094 		// Parse retrieved data
1095 		while (!padDataString.empty())
1096 		{
1097 			// Look for optional "pg:"
1098 			int page = 0;
1099 			size_t strPos = padDataString.find (keywords[0]);
1100 			size_t nextPos = 0;
1101 			if ((strPos != std::string::npos) && (strPos + 3 <= padDataString.length()))
1102 			{
1103 				padDataString.erase (0, strPos + 3);
1104 				int p;
1105 				try {p = std::stof (padDataString, &nextPos);}
1106 				catch  (const std::exception& e)
1107 				{
1108 					fprintf (stderr, "BJumblr.lv2: Restore pad state incomplete. Can't parse page from \"%s...\"", padDataString.substr (0, 63).c_str());
1109 					break;
1110 				}
1111 
1112 				if (nextPos > 0) padDataString.erase (0, nextPos);
1113 				if ((p < 0) || (p >= MAXPAGES))
1114 				{
1115 					fprintf (stderr, "BJumblr.lv2: Restore pad state incomplete. Invalid matrix data block loaded with page %i. Try to use the data before this page.\n", p);
1116 					break;
1117 				}
1118 				if (p >= nrPages) nrPages = p + 1;
1119 				page = p;
1120 			}
1121 
1122 			// Look for "id:"
1123 			strPos = padDataString.find (keywords[1]);
1124 			nextPos = 0;
1125 			if (strPos == std::string::npos) break;	// No "id:" found => end
1126 			if (strPos + 3 > padDataString.length()) break;	// Nothing more after id => end
1127 			padDataString.erase (0, strPos + 3);
1128 			int id;
1129 			try {id = std::stof (padDataString, &nextPos);}
1130 			catch  (const std::exception& e)
1131 			{
1132 				fprintf (stderr, "BJumblr.lv2: Restore pad state incomplete. Can't parse ID from \"%s...\"", padDataString.substr (0, 63).c_str());
1133 				break;
1134 			}
1135 
1136 			if (nextPos > 0) padDataString.erase (0, nextPos);
1137 			if ((id < 0) || (id >= MAXSTEPS * MAXSTEPS))
1138 			{
1139 				fprintf (stderr, "BJumblr.lv2: Restore pad state incomplete. Invalid matrix data block loaded with ID %i. Try to use the data before this id.\n", id);
1140 				break;
1141 			}
1142 			int row = id % MAXSTEPS;
1143 			int step = id / MAXSTEPS;
1144 
1145 			// Look for pad data
1146 			for (int i = 2; i < 3; ++i)
1147 			{
1148 				strPos = padDataString.find (keywords[i]);
1149 				if (strPos == std::string::npos) continue;	// Keyword not found => next keyword
1150 				if (strPos + 3 >= padDataString.length())	// Nothing more after keyword => end
1151 				{
1152 					padDataString ="";
1153 					break;
1154 				}
1155 				if (strPos > 0) padDataString.erase (0, strPos + 3);
1156 				float val;
1157 				try {val = std::stof (padDataString, &nextPos);}
1158 				catch  (const std::exception& e)
1159 				{
1160 					fprintf (stderr, "BJumblr.lv2: Restore padstate incomplete. Can't parse %s from \"%s...\"",
1161 							 keywords[i].substr(0,2).c_str(), padDataString.substr (0, 63).c_str());
1162 					break;
1163 				}
1164 
1165 				if (nextPos > 0) padDataString.erase (0, nextPos);
1166 				switch (i) {
1167 				case 2:	pads[page][row][step].level = val;
1168 					break;
1169 				default:break;
1170 				}
1171 			}
1172 		}
1173 
1174 
1175 		// Validate all pads
1176 		for (int p = 0; p < nrPages; ++p)
1177 		{
1178 			for (int i = 0; i < MAXSTEPS; ++i)
1179 			{
1180 				for (int j = 0; j < MAXSTEPS; ++j)
1181 				{
1182 					Pad valPad = validatePad (pads[p][i][j]);
1183 					if (valPad != pads[p][i][j])
1184 					{
1185 						fprintf (stderr, "BJumblr.lv2: Pad out of range in state_restore (): pads[%i][%i][%i].\n", p, i, j);
1186 						pads[p][i][j] = valPad;
1187 					}
1188 				}
1189 			}
1190 
1191 			scheduleNotifyFullPatternToGui[p] = true;
1192 		}
1193 
1194 		// Force GUI notification
1195 		scheduleNotifyPadsToGui = true;
1196 	}
1197 
1198 	// Force GUI notification
1199 	scheduleNotifyStatusToGui = true;
1200 
1201 	return LV2_STATE_SUCCESS;
1202 }
1203 
work(LV2_Worker_Respond_Function respond,LV2_Worker_Respond_Handle handle,uint32_t size,const void * data)1204 LV2_Worker_Status BJumblr::work (LV2_Worker_Respond_Function respond, LV2_Worker_Respond_Handle handle, uint32_t size, const void* data)
1205 {
1206 	const LV2_Atom* atom = (const LV2_Atom*)data;
1207 	if (!atom) return LV2_WORKER_ERR_UNKNOWN;
1208 
1209 	// Free old sample
1210         if (atom->type == uris.notify_sampleFreeEvent)
1211 	{
1212 		const WorkerMessage* workerMessage = (WorkerMessage*) atom;
1213 		if (workerMessage->sample) delete workerMessage->sample;
1214         }
1215 
1216 	// Load sample
1217 	else
1218 	{
1219                 const LV2_Atom_Object* obj = (const LV2_Atom_Object*)data;
1220 
1221 		if (obj->body.otype == uris.notify_pathEvent)
1222 		{
1223 			const LV2_Atom* path = NULL, *oStart = NULL, *oEnd = NULL, *oAmp = NULL, *oLoop = NULL;
1224 			lv2_atom_object_get
1225 			(
1226 				obj,
1227 				uris.notify_samplePath, &path,
1228 				uris.notify_sampleStart, &oStart,
1229 				uris.notify_sampleEnd, &oEnd,
1230 				uris.notify_sampleAmp, &oAmp,
1231 				uris.notify_sampleLoop, &oLoop,
1232 				0
1233 			);
1234 
1235 			if (path && (path->type == uris.atom_Path))
1236 			{
1237 				message.deleteMessage (CANT_OPEN_SAMPLE);
1238 				Sample* s = nullptr;
1239 				try {s = new Sample ((const char*)LV2_ATOM_BODY_CONST(path));}
1240 				catch (std::bad_alloc &ba)
1241 				{
1242 					fprintf (stderr, "BJumblr.lv2: Can't allocate enough memory to open sample file.\n");
1243 					message.setMessage (CANT_OPEN_SAMPLE);
1244 					return LV2_WORKER_ERR_NO_SPACE;
1245 				}
1246 				catch (std::invalid_argument &ia)
1247 				{
1248 					fprintf (stderr, "%s\n", ia.what());
1249 					message.setMessage (CANT_OPEN_SAMPLE);
1250 					return LV2_WORKER_ERR_UNKNOWN;
1251 				}
1252 
1253 				if (s)
1254 				{
1255 					WorkerMessage sAtom;
1256 					sAtom.atom = {sizeof (s), uris.notify_installSample};
1257 					sAtom.sample = s;
1258 					sAtom.start = (oStart && (oStart->type == uris.atom_Long) ? ((LV2_Atom_Long*)oStart)->body : 0);
1259 					sAtom.end = (oEnd && (oEnd->type == uris.atom_Long) ? ((LV2_Atom_Long*)oEnd)->body : s->info.frames);
1260 					sAtom.amp = (oAmp && (oAmp->type == uris.atom_Float) ? ((LV2_Atom_Float*)oAmp)->body : 1.0f);
1261 					sAtom.loop = (oLoop && (oLoop->type == uris.atom_Bool) ? ((LV2_Atom_Bool*)oLoop)->body : 0);
1262 					respond (handle, sizeof(sAtom), &sAtom);
1263 				}
1264 				if (s) respond (handle, sizeof(s), &s);
1265 			}
1266 
1267 			else return LV2_WORKER_ERR_UNKNOWN;
1268 		}
1269         }
1270 
1271         return LV2_WORKER_SUCCESS;
1272 }
1273 
work_response(uint32_t size,const void * data)1274 LV2_Worker_Status BJumblr::work_response (uint32_t size, const void* data)
1275 {
1276 	const LV2_Atom* atom = (const LV2_Atom*)data;
1277 	if (!atom) return LV2_WORKER_ERR_UNKNOWN;
1278 
1279 	if (atom->type == uris.notify_installSample)
1280 	{
1281 		const WorkerMessage* nAtom = (const WorkerMessage*)data;
1282 		// Schedule worker to free old sample
1283 		WorkerMessage sAtom = {{sizeof (Sample*), uris.notify_sampleFreeEvent}, sample};
1284 		workerSchedule->schedule_work (workerSchedule->handle, sizeof (sAtom), &sAtom);
1285 
1286 		// Install new sample from data
1287 		sample = nAtom->sample;
1288 		if (sample)
1289 		{
1290 			sample->start = LIMIT (nAtom->start, 0, sample->info.frames - 1);
1291 			sample->end = LIMIT (nAtom->end, sample->start, sample->info.frames);
1292 			sampleAmp = LIMIT (nAtom->amp, 0.0f, 1.0f);
1293 			sample->loop = bool (nAtom->loop);
1294 			scheduleNotifyStateChanged = true;
1295 			return LV2_WORKER_SUCCESS;
1296 		}
1297 
1298 		else
1299 		{
1300 			scheduleNotifyStateChanged = true;
1301 			return LV2_WORKER_ERR_UNKNOWN;
1302 		}
1303 	}
1304 
1305 	else return LV2_WORKER_ERR_UNKNOWN;
1306 }
1307 
1308 /*
1309  * Checks if a value is within a limit, and if not, puts the value within
1310  * this limit.
1311  * @param value
1312  * @param limit
1313  * @return		Value is within the limit
1314  */
validateValue(float value,const Limit limit)1315 float BJumblr::validateValue (float value, const Limit limit)
1316 {
1317 	float ltdValue = ((limit.step != 0) ? (limit.min + round ((value - limit.min) / limit.step) * limit.step) : value);
1318 	return LIMIT (ltdValue, limit.min, limit.max);
1319 }
1320 
1321 /*
1322  * Validates a single pad
1323  */
validatePad(Pad pad)1324 Pad BJumblr::validatePad (Pad pad)
1325 {
1326 	return Pad(validateValue (pad.level, {0, 1, 0}));
1327 }
1328 
1329 /*
1330  * Appends a single pad to padMessageBuffer
1331  */
padMessageBufferAppendPad(int page,int row,int step,Pad pad)1332 bool BJumblr::padMessageBufferAppendPad (int page, int row, int step, Pad pad)
1333 {
1334 	PadMessage end = PadMessage (ENDPADMESSAGE);
1335 	PadMessage msg = PadMessage (step, row, pad.level);
1336 
1337 	for (int i = 0; i < MAXSTEPS * MAXSTEPS; ++i)
1338 	{
1339 		if (padMessageBuffer[page][i] != end)
1340 		{
1341 			padMessageBuffer[page][i] = msg;
1342 			if (i < MAXSTEPS * MAXSTEPS - 1) padMessageBuffer[page][i + 1] = end;
1343 			return true;
1344 		}
1345 	}
1346 	return false;
1347 }
1348 
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)1349 LV2_Atom_Forge_Ref BJumblr::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)
1350 {
1351 	const LV2_Atom_Forge_Ref msg = lv2_atom_forge_object (forge, frame, 0, uris.notify_pathEvent);
1352 	if (msg)
1353 	{
1354 		lv2_atom_forge_key (forge, uris.notify_samplePath);
1355 		lv2_atom_forge_path (forge, path, strlen (path) + 1);
1356 		lv2_atom_forge_key (forge, uris.notify_sampleStart);
1357 		lv2_atom_forge_long (forge, start);
1358 		lv2_atom_forge_key (forge, uris.notify_sampleEnd);
1359 		lv2_atom_forge_long (forge, end);
1360 		lv2_atom_forge_key (forge, uris.notify_sampleAmp);
1361 		lv2_atom_forge_float (forge, amp);
1362 		lv2_atom_forge_key (forge, uris.notify_sampleLoop);
1363 		lv2_atom_forge_bool (forge, loop);
1364 	}
1365 	return msg;
1366 }
1367 
notifyPadsToGui()1368 void BJumblr::notifyPadsToGui ()
1369 {
1370 	PadMessage endmsg (ENDPADMESSAGE);
1371 
1372 	for (int p = 0; p < nrPages; ++p)
1373 	{
1374 
1375 		LV2_Atom_Forge_Frame frame;
1376 		lv2_atom_forge_frame_time(&notifyForge, 0);
1377 		lv2_atom_forge_object(&notifyForge, &frame, 0, uris.notify_padEvent);
1378 		lv2_atom_forge_key(&notifyForge, uris.notify_editMode);
1379 		lv2_atom_forge_int(&notifyForge, editMode);
1380 		lv2_atom_forge_key(&notifyForge, uris.notify_padPage);
1381 		lv2_atom_forge_int(&notifyForge, p);
1382 
1383 		if (scheduleNotifyFullPatternToGui[p])
1384 		{
1385 			lv2_atom_forge_key(&notifyForge, uris.notify_padFullPattern);
1386 			lv2_atom_forge_vector(&notifyForge, sizeof(float), uris.atom_Float, MAXSTEPS * MAXSTEPS * sizeof(Pad) / sizeof(float), (void*) &pads[p]);
1387 		}
1388 
1389 		else if (!(endmsg == padMessageBuffer[p][0]))
1390 		{
1391 
1392 			// Get padMessageBuffer size
1393 			int end = 0;
1394 			for (int i = 0; (i < MAXSTEPS * MAXSTEPS) && (!(padMessageBuffer[p][i] == endmsg)); ++i) end = i;
1395 
1396 			lv2_atom_forge_key(&notifyForge, uris.notify_pad);
1397 			lv2_atom_forge_vector(&notifyForge, sizeof(float), uris.atom_Float, sizeof(PadMessage) / sizeof(float) * (end + 1), (void*) &padMessageBuffer[p]);
1398 		}
1399 
1400 		lv2_atom_forge_pop(&notifyForge, &frame);
1401 
1402 		// Empty padMessageBuffer
1403 		padMessageBuffer[p][0] = endmsg;
1404 
1405 		scheduleNotifyFullPatternToGui[p] = false;
1406 	}
1407 
1408 	scheduleNotifyPadsToGui = false;
1409 }
1410 
notifyStatusToGui()1411 void BJumblr::notifyStatusToGui ()
1412 {
1413 	// Prepare forge buffer and initialize atom sequence
1414 	LV2_Atom_Forge_Frame frame;
1415 	lv2_atom_forge_frame_time(&notifyForge, 0);
1416 	lv2_atom_forge_object(&notifyForge, &frame, 0, uris.notify_statusEvent);
1417 	lv2_atom_forge_key(&notifyForge, uris.notify_cursor);
1418 	lv2_atom_forge_float(&notifyForge, cursor);
1419 	float delay = progressionDelay + controllers[MANUAL_PROGRSSION_DELAY];
1420 	lv2_atom_forge_key(&notifyForge, uris.notify_progressionDelay);
1421 	lv2_atom_forge_float(&notifyForge, delay);
1422 	lv2_atom_forge_key(&notifyForge, uris.notify_padFlipped);
1423 	lv2_atom_forge_bool(&notifyForge, patternFlipped);
1424 	lv2_atom_forge_pop(&notifyForge, &frame);
1425 
1426 	scheduleNotifyStatusToGui = false;
1427 }
1428 
notifyWaveformToGui(const int start,const int end)1429 void BJumblr::notifyWaveformToGui (const int start, const int end)
1430 {
1431 	int p1 = (start <= end ? end : WAVEFORMSIZE - 1);
1432 
1433 	// Notify shapeBuffer (position to end)
1434 	LV2_Atom_Forge_Frame frame;
1435 	lv2_atom_forge_frame_time(&notifyForge, 0);
1436 	lv2_atom_forge_object(&notifyForge, &frame, 0, uris.notify_waveformEvent);
1437 	lv2_atom_forge_key(&notifyForge, uris.notify_waveformStart);
1438 	lv2_atom_forge_int(&notifyForge, start);
1439 	lv2_atom_forge_key(&notifyForge, uris.notify_waveformData);
1440 	lv2_atom_forge_vector(&notifyForge, sizeof(float), uris.atom_Float, (uint32_t) (p1 + 1 - start), &waveform[start]);
1441 	lv2_atom_forge_pop(&notifyForge, &frame);
1442 
1443 	// Additional notification if position exceeds end
1444 	if (start > waveformCounter)
1445 	{
1446 		LV2_Atom_Forge_Frame frame;
1447 		lv2_atom_forge_frame_time(&notifyForge, 0);
1448 		lv2_atom_forge_object(&notifyForge, &frame, 0, uris.notify_waveformEvent);
1449 		lv2_atom_forge_key(&notifyForge, uris.notify_waveformStart);
1450 		lv2_atom_forge_int(&notifyForge, 0);
1451 		lv2_atom_forge_key(&notifyForge, uris.notify_waveformData);
1452 		lv2_atom_forge_vector(&notifyForge, sizeof(float), uris.atom_Float, (uint32_t) (end), &waveform[0]);
1453 		lv2_atom_forge_pop(&notifyForge, &frame);
1454 	}
1455 
1456 	scheduleNotifyWaveformToGui = false;
1457 	lastWaveformCounter = end;
1458 }
1459 
notifySchedulePageToGui()1460 void BJumblr::notifySchedulePageToGui ()
1461 {
1462 	LV2_Atom_Forge_Frame frame;
1463 	lv2_atom_forge_frame_time(&notifyForge, 0);
1464 	lv2_atom_forge_object(&notifyForge, &frame, 0, uris.notify_statusEvent);
1465 	lv2_atom_forge_key(&notifyForge, uris.notify_schedulePage);
1466 	lv2_atom_forge_int(&notifyForge, schedulePage);
1467 	lv2_atom_forge_pop(&notifyForge, &frame);
1468 
1469 	scheduleNotifySchedulePageToGui = false;
1470 }
1471 
notifyPlaybackPageToGui()1472 void BJumblr::notifyPlaybackPageToGui ()
1473 {
1474 	LV2_Atom_Forge_Frame frame;
1475 	lv2_atom_forge_frame_time(&notifyForge, 0);
1476 	lv2_atom_forge_object(&notifyForge, &frame, 0, uris.notify_statusEvent);
1477 	lv2_atom_forge_key(&notifyForge, uris.notify_playbackPage);
1478 	lv2_atom_forge_int(&notifyForge, playPage);
1479 	lv2_atom_forge_pop(&notifyForge, &frame);
1480 
1481 	scheduleNotifyPlaybackPageToGui = false;
1482 }
1483 
notifyMidiLearnedToGui()1484 void BJumblr::notifyMidiLearnedToGui ()
1485 {
1486 	uint32_t ml = midiLearned[0] * 0x1000000 + midiLearned[1] * 0x10000 + midiLearned[2] * 0x100 + midiLearned[3];
1487 	LV2_Atom_Forge_Frame frame;
1488 	lv2_atom_forge_frame_time(&notifyForge, 0);
1489 	lv2_atom_forge_object(&notifyForge, &frame, 0, uris.notify_statusEvent);
1490 	lv2_atom_forge_key(&notifyForge, uris.notify_midiLearned);
1491 	lv2_atom_forge_int(&notifyForge, ml);
1492 	lv2_atom_forge_pop(&notifyForge, &frame);
1493 
1494 	scheduleNotifyMidiLearnedToGui = false;
1495 }
1496 
notifyMessageToGui()1497 void BJumblr::notifyMessageToGui()
1498 {
1499 	uint32_t messageNr = message.loadMessage ();
1500 
1501 	// Send notifications
1502 	LV2_Atom_Forge_Frame frame;
1503 	lv2_atom_forge_frame_time(&notifyForge, 0);
1504 	lv2_atom_forge_object(&notifyForge, &frame, 0, uris.notify_messageEvent);
1505 	lv2_atom_forge_key(&notifyForge, uris.notify_message);
1506 	lv2_atom_forge_int(&notifyForge, messageNr);
1507 	lv2_atom_forge_pop(&notifyForge, &frame);
1508 }
1509 
notifySamplePathToGui()1510 void BJumblr::notifySamplePathToGui ()
1511 {
1512 	if (sample && sample->path)
1513 	{
1514 		LV2_Atom_Forge_Frame frame;
1515 		lv2_atom_forge_frame_time(&notifyForge, 0);
1516 
1517 		if (sample && sample->path && (sample->path[0] != 0))
1518 		{
1519 			forgeSamplePath (&notifyForge, &frame, sample->path, sample->start, sample->end, sampleAmp, int32_t (sample->loop));
1520 		}
1521 		else
1522 		{
1523 			const char* path = ".";
1524 			forgeSamplePath (&notifyForge, &frame, path, 0, 0, sampleAmp, false);
1525 		}
1526 
1527 		lv2_atom_forge_pop(&notifyForge, &frame);
1528 	}
1529 
1530 	scheduleNotifySamplePathToGui = false;
1531 }
1532 
notifyStateChanged()1533 void BJumblr::notifyStateChanged()
1534 {
1535 	LV2_Atom_Forge_Frame frame;
1536 	lv2_atom_forge_frame_time(&notifyForge, 0);
1537 	lv2_atom_forge_object(&notifyForge, &frame, 0, uris.state_StateChanged);
1538 	lv2_atom_forge_pop(&notifyForge, &frame);
1539 	scheduleNotifyStateChanged = false;
1540 }
1541 
1542 /*
1543  *
1544  *
1545  ******************************************************************************
1546  *  LV2 specific declarations
1547  */
1548 
instantiate(const LV2_Descriptor * descriptor,double samplerate,const char * bundle_path,const LV2_Feature * const * features)1549 static LV2_Handle instantiate (const LV2_Descriptor* descriptor, double samplerate, const char* bundle_path, const LV2_Feature* const* features)
1550 {
1551 	// New instance
1552 	BJumblr* instance;
1553 	try {instance = new BJumblr(samplerate, features);}
1554 	catch (std::exception& exc)
1555 	{
1556 		fprintf (stderr, "BJumblr.lv2: Plugin instantiation failed. %s\n", exc.what ());
1557 		return NULL;
1558 	}
1559 
1560 	return (LV2_Handle)instance;
1561 }
1562 
connect_port(LV2_Handle instance,uint32_t port,void * data)1563 static void connect_port (LV2_Handle instance, uint32_t port, void *data)
1564 {
1565 	BJumblr* inst = (BJumblr*) instance;
1566 	inst->connect_port (port, data);
1567 }
1568 
activate(LV2_Handle instance)1569 static void activate (LV2_Handle instance)
1570 {
1571 	BJumblr* inst = (BJumblr*) instance;
1572 	if (inst) inst->activate();
1573 }
1574 
run(LV2_Handle instance,uint32_t n_samples)1575 static void run (LV2_Handle instance, uint32_t n_samples)
1576 {
1577 	BJumblr* inst = (BJumblr*) instance;
1578 	if (inst) inst->run (n_samples);
1579 }
1580 
deactivate(LV2_Handle instance)1581 static void deactivate (LV2_Handle instance)
1582 {
1583 	BJumblr* inst = (BJumblr*) instance;
1584 	if (inst) inst->deactivate();
1585 }
1586 
state_save(LV2_Handle instance,LV2_State_Store_Function store,LV2_State_Handle handle,uint32_t flags,const LV2_Feature * const * features)1587 static LV2_State_Status state_save(LV2_Handle instance, LV2_State_Store_Function store, LV2_State_Handle handle, uint32_t flags,
1588            const LV2_Feature* const* features)
1589 {
1590 	BJumblr* inst = (BJumblr*)instance;
1591 	if (!inst) return LV2_STATE_SUCCESS;
1592 
1593 	return inst->state_save (store, handle, flags, features);
1594 }
1595 
state_restore(LV2_Handle instance,LV2_State_Retrieve_Function retrieve,LV2_State_Handle handle,uint32_t flags,const LV2_Feature * const * features)1596 static LV2_State_Status state_restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve, LV2_State_Handle handle, uint32_t flags,
1597            const LV2_Feature* const* features)
1598 {
1599 	BJumblr* inst = (BJumblr*)instance;
1600 	if (!inst) return LV2_STATE_SUCCESS;
1601 
1602 	return inst->state_restore (retrieve, handle, flags, features);
1603 }
1604 
work(LV2_Handle instance,LV2_Worker_Respond_Function respond,LV2_Worker_Respond_Handle handle,uint32_t size,const void * data)1605 static LV2_Worker_Status work (LV2_Handle instance, LV2_Worker_Respond_Function respond, LV2_Worker_Respond_Handle handle,
1606 	uint32_t size, const void* data)
1607 {
1608 	BJumblr* inst = (BJumblr*)instance;
1609 	if (!inst) return LV2_WORKER_SUCCESS;
1610 
1611 	return inst->work (respond, handle, size, data);
1612 }
1613 
work_response(LV2_Handle instance,uint32_t size,const void * data)1614 static LV2_Worker_Status work_response (LV2_Handle instance, uint32_t size,  const void* data)
1615 {
1616 	BJumblr* inst = (BJumblr*)instance;
1617 	if (!inst) return LV2_WORKER_SUCCESS;
1618 
1619 	return inst->work_response (size, data);
1620 }
1621 
cleanup(LV2_Handle instance)1622 static void cleanup (LV2_Handle instance)
1623 {
1624 	BJumblr* inst = (BJumblr*) instance;
1625 	if (inst) delete inst;
1626 }
1627 
1628 
extension_data(const char * uri)1629 static const void* extension_data(const char* uri)
1630 {
1631   static const LV2_State_Interface  state  = {state_save, state_restore};
1632   static const LV2_Worker_Interface worker = {work, work_response, NULL};
1633   if (!strcmp(uri, LV2_STATE__interface)) return &state;
1634   if (!strcmp(uri, LV2_WORKER__interface)) return &worker;
1635   return NULL;
1636 }
1637 
1638 
1639 static const LV2_Descriptor descriptor =
1640 {
1641 		BJUMBLR_URI,
1642 		instantiate,
1643 		connect_port,
1644 		activate,
1645 		run,
1646 		deactivate,
1647 		cleanup,
1648 		extension_data
1649 };
1650 
1651 // LV2 Symbol Export
lv2_descriptor(uint32_t index)1652 LV2_SYMBOL_EXPORT const LV2_Descriptor* lv2_descriptor (uint32_t index)
1653 {
1654 	switch (index)
1655 	{
1656 	case 0: return &descriptor;
1657 	default: return NULL;
1658 	}
1659 }
1660 
1661 /* End of LV2 specific declarations
1662  *
1663  * *****************************************************************************
1664  *
1665  *
1666  */
1667