1 /*
2  * Author: Harry van Haaren 2013
3  *         harryhaaren@gmail.com
4  *
5  *  This program is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation, either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "gui.hxx"
20 #include "avtk/avtk_image.h"
21 #include "avtk/avtk_button.h"
22 
23 #include <sstream>
24 
25 #pragma GCC diagnostic ignored "-Wunused-parameter"
26 #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
27 
28 // ONLY to be used for QUIT!
29 #include "jack.hxx"
30 extern Jack* jack;
31 
32 #include "audiobuffer.hxx"
33 #include "controller/nonseq.hxx"
34 #include "controller/genericmidi.hxx"
35 
36 #include "icon.xpm"
37 #include <FL/x.H>
38 #include <FL/fl_draw.H>
39 
40 #include <stdlib.h>
41 #include <FL/Fl.H>
42 #include <FL/fl_ask.H>
43 #include <FL/Fl_Window.H>
44 #include <FL/Fl_Group.H>
45 #include <FL/Fl_Wizard.H>
46 #include <FL/Fl_Button.H>
47 #include <FL/Fl_Multiline_Output.H>
48 
49 // include the header.c file in the planning dir:
50 // its the GIMP .c export of the LUPPP header image
51 #include "../planning/header.c"
52 #include "../planning/luppp.c"
53 #include "../planning/bg.c"
54 
55 using namespace std;
56 
57 extern Gui* gui;
58 extern int signalHanlderInt;
59 
signalChecker(void *)60 static void signalChecker(void*)
61 {
62 	if ( signalHanlderInt ) {
63 		// Luppp recieved either a SIGTERM or SIGINT: quit gracefully
64 		gui->quit();
65 	} else {
66 		Fl::repeat_timeout( 0.1, (Fl_Timeout_Handler)&signalChecker, 0 );
67 	}
68 }
69 
close_cb(Fl_Widget * o,void *)70 void close_cb(Fl_Widget*o, void*)
71 {
72 	if ( (Fl::event() == FL_KEYDOWN || Fl::event() == FL_SHORTCUT) && Fl::event_key() == FL_Escape) {
73 		// on excape, as about quitting
74 		gui->askQuit();
75 	} else {
76 		gui->quit();
77 	}
78 }
gui_static_read_rb(void * inst)79 static void gui_static_read_rb(void* inst)
80 {
81 	handleGuiEvents();
82 
83 	Fl::repeat_timeout( 1 / 30.f, &gui_static_read_rb, inst);
84 }
85 
gui_static_nsm_cb(void * inst)86 static void gui_static_nsm_cb(void* inst)
87 {
88 	nsm_check_nowait( gui->getNsm() );
89 	Fl::repeat_timeout( 1 / 30.f, &gui_static_nsm_cb, inst);
90 }
91 
option_controller_cb(Fl_Widget *,void * data)92 void option_controller_cb(Fl_Widget*,void* data)
93 {
94 	LUPPP_NOTE("%s","Controller cb");
95 }
96 
gui_header_callback(Fl_Widget * w,void * data)97 static void gui_header_callback(Fl_Widget *w, void *data)
98 {
99 	Gui* g = (Gui*)data;
100 	if ( Fl::event_x() > 130 ) {
101 		return;
102 	}
103 
104 	Fl_Menu_Item rclick_menu[] = {
105 		{ "New Session" },
106 		{ "Load Session" },
107 		{ "Save Session   ", 0, 0, 0, FL_MENU_DIVIDER},
108 		{ "Setup", 0, 0, 0, FL_MENU_DIVIDER},
109 		{ "Quit" },
110 		{ 0 }
111 	};
112 
113 	// check for NSM running, deactivate new / save / load if yes
114 	if ( gui->getNsm() ) {
115 		rclick_menu[1].deactivate();
116 		rclick_menu[2].deactivate();
117 	}
118 
119 	Fl_Menu_Item *m = (Fl_Menu_Item*) rclick_menu->popup( 10, 38, 0, 0, 0);
120 
121 	if ( !m ) {
122 		return;
123 	} else if ( strcmp(m->label(), "New Session") == 0 ) {
124 		int yes = fl_choice("Start a new session?","Cancel","Yes",0);
125 		if ( yes ) {
126 			gui->reset();
127 		}
128 	} else if ( strcmp(m->label(), "Load Session") == 0 ) {
129 
130 		std::string tmp;
131 		{
132 			// Create the file chooser, and show it
133 			Fl_File_Chooser chooser(gui->getProjectsDir().c_str(),
134 			                        "*",
135 			                        Fl_File_Chooser::DIRECTORY,
136 			                        "Load Session");
137 			chooser.show();
138 
139 			// Block until user picks something.
140 			//     (The other way to do this is to use a callback())
141 			//
142 			while(chooser.shown()) {
143 				Fl::wait();
144 			}
145 
146 			// User hit cancel?
147 			if ( chooser.value() == NULL ) {
148 				fprintf(stderr, "(User hit 'Cancel')\n");
149 				return;
150 			}
151 
152 			// Print what the user picked
153 			fprintf(stderr, "--------------------\n");
154 			fprintf(stderr, "DIRECTORY: '%s'\n", chooser.directory());
155 			fprintf(stderr, "    VALUE: '%s'\n", chooser.value());
156 			fprintf(stderr, "    COUNT: %d files selected\n", chooser.count());
157 
158 			tmp = chooser.value();
159 			chooser.hide();
160 
161 			/*
162 			// try to make the Load window dissapear *now*
163 			Fl::check();
164 			Fl::flush();
165 			Fl::wait(0);
166 			*/
167 		}
168 
169 		LUPPP_NOTE( "Loading session from dir %s", tmp.c_str() );
170 
171 		// clear the current session: just do a state reset
172 		EventStateReset e;
173 		writeToDspRingbuffer( &e );
174 
175 		int sess = gui->getDiskReader()->readSession( tmp );
176 		if ( sess != LUPPP_RETURN_OK )
177 			LUPPP_ERROR( "Error loading session" );
178 
179 		return;
180 	} else if ( strcmp(m->label(), "Save Session   ") == 0 ) {
181 		const char* name = fl_input( "Save session as", gui->getDiskWriter()->getLastSaveName().c_str() );
182 		if ( name ) {
183 			gui->getDiskWriter()->initialize( gui->getProjectsDir().c_str(), name );
184 			LUPPP_NOTE("%s %s","Saving session as ", name );
185 			EventStateSave e;
186 			writeToDspRingbuffer( &e );
187 		}
188 	} else if ( strcmp(m->label(), "Setup") == 0 ) {
189 		g->getOptionsWindow()->show();
190 	} else if ( strcmp(m->label(), "Quit") == 0 ) {
191 		g->askQuit();
192 	}
193 }
194 
getOptionsWindow()195 OptionsWindow* Gui::getOptionsWindow()
196 {
197 	return optionWindow;
198 }
199 
selectLoadController(Fl_Widget * w,void *)200 void Gui::selectLoadController(Fl_Widget* w, void*)
201 {
202 	// FIXME: refactor
203 	string path;
204 	Fl_Native_File_Chooser fnfc;
205 	fnfc.title("Pick a controller definition");
206 	fnfc.type(Fl_Native_File_Chooser::BROWSE_FILE);
207 	fnfc.filter("Controllers\t*.ctlr");
208 	fnfc.directory( getenv("HOME") ); // default directory to use
209 	// Show native chooser
210 	switch ( fnfc.show() ) {
211 	case -1:
212 		printf("ERROR: %s\n", fnfc.errmsg());
213 		break;  // ERROR
214 	case  1:
215 		printf("CANCEL\n");
216 		break;  // CANCEL
217 	default:
218 		printf("Loading controller at %s\n", fnfc.filename());
219 		path = fnfc.filename();
220 		break;
221 	}
222 
223 	if ( strcmp( path.c_str(), "" ) == 0 )
224 		return;
225 
226 	LUPPP_NOTE("%s","ADD Controller cb");
227 	Controller* c = new GenericMIDI( path );
228 
229 	if ( c->status() == Controller::CONTROLLER_OK ) {
230 		EventControllerInstance e(c);
231 		writeToDspRingbuffer( &e );
232 	} else {
233 		LUPPP_ERROR("Controller initialization failed!");
234 	}
235 
236 }
237 
setProjectsDir(string dir)238 void Gui::setProjectsDir(string dir)
239 {
240 	lupppProjectsDir=dir;
241 }
242 
getProjectsDir()243 string Gui::getProjectsDir()
244 {
245 	return lupppProjectsDir;
246 }
247 
selectSaveSample(int track,int scene)248 void Gui::selectSaveSample( int track, int scene )
249 {
250 	EventStateSaveBuffer e;
251 	e.track = track,
252 	  e.scene = scene,
253 	    writeToDspRingbuffer( &e );
254 }
255 
256 char *
selectSavePath()257 Gui::selectSavePath()
258 {
259 	string path;
260 	Fl_Native_File_Chooser fnfc;
261 	fnfc.title("Save filename?");
262 	fnfc.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE);
263 
264 	std::string defLoadPath = gui->getDiskReader()->getLastLoadedSamplePath();
265 	fnfc.directory( defLoadPath.c_str() ); // default directory to use
266 
267 	// Show native chooser
268 	switch ( fnfc.show() ) {
269 	case -1: /*printf("ERROR: %s\n", fnfc.errmsg()); */
270 		break;  // ERROR
271 	case  1: /*(printf("CANCEL\n");                  */
272 		break;  // CANCEL
273 	default: /*printf("Loading directory: %s\n", fnfc.filename()); */
274 		path = fnfc.filename();
275 		break;
276 	}
277 
278 	if ( strcmp( path.c_str(), "" ) == 0 )
279 		return 0;
280 
281 	return strdup(path.c_str());
282 }
283 
selectLoadSample(int track,int scene)284 void Gui::selectLoadSample( int track, int scene )
285 {
286 	// FIXME: refactor
287 	string path;
288 	Fl_Native_File_Chooser fnfc;
289 	fnfc.title("Pick a file");
290 	fnfc.type(Fl_Native_File_Chooser::BROWSE_FILE);
291 
292 	fnfc.filter("Audio\t{*.aiff,*.wav,*.flac,*.ogg}");
293 
294 	std::string defLoadPath = gui->getDiskReader()->getLastLoadedSamplePath();
295 	fnfc.directory( defLoadPath.c_str() ); // default directory to use
296 
297 	// Show native chooser
298 	switch ( fnfc.show() ) {
299 	case -1: /*printf("ERROR: %s\n", fnfc.errmsg()); */
300 		break;  // ERROR
301 	case  1: /*(printf("CANCEL\n");                  */
302 		break;  // CANCEL
303 	default: /*printf("Loading directory: %s\n", fnfc.filename()); */
304 		path = fnfc.filename();
305 		break;
306 	}
307 
308 	if ( strcmp( path.c_str(), "" ) == 0 )
309 		return;
310 
311 	// diskReader loads sample, and parses for sample.cfg
312 	diskReader->loadSample( track, scene, path );
313 }
314 
getAudioEditor()315 AudioEditor* Gui::getAudioEditor()
316 {
317 	return audioEditor;
318 }
319 
320 
cb_nsm_open(const char * name,const char * display_name,const char * client_id,char ** out_msg,void * userdata)321 static int cb_nsm_open (const char *name,
322                         const char *display_name,
323                         const char *client_id,
324                         char **out_msg,
325                         void *userdata )
326 {
327 	LUPPP_NOTE("NSM: Open, displayname: %s", display_name );
328 
329 	Jack::setup( client_id );
330 
331 	// we *must* get the samplerate here: loading files depends on this information!
332 	gui->samplerate = jack->getSamplerate();
333 
334 	stringstream loadPath;
335 	loadPath << name;
336 
337 	// load the NSM provided directory
338 	gui->getDiskReader()->readSession( loadPath.str() );
339 
340 	// initialize the disk-writer to the same directory:
341 	// we *always* overwrite the old save file when using NSM
342 	gui->getDiskWriter()->initialize( name, display_name );
343 
344 	return ERR_OK;
345 }
346 
cb_nsm_save(char ** out_msg,void * userdata)347 static int cb_nsm_save ( char **out_msg, void *userdata )
348 {
349 	LUPPP_NOTE("NSM: saving..." );
350 
351 	// disk-writer already initialized to the right directory, so just write!
352 	EventStateSave e;
353 	writeToDspRingbuffer( &e );
354 
355 	return 0;
356 }
357 
358 
359 
Gui(const char * argZero)360 Gui::Gui(const char* argZero) :
361 	samplerate( 0 ),
362 	window(1110,700),
363 	enablePerTrackOutput(false),
364 	diskReader( new DiskReader() ),
365 	diskWriter( new DiskWriter() )
366 {
367 	gui = this;
368 
369 	// setup window icon before calling show()
370 	fl_open_display();
371 	Fl_Pixmap* pixmap = new Fl_Pixmap( icon_xpm );
372 	Fl_Offscreen lupppIcon = XCreatePixmap(fl_display, RootWindow(fl_display, fl_screen),
373 	                                       pixmap->w(), pixmap->h(), fl_visual->depth);
374 	fl_gc = XCreateGC(fl_display, lupppIcon, 0, 0);
375 	fl_begin_offscreen(lupppIcon);
376 	pixmap->draw(0,0);
377 	fl_end_offscreen();
378 	delete pixmap;
379 	XFreeGC(fl_display, fl_gc);
380 
381 	window.icon( (void*)lupppIcon );
382 
383 	// setup callback to signalChecker()
384 	Fl::add_timeout( 0.1, (Fl_Timeout_Handler)&signalChecker, 0 );
385 
386 	// add keyboard shortcut handler
387 	Fl::add_handler( keyboardHandler );
388 
389 	//window.resize( false );
390 	window.xclass("luppp");
391 	window.iconlabel("luppp");
392 
393 	window.color(FL_BLACK);
394 	window.label("Luppp");
395 	window.callback( close_cb, 0 );
396 	window.size_range( 800, 450 );
397 
398 	window.color( fl_rgb_color (7,7,7) );
399 
400 	// horizontal no-resize-images group
401 	Fl_Group* headerImages = new Fl_Group( 0, 0, 1110, 650, "header");
402 	{
403 		//Fl_Pack* vHeaderImages = new Fl_Pack( 0, 0, 1110, 650, "verticalHeader");
404 		{
405 			Avtk::Image* bgImage = new Avtk::Image(0,0,1920,36,"bg");
406 			bgImage->setPixbuf( bgImg.pixel_data, 4 );
407 
408 			Avtk::Image* lupppImage = new Avtk::Image(0,0,130,36,"luppp");
409 			lupppImage->setPixbuf( lupppImg.pixel_data, 4 );
410 			lupppImage->callback( gui_header_callback, this );
411 
412 			Avtk::Image* headerImage = new Avtk::Image( window.w() - 270,0,270,36,"header");
413 			headerImage->setPixbuf( header.pixel_data, 4 );
414 			headerImage->stickToRight = true;
415 
416 
417 			Fl_Box* box = new Fl_Box( 130, 0, 400, 36 );
418 			headerImages->resizable( box );
419 
420 			//vHeaderImages->set_vertical();
421 			//vHeaderImages->relayout();
422 		}
423 		//vHeaderImages->end();
424 
425 		Fl_Box* box = new Fl_Box( 130, 0, 400, 36 );
426 		headerImages->resizable( box );
427 	}
428 	headerImages->end();
429 
430 	// create a new "Group" with all Luppp GUI contents, for resizing
431 	lupppGroup = new Fl_Group( 0, 0, 1110, 700, "Luppp");
432 	{
433 		int i = 0;
434 		for (; i < NTRACKS; i++ ) {
435 			stringstream s;
436 			s << "Track " << i+1;
437 			tracks.push_back( std::make_shared<GTrack>(8 + i * 118, 40, 110, 650, s.str().c_str() ) );
438 		}
439 		master = new GMasterTrack(8 + i * 118, 40, 150, 650, "Master");
440 	}
441 	lupppGroup->end();
442 
443 	window.resizable( lupppGroup );
444 
445 	window.end();
446 
447 	specialTrack = 0;
448 	specialScene = 0;
449 	tracks.at( specialTrack )->getClipSelector()->setSpecial( specialScene );
450 
451 
452 	optionWindow = new OptionsWindow();
453 
454 	// Create AudioEditor after window.end() has been called
455 	audioEditor = new AudioEditor();
456 
457 	// read settings file using diskreader, and setup controllers etc
458 	int prefs = diskReader->loadPreferences();
459 	if ( prefs != LUPPP_RETURN_OK ) {
460 		LUPPP_WARN("No preferences loaded, using defaults.");
461 	} else {
462 		LUPPP_NOTE("Loaded preferences");
463 	}
464 
465 	// NSM stuff
466 	nsm = 0;
467 	const char *nsm_url = getenv( "NSM_URL" );
468 	if ( nsm_url ) {
469 		nsm = nsm_new();
470 
471 		nsm_set_open_callback( nsm, cb_nsm_open, this );
472 		nsm_set_save_callback( nsm, cb_nsm_save, this );
473 
474 		if ( nsm_init( nsm, nsm_url ) == 0 ) {
475 			nsm_send_announce( nsm, "Luppp", "", argZero );
476 			LUPPP_NOTE("Announcing to NSM");
477 		} else {
478 			nsm_free( nsm );
479 			nsm = 0;
480 		}
481 	}
482 }
483 
addMidiControllerToSetup(std::string c)484 void Gui::addMidiControllerToSetup(std::string c)
485 {
486 	controllerVector.push_back( c );
487 }
488 
setupMidiControllers()489 void Gui::setupMidiControllers()
490 {
491 	for(unsigned int i = 0; i < controllerVector.size(); i++) {
492 		GenericMIDI* c = new GenericMIDI( controllerVector.at(i).c_str() );
493 		if ( c ) {
494 			EventControllerInstance e(c);
495 			writeToDspRingbuffer( &e );
496 		}
497 	}
498 }
499 
reset()500 void Gui::reset()
501 {
502 	// signal to DSP to reset state
503 	EventStateReset ev;
504 	writeToDspRingbuffer( &ev );
505 
506 	// clear UI state: track names / scene names
507 	for(unsigned int i = 0; i < NTRACKS; i++) {
508 		stringstream s;
509 		s << "Track " << i+1;
510 		tracks.at(i)->bg.copy_label( s.str().c_str() );
511 
512 		for(unsigned int s = 0; s < NSCENES; s++) {
513 			tracks.at(i)->getClipSelector()->clipName( s, "" );
514 		}
515 	}
516 
517 	for(unsigned int i = 0; i < NSCENES; i++) {
518 		stringstream s;
519 		s << "Scene " << i+1;
520 		master->getClipSelector()->clipName( i, s.str() );
521 	}
522 
523 }
524 
getTrack(int id) const525 std::shared_ptr<GTrack> Gui::getTrack(int id) const
526 {
527 	return tracks.at(id);
528 }
529 
show()530 int Gui::show()
531 {
532 	window.show();
533 
534 	gui_static_read_rb( this );
535 
536 	// only launch NSM check callbacks if NSM is setup
537 	if ( gui->getNsm() )
538 		gui_static_nsm_cb( this );
539 
540 	return Fl::run();
541 }
542 
543 
quit()544 int Gui::quit()
545 {
546 	// close JACK client
547 	jack->quit();
548 
549 	// ensure the subwindows are closed
550 	optionWindow->hide();
551 	audioEditor->hide();
552 
553 	// quit main window, causing program termination
554 	window.hide();
555 
556 	return 0;
557 }
558 
askQuit()559 void Gui::askQuit()
560 {
561 	int quit = fl_choice("Really Quit?","Cancel","Quit",0);
562 	if ( quit ) { // JUST QUIT
563 		gui->quit();
564 	}
565 }
566 
keyboardHandler(int event)567 int Gui::keyboardHandler(int event)
568 {
569 
570 	switch( event ) {
571 	case FL_SHORTCUT:
572 		if     ( strcmp( Fl::event_text(), "1" ) == 0 ) {
573 			EventGridEvent e( 0, 0, true );
574 			writeToDspRingbuffer( &e );
575 			return 1;
576 		} else if( strcmp( Fl::event_text(), "2" ) == 0 ) {
577 			EventGridEvent e( 1, 0, true );
578 			writeToDspRingbuffer( &e );
579 			return 1;
580 		} else if( strcmp( Fl::event_text(), "3" ) == 0 ) {
581 			EventGridEvent e( 2, 0, true );
582 			writeToDspRingbuffer( &e );
583 			return 1;
584 		} else if( strcmp( Fl::event_text(), "4" ) == 0 ) {
585 			EventGridEvent e( 3, 0, true );
586 			writeToDspRingbuffer( &e );
587 			return 1;
588 		} else if( strcmp( Fl::event_text(), "5" ) == 0 ) {
589 			EventGridEvent e( 4, 0, true );
590 			writeToDspRingbuffer( &e );
591 			return 1;
592 		} else if( strcmp( Fl::event_text(), "6" ) == 0 ) {
593 			EventGridEvent e( 5, 0, true );
594 			writeToDspRingbuffer( &e );
595 			return 1;
596 		} else if( strcmp( Fl::event_text(), "7" ) == 0 ) {
597 			EventGridEvent e( 6, 0, true );
598 			writeToDspRingbuffer( &e );
599 			return 1;
600 		} else if( strcmp( Fl::event_text(), "8" ) == 0 ) {
601 			EventGridEvent e( 7, 0, true );
602 			writeToDspRingbuffer( &e );
603 			return 1;
604 		}
605 
606 		else if( strcmp( Fl::event_text(), "!" ) == 0 ) {
607 			EventGridState e( 0, 0, GridLogic::STATE_EMPTY );
608 			writeToDspRingbuffer( &e );
609 			return 1;
610 		} else if( strcmp( Fl::event_text(), "@" ) == 0 ) {
611 			EventGridState e( 1, 0, GridLogic::STATE_EMPTY );
612 			writeToDspRingbuffer( &e );
613 			return 1;
614 		} else if( strcmp( Fl::event_text(), "\"" ) == 0 ) {
615 			EventGridState e( 1, 0, GridLogic::STATE_EMPTY );        // for UK/Ireland keyboards
616 			writeToDspRingbuffer( &e );
617 			return 1;
618 		} else if( strcmp( Fl::event_text(), "#" ) == 0 ) {
619 			EventGridState e( 2, 0, GridLogic::STATE_EMPTY );
620 			writeToDspRingbuffer( &e );
621 			return 1;
622 		} else if( strcmp( Fl::event_text(), "£" ) == 0 ) {
623 			EventGridState e( 2, 0, GridLogic::STATE_EMPTY );        // for UK/Ireland keyboards
624 			writeToDspRingbuffer( &e );
625 			return 1;
626 		} else if( strcmp( Fl::event_text(), "$" ) == 0 ) {
627 			EventGridState e( 3, 0, GridLogic::STATE_EMPTY );
628 			writeToDspRingbuffer( &e );
629 			return 1;
630 		} else if( strcmp( Fl::event_text(), "%" ) == 0 ) {
631 			EventGridState e( 4, 0, GridLogic::STATE_EMPTY );
632 			writeToDspRingbuffer( &e );
633 			return 1;
634 		} else if( strcmp( Fl::event_text(), "^" ) == 0 ) {
635 			EventGridState e( 5, 0, GridLogic::STATE_EMPTY );
636 			writeToDspRingbuffer( &e );
637 			return 1;
638 		} else if( strcmp( Fl::event_text(), "&" ) == 0 ) {
639 			EventGridState e( 6, 0, GridLogic::STATE_EMPTY );
640 			writeToDspRingbuffer( &e );
641 			return 1;
642 		} else if( strcmp( Fl::event_text(), "*" ) == 0 ) {
643 			EventGridState e( 7, 0, GridLogic::STATE_EMPTY );
644 			writeToDspRingbuffer( &e );
645 			return 1;
646 		}
647 
648 		else if( strcmp( Fl::event_text(), "q" ) == 0 ) {
649 			EventGridEvent e( 0, 1, true );
650 			writeToDspRingbuffer( &e );
651 			return 1;
652 		} else if( strcmp( Fl::event_text(), "w" ) == 0 ) {
653 			EventGridEvent e( 1, 1, true );
654 			writeToDspRingbuffer( &e );
655 			return 1;
656 		} else if( strcmp( Fl::event_text(), "e" ) == 0 ) {
657 			EventGridEvent e( 2, 1, true );
658 			writeToDspRingbuffer( &e );
659 			return 1;
660 		} else if( strcmp( Fl::event_text(), "r" ) == 0 ) {
661 			EventGridEvent e( 3, 1, true );
662 			writeToDspRingbuffer( &e );
663 			return 1;
664 		} else if( strcmp( Fl::event_text(), "t" ) == 0 ) {
665 			EventGridEvent e( 4, 1, true );
666 			writeToDspRingbuffer( &e );
667 			return 1;
668 		} else if( strcmp( Fl::event_text(), "y" ) == 0 ) {
669 			EventGridEvent e( 5, 1, true );
670 			writeToDspRingbuffer( &e );
671 			return 1;
672 		} else if( strcmp( Fl::event_text(), "u" ) == 0 ) {
673 			EventGridEvent e( 6, 1, true );
674 			writeToDspRingbuffer( &e );
675 			return 1;
676 		} else if( strcmp( Fl::event_text(), "i" ) == 0 ) {
677 			EventGridEvent e( 7, 1, true );
678 			writeToDspRingbuffer( &e );
679 			return 1;
680 		}
681 
682 		else if( strcmp( Fl::event_text(), "Q" ) == 0 ) {
683 			EventGridState e( 0, 1, GridLogic::STATE_EMPTY );
684 			writeToDspRingbuffer( &e );
685 			return 1;
686 		} else if( strcmp( Fl::event_text(), "W" ) == 0 ) {
687 			EventGridState e( 1, 1, GridLogic::STATE_EMPTY );
688 			writeToDspRingbuffer( &e );
689 			return 1;
690 		} else if( strcmp( Fl::event_text(), "E" ) == 0 ) {
691 			EventGridState e( 2, 1, GridLogic::STATE_EMPTY );
692 			writeToDspRingbuffer( &e );
693 			return 1;
694 		} else if( strcmp( Fl::event_text(), "R" ) == 0 ) {
695 			EventGridState e( 3, 1, GridLogic::STATE_EMPTY );
696 			writeToDspRingbuffer( &e );
697 			return 1;
698 		} else if( strcmp( Fl::event_text(), "T" ) == 0 ) {
699 			EventGridState e( 4, 1, GridLogic::STATE_EMPTY );
700 			writeToDspRingbuffer( &e );
701 			return 1;
702 		} else if( strcmp( Fl::event_text(), "Y" ) == 0 ) {
703 			EventGridState e( 5, 1, GridLogic::STATE_EMPTY );
704 			writeToDspRingbuffer( &e );
705 			return 1;
706 		} else if( strcmp( Fl::event_text(), "U" ) == 0 ) {
707 			EventGridState e( 6, 1, GridLogic::STATE_EMPTY );
708 			writeToDspRingbuffer( &e );
709 			return 1;
710 		} else if( strcmp( Fl::event_text(), "I" ) == 0 ) {
711 			EventGridState e( 7, 1, GridLogic::STATE_EMPTY );
712 			writeToDspRingbuffer( &e );
713 			return 1;
714 		}
715 
716 		else if( strcmp( Fl::event_text(), "a" ) == 0 ) {
717 			EventGridEvent e( 0, 2, true );
718 			writeToDspRingbuffer( &e );
719 			return 1;
720 		} else if( strcmp( Fl::event_text(), "s" ) == 0 ) {
721 			EventGridEvent e( 1, 2, true );
722 			writeToDspRingbuffer( &e );
723 			return 1;
724 		} else if( strcmp( Fl::event_text(), "d" ) == 0 ) {
725 			EventGridEvent e( 2, 2, true );
726 			writeToDspRingbuffer( &e );
727 			return 1;
728 		} else if( strcmp( Fl::event_text(), "f" ) == 0 ) {
729 			EventGridEvent e( 3, 2, true );
730 			writeToDspRingbuffer( &e );
731 			return 1;
732 		} else if( strcmp( Fl::event_text(), "g" ) == 0 ) {
733 			EventGridEvent e( 4, 2, true );
734 			writeToDspRingbuffer( &e );
735 			return 1;
736 		} else if( strcmp( Fl::event_text(), "h" ) == 0 ) {
737 			EventGridEvent e( 5, 2, true );
738 			writeToDspRingbuffer( &e );
739 			return 1;
740 		} else if( strcmp( Fl::event_text(), "j" ) == 0 ) {
741 			EventGridEvent e( 6, 2, true );
742 			writeToDspRingbuffer( &e );
743 			return 1;
744 		} else if( strcmp( Fl::event_text(), "k" ) == 0 ) {
745 			EventGridEvent e( 7, 2, true );
746 			writeToDspRingbuffer( &e );
747 			return 1;
748 		}
749 
750 		else if( strcmp( Fl::event_text(), "A" ) == 0 ) {
751 			EventGridState e( 0, 2, GridLogic::STATE_EMPTY );
752 			writeToDspRingbuffer( &e );
753 			return 1;
754 		} else if( strcmp( Fl::event_text(), "S" ) == 0 ) {
755 			EventGridState e( 1, 2, GridLogic::STATE_EMPTY );
756 			writeToDspRingbuffer( &e );
757 			return 1;
758 		} else if( strcmp( Fl::event_text(), "D" ) == 0 ) {
759 			EventGridState e( 2, 2, GridLogic::STATE_EMPTY );
760 			writeToDspRingbuffer( &e );
761 			return 1;
762 		} else if( strcmp( Fl::event_text(), "F" ) == 0 ) {
763 			EventGridState e( 3, 2, GridLogic::STATE_EMPTY );
764 			writeToDspRingbuffer( &e );
765 			return 1;
766 		} else if( strcmp( Fl::event_text(), "G" ) == 0 ) {
767 			EventGridState e( 4, 2, GridLogic::STATE_EMPTY );
768 			writeToDspRingbuffer( &e );
769 			return 1;
770 		} else if( strcmp( Fl::event_text(), "H" ) == 0 ) {
771 			EventGridState e( 5, 2, GridLogic::STATE_EMPTY );
772 			writeToDspRingbuffer( &e );
773 			return 1;
774 		} else if( strcmp( Fl::event_text(), "J" ) == 0 ) {
775 			EventGridState e( 6, 2, GridLogic::STATE_EMPTY );
776 			writeToDspRingbuffer( &e );
777 			return 1;
778 		} else if( strcmp( Fl::event_text(), "K" ) == 0 ) {
779 			EventGridState e( 7, 2, GridLogic::STATE_EMPTY );
780 			writeToDspRingbuffer( &e );
781 			return 1;
782 		}
783 
784 		else if( strcmp( Fl::event_text(), "z" ) == 0 ) {
785 			EventGridEvent e( 0, 3, true );
786 			writeToDspRingbuffer( &e );
787 			return 1;
788 		} else if( strcmp( Fl::event_text(), "x" ) == 0 ) {
789 			EventGridEvent e( 1, 3, true );
790 			writeToDspRingbuffer( &e );
791 			return 1;
792 		} else if( strcmp( Fl::event_text(), "c" ) == 0 ) {
793 			EventGridEvent e( 2, 3, true );
794 			writeToDspRingbuffer( &e );
795 			return 1;
796 		} else if( strcmp( Fl::event_text(), "v" ) == 0 ) {
797 			EventGridEvent e( 3, 3, true );
798 			writeToDspRingbuffer( &e );
799 			return 1;
800 		} else if( strcmp( Fl::event_text(), "b" ) == 0 ) {
801 			EventGridEvent e( 4, 3, true );
802 			writeToDspRingbuffer( &e );
803 			return 1;
804 		} else if( strcmp( Fl::event_text(), "n" ) == 0 ) {
805 			EventGridEvent e( 5, 3, true );
806 			writeToDspRingbuffer( &e );
807 			return 1;
808 		} else if( strcmp( Fl::event_text(), "m" ) == 0 ) {
809 			EventGridEvent e( 6, 3, true );
810 			writeToDspRingbuffer( &e );
811 			return 1;
812 		} else if( strcmp( Fl::event_text(), "," ) == 0 ) {
813 			EventGridEvent e( 7, 3, true );
814 			writeToDspRingbuffer( &e );
815 			return 1;
816 		}
817 
818 		else if( strcmp( Fl::event_text(), "Z" ) == 0 ) {
819 			EventGridState e( 0, 3, GridLogic::STATE_EMPTY );
820 			writeToDspRingbuffer( &e );
821 			return 1;
822 		} else if( strcmp( Fl::event_text(), "X" ) == 0 ) {
823 			EventGridState e( 1, 3, GridLogic::STATE_EMPTY );
824 			writeToDspRingbuffer( &e );
825 			return 1;
826 		} else if( strcmp( Fl::event_text(), "C" ) == 0 ) {
827 			EventGridState e( 2, 3, GridLogic::STATE_EMPTY );
828 			writeToDspRingbuffer( &e );
829 			return 1;
830 		} else if( strcmp( Fl::event_text(), "V" ) == 0 ) {
831 			EventGridState e( 3, 3, GridLogic::STATE_EMPTY );
832 			writeToDspRingbuffer( &e );
833 			return 1;
834 		} else if( strcmp( Fl::event_text(), "B" ) == 0 ) {
835 			EventGridState e( 4, 3, GridLogic::STATE_EMPTY );
836 			writeToDspRingbuffer( &e );
837 			return 1;
838 		} else if( strcmp( Fl::event_text(), "N" ) == 0 ) {
839 			EventGridState e( 5, 3, GridLogic::STATE_EMPTY );
840 			writeToDspRingbuffer( &e );
841 			return 1;
842 		} else if( strcmp( Fl::event_text(), "M" ) == 0 ) {
843 			EventGridState e( 6, 3, GridLogic::STATE_EMPTY );
844 			writeToDspRingbuffer( &e );
845 			return 1;
846 		} else if( strcmp( Fl::event_text(), "<" ) == 0 ) {
847 			EventGridState e( 7, 3, GridLogic::STATE_EMPTY );
848 			writeToDspRingbuffer( &e );
849 			return 1;
850 		}
851 
852 		else if( strcmp( Fl::event_text(), "9" ) == 0 ) {
853 			EventGridLaunchScene e( 0 );
854 			writeToDspRingbuffer( &e );
855 			return 1;
856 		} else if( strcmp( Fl::event_text(), "o" ) == 0 ) {
857 			EventGridLaunchScene e( 1 );
858 			writeToDspRingbuffer( &e );
859 			return 1;
860 		} else if( strcmp( Fl::event_text(), "l" ) == 0 ) {
861 			EventGridLaunchScene e( 2 );
862 			writeToDspRingbuffer( &e );
863 			return 1;
864 		} else if( strcmp( Fl::event_text(), "." ) == 0 ) {
865 			EventGridLaunchScene e( 3 );
866 			writeToDspRingbuffer( &e );
867 			return 1;
868 		}
869 
870 		else {
871 			//printf("%s\n", Fl::event_text() ); return 1;
872 		}
873 	}
874 
875 	// keyboard arrows / space to special key mapping
876 	if ( Fl::event_key( 32 ) &&  Fl::event_state( FL_SHIFT ) ) { //spacebar + shift
877 		EventGridState e( gui->specialTrack, gui->specialScene, GridLogic::STATE_EMPTY  );
878 		writeToDspRingbuffer( &e );
879 		return 1;
880 	}
881 	if ( Fl::event_key( 32 ) ) { //spacebar
882 		EventGridEvent e( gui->specialTrack, gui->specialScene, true );
883 		writeToDspRingbuffer( &e );
884 		return 1;
885 	}
886 	if ( Fl::event_key( FL_Left  ) ) {
887 		EventGridSelectNewChosen e( gui->specialTrack-1, gui->specialScene  );
888 		writeToDspRingbuffer( &e );
889 		return 1;
890 	}
891 	if ( Fl::event_key( FL_Right ) ) {
892 		EventGridSelectNewChosen e( gui->specialTrack+1, gui->specialScene  );
893 		writeToDspRingbuffer( &e );
894 		return 1;
895 	}
896 	if ( Fl::event_key( FL_Up    ) ) {
897 		EventGridSelectNewChosen e( gui->specialTrack  , gui->specialScene-1);
898 		writeToDspRingbuffer( &e );
899 		return 1;
900 	}
901 	if ( Fl::event_key( FL_Down  ) ) {
902 		EventGridSelectNewChosen e( gui->specialTrack  , gui->specialScene+1);
903 		writeToDspRingbuffer( &e );
904 		return 1;
905 	}
906 
907 	return 0;
908 }
909 
910 
~Gui()911 Gui::~Gui()
912 {
913 	delete optionWindow;
914 	delete audioEditor;
915 
916 	delete diskReader;
917 	delete diskWriter;
918 
919 	delete master;
920 }
921