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 (¬ifyForge, 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(¬ifyForge, (uint8_t*) notifyPort, space);
379 lv2_atom_forge_sequence_head(¬ifyForge, ¬ifyFrame, 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(¬ifyForge, ¬ifyFrame);
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(¬ifyForge, 0);
1377 lv2_atom_forge_object(¬ifyForge, &frame, 0, uris.notify_padEvent);
1378 lv2_atom_forge_key(¬ifyForge, uris.notify_editMode);
1379 lv2_atom_forge_int(¬ifyForge, editMode);
1380 lv2_atom_forge_key(¬ifyForge, uris.notify_padPage);
1381 lv2_atom_forge_int(¬ifyForge, p);
1382
1383 if (scheduleNotifyFullPatternToGui[p])
1384 {
1385 lv2_atom_forge_key(¬ifyForge, uris.notify_padFullPattern);
1386 lv2_atom_forge_vector(¬ifyForge, 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(¬ifyForge, uris.notify_pad);
1397 lv2_atom_forge_vector(¬ifyForge, sizeof(float), uris.atom_Float, sizeof(PadMessage) / sizeof(float) * (end + 1), (void*) &padMessageBuffer[p]);
1398 }
1399
1400 lv2_atom_forge_pop(¬ifyForge, &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(¬ifyForge, 0);
1416 lv2_atom_forge_object(¬ifyForge, &frame, 0, uris.notify_statusEvent);
1417 lv2_atom_forge_key(¬ifyForge, uris.notify_cursor);
1418 lv2_atom_forge_float(¬ifyForge, cursor);
1419 float delay = progressionDelay + controllers[MANUAL_PROGRSSION_DELAY];
1420 lv2_atom_forge_key(¬ifyForge, uris.notify_progressionDelay);
1421 lv2_atom_forge_float(¬ifyForge, delay);
1422 lv2_atom_forge_key(¬ifyForge, uris.notify_padFlipped);
1423 lv2_atom_forge_bool(¬ifyForge, patternFlipped);
1424 lv2_atom_forge_pop(¬ifyForge, &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(¬ifyForge, 0);
1436 lv2_atom_forge_object(¬ifyForge, &frame, 0, uris.notify_waveformEvent);
1437 lv2_atom_forge_key(¬ifyForge, uris.notify_waveformStart);
1438 lv2_atom_forge_int(¬ifyForge, start);
1439 lv2_atom_forge_key(¬ifyForge, uris.notify_waveformData);
1440 lv2_atom_forge_vector(¬ifyForge, sizeof(float), uris.atom_Float, (uint32_t) (p1 + 1 - start), &waveform[start]);
1441 lv2_atom_forge_pop(¬ifyForge, &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(¬ifyForge, 0);
1448 lv2_atom_forge_object(¬ifyForge, &frame, 0, uris.notify_waveformEvent);
1449 lv2_atom_forge_key(¬ifyForge, uris.notify_waveformStart);
1450 lv2_atom_forge_int(¬ifyForge, 0);
1451 lv2_atom_forge_key(¬ifyForge, uris.notify_waveformData);
1452 lv2_atom_forge_vector(¬ifyForge, sizeof(float), uris.atom_Float, (uint32_t) (end), &waveform[0]);
1453 lv2_atom_forge_pop(¬ifyForge, &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(¬ifyForge, 0);
1464 lv2_atom_forge_object(¬ifyForge, &frame, 0, uris.notify_statusEvent);
1465 lv2_atom_forge_key(¬ifyForge, uris.notify_schedulePage);
1466 lv2_atom_forge_int(¬ifyForge, schedulePage);
1467 lv2_atom_forge_pop(¬ifyForge, &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(¬ifyForge, 0);
1476 lv2_atom_forge_object(¬ifyForge, &frame, 0, uris.notify_statusEvent);
1477 lv2_atom_forge_key(¬ifyForge, uris.notify_playbackPage);
1478 lv2_atom_forge_int(¬ifyForge, playPage);
1479 lv2_atom_forge_pop(¬ifyForge, &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(¬ifyForge, 0);
1489 lv2_atom_forge_object(¬ifyForge, &frame, 0, uris.notify_statusEvent);
1490 lv2_atom_forge_key(¬ifyForge, uris.notify_midiLearned);
1491 lv2_atom_forge_int(¬ifyForge, ml);
1492 lv2_atom_forge_pop(¬ifyForge, &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(¬ifyForge, 0);
1504 lv2_atom_forge_object(¬ifyForge, &frame, 0, uris.notify_messageEvent);
1505 lv2_atom_forge_key(¬ifyForge, uris.notify_message);
1506 lv2_atom_forge_int(¬ifyForge, messageNr);
1507 lv2_atom_forge_pop(¬ifyForge, &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(¬ifyForge, 0);
1516
1517 if (sample && sample->path && (sample->path[0] != 0))
1518 {
1519 forgeSamplePath (¬ifyForge, &frame, sample->path, sample->start, sample->end, sampleAmp, int32_t (sample->loop));
1520 }
1521 else
1522 {
1523 const char* path = ".";
1524 forgeSamplePath (¬ifyForge, &frame, path, 0, 0, sampleAmp, false);
1525 }
1526
1527 lv2_atom_forge_pop(¬ifyForge, &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(¬ifyForge, 0);
1537 lv2_atom_forge_object(¬ifyForge, &frame, 0, uris.state_StateChanged);
1538 lv2_atom_forge_pop(¬ifyForge, &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