1 
2 #include "fabla2_ui.hxx"
3 
4 #include "utils.hxx"
5 #include "theme.hxx"
6 
7 #include "pad.hxx"
8 #include "fader.hxx"
9 #include "volume.hxx"
10 #include "mixstrip.hxx"
11 
12 // include the data files for the header images
13 #include "header_fabla.c"
14 #include "header_openav.c"
15 
16 #include <sstream>
17 
18 #include "../shared.hxx"
19 #include "../lv2_messaging.hxx"
20 #include "../dsp/pad.hxx"
21 
22 // hack to get access to PUGL types
23 // perhaps include AVTK wrapper in future?
24 #include "avtk/avtk/pugl/event.h"
25 
26 // implementation of LV2 Atom writing
27 #include "helper.hxx"
28 
29 // for file browsing
30 extern "C" {
31 #include "sofd/libsofd.h"
32 }
33 
34 // AVTK themes
35 #include "themes.hxx"
36 
37 // The default OSC port used by Maschine.rs userspace driver
38 #define PORT_NUM 42435
39 
fabla2_ui_seqStepValueCB(Avtk::Widget * w,void * ud)40 static void fabla2_ui_seqStepValueCB( Avtk::Widget* w, void* ud )
41 {
42 	((Fabla2UI*)ud)->seqStepValueCB(w);
43 }
44 
45 enum FABLA2_THEMES {
46 	THEME_BLUE = 0,
47 	THEME_ORANGE,
48 	THEME_GREEN,
49 	THEME_YELLOW,
50 	THEME_BLUE_2,
51 	THEME_RED,
52 };
53 
Fabla2UI(PuglNativeWindow parent)54 Fabla2UI::Fabla2UI( PuglNativeWindow parent ):
55 	Avtk::UI( 856, 322, parent ),
56 	currentBank( 0 ),
57 	currentPad( 0 ),
58 	currentLayer(0),
59 	followPad( true )
60 {
61 	themes.push_back( new Avtk::Theme( this, AVTK_ORANGE ) );
62 	themes.push_back( new Avtk::Theme( this, AVTK_GREEN ) );
63 	themes.push_back( new Avtk::Theme( this, AVTK_YELLOW ) );
64 	themes.push_back( new Avtk::Theme( this, AVTK_BLUE ) );
65 	themes.push_back( new Avtk::Theme( this, AVTK_RED ) );
66 	themes.push_back( new Avtk::Theme( this, AVTK_WHITE ) );
67 
68 	Avtk::Image* headerImage = 0;
69 	headerImage = new Avtk::Image( this, 0, 0, 200, 36, "Header Image - Fabla" );
70 	headerImage->load( header_fabla.pixel_data );
71 	headerImage = new Avtk::Image( this, w()-130, 0, 130, 36, "Header Image - OpenAV" );
72 	headerImage->load( header_openav.pixel_data );
73 
74 	int s = 32;
75 	bankBtns[0] = new Avtk::Button( this, 5      , 43    , s, s, "A" );
76 	bankBtns[1] = new Avtk::Button( this, 5 + s+6, 43    , s, s, "B" );
77 	bankBtns[1]->theme( theme( THEME_ORANGE ) );
78 	bankBtns[2] = new Avtk::Button( this, 5      , 43+s+6, s, s, "C" );
79 	bankBtns[2]->theme( theme( THEME_GREEN ) );
80 	bankBtns[3] = new Avtk::Button( this, 5 + s+6, 43+s+6, s, s, "D" );
81 	bankBtns[3]->theme( theme( THEME_YELLOW ) );
82 
83 	for(int i = 0; i < 4; i++)
84 		bankBtns[i]->clickMode( Avtk::Widget::CLICK_TOGGLE );
85 
86 
87 	int wx = 5;
88 	int wy = 43+(s+6)*2; // bottom of bank buttons
89 	Avtk::Widget* waste = 0;
90 
91 	panicButton = new Avtk::Button( this, wx, wy, s * 2 + 6, 32,  "PANIC" );
92 	panicButton->clickMode( Avtk::Widget::CLICK_MOMENTARY );
93 	panicButton->theme( theme(THEME_RED) );
94 	wy += 32 + 10;
95 
96 	waste = new Avtk::Box( this, wx, wy, 70, 74,  "Views" );
97 	waste->clickMode( Widget::CLICK_NONE );
98 	waste->value(0);
99 	wy += 20;
100 
101 	uiViewGroup = new Avtk::List( this, wx+2, wy, 70-4, 78, "UiViewGroup");
102 	uiViewGroup->spacing( 2 );
103 	uiViewGroup->mode      ( Group::WIDTH_EQUAL );
104 	uiViewGroup->valueMode ( Group::VALUE_SINGLE_CHILD );
105 
106 	padsView = new Avtk::ListItem( this, wx, 10, 70, 16,  "Pads" );
107 	padsView->clickMode( Avtk::Widget::CLICK_TOGGLE );
108 	padsView->value( 1 );
109 
110 	liveView = new Avtk::ListItem( this, wx, 10, 70, 16,  "Live" );
111 	liveView->clickMode( Avtk::Widget::CLICK_TOGGLE );
112 
113 	fileView = new Avtk::ListItem( this, wx, 10, 70, 16,  "File" );
114 	fileView->clickMode( Avtk::Widget::CLICK_TOGGLE );
115 
116 	seqView = new Avtk::ListItem( this, wx, 10, 70, 16,  "Seq" );
117 	seqView->clickMode( Avtk::Widget::CLICK_TOGGLE );
118 
119 	uiViewGroup->end();
120 	wy += 78;
121 
122 	followPadBtn = new Avtk::Button( this, wx, wy, 70, 20,  "Follow" );
123 	followPadBtn->clickMode( Avtk::Widget::CLICK_TOGGLE );
124 	wy += 26;
125 
126 	recordOverPad = new Avtk::Button( this, wx, wy, 70, 30,  "REC" );
127 	recordOverPad->theme( theme(THEME_RED) );
128 	recordOverPad->clickMode( Avtk::Widget::CLICK_TOGGLE );
129 
130 
131 	waveformGroup = new Avtk::Group( this, 355, 42, FABLA2_UI_WAVEFORM_PX, 113, "WaveformGroup");
132 	waveform = new Avtk::Waveform( this, 355, 42, FABLA2_UI_WAVEFORM_PX, 113, "Waveform" );
133 
134 	/// waveform overlays
135 	int waveX = 355;
136 	int waveY = 42;
137 	int waveTW = 120;
138 	sampleName = new Avtk::Text( this, waveX + 8, waveY + 100, waveTW, 14, "-" );
139 
140 	waveformGroup->end();
141 
142 
143 
144 	/// sample edit view =========================================================
145 	int colWidth = 90;
146 	const int spacer = 4;
147 	wx = 355;
148 	wy = 161;
149 	int divider = 35;
150 	sampleControlGroup = new Avtk::Group( this, wx, wy, FABLA2_UI_WAVEFORM_PX, 260, "SampleControlGroup");
151 
152 	/// layers
153 	waste = new Avtk::Box( this, wx, wy, colWidth, 146,  "Layers" );
154 	waste->clickMode( Widget::CLICK_NONE );
155 	layers    = new Avtk::List( this, wx, wy+18, colWidth, 204-18, "LayersList" );
156 	layers->end();
157 
158 	/// next column
159 	wx += colWidth + spacer;
160 	wy = 161;
161 
162 	/// Sample triggering options
163 	waste = new Avtk::Box( this, wx, wy, colWidth, 50,  "Mt-Of-Trg-Swt" );
164 	waste->clickMode( Widget::CLICK_NONE );
165 	wy += 14;
166 	muteGroup = new Avtk::Number( this, wx + 2, wy + 8, 20, 19, "Mute Group" );
167 	muteGroup->valueMode( Avtk::Widget::VALUE_INT, 0, 8 );
168 
169 	offGroup = new Avtk::Number( this, wx + 24, wy + 8, 20, 19, "Off Group" );
170 	offGroup->valueMode( Avtk::Widget::VALUE_INT, 0, 8 );
171 
172 	triggerMode = new Avtk::Number( this, wx + 46, wy + 8, 20, 19, "Trigger Mode" );
173 	triggerMode->valueMode( Avtk::Widget::VALUE_INT, 0, 1 );
174 
175 	switchType = new Avtk::Number( this, wx + 68, wy + 8, 20, 19, "Switch Type" );
176 	switchType->valueMode( Avtk::Widget::VALUE_INT, Fabla2::Pad::SS_MIN, Fabla2::Pad::SS_MAX );
177 	wy += 40;
178 
179 
180 	/// velocity ranges
181 	waste = new Avtk::Box( this, wx, wy, colWidth, 50,  "Velocity Map" );
182 	waste->clickMode( Widget::CLICK_NONE );
183 	wy += 14;
184 	velocityStartPoint = new Avtk::Dial( this, wx     , wy, 40, 40, "Velocity Low" );
185 	velocityStartPoint->label_visible = 0;
186 	velocityEndPoint   = new Avtk::Dial( this, wx + 44, wy, 40, 40, "Velocity High" );
187 	velocityStartPoint->value( 0 );
188 	velocityEndPoint  ->value( 1 );
189 	velocityEndPoint->label_visible = 0;
190 	wy += 40;
191 
192 	/*
193 	/// Velocity -> Volume / Filter
194 	waste = new Avtk::Box( this, wx, wy, colWidth, 50,  "Vel -> Vol-Fil" );
195 	waste->clickMode( Widget::CLICK_NONE );
196 	wy += 14;
197 	waste = new Avtk::Dial( this, wx     , wy, 40, 40, "VelocityToVolume" );
198 	waste = new Avtk::Dial( this, wx + 44, wy, 40, 40, "VelocityToFilter" );
199 	waste->value( 0 );
200 	wy += 40;
201 	*/
202 
203 	/// Filter
204 	waste = new Avtk::Box( this, wx, wy, colWidth, 50, "Filter" );
205 	waste->clickMode( Widget::CLICK_NONE );
206 
207 	filterType = new Avtk::Number( this, wx + colWidth-divider, wy, divider, 14, "Filter Type" );
208 	filterType->valueMode( Widget::VALUE_INT, 0, 3 );
209 
210 	wy += 14;
211 	filterFrequency = new Avtk::Dial( this, wx, wy, 40, 40, "Filter Frequency" );
212 	filterFrequency->label_visible = 0;
213 	filterResonance = new Avtk::Dial( this, wx + divider + 10, wy, 40, 40, "Filter Resonance" );
214 	filterResonance->label_visible = 0;
215 
216 
217 
218 	/// next col
219 	wx += colWidth + spacer;
220 	wy = 161;
221 
222 	/// gain pan
223 	waste = new Avtk::Box( this, wx, wy, colWidth, 50,  "Gain / Pan" );
224 	waste->clickMode( Widget::CLICK_NONE );
225 	wy += 16;
226 	sampleGain = new Avtk::Dial( this, wx + 4, wy, 40, 40, "Gain" );
227 	sampleGain->label_visible = false;
228 	sampleGain->value( 0.75 );
229 	samplePan  = new Avtk::Dial( this, wx + 46, wy, 40, 40, "Pan" );
230 	samplePan->value( 0.5 );
231 	samplePan->label_visible = false;
232 	wy += 38;
233 
234 	/// start / end point dials
235 	waste = new Avtk::Box( this, wx, wy, colWidth, 50,  "Start / End" );
236 	waste->clickMode( Widget::CLICK_NONE );
237 	wy += 14;
238 	sampleStartPoint = new Avtk::Dial( this, wx     , wy, 40, 40, "Sample Start Point" );
239 	sampleStartPoint->label_visible = false;
240 	sampleEndPoint   = new Avtk::Dial( this, wx + 44, wy, 40, 40, "Sample End Point" );
241 	sampleEndPoint->label_visible = false;
242 	sampleEndPoint->value( true );
243 	wy += 40;
244 
245 	/// pitch / time
246 	waste = new Avtk::Box( this, wx, wy, colWidth, 50,  "Pitch / Time" );
247 	waste->clickMode( Widget::CLICK_NONE );
248 	wy += 14;
249 	samplePitch = new Avtk::Dial( this, wx     , wy, 40, 40, "Pitch" );
250 	samplePitch->label_visible = false;
251 	samplePitch->value( 0.5 );
252 	sampleTime   = new Avtk::Dial( this, wx + 44, wy, 40, 40, "Time" );
253 	sampleTime->label_visible = false;
254 	sampleTime->clickMode( Widget::CLICK_NONE );
255 	sampleTime->theme( theme(THEME_GREEN) );
256 
257 	/// next col
258 	wx += colWidth + spacer;
259 	wy = 161;
260 	waste = new Avtk::Box( this, wx, wy, colWidth, 50,  "ADSR" );
261 	waste->clickMode( Widget::CLICK_NONE );
262 	wy += 12;
263 	adsrA = new Avtk::Dial( this, wx - 2 , wy   , 32, 32, "adsrA" );
264 	adsrD = new Avtk::Dial( this, wx + 21, wy+10, 32, 32, "adsrD" );
265 	adsrS = new Avtk::Dial( this, wx + 42, wy   , 32, 32, "adsrS" );
266 	adsrR = new Avtk::Dial( this, wx + 63, wy+10, 32, 32, "adsrR" );
267 	adsrA->label_visible = false;
268 	adsrD->label_visible = false;
269 	adsrS->label_visible = false;
270 	adsrR->label_visible = false;
271 	adsrS->value( 1.0 );
272 	wy += 40;
273 
274 	waste = new Avtk::Box( this, wx, wy, colWidth, 50,  "AuxBus 1 2" );
275 	waste->clickMode( Widget::CLICK_NONE );
276 	wy += 14;
277 	send1 = new Avtk::Dial( this, wx     , wy, 40, 40, "AuxBus 1" );
278 	send1->theme( theme(THEME_ORANGE) );
279 	send1->label_visible = false;
280 	send2 = new Avtk::Dial( this, wx + 44, wy, 40, 40, "AuxBus 2" );
281 	send2->theme( theme(THEME_GREEN) );
282 	send2->label_visible = false;
283 	wy += 40;
284 
285 	waste = new Avtk::Box( this, wx, wy, colWidth, 50,  "AuxBus 3 4" );
286 	waste->clickMode( Widget::CLICK_NONE );
287 	wy += 14;
288 	send3 = new Avtk::Dial( this, wx     , wy, 40, 40, "AuxBus 3" );
289 	send3->label_visible = false;
290 	send3->theme( theme(THEME_YELLOW) );
291 	send4 = new Avtk::Dial( this, wx + 44, wy, 40, 40, "AuxBus 4" );
292 	send4->theme( theme(THEME_RED) );
293 	send4->label_visible = false;
294 	wy += 40;
295 
296 	///  pad master
297 	wx += colWidth + spacer;
298 	wy = 161;
299 	waste = new Avtk::Box( this, wx, wy, colWidth/2, (14+40)*3-4,  "Pad" );
300 	waste->clickMode( Widget::CLICK_NONE );
301 	wy += 18;
302 	padPlay = new Avtk::Button( this, wx+3, wy, 38, 15,  "Play" );
303 	padPlay->theme( theme( THEME_GREEN ) );
304 	wy += 19;
305 	padMute = new Avtk::Button( this, wx+3, wy, 38, 15,  "Mute" );
306 	padMute->clickMode( Widget::CLICK_TOGGLE );
307 	padMute->theme( theme( THEME_ORANGE ) );
308 	wy += 55-36;
309 	padVolume = new Avtk::Fader( this, wx+10, wy, 25, 100,  "PadVolume" );
310 	padVolume->clickMode( Widget::CLICK_NONE );
311 	padVolume->value( 0.75 );
312 
313 	//sampleControlGroup->visible( false );
314 	sampleControlGroup->end();
315 
316 
317 	/// load defaults config dir
318 	loadConfigFile( defaultDir );
319 	currentDir = defaultDir;
320 
321 	/// Sample Browser panes =====================================================
322 	wx = 82;
323 	wy = 43;
324 	sampleBrowseGroup = new Avtk::Group( this, wx, wy, 266, 276, "SampleBrowseGroup");
325 	sampleViewHeader = new Avtk::Box( this, wx, wy, 266, 276,  "Sample Browser" );
326 	wy += 20 + spacer;
327 
328 	fileViewHome = new Avtk::Button( this, wx     , wy, 50, 23, "Home" );
329 	fileViewUp   = new Avtk::Button( this, wx + 55, wy, 50, 23, "Up" );
330 	wy += 25;
331 
332 	// samples folder view
333 	sampleDirScroll = new Avtk::Scroll( this, wx, wy, 110, 166-25, "SampleFilesScroll" );
334 
335 	listSampleDirs = new Avtk::List( this, 82, 73, 110, 216, "Folder" );
336 	listSampleDirs->mode      ( Group::WIDTH_EQUAL );
337 	listSampleDirs->valueMode ( Group::VALUE_SINGLE_CHILD );
338 	listSampleDirs->resizeMode( Group::RESIZE_FIT_TO_CHILDREN );
339 	listSampleDirs->end();
340 
341 	sampleDirScroll->set( listSampleDirs );
342 
343 	sampleDirScroll->end();
344 
345 	wx = 198;
346 	wy = 43 + 20 + spacer;
347 	// samples view
348 	sampleFileScroll = new Avtk::Scroll( this, wx, wy, 146, 166, "SampleFilesScroll" );
349 
350 	listSampleFiles = new Avtk::List( this, 0, 0, 126, 866, "Sample Files" );
351 	listSampleFiles->mode      ( Group::WIDTH_EQUAL );
352 	listSampleFiles->valueMode ( Group::VALUE_SINGLE_CHILD );
353 	listSampleFiles->resizeMode( Group::RESIZE_FIT_TO_CHILDREN );
354 	listSampleFiles->end();
355 
356 	sampleFileScroll->set( listSampleFiles );
357 	sampleFileScroll->end();
358 
359 
360 	sampleBrowseGroup->visible(false);
361 	sampleBrowseGroup->end();
362 
363 	// pads
364 	wx = 82;
365 	wy = 43;
366 	int xS = 57;
367 	int yS = 56;
368 	int border = 9;
369 
370 	padsGroup = new Avtk::Group( this,  wx, wy, 266, 276, "Pads Group");
371 	waste = new Avtk::Box( this, wx, wy, 266, 276, "Pads" );
372 	waste->clickMode( Widget::CLICK_NONE );
373 
374 	int x = 87;
375 	int y = (yS+border) * 4 - 1.5;
376 	for(int i = 0; i < 16; i++ ) {
377 		if( i != 0 && i % 4 == 0 ) {
378 			y -= yS + border;
379 			x = 87;
380 		}
381 
382 		std::stringstream s;
383 		s << i + 1;
384 		pads[i] = new Avtk::Pad( this, x, y, xS, yS, s.str().c_str() );
385 
386 		x += xS + border;
387 	}
388 
389 	padsGroup->end();
390 
391 	/// live view =======================================================
392 	wx = 82;
393 	wy = 43;
394 	liveGroup = new Avtk::Group( this, wx, wy, 266, 276, "SampleBrowseGroup");
395 
396 	int livePadsX = 464;
397 	int livePadsY = 276;
398 	padsHeaderBox = new Avtk::Box( this, wx, wy, livePadsX, 14,  "16 Pads" );
399 	padsHeaderBox->clickMode( Widget::CLICK_NONE );
400 	wy += 14;
401 
402 	for(int i = 0; i < 16; ++i) {
403 		int mx = wx + (livePadsX/16.f*i);
404 		int my = wy;
405 		int mw = (livePadsX/16.f);
406 
407 		std::stringstream s;
408 		s << i + 1;
409 		mixStrip[i] = new Avtk::MixStrip( this, mx, my, mw, livePadsY - 14, s.str().c_str() );
410 		mixStrip[i]->clickMode( Widget::CLICK_NONE );
411 		mixStrip[i]->setNum( s.str() );
412 
413 		// dials
414 		int size = mw+4;
415 		mw -= 6;
416 		auxDials[ 0+i] = new Avtk::Dial( this, mx, my       , size, size, "Aux1" );
417 		auxDials[16+i] = new Avtk::Dial( this, mx, my + mw  , size, size, "Aux2" );
418 		auxDials[32+i] = new Avtk::Dial( this, mx, my + mw*2, size, size, "Aux3" );
419 		auxDials[48+i] = new Avtk::Dial( this, mx, my + mw*3, size, size, "Aux4" );
420 
421 		auxDials[ 0+i]->theme( theme( THEME_ORANGE ) );
422 		auxDials[16+i]->theme( theme( THEME_GREEN  ) );
423 		auxDials[32+i]->theme( theme( THEME_YELLOW ) );
424 		auxDials[48+i]->theme( theme( THEME_RED    ) );
425 
426 		auxDials[ 0+i]->label_visible = false;
427 		auxDials[16+i]->label_visible = false;
428 		auxDials[32+i]->label_visible = false;
429 		auxDials[48+i]->label_visible = false;
430 
431 		my += mw*5;
432 
433 		// pad faders
434 		padFaders[i] = new Avtk::Fader( this, mx + 3, my, mw, 120, "Vol" );
435 	}
436 
437 	wx = 82;
438 	wy = 43;
439 	wx += padsHeaderBox->w() + spacer;
440 
441 	waste = new Avtk::Box( this, wx, wy, 228, 14, "AuxBus" );
442 	waste->clickMode( Widget::CLICK_NONE );
443 	wy += 14;
444 
445 	for(int i = 0; i < 4; ++i) {
446 		int mx = wx + (228/4.f*i);
447 		int my = wy;
448 		int mw = 228 / 4;
449 		int mh = 276-14;
450 		std::stringstream s;
451 		s << i + 1;
452 
453 		const char* names[] = {
454 			"Reverb / Delay",
455 			"Compression",
456 			"Sidechain Key",
457 			"Monitor / Rec",
458 		};
459 
460 		auxbus[i] = new Avtk::MixStrip( this, mx, my, mw, mh, names[i] );
461 		auxbus[i]->clickMode( Widget::CLICK_NONE );
462 		auxbus[i]->setNum( s.str().c_str() );
463 
464 		// buttons
465 		int high = 19;
466 		my += 4;
467 		waste = new Avtk::Button( this, mx + 4, my, mw - 8, high,  "Solo" );
468 		waste->clickMode( Widget::CLICK_TOGGLE );
469 		waste->theme( theme( THEME_ORANGE ) );
470 		my += high + 4;
471 
472 		waste = new Avtk::Button( this, mx + 4, my, mw - 8, high,  "Mute" );
473 		waste->clickMode( Widget::CLICK_TOGGLE );
474 		waste->theme( theme( THEME_GREEN ) );
475 		my += high + 4;
476 
477 		waste = new Avtk::Button( this, mx + 4, my, mw - 8, high,  "Audit" );
478 		waste->clickMode( Widget::CLICK_TOGGLE );
479 		waste->theme( theme( THEME_YELLOW ) );
480 		my += high + 4;
481 
482 		waste = new Avtk::Button( this, mx + 4, my, mw - 8, high,  "Meta" );
483 		waste->clickMode( Widget::CLICK_TOGGLE );
484 		waste->theme( theme( THEME_RED ) );
485 		my += high + 4;
486 
487 		// fader
488 		mw -= 6;
489 		my += 24;
490 		auxFaders[i] = new Avtk::Fader( this, mx + 8, my, 30, 140, names[i] );
491 		auxFaders[i]->theme( theme( THEME_ORANGE+i) ); // hack for theme indexs
492 		auxFaders[i]->useCustomTheme = true;
493 	}
494 	auxFaders[3]->theme( theme( THEME_RED )); // fix last one
495 	liveGroup->visible( false );
496 	liveGroup->end();
497 
498 	/// sequencer view ===============================================
499 	wx = 82;
500 	wy = 43;
501 	seqGroup = new Avtk::Group( this, wx, wy, 266, 276, "SequencerView");
502 
503 	int stepSize = 276 / (SEQ_ROWS+3);
504 	waste = new Avtk::Button(this, wx, wy, 58, (stepSize+3)*16, "Pads");
505 
506 	wx = 82 + 62;
507 	wy = 43;
508 	for(int i = 0; i < SEQ_ROWS; i++) {
509 		for(int j = 0; j < SEQ_STEPS; j++) {
510 			Avtk::Step* s = new Avtk::Step(this,
511 						 wx + j * (stepSize+3), wy,
512 						 stepSize, stepSize, "-");
513 			s->clickMode( Widget::CLICK_TOGGLE );
514 			s->row = i;
515 			s->col = j;
516 			if( j % 4 == 0) {
517 				s->theme(ui->theme(3));
518 			}
519 			s->callback = fabla2_ui_seqStepValueCB;
520 			s->callbackUD = this;
521 			seqSteps[i*SEQ_STEPS+j] = (Avtk::Step*)s;
522 		}
523 		wy += stepSize +3;
524 	}
525 
526 	wx = 82 + 62 + (stepSize+3)*SEQ_STEPS + 3;
527 
528 	seqGroup->end();
529 	seqGroup->visible( false );
530 
531 	/// Master view on right
532 	wx = 782;
533 	wy = 43;
534 	waste = new Avtk::Box( this, wx, wy, 70, 276, "Master" );
535 	waste->clickMode( Widget::CLICK_NONE );
536 	wy += 18;
537 
538 	masterAuxFader1 = new Avtk::Fader( this, wx+ 1, wy+3, 15, 90, "Master Aux 1" );
539 	masterAuxFader1->theme( theme(THEME_ORANGE) );
540 	masterAuxFader1->useCustomTheme = true;
541 
542 	masterAuxFader2 = new Avtk::Fader( this, wx+19, wy+3, 15, 90, "Master Aux 2" );
543 	masterAuxFader2->theme( theme(THEME_GREEN) );
544 	masterAuxFader2->useCustomTheme = true;
545 
546 	masterAuxFader3 = new Avtk::Fader( this, wx+37, wy+3, 15, 90, "Master Aux 3" );
547 	masterAuxFader3->theme( theme(THEME_YELLOW) );
548 	masterAuxFader3->useCustomTheme = true;
549 
550 	masterAuxFader4 = new Avtk::Fader( this, wx+55, wy+3, 15, 90, "Master Aux 4" );
551 	masterAuxFader4->theme( theme(THEME_RED) );
552 	masterAuxFader4->useCustomTheme = true;
553 
554 	masterDB = new Avtk::Volume( this, wx+4, wy+96,38, 160,  "MasterDB");
555 	// FIXME : add white theme to AVTK, then update this
556 	masterDB->theme( theme(THEME_BLUE) );
557 
558 	masterVolume = new Avtk::Fader( this, wx+4, wy+96,38, 160,  "Master Vol" );
559 	//masterVolume->clickMode( Widget::CLICK_NONE );
560 	masterVolume->value( 0.75 );
561 
562 	// Transport layer (always visible on top)
563 	wy = 8;
564 	wx = 170;
565 	transport_play = new Avtk::Button(this, wx, wy, 60, 28, "Play");
566 	wx += 62;
567 	transport_bpm  = new Avtk::Dial(this, wx, wy-6, 34, 34, "BPM");
568 	transport_play->clickMode( Widget::CLICK_TOGGLE );
569 
570 	if( 1 ) // hide WIP features in UI
571 	{
572 		transport_play->visible(0);
573 		transport_bpm->visible(0);
574 		seqGroup->visible(0);
575 	}
576 
577 	// initial values
578 	bankBtns[0]->value( true );
579 	followPadBtn->value( followPad );
580 
581 	redrawRev = 0;
582 
583 	/// created last, so its on top
584 	deleteLayer = new Avtk::Dialog( this, 0, 0, 320, 120, "Delete Sample?" );
585 
586 	sock.bindTo(PORT_NUM);
587 	if(!sock.isOk()) {
588 		printf("Fabla2UI: Error opening OSC port %d: %s\n",
589 		       PORT_NUM, &sock.errorMessage()[0]);
590 		printf("=> Maschine devices OSC interface wont work!\n");
591 	} else {
592 		printf("=> Maschine devices OSC interface OK!\n");
593 	}
594 	maschine_addr = std::string();
595 }
596 
handleMaschine()597 void Fabla2UI::handleMaschine()
598 {
599 	PacketReader pr;
600 	if (sock.receiveNextPacket(0 /* timeout, in ms */)) {
601 		pr.init(sock.packetData(), sock.packetSize());
602 		oscpkt::Message *msg;
603 		while (pr.isOk() && (msg = pr.popMessage()) != 0) {
604 			//handle_message(&sock, msg);
605 			int press;
606 			msg->arg().popInt32(press);
607 
608 			PacketWriter pw;
609 			Message repl;
610 			repl.init(&msg->address[0]).pushInt32(press);
611 			pw.init().addMessage(repl);
612 			sock.sendPacketTo(pw.packetData(), pw.packetSize(), sock.packetOrigin());
613 
614 			// Save the address, then return
615 			if( strlen(&maschine_addr[0]) == 0)  {
616 				maschine_addr = sock.remote_addr.asString();
617 				printf("Maschine address - %s\n", &maschine_addr[0]);
618 				PacketWriter pw;
619 				Message repl;
620 				repl.init("/maschine/midi_note_base").pushInt32(36);
621 				pw.init().addMessage(repl);
622 				sock.sendPacketTo(pw.packetData(), pw.packetSize(), sock.packetOrigin());
623 
624 				for(int i = 0; i < 16; i++)
625 					updateMaschine(i, 10, 31, 0xFF, 15);
626 				break;
627 			}
628 
629 			/* Handle press + release events */
630 			if(strcmp(&msg->address[0],"/maschine/button/rec") == 0) {
631 				float tmp = press;
632 				write_function(controller, Fabla2::RECORD_OVER_LAST_PLAYED_PAD, sizeof(float), 0, &tmp);
633 			} else if(strcmp(&msg->address[0],"/maschine/button/play") == 0) {
634 				int current = transport_play->value();
635 				if(press) {
636 					current = !current;
637 					float tmp = current;
638 
639 					transport_play->value(current);
640 					write_function(controller, Fabla2::TRANSPORT_PLAY, sizeof(float), 0, &tmp);
641 				} else {
642 					PacketWriter pw;
643 					Message repl;
644 					repl.init("/maschine/button/play").pushInt32(current);
645 					pw.init().addMessage(repl);
646 					sock.sendPacketTo(pw.packetData(), pw.packetSize(), sock.packetOrigin());
647 					transport_play->value(current);
648 				}
649 			}
650 
651 			if(!press)
652 				break; // button release
653 			if(       strcmp(&msg->address[0],"/maschine/button/f1") == 0) {
654 				showPadsView();
655 			} else if(strcmp(&msg->address[0],"/maschine/button/f2") == 0) {
656 				showLiveView();
657 			} else if(strcmp(&msg->address[0],"/maschine/button/f3") == 0) {
658 				showFileView();
659 				showPadsView();
660 			}
661 		}
662 	}
663 }
664 
updateMaschine(int pad,int r,int g,int b,int a)665 void Fabla2UI::updateMaschine(int pad, int r, int g, int b, int a)
666 {
667 	PacketWriter pw;
668 	Message repl;
669 	// TODO different banks?
670 
671 	// convert to maschine way of counting pads
672 	int col = pad % 4;
673 	int row = 4 - (pad/4);
674 	int p = (row-1)*4 + col;
675 	if( p < 16 && p >= 0 )
676 	{
677 		uint32_t color = 0;
678 		color += r << 16;
679 		color += g << 8;
680 		color += b;
681 		if( a < 100 )
682 			a = 0; // nuke offs to 0
683 		repl.init("/maschine/pad").pushInt32(p).pushInt32(color).pushFloat(a/255.f);
684 		pw.init().addMessage(repl);
685 		sock.sendPacketTo(pw.packetData(), pw.packetSize(), sock.packetOrigin());
686 	}
687 }
688 
blankSampleState()689 void Fabla2UI::blankSampleState()
690 {
691 	padVolume       ->value( 0 );
692 
693 	muteGroup       ->value( 0 );
694 	offGroup        ->value( 0 );
695 	triggerMode     ->value( 0 );
696 	switchType      ->value( 0 );
697 
698 	sampleGain      ->value( 0 );
699 	samplePan       ->value( 0 );
700 
701 	samplePitch     ->value( 0 );
702 	sampleTime      ->value( 0 );
703 
704 	sampleStartPoint->value( 0 );
705 	sampleEndPoint  ->value( 0 );
706 
707 	velocityStartPoint->value( 0 );
708 	velocityEndPoint->value( 0 );
709 
710 	adsrA->value( 0 );
711 	adsrD->value( 0 );
712 	adsrS->value( 0 );
713 	adsrR->value( 0 );
714 
715 	send1           ->value( 0 );
716 	send2           ->value( 0 );
717 	send3           ->value( 0 );
718 	send4           ->value( 0 );
719 
720 	filterType      ->value( 0 );
721 	filterFrequency ->value( 0 );
722 	filterResonance ->value( 0 );
723 
724 	sampleName->label("-");
725 
726 	layers->clear();
727 
728 	waveform->setStartPoint( 0 );
729 
730 	std::vector<float> tmp(FABLA2_UI_WAVEFORM_PX);
731 	for(int i = 0; i < FABLA2_UI_WAVEFORM_PX; ++i)
732 		tmp[i] = 0.0;
733 	waveform->show( tmp );
734 
735 }
736 
737 
loadNewDir(std::string newDir)738 void Fabla2UI::loadNewDir( std::string newDir )
739 {
740 	printf("loadNewDir() %s\n", newDir.c_str() );
741 	std::vector< std::string > tmp;
742 	int error = Avtk::directories( newDir, tmp, true, true );
743 
744 	if( !error ) {
745 		// don't navigate into a dir with only . and ..
746 		if( tmp.size() > 2 ) {
747 			currentDir = newDir;
748 			printf("%s, %d : new dir : %s\n", __PRETTY_FUNCTION__, __LINE__, newDir.c_str() );
749 			listSampleDirs->clear();
750 			listSampleDirs->show( tmp );
751 		} else {
752 			printf("%s , %d : not moving to sub-dir : has no folders to cd into\n", __PRETTY_FUNCTION__, __LINE__ );
753 		}
754 
755 
756 		currentFilesDir = newDir;
757 		tmp.clear();
758 		listSampleFiles->clear();
759 		error = Avtk::directoryContents( currentFilesDir, tmp, strippedFilenameStart );
760 		if( !error ) {
761 			if( tmp.size() ) {
762 				listSampleFiles->show( tmp );
763 				printf("%s , %d : error showing contents of %s\n", __PRETTY_FUNCTION__, __LINE__, currentFilesDir.c_str() );
764 			} else {
765 				printf("tmp.size() == 0, not showing\n");
766 			}
767 		}
768 	} else {
769 		printf("%s , %d :  Error loading dir %s", __PRETTY_FUNCTION__, __LINE__, newDir.c_str() );
770 		return;
771 	}
772 }
773 
showSeqView()774 void Fabla2UI::showSeqView()
775 {
776 	padsGroup         ->visible( false );
777 	waveformGroup     ->visible( false );
778 	sampleBrowseGroup ->visible( false );
779 	sampleControlGroup->visible( false );
780 	liveGroup         ->visible( false );
781 
782 	seqGroup          ->visible( true );
783 	uiViewGroup->value( 3 );
784 	redraw();
785 }
786 
showLiveView()787 void Fabla2UI::showLiveView()
788 {
789 	padsGroup         ->visible( false );
790 	waveformGroup     ->visible( false );
791 	sampleBrowseGroup ->visible( false );
792 	sampleControlGroup->visible( false );
793 	seqGroup          ->visible( false );
794 
795 	liveGroup         ->visible( true  );
796 	uiViewGroup->value( 1 );
797 	redraw();
798 }
799 
showPadsView()800 void Fabla2UI::showPadsView()
801 {
802 	liveGroup         ->visible( false );
803 	sampleBrowseGroup ->visible( false );
804 	seqGroup          ->visible( false );
805 
806 	padsGroup         ->visible( true );
807 	waveformGroup     ->visible( true );
808 	sampleControlGroup->visible( true );
809 
810 	uiViewGroup->value( 0 );
811 
812 	// info could be outdated from live view
813 	requestSampleState( currentBank, currentPad, currentLayer );
814 	redraw();
815 }
816 
fabla2_file_select_callback(const char * c,void * userdata)817 static void fabla2_file_select_callback(const char *c, void *userdata)
818 {
819 	Fabla2UI* self = (Fabla2UI*)userdata;
820 #define OBJ_BUF_SIZE 1024
821 	uint8_t obj_buf[OBJ_BUF_SIZE];
822 	lv2_atom_forge_set_buffer(&self->forge, obj_buf, OBJ_BUF_SIZE);
823 	// true = audition sample only flag
824 	LV2_Atom* msg = writeSetFile( &self->forge, &self->uris, -1, -1, c, true);
825 	self->write_function(self->controller, 0, lv2_atom_total_size(msg), self->uris.atom_eventTransfer, msg);
826 }
827 
828 /// taken from SOFD example - thanks x42 for this awesome library!
829 // TODO: This can probably be "non-modal" to allow UI redraws in BG
830 // by using x_fib_handle_events() without the loop, and calling it // using a wrapper-widget or else just manually hack it :)
fabla2_showFileBrowser(std::string dir,Fabla2UI * t)831 std::string fabla2_showFileBrowser(std::string dir, Fabla2UI* t)
832 {
833 	Display* dpy = XOpenDisplay(0);
834 	if (!dpy) {
835 		return "";
836 	}
837 	//x_fib_cfg_filter_callback (sofd_filter);
838 	x_fib_configure (1, "Open File");
839 	x_fib_load_recent ("/tmp/sofd.recent");
840 	x_fib_show (dpy, 0, 400, 320);
841 	x_fib_file_changed_cb( fabla2_file_select_callback, (void *)t);
842 
843 	// stores result to return
844 	std::string ret;
845 
846 	while (1) {
847 		XEvent event;
848 		while (XPending (dpy) > 0) {
849 			XNextEvent (dpy, &event);
850 			if (x_fib_handle_events (dpy, &event)) {
851 				if (x_fib_status () > 0) {
852 					char *fn = x_fib_filename ();
853 					x_fib_add_recent (fn, time (NULL));
854 
855 					ret = fn;
856 					free (fn);
857 				}
858 			}
859 		}
860 		if (x_fib_status ()) {
861 			break;
862 		}
863 		usleep (80000);
864 	}
865 	x_fib_close (dpy);
866 
867 	x_fib_save_recent ("/tmp/sofd.recent");
868 
869 	x_fib_free_recent ();
870 	XCloseDisplay (dpy);
871 
872 	return ret;
873 }
874 
showFileView()875 void Fabla2UI::showFileView()
876 {
877 	liveGroup->visible( false );
878 	padsGroup->visible( false );
879 	seqGroup ->visible( false );
880 
881 	// sofd temp replacing in-UI browser
882 	sampleBrowseGroup->visible( false );
883 
884 	waveformGroup->visible( true );
885 	sampleControlGroup->visible( true );
886 
887 	// TODO/FIXME: We should return and allow the redraw to occur,
888 	// and register a callback to open SOFD. This would allow the UI
889 	// to have redrawed a dialog saying "External file browser open",
890 	// and automatically close that dialog when done with SOFD.
891 	redraw();
892 
893 	/*
894 	loadNewDir( currentDir );
895 	sampleFileScroll->set( listSampleFiles );
896 	*/
897 	//printf("spawming SOFD now!\n");
898 	std::string chosen = fabla2_showFileBrowser( currentDir, this );
899 
900 	if( chosen.size() > 0 ) {
901 		//printf("SOFD returned %s\n", chosen.c_str() );
902 #define OBJ_BUF_SIZE 1024
903 		uint8_t obj_buf[OBJ_BUF_SIZE];
904 		lv2_atom_forge_set_buffer(&forge, obj_buf, OBJ_BUF_SIZE);
905 		LV2_Atom* msg = writeSetFile( &forge, &uris, currentBank, currentPad, chosen.c_str(), 0);
906 		write_function(controller, 0, lv2_atom_total_size(msg), uris.atom_eventTransfer, msg);
907 		// return to pads view for triggering
908 	}
909 	showPadsView();
910 	uiViewGroup->value( 0 );
911 	redraw();
912 }
913 
914 
padEvent(int bank,int pad,int layer,bool noteOn,int velocity)915 void Fabla2UI::padEvent( int bank, int pad, int layer, bool noteOn, int velocity )
916 {
917 	//printf("pad event %d - note on %d, layer %d\n", pad, noteOn, layer);
918 	if( pad < 0 || pad >= 16 ) {
919 		return; // invalid pad number
920 	}
921 
922 	// change widget properties
923 	pads[pad]->value( noteOn );
924 	mixStrip[pad]->value(noteOn);
925 
926 	// Sample view, highlight the layer
927 	layers->value(layer);
928 
929 	currentBank  = bank;
930 	currentPad   = pad;
931 	if(noteOn) // not off contains -1 in layer!
932 		currentLayer = layer;
933 
934 	float fin = noteOn ? 255 : 15;
935 	//printf("sending pad %d : alpha %f tl maschine\n", pad, fin );
936 	updateMaschine(pad, 10, 31, 0xFF, fin);
937 
938 	if(followPad) {
939 		//requestSampleState( currentBank, currentPad, currentLayer );
940 	}
941 
942 	redraw();
943 }
944 
945 
requestSampleState(int bank,int pad,int layer)946 void Fabla2UI::requestSampleState( int bank, int pad, int layer )
947 {
948 	uint8_t obj_buf[UI_ATOM_BUF_SIZE];
949 	lv2_atom_forge_set_buffer(&forge, obj_buf, UI_ATOM_BUF_SIZE);
950 
951 	// write message
952 	LV2_Atom_Forge_Frame frame;
953 	LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object( &forge, &frame, 0, uris.fabla2_RequestUiSampleState);
954 
955 	lv2_atom_forge_key(&forge, uris.fabla2_bank);
956 	lv2_atom_forge_int(&forge, currentBank );
957 
958 	lv2_atom_forge_key(&forge, uris.fabla2_pad);
959 	lv2_atom_forge_int(&forge, currentPad );
960 
961 	lv2_atom_forge_key(&forge, uris.fabla2_layer);
962 	lv2_atom_forge_int(&forge, currentLayer );
963 
964 	//printf("UI writes requestSampleState %i, %i, %i\n", currentBank, currentPad, currentLayer );
965 
966 	lv2_atom_forge_pop(&forge, &frame);
967 
968 	// send it
969 	redrawRev++;
970 	write_function(controller, 0, lv2_atom_total_size(msg), uris.atom_eventTransfer, msg);
971 }
972 
setBank(int bank)973 void Fabla2UI::setBank( int bank )
974 {
975 	bankBtns[currentBank]->value( false );
976 	currentBank = bank;
977 	bankBtns[currentBank]->value( true );
978 
979 	Avtk::Theme* t = theme( bank );
980 	waveform->theme( t );
981 
982 	for(int i = 0; i < 16; i++)
983 		mixStrip[i]->theme( t );
984 
985 	for(int i = 0; i < 16; i++) {
986 		pads[i]->theme( t );
987 	}
988 }
989 
writePadPlayStop(bool noteOn,int bank,int pad,int layer)990 void Fabla2UI::writePadPlayStop( bool noteOn, int bank, int pad, int layer )
991 {
992 	uint8_t obj_buf[UI_ATOM_BUF_SIZE];
993 	lv2_atom_forge_set_buffer(&forge, obj_buf, UI_ATOM_BUF_SIZE);
994 
995 	LV2_Atom_Forge_Frame frame;
996 	int uri = uris.fabla2_PadStop;
997 	if( noteOn )
998 		uri = uris.fabla2_PadPlay;
999 
1000 	LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object( &forge, &frame, 0, uri);
1001 
1002 	lv2_atom_forge_key(&forge, uris.fabla2_bank);
1003 	lv2_atom_forge_int(&forge, bank );
1004 
1005 	lv2_atom_forge_key(&forge, uris.fabla2_pad);
1006 	lv2_atom_forge_int(&forge, pad );
1007 
1008 	lv2_atom_forge_key(&forge, uris.fabla2_layer);
1009 	lv2_atom_forge_int(&forge, layer );
1010 
1011 	lv2_atom_forge_pop(&forge, &frame);
1012 
1013 	// send it
1014 	write_function(controller, 0, lv2_atom_total_size(msg), uris.atom_eventTransfer, msg);
1015 }
1016 
writeAtomForPad(int eventURI,int pad,float value)1017 void Fabla2UI::writeAtomForPad( int eventURI, int pad, float value )
1018 {
1019 	uint8_t obj_buf[UI_ATOM_BUF_SIZE];
1020 	lv2_atom_forge_set_buffer(&forge, obj_buf, UI_ATOM_BUF_SIZE);
1021 	LV2_Atom_Forge_Frame frame;
1022 	LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object( &forge, &frame, 0, eventURI);
1023 
1024 	lv2_atom_forge_key(&forge, uris.fabla2_bank);
1025 	lv2_atom_forge_int(&forge, currentBank );
1026 	lv2_atom_forge_key(&forge, uris.fabla2_pad);
1027 	lv2_atom_forge_int(&forge, pad );
1028 	lv2_atom_forge_key(&forge, uris.fabla2_layer);
1029 	// layer not used in pad message, but needs to be a valid one.
1030 	lv2_atom_forge_int(&forge, 0 );
1031 	lv2_atom_forge_key(&forge, uris.fabla2_value);
1032 	lv2_atom_forge_float(&forge, value );
1033 	lv2_atom_forge_pop(&forge, &frame);
1034 
1035 	write_function(controller, 0, lv2_atom_total_size(msg), uris.atom_eventTransfer, msg);
1036 }
1037 
writeAuxBus(int uri,int bus,float value)1038 void Fabla2UI::writeAuxBus( int uri, int bus, float value )
1039 {
1040 	uint8_t obj_buf[UI_ATOM_BUF_SIZE];
1041 	lv2_atom_forge_set_buffer(&forge, obj_buf, UI_ATOM_BUF_SIZE);
1042 	LV2_Atom_Forge_Frame frame;
1043 	LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object( &forge, &frame, 0, uri);
1044 
1045 	lv2_atom_forge_key(&forge, uris.fabla2_auxBusNumber);
1046 	lv2_atom_forge_int(&forge, bus );
1047 
1048 	lv2_atom_forge_key  (&forge, uris.fabla2_value );
1049 	lv2_atom_forge_float(&forge, value );
1050 
1051 	lv2_atom_forge_pop( &forge, &frame );
1052 
1053 	write_function(controller, 0, lv2_atom_total_size(msg), uris.atom_eventTransfer, msg);
1054 }
1055 
writeAtom(int eventURI,float value)1056 void Fabla2UI::writeAtom( int eventURI, float value )
1057 {
1058 	uint8_t obj_buf[UI_ATOM_BUF_SIZE];
1059 	lv2_atom_forge_set_buffer(&forge, obj_buf, UI_ATOM_BUF_SIZE);
1060 
1061 	//printf("Fabla2:UI writeAtom %i, %f: pad %d, layer %d\n", eventURI, value, currentPad, currentLayer );
1062 	LV2_Atom_Forge_Frame frame;
1063 	LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object( &forge, &frame, 0, eventURI);
1064 
1065 	lv2_atom_forge_key(&forge, uris.fabla2_bank);
1066 	lv2_atom_forge_int(&forge, currentBank );
1067 
1068 	lv2_atom_forge_key(&forge, uris.fabla2_pad);
1069 	lv2_atom_forge_int(&forge, currentPad );
1070 
1071 	// don't write layer if its a pad play event, do for audition URIs
1072 	//if( eventURI != uris.fabla2_PadPlay && eventURI != uris.fabla2_PadStop ) {
1073 		lv2_atom_forge_key(&forge, uris.fabla2_layer);
1074 		lv2_atom_forge_int(&forge, currentLayer );
1075 	//}
1076 
1077 	lv2_atom_forge_key  (&forge, uris.fabla2_value);
1078 	lv2_atom_forge_float(&forge, value );
1079 
1080 	lv2_atom_forge_pop(&forge, &frame);
1081 
1082 	// send it
1083 	write_function(controller, 0, lv2_atom_total_size(msg), uris.atom_eventTransfer, msg);
1084 }
1085 
handle(const PuglEvent * e)1086 int Fabla2UI::handle( const PuglEvent* e )
1087 {
1088 	// handle key presses here, playing pads press/release
1089 	if( e->type == PUGL_KEY_PRESS ||
1090 	    e->type == PUGL_KEY_RELEASE ) {
1091 		int pad = -1;
1092 		switch( e->key.character ) {
1093 		case 'z':
1094 			pad =  0;
1095 			break;
1096 		case 'x':
1097 			pad =  1;
1098 			break;
1099 		case 'c':
1100 			pad =  2;
1101 			break;
1102 		case 'v':
1103 			pad =  3;
1104 			break;
1105 		case 'a':
1106 			pad =  4;
1107 			break;
1108 		case 's':
1109 			pad =  5;
1110 			break;
1111 		case 'd':
1112 			pad =  6;
1113 			break;
1114 		case 'f':
1115 			pad =  7;
1116 			break;
1117 		case 'q':
1118 			pad =  8;
1119 			break;
1120 		case 'w':
1121 			pad =  9;
1122 			break;
1123 		case 'e':
1124 			pad = 10;
1125 			break;
1126 		case 'r':
1127 			pad = 11;
1128 			break;
1129 		case '1':
1130 			pad = 12;
1131 			break;
1132 		case '2':
1133 			pad = 13;
1134 			break;
1135 		case '3':
1136 			pad = 14;
1137 			break;
1138 		case '4':
1139 			pad = 15;
1140 			break;
1141 		}
1142 		if( pad >= 0 ) {
1143 			int uri = e->type == PUGL_KEY_PRESS ? uris.fabla2_PadPlay : uris.fabla2_PadStop;
1144 			currentPad = pad;
1145 			writeAtom( uri, 1 );
1146 			//printf("playing pad %i, uri %i\n", pad, uri );
1147 			//writePadPlayStop( true, currentBank, pad, 0 );
1148 			if( e->type == PUGL_KEY_PRESS )
1149 				updateMaschine(pad, 0, 51, 255, 255);
1150 			else
1151 				updateMaschine(pad, 0, 51, 255, 25);
1152 			return 1; // handled
1153 		}
1154 	}
1155 
1156 	return 0;
1157 }
1158 
seqStepValueCB(Avtk::Widget * w)1159 void Fabla2UI::seqStepValueCB(Avtk::Widget* w)
1160 {
1161 	Avtk::Step* s = (Avtk::Step*) w;
1162 	// TODO write Atom here, setting step to value
1163 	uint8_t obj_buf[UI_ATOM_BUF_SIZE];
1164 	lv2_atom_forge_set_buffer(&forge, obj_buf, UI_ATOM_BUF_SIZE);
1165 	LV2_Atom_Forge_Frame frame;
1166 	LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object( &forge, &frame, 3, uris.fabla2_SeqStepState);
1167 	if( !msg )
1168 		printf("message not valid!!\n");
1169 
1170 	lv2_atom_forge_key(&forge, uris.fabla2_bank);
1171 	lv2_atom_forge_int(&forge, 0 );
1172 	lv2_atom_forge_key(&forge, uris.fabla2_pad);
1173 	lv2_atom_forge_int(&forge, 15 - s->row );
1174 	lv2_atom_forge_key(&forge, uris.fabla2_step);
1175 	lv2_atom_forge_int(&forge, s->col );
1176 	lv2_atom_forge_key(&forge, uris.fabla2_value);
1177 	int tmp = int(w->value()+0.5);
1178 	lv2_atom_forge_int(&forge, tmp);
1179 
1180 	lv2_atom_forge_pop(&forge, &frame);
1181 	write_function(controller, 0, lv2_atom_total_size(msg), uris.atom_eventTransfer, msg);
1182 }
1183 
widgetValueCB(Avtk::Widget * w)1184 void Fabla2UI::widgetValueCB( Avtk::Widget* w)
1185 {
1186 	float tmp = w->value();
1187 	//printf("widgetCB : %s, value: %f\n", w->label(), tmp );
1188 	if( w == recordOverPad ) {
1189 		write_function( controller, Fabla2::RECORD_OVER_LAST_PLAYED_PAD, sizeof(float), 0, &tmp );
1190 	}
1191 	/*
1192 	else if( w == masterPitch )
1193 	{
1194 	  float scaleVal = tmp * 24 - 12;
1195 	  write_function( controller, Fabla2::MASTER_PITCH, sizeof(float), 0, &scaleVal );
1196 	}
1197 	*/
1198 	else if( w == layers ) {
1199 		currentLayer = int( layers->value() );
1200 		//printf("%s %d : currentLayer = %d\n", __FILE__, __LINE__, currentLayer);
1201 		if( w->mouseButton() == 3 ) {
1202 			int mx = w->mouseX();
1203 			int my = w->mouseY();
1204 			printf("%i %i\n", mx, my );
1205 
1206 			std::stringstream s;
1207 			s << "Delete layer " << layers->selectedString() << "?";
1208 
1209 			deleteLayer->run("Delete Layer", s.str().c_str(), Avtk::Dialog::OK_CANCEL, mx, my );
1210 		} else {
1211 			int lay = int( layers->value() );
1212 			//printf("click on layer %i : value() %f\n", lay, tmp );
1213 			if( true ) //;;tmp > 0.4999 )
1214 				writePadPlayStop( true, currentBank, currentPad, lay );
1215 			else
1216 				writePadPlayStop( false, currentBank, currentPad, lay );
1217 		}
1218 	} else if( w == deleteLayer ) {
1219 		// user clicked OK on delete layer dialog
1220 		if( int(tmp) == 1 ) {
1221 			//printf("UI writing sampleUnload\n");
1222 			writeAtom( uris.fabla2_SampleUnload, true );
1223 			requestSampleState( currentBank, currentPad, currentLayer );
1224 		}
1225 	} else if( w == fileViewUp ) {
1226 		std::string newDir;
1227 		std::string current = listSampleDirs->selectedString();
1228 		Avtk::fileUpLevel( current, newDir );
1229 		loadNewDir( newDir );
1230 	} else if( w == fileViewHome ) {
1231 		std::string newDir = getenv("HOME");
1232 		loadNewDir( newDir );
1233 	} else if( w == panicButton ) {
1234 		writeAtom( uris.fabla2_Panic , true );
1235 	} else if( w == followPadBtn ) {
1236 		followPad = int(tmp);
1237 		if( !followPad ) {
1238 			pads[currentPad]->value(0);
1239 		}
1240 	} else if( w == liveView ) {
1241 		showLiveView();
1242 	} else if( w == seqView ) {
1243 		showSeqView();
1244 	} else if( w == padsView ) {
1245 		showPadsView();
1246 	} else if( w == fileView ) {
1247 		showFileView();
1248 	} else if( w == listSampleDirs ) {
1249 		std::string selected = listSampleDirs->selectedString();
1250 		std::stringstream s;
1251 		s << currentDir << "/" << selected;
1252 		// load the new dir
1253 		loadNewDir( s.str().c_str() );
1254 	} else if( w == listSampleFiles ) {
1255 		/*
1256 		// TMP Replaced by SOFD
1257 		std::string selected = listSampleFiles->selectedString();
1258 		std::stringstream s;
1259 		s << currentFilesDir << "/" << strippedFilenameStart << selected;
1260 		printf("UI sending sample load: %s\n", s.str().c_str() );
1261 
1262 		#define OBJ_BUF_SIZE 1024
1263 		uint8_t obj_buf[OBJ_BUF_SIZE];
1264 		lv2_atom_forge_set_buffer(&forge, obj_buf, OBJ_BUF_SIZE);
1265 		LV2_Atom* msg = writeSetFile( &forge, &uris, currentBank, currentPad, s.str() );
1266 		write_function(controller, 0, lv2_atom_total_size(msg), uris.atom_eventTransfer, msg);
1267 		*/
1268 	} else if( w == offGroup ) {
1269 		writeAtom( uris.fabla2_PadOffGroup, tmp );
1270 	} else if( w == muteGroup ) {
1271 		writeAtom( uris.fabla2_PadMuteGroup, tmp );
1272 	} else if( w == triggerMode ) {
1273 		writeAtom( uris.fabla2_PadTriggerMode, tmp );
1274 	} else if( w == switchType ) {
1275 		writeAtom( uris.fabla2_PadSwitchType, tmp );
1276 	} else if( w == padVolume ) {
1277 		writeAtom( uris.fabla2_PadVolume, tmp );
1278 	} else if( w == velocityStartPoint ) {
1279 		writeAtom( uris.fabla2_SampleVelStartPnt, tmp );
1280 	} else if( w == velocityEndPoint ) {
1281 		writeAtom( uris.fabla2_SampleVelEndPnt, tmp );
1282 	} else if( w == sampleGain ) {
1283 		writeAtom( uris.fabla2_SampleGain, tmp );
1284 	} else if( w == samplePitch ) {
1285 		writeAtom( uris.fabla2_SamplePitch, tmp );
1286 	} else if( w == samplePan ) {
1287 		writeAtom( uris.fabla2_SamplePan, tmp );
1288 	} else if( w == sampleStartPoint ) {
1289 		waveform->setStartPoint( tmp );
1290 		writeAtom( uris.fabla2_SampleStartPoint, tmp );
1291 	} else if( w == filterType ) {
1292 		writeAtom( uris.fabla2_SampleFilterType, tmp );
1293 	} else if( w == filterFrequency ) {
1294 		writeAtom( uris.fabla2_SampleFilterFrequency, tmp );
1295 	} else if( w == filterResonance ) {
1296 		writeAtom( uris.fabla2_SampleFilterResonance, tmp );
1297 	} else if( w == masterVolume ) {
1298 		write_function( controller, Fabla2::MASTER_VOL, sizeof(float), 0, &tmp );
1299 	} else if( w == padsView ) {
1300 		/*
1301 		followPad = (int)tmp;
1302 		// reset current "followed" pad to normal color
1303 		if( !followPad ) {
1304 			pads[currentPad]->value( 0 );
1305 			pads[currentPad]->theme( theme( currentBank ) );
1306 		}
1307 		*/
1308 	} else if( w == adsrA ) {
1309 		writeAtom( uris.fabla2_SampleAdsrAttack, tmp );
1310 	} else if( w == adsrD ) {
1311 		writeAtom( uris.fabla2_SampleAdsrDecay, tmp );
1312 	} else if( w == adsrS ) {
1313 		writeAtom( uris.fabla2_SampleAdsrSustain, tmp );
1314 	} else if( w == adsrR ) {
1315 		writeAtom( uris.fabla2_SampleAdsrRelease, tmp );
1316 	} else if( w == send1 ) {
1317 		writeAtom( uris.fabla2_PadAuxBus1, tmp );
1318 	} else if( w == send2 ) {
1319 		writeAtom( uris.fabla2_PadAuxBus2, tmp );
1320 	} else if( w == send3 ) {
1321 		writeAtom( uris.fabla2_PadAuxBus3, tmp );
1322 	} else if( w == send4 ) {
1323 		writeAtom( uris.fabla2_PadAuxBus4, tmp );
1324 	} else if( w == masterAuxFader1 ) {
1325 		auxFaders[0]->value( tmp );
1326 		writeAuxBus( uris.fabla2_AuxBus, 0, tmp );
1327 	} else if( w == masterAuxFader2 ) {
1328 		auxFaders[1]->value( tmp );
1329 		writeAuxBus( uris.fabla2_AuxBus, 1, tmp );
1330 	} else if( w == masterAuxFader3 ) {
1331 		auxFaders[2]->value( tmp );
1332 		writeAuxBus( uris.fabla2_AuxBus, 2, tmp );
1333 	} else if( w == masterAuxFader4 ) {
1334 		auxFaders[3]->value( tmp );
1335 		writeAuxBus( uris.fabla2_AuxBus, 3, tmp );
1336 	} else if( w == transport_bpm ) {
1337 		float v = (200*tmp)+40;
1338 		write_function( controller, Fabla2::TRANSPORT_BPM, sizeof(float), 0, &v );
1339 	} else if( w == transport_play ) {
1340 		write_function( controller, Fabla2::TRANSPORT_PLAY, sizeof(float), 0, &tmp );
1341 	} else {
1342 		// check bank buttons
1343 		for(int i = 0; i < 4; i++) {
1344 			if( w == bankBtns[i] ) {
1345 				setBank( i );
1346 				return;
1347 			} else if( w == auxFaders[i] ) {
1348 				if(i == 0 ) {
1349 					masterAuxFader1->value( tmp );
1350 					writeAuxBus( uris.fabla2_AuxBus, 0, tmp );
1351 				} else if(i == 1 ) {
1352 					masterAuxFader2->value( tmp );
1353 					writeAuxBus( uris.fabla2_AuxBus, 1, tmp );
1354 				} else if(i == 2 ) {
1355 					masterAuxFader3->value( tmp );
1356 					writeAuxBus( uris.fabla2_AuxBus, 2, tmp );
1357 				}
1358 				if(i == 3 ) {
1359 					masterAuxFader4->value( tmp );
1360 					writeAuxBus( uris.fabla2_AuxBus, 3, tmp );
1361 				}
1362 				//printf("AuxBus urid %i\n", uris.fabla2_AuxBus );
1363 			}
1364 		}
1365 
1366 		for(int i = 0; i < 16; i++) {
1367 			// check the Aux dials in live view
1368 			for(int aux = 0; aux  < 4; ++aux) {
1369 				if( w == auxDials[aux*16+i] ) {
1370 					currentBank = i/16;
1371 					currentPad  = i%16;
1372 					if( aux == 0 )
1373 						writeAtomForPad( uris.fabla2_PadAuxBus1, i, tmp );
1374 					if( aux == 1 )
1375 						writeAtomForPad( uris.fabla2_PadAuxBus2, i, tmp );
1376 					if( aux == 2 )
1377 						writeAtomForPad( uris.fabla2_PadAuxBus3, i, tmp );
1378 					if( aux == 3 )
1379 						writeAtomForPad( uris.fabla2_PadAuxBus4, i, tmp );
1380 				}
1381 			}
1382 
1383 			// check padFaders
1384 			if( w == padFaders[i] ) {
1385 				writeAtomForPad( uris.fabla2_PadVolume, i, tmp );
1386 			}
1387 
1388 			// check pads
1389 			if( w == pads[i] ) {
1390 				// right mouse, click press event
1391 				if( w->mouseButton() == 3 && tmp ) {
1392 					// load pad
1393 					currentPad = i;
1394 					showFileView();
1395 				} else {
1396 					if( tmp ) {
1397 						currentPad = i;
1398 						//printf("CurrentPad %d, clicked pad %d\n", currentPad, i);
1399 						writeAtom( uris.fabla2_PadPlay, w->value() );
1400 						if(pads[currentPad]->loaded_)
1401 							updateMaschine(i, 10, 31, 255, 255);
1402 							if(followPad) {
1403 								requestSampleState( currentBank, currentPad, currentLayer );
1404 							}
1405 					} else {
1406 						writeAtom( uris.fabla2_PadStop, 0 );
1407 						updateMaschine(i, 10, 31, 255, 10);
1408 					}
1409 				}
1410 				return;
1411 			}
1412 		}
1413 	}
1414 }
1415