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