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