1
2 /// lv2 core / ui includes
3 #include "lv2/lv2plug.in/ns/lv2core/lv2.h"
4 #include "lv2/lv2plug.in/ns/extensions/ui/ui.h"
5
6
7 #include "shared.hxx"
8
9 #include "ui/fabla2_ui.hxx"
10 #include "ui/pad.hxx"
11 #include "ui/fader.hxx"
12 #include "ui/mixstrip.hxx"
13 #include "ui/volume.hxx"
14
15 #include "plotter.hxx"
16
fabla2_instantiate(const struct LV2UI_Descriptor * descriptor,const char * plugin_uri,const char * bundle_path,LV2UI_Write_Function write_function,LV2UI_Controller controller,LV2UI_Widget * widget,const LV2_Feature * const * features)17 static LV2UI_Handle fabla2_instantiate(const struct LV2UI_Descriptor * descriptor,
18 const char * plugin_uri,
19 const char * bundle_path,
20 LV2UI_Write_Function write_function,
21 LV2UI_Controller controller,
22 LV2UI_Widget * widget,
23 const LV2_Feature * const * features)
24 {
25 if (strcmp(plugin_uri, FABLA2_URI) != 0) {
26 fprintf(stderr, "FABLA2_UI_URI error: this GUI does not support plugin with URI %s\n", plugin_uri);
27 return NULL;
28 }
29
30 LV2_URID_Map* map = 0;
31 LV2UI_Resize* resize = 0;
32 PuglNativeWindow parentXwindow = 0;
33
34 for (int i = 0; features[i]; ++i) {
35 //printf("Feature %s\n", features[i]->URI );
36 if (!strcmp(features[i]->URI, LV2_UI__parent)) {
37 parentXwindow = (PuglNativeWindow)features[i]->data;
38 } else if (!strcmp(features[i]->URI, LV2_UI__resize)) {
39 resize = (LV2UI_Resize*)features[i]->data;
40 } else if (!strcmp(features[i]->URI, LV2_URID__map)) {
41 map = (LV2_URID_Map*)features[i]->data;
42 }
43 }
44
45 // ensure we have the LV2 requirements
46 if( !map || !write_function || !controller || !parentXwindow ) {
47 return 0;
48 }
49
50 Fabla2UI* t = new Fabla2UI( parentXwindow );
51
52 t->map = map;
53 t->write_function = write_function;
54 t->controller = controller;
55
56 mapUri( &t->uris, map );
57 lv2_atom_forge_init( &t->forge, map );
58
59 *widget = (void*)t->getNativeHandle();
60
61 if (resize) {
62 resize->ui_resize(resize->handle, t->w(), t->h() );
63 } else {
64 printf("Your host does not support LV2:Resize, please ask the developers to implement it!\n");
65 }
66
67 t->init();
68
69 return t;
70 }
71
fabla2_cleanup(LV2UI_Handle ui)72 static void fabla2_cleanup(LV2UI_Handle ui)
73 {
74 delete (Fabla2UI*)ui;
75 }
76
fabla2_port_event(LV2UI_Handle handle,uint32_t port_index,uint32_t buffer_size,uint32_t format,const void * buffer)77 static void fabla2_port_event(LV2UI_Handle handle,
78 uint32_t port_index,
79 uint32_t buffer_size,
80 uint32_t format,
81 const void * buffer)
82 {
83 Fabla2UI* ui = (Fabla2UI*)handle;
84
85 if(port_index == Fabla2::TRANSPORT_PLAY)
86 printf("transport UI");
87
88 /* Check type of data received
89 * - format == 0: Control port event (float)
90 * - format > 0: Message (atom)
91 */
92
93 if (format == ui->uris.atom_eventTransfer) {
94 const LV2_Atom* atom = (const LV2_Atom*)buffer;
95
96 const LV2_Atom_Object* obj = (const LV2_Atom_Object*)atom;
97
98 int padStop = (obj->body.otype == ui->uris.fabla2_PadStop);
99 int padPlay = 0;
100 if(obj->body.otype == ui->uris.fabla2_PadPlay)
101 padPlay = 1;
102 if (padPlay || padStop) {
103 //printf("UI: Fabla Pad Event: play %d, stop %d\n", padPlay, padStop);
104 const LV2_Atom* bank = NULL;
105 const LV2_Atom* pad = NULL;
106 const LV2_Atom* lay = NULL;
107 const LV2_Atom* vel = NULL;
108 const int n_props = lv2_atom_object_get( obj,
109 ui->uris.fabla2_bank , &bank,
110 ui->uris.fabla2_pad , &pad,
111 ui->uris.fabla2_layer , &lay,
112 ui->uris.fabla2_velocity, &vel,
113 NULL);
114
115 if ( !bank || bank->type != ui->uris.atom_Int ||
116 !pad || pad->type != ui->uris.atom_Int ||
117 !lay || lay->type != ui->uris.atom_Int ) {
118 //printf("Fabla2-UI::port_event() error: Corrupt state message\n");
119 return;
120 } else {
121 const int32_t b = ((const LV2_Atom_Int*)bank)->body;
122 const int32_t p = ((const LV2_Atom_Int*)pad)->body;
123 int32_t layer = ((const LV2_Atom_Int*)lay)->body;
124
125 int32_t v = 127;
126 if( vel )
127 v = ((const LV2_Atom_Int*)vel)->body;
128
129 // Trying to hack the UI pad play feedback issue
130 // - now MIDI notes won't show the pads :/
131 //if(ui->redrawRev != ui->redrawRevDone) {
132 {
133 //printf("UI pad event bank: %i, pad: %i, layer: %i, velo: %d, noteOn: %d\n", b, p, layer, v, padPlay);
134 ui->padEvent( b, p, layer, padPlay, v );
135 ui->redrawRevDone = ui->redrawRev;
136 }
137 }
138 } else if( obj->body.otype == ui->uris.fabla2_SampleAudioData ) {
139 const LV2_Atom* data_val = NULL;
140 const int n_props = lv2_atom_object_get( obj,
141 ui->uris.fabla2_audioData, &data_val, NULL);
142
143 if ( !data_val || data_val->type != ui->uris.atom_Vector) {
144 // Object does not have the required properties with correct types
145 fprintf(stderr, "Fabla2 UI error: Corrupt audio message\n");
146 return;
147 }
148
149 // Get the values we need from the body of the property value atoms
150 const LV2_Atom_Vector* vec = (const LV2_Atom_Vector*)data_val;
151 if (vec->body.child_type != ui->uris.atom_Float) {
152 fprintf(stderr, "Fabla2 UI error: Corrupt audio message, incorrect element type!\n");
153 return; // Vector has incorrect element type
154 }
155
156 // Number of elements = (total size - header size) / element size
157 const size_t n_elem = ((data_val->size - sizeof(LV2_Atom_Vector_Body))
158 / sizeof(float));
159
160 // Float elements immediately follow the vector body header
161 const float* data = (const float*)(&vec->body + 1);
162
163 //printf("Fabla UI got %i elements for waveform data\n", n_elem );
164
165 //Plotter::plot( "waveformArrived.dat", FABLA2_UI_WAVEFORM_PX, data );
166 ui->waveform->show( FABLA2_UI_WAVEFORM_PX, data );
167 ui->redraw();
168 } else if( obj->body.otype == ui->uris.fabla2_dbMeter ) {
169 const LV2_Atom* m = 0;
170 const LV2_Atom* v = 0;
171 const int n_props = lv2_atom_object_get( obj,
172 ui->uris.fabla2_dbMeter, &m,
173 ui->uris.fabla2_value, &v, NULL);
174 if( m && v )
175 {
176 const int32_t meter = ((const LV2_Atom_Int*)m)->body;
177 const float value = ((const LV2_Atom_Float*)v)->body;
178 float lin = pow(10, value/20.f);
179 ui->masterDB->value(lin);
180 }
181 } else if( obj->body.otype == ui->uris.fabla2_AuxBus ) {
182 const LV2_Atom* a = 0;
183 const LV2_Atom* v = 0;
184 const int n_props = lv2_atom_object_get( obj,
185 ui->uris.fabla2_auxBusNumber, &a,
186 ui->uris.fabla2_value, &v, NULL);
187 if( a && v ) {
188 const int32_t i = ((const LV2_Atom_Int*)a)->body;
189 const float val = ((const LV2_Atom_Float*)v)->body;
190 // live view aux faders (big)
191 ui->auxFaders[i]->value(val);
192 // master pane, smaller ones
193 switch(i) {
194 case 0: ui->masterAuxFader1->value(val); break;
195 case 1: ui->masterAuxFader2->value(val); break;
196 case 2: ui->masterAuxFader3->value(val); break;
197 case 3: ui->masterAuxFader4->value(val); break;
198 default: break;
199 }
200 ui->redraw();
201 }
202
203 } else if( obj->body.otype == ui->uris.fabla2_PadRefreshLayers ) {
204 const LV2_Atom* bank = 0;
205 const LV2_Atom* pad = 0;
206 const LV2_Atom* lay = 0;
207 const LV2_Atom* name = 0;
208 const int n_props = lv2_atom_object_get( obj,
209 ui->uris.fabla2_bank , &bank,
210 ui->uris.fabla2_pad , &pad,
211 ui->uris.fabla2_layer , &lay,
212 ui->uris.fabla2_name , &name,
213 NULL);
214
215 if (n_props != 4 ||
216 bank->type != ui->uris.atom_Int ||
217 pad->type != ui->uris.atom_Int ||
218 lay->type != ui->uris.atom_Int )
219 //name->type != ui->uris.atom_String )
220 {
221 printf("Fabla2::port_event() error: Corrupt state message\n");
222 return;
223 } else {
224 const int32_t b = ((const LV2_Atom_Int*)bank)->body;
225 const int32_t p = ((const LV2_Atom_Int*)pad)->body;
226 int32_t layer = ((const LV2_Atom_Int*)lay)->body;
227 std::string n = (const char*) LV2_ATOM_BODY_CONST( name );
228
229 //printf("UI got PadRefresh: layer = %i, name = %s\n", layer, n.c_str() );
230
231 if( layer == 0 ) { // starting from start: reset
232 ui->layers->clear();
233 }
234 ui->layers->addItem( n );
235 // not needed, split to "padHasSample" message.
236 //ui->pads[p]->loaded( true );
237 ui->mixStrip[p]->label( n.c_str() );
238 }
239 } else if( obj->body.otype == ui->uris.fabla2_PadHasSample ) {
240 const LV2_Atom* bank = 0;
241 const LV2_Atom* pad = 0;
242 const LV2_Atom* loaded = 0;
243 const int n_props = lv2_atom_object_get( obj,
244 ui->uris.fabla2_bank , &bank,
245 ui->uris.fabla2_pad , &pad,
246 ui->uris.fabla2_PadHasSample, &loaded,
247 NULL );
248 if(n_props != 3)
249 return;
250 const int32_t b = ((const LV2_Atom_Int*)bank)->body;
251 const int32_t p = ((const LV2_Atom_Int*)pad)->body;
252 const int32_t l = ((const LV2_Atom_Int*)loaded)->body;
253 ui->pads[p]->loaded( l );
254 ui->redraw();
255 } else if( obj->body.otype == ui->uris.fabla2_UiPadsState ) {
256 const LV2_Atom* aBank = 0;
257 const LV2_Atom* aPad = 0;
258 //const LV2_Atom* aName = 0;
259 const LV2_Atom* aVol = 0;
260 const LV2_Atom* aLoaded = 0;
261 const LV2_Atom* aux1 = 0;
262 const LV2_Atom* aux2 = 0;
263 const LV2_Atom* aux3 = 0;
264 const LV2_Atom* aux4 = 0;
265
266 const int n_props = lv2_atom_object_get( obj,
267 ui->uris.fabla2_bank , &aBank,
268 ui->uris.fabla2_pad , &aPad,
269 ui->uris.fabla2_PadVolume , &aVol,
270 ui->uris.fabla2_value , &aLoaded,
271 ui->uris.fabla2_PadAuxBus1 , &aux1,
272 ui->uris.fabla2_PadAuxBus2 , &aux2,
273 ui->uris.fabla2_PadAuxBus3 , &aux3,
274 ui->uris.fabla2_PadAuxBus4 , &aux4,
275 0 );
276
277 if( n_props == 8 ) {
278 int bank = ((const LV2_Atom_Int*)aBank)->body;
279 int pad = ((const LV2_Atom_Int*)aPad )->body;
280 if( bank == ui->currentBank ) {
281 float vol= ((const LV2_Atom_Float*)aVol)->body;
282 float a1 = ((const LV2_Atom_Float*)aux1)->body;
283 float a2 = ((const LV2_Atom_Float*)aux2)->body;
284 float a3 = ((const LV2_Atom_Float*)aux3)->body;
285 float a4 = ((const LV2_Atom_Float*)aux4)->body;
286 int load = ((const LV2_Atom_Int*)aLoaded)->body;
287
288 if( ui->currentPad == pad )
289 ui->padVolume->value( vol );
290
291 ui->padFaders[pad]->value( vol );
292
293 ui->auxDials[16*0+pad]->value( a1 );
294 ui->auxDials[16*1+pad]->value( a2 );
295 ui->auxDials[16*2+pad]->value( a3 );
296 ui->auxDials[16*3+pad]->value( a4 );
297 }
298 }
299 } else if( obj->body.otype == ui->uris.fabla2_ReplyUiSampleState ) {
300 // atoms to represent the data
301 const LV2_Atom* aPad = 0;
302
303 const LV2_Atom* aPadVolume = 0;
304 const LV2_Atom* aPadAux1 = 0;
305 const LV2_Atom* aPadAux2 = 0;
306 const LV2_Atom* aPadAux3 = 0;
307 const LV2_Atom* aPadAux4 = 0;
308
309 const LV2_Atom* aPadOffGrp = 0;
310 const LV2_Atom* aPadMuteGrp = 0;
311 const LV2_Atom* aPadTrigMode= 0;
312 const LV2_Atom* aPadSwtchSys= 0;
313
314 const LV2_Atom* aName = 0;
315
316 const LV2_Atom* aGain = 0;
317 const LV2_Atom* aPan = 0;
318
319 const LV2_Atom* aPitch = 0;
320 const LV2_Atom* aTime = 0;
321
322 const LV2_Atom* aStartPoint = 0;
323 const LV2_Atom* aEndPoint = 0;
324
325 const LV2_Atom* aVelLow = 0;
326 const LV2_Atom* aVelHigh = 0;
327
328 const LV2_Atom* aFiltType = 0;
329 const LV2_Atom* aFiltFreq = 0;
330 const LV2_Atom* aFiltReso = 0;
331
332 const LV2_Atom* aAttack = 0;
333 const LV2_Atom* aDecay = 0;
334 const LV2_Atom* aSustain = 0;
335 const LV2_Atom* aRelease = 0;
336
337 const int n_props = lv2_atom_object_get( obj,
338 ui->uris.fabla2_pad , &aPad,
339 ui->uris.fabla2_PadVolume , &aPadVolume,
340 ui->uris.fabla2_PadAuxBus1 , &aPadAux1,
341 ui->uris.fabla2_PadAuxBus2 , &aPadAux2,
342 ui->uris.fabla2_PadAuxBus3 , &aPadAux3,
343 ui->uris.fabla2_PadAuxBus4 , &aPadAux4,
344 ui->uris.fabla2_PadOffGroup , &aPadOffGrp,
345 ui->uris.fabla2_PadMuteGroup , &aPadMuteGrp,
346 ui->uris.fabla2_PadTriggerMode , &aPadTrigMode,
347 ui->uris.fabla2_PadSwitchType , &aPadSwtchSys,
348 ui->uris.fabla2_name , &aName,
349 ui->uris.fabla2_SampleGain , &aGain,
350 ui->uris.fabla2_SamplePitch , &aPitch,
351 ui->uris.fabla2_SampleTime , &aTime,
352 ui->uris.fabla2_SampleStartPoint , &aStartPoint,
353 ui->uris.fabla2_SampleEndPoint , &aEndPoint,
354 ui->uris.fabla2_SampleVelStartPnt , &aVelLow,
355 ui->uris.fabla2_SampleVelEndPnt , &aVelHigh,
356 ui->uris.fabla2_SamplePan , &aPan,
357 ui->uris.fabla2_SampleFilterType , &aFiltType,
358 ui->uris.fabla2_SampleFilterFrequency,&aFiltFreq,
359 ui->uris.fabla2_SampleFilterResonance,&aFiltReso,
360
361 ui->uris.fabla2_SampleAdsrAttack ,&aAttack,
362 ui->uris.fabla2_SampleAdsrDecay ,&aDecay,
363 ui->uris.fabla2_SampleAdsrSustain ,&aSustain,
364 ui->uris.fabla2_SampleAdsrRelease ,&aRelease,
365 0 );
366
367 if( n_props == 24 ) {
368 float tmp = ((const LV2_Atom_Float*)aPadVolume)->body;
369 ui->padVolume ->value( tmp );
370
371 ui->send1->value( ((const LV2_Atom_Float*)aPadAux1)->body );
372 ui->send2->value( ((const LV2_Atom_Float*)aPadAux2)->body );
373 ui->send3->value( ((const LV2_Atom_Float*)aPadAux3)->body );
374 ui->send4->value( ((const LV2_Atom_Float*)aPadAux4)->body );
375
376 int mute = ((const LV2_Atom_Int*)aPadMuteGrp)->body;
377 int off = ((const LV2_Atom_Int*)aPadOffGrp)->body;
378 int trig = ((const LV2_Atom_Int*)aPadTrigMode)->body;
379 int swtc = ((const LV2_Atom_Int*)aPadSwtchSys)->body;
380 //printf("UI numbers: %i, %i, %i, %i\n", mute, off, trig, swtc );
381
382 ui->muteGroup ->value( mute );
383 ui->offGroup ->value( off );
384 ui->triggerMode ->value( trig );
385 ui->switchType ->value( swtc );
386
387 // sample string up top of waveform
388 const char* n = (const char*) LV2_ATOM_BODY_CONST( aName );
389 ui->sampleName->label( n );
390
391 ui->sampleGain ->value( ((const LV2_Atom_Float*)aGain)->body );
392 ui->samplePan ->value( ((const LV2_Atom_Float*)aPan )->body );
393 ui->samplePitch ->value( ((const LV2_Atom_Float*)aPitch)->body);
394
395 ui->sampleStartPoint->value( ((const LV2_Atom_Float*)aStartPoint)->body);
396 ui->waveform->setStartPoint( ((const LV2_Atom_Float*)aStartPoint)->body);
397
398 ui->velocityStartPoint->value(((const LV2_Atom_Float*)aVelLow)->body );
399 ui->velocityEndPoint ->value(((const LV2_Atom_Float*)aVelHigh)->body );
400
401 ui->filterType ->value( ((const LV2_Atom_Float*)aFiltType)->body);
402 ui->filterFrequency ->value( ((const LV2_Atom_Float*)aFiltFreq)->body);
403 ui->filterResonance ->value( ((const LV2_Atom_Float*)aFiltReso)->body);
404
405 ui->adsrA ->value( ((const LV2_Atom_Float*)aAttack)->body);
406 ui->adsrD ->value( ((const LV2_Atom_Float*)aDecay)->body);
407 ui->adsrS ->value( ((const LV2_Atom_Float*)aSustain)->body);
408 ui->adsrR ->value( ((const LV2_Atom_Float*)aRelease)->body);
409 } else {
410 // sample-state event was written to the UI was not complete. If we have
411 // a pad, "unload" it in the UI. Blank state
412 ui->blankSampleState();
413 }
414 ui->redraw();
415 } else {
416 fprintf(stderr, "Unknown message type.\n");
417 }
418 }
419 }
420
fabla2_idle(LV2UI_Handle handle)421 static int fabla2_idle(LV2UI_Handle handle)
422 {
423 Fabla2UI* ui = (Fabla2UI*)handle;
424 ui->idle();
425 ui->handleMaschine();
426 return 0;
427 }
428
429 static const LV2UI_Idle_Interface idle_iface = { fabla2_idle };
430
431 static const void*
fabla2_extension_data(const char * uri)432 fabla2_extension_data(const char* uri)
433 {
434 if (!strcmp(uri, LV2_UI__idleInterface)) {
435 return &idle_iface;
436 }
437 return NULL;
438 }
439
440 static const LV2UI_Descriptor descriptor = {
441 FABLA2_UI_URI,
442 fabla2_instantiate,
443 fabla2_cleanup,
444 fabla2_port_event,
445 fabla2_extension_data
446 };
447
lv2ui_descriptor(uint32_t index)448 LV2_SYMBOL_EXPORT const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index)
449 {
450 switch (index) {
451 case 0:
452 return &descriptor;
453 default:
454 return NULL;
455 }
456 }
457
458