MIDI set_sync_client fix, cleanups, compilation fixes for gcc 2.95 - Alex
[terminatorX.git] / src / tX_seqpar.cc
1 /*
2     terminatorX - realtime audio scratching software
3     Copyright (C) 1999, 2000 Alexander K├Ânig
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 2 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, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  
19     File: tX_seqpar.cc
20  
21     Description: This implements the "sequenceable parameters".
22 */    
23
24 #include "tX_seqpar.h"
25 #include "tX_vtt.h"
26 #include <stdio.h>
27 #include "tX_mastergui.h"
28 #include "tX_global.h"
29 #include "tX_sequencer.h"
30 #include "tX_extdial.h"
31 #include "tX_engine.h"
32 #include <malloc.h>
33
34 #define TX_SEQPAR_DEFAULT_SCALE 0.05
35
36 list <tX_seqpar *> tX_seqpar :: all;
37 list <tX_seqpar *> tX_seqpar :: update;
38 pthread_mutex_t tX_seqpar :: update_lock = PTHREAD_MUTEX_INITIALIZER;
39
40 #define tt ((vtt_class *) vtt)
41
42 tX_seqpar :: tX_seqpar () : bound_midi_event()
43 {
44         touched=0;
45         gui_active=1;
46         vtt=NULL;
47         max_value=0;
48         min_value=0;
49         scale_value=0;
50         is_boolean=false;
51         is_mappable=1;
52         all.push_back(this);
53         last_event_recorded=NULL;
54         
55         midi_lower_bound_set=false;
56         midi_upper_bound_set=false;
57 }
58
59 void tX_seqpar :: set_mapping_parameters(float max, float min, float scale, int mappable)
60 {
61         max_value=max;
62         min_value=min;
63         scale_value=scale;
64         is_mappable=mappable;
65 }
66
67 void tX_seqpar :: handle_mouse_input(float adjustment)
68 {
69         float tmpvalue;
70         
71         tmpvalue=get_value()+adjustment*scale_value;
72         if (tmpvalue>max_value) tmpvalue=max_value;
73         if (tmpvalue<min_value) tmpvalue=min_value;
74         
75         /*printf("Handling %s, max %f, min %f, scale %f,  val: %f\n", get_name(), max_value, min_value, scale_value, tmpvalue);*/
76         
77         receive_input_value(tmpvalue);
78 }
79
80 #ifdef USE_ALSA_MIDI_IN
81 void tX_seqpar :: handle_midi_input( const tX_midievent& event )
82 {
83         double tmpvalue = -1000;
84         double max=max_value;
85         double min=min_value;
86         
87         if (midi_upper_bound_set) {
88                 max=midi_upper_bound;
89         }
90         
91         if (midi_lower_bound_set) {
92                 min=midi_lower_bound;
93         }
94         
95         if( !is_boolean ) {
96                 switch (event.type) {
97                         case tX_midievent::CC:
98                         case tX_midievent::CC14:
99                         case tX_midievent::PITCHBEND:
100                         case tX_midievent::RPN:
101                         case tX_midievent::NRPN:
102                                         tmpvalue = event.value * (max-min) + min;
103                                 break;
104                         case tX_midievent::NOTE:
105                                         tmpvalue = event.is_noteon;
106                                 break;
107                         default:
108                                 return;
109                 }
110
111                 if (tmpvalue>max) tmpvalue=max;
112                 else if (tmpvalue<min) tmpvalue=min;
113         } else {
114                 tmpvalue=event.value;
115         }
116         
117         touch();
118
119         /* Not using receive() as we want immediate GUI update... */
120         do_exec(tmpvalue);
121         record_value(tmpvalue);
122         do_update_graphics();
123 }
124 #endif
125
126 void tX_seqpar :: set_vtt (void *mytt)
127 {
128         vtt=mytt;
129 }
130
131 tX_seqpar :: ~tX_seqpar()
132 {
133         pthread_mutex_lock(&update_lock);
134         update.remove(this);
135         pthread_mutex_unlock(&update_lock);
136         sequencer.delete_all_events_for_sp(this, tX_sequencer::DELETE_ALL);
137         all.remove(this);
138 }
139
140 void tX_seqpar :: do_touch()
141 {
142         if (sequencer.is_recording())
143         {
144                 touched=1;
145                 touch_timestamp=sequencer.get_timestamp();
146         }
147 }
148
149 void tX_seqpar :: untouch_all()
150 {
151         list <tX_seqpar *> :: iterator sp;
152         
153         for (sp=all.begin(); sp!=all.end(); sp++)
154         {
155                 (*sp)->untouch();
156         }
157 }
158
159 void tX_seqpar :: create_persistence_ids()
160 {
161         list <tX_seqpar *> :: iterator sp;
162         int pid=0;
163         
164         for (sp=all.begin(); sp!=all.end(); sp++)
165         {
166                 pid++;
167                 (*sp)->set_persistence_id(pid);
168         }
169 }
170
171 tX_seqpar* tX_seqpar :: get_sp_by_persistence_id(unsigned int pid)
172 {
173         list <tX_seqpar *> :: iterator sp;
174         
175         for (sp=all.begin(); sp!=all.end(); sp++)
176         {
177                 if ((*sp)->get_persistence_id()==pid) return ((*sp));
178         }
179         
180         fprintf (stderr, "oops: failed to lookup persistence id [%i].\n", pid); 
181         return (NULL);
182 }
183
184
185 void tX_seqpar :: record_value(const float value)
186 {
187 #define last_event ((tX_event *) last_event_recorded)
188
189         /* recording more than one event per seqpar for
190           one timestamp doesn't make sense... so if the 
191           last_event_recorded was for the current timestamp
192           we simply set that event's value to the current one.
193         */
194         if ((last_event) && (last_event->get_timestamp() == sequencer.get_timestamp()))
195         {
196                 last_event->set_value(value);
197         }
198         else last_event_recorded=(void *) sequencer.record(this, value);
199 }
200
201 void tX_seqpar :: receive_gui_value(const float value)
202 {
203         if (gui_active)
204         {
205                 touch();
206                 do_exec(value);
207                 record_value(value);
208         }
209 }
210
211 void tX_seqpar :: receive_input_value(const float value)
212 {
213         touch();
214         exec_value(value);
215         record_value(value);
216 }
217
218 void tX_seqpar :: receive_forward_value(const float value)
219 {
220         fwd_value=value;
221 }
222
223 void tX_seqpar :: materialize_forward_values()
224 {
225         list <tX_seqpar *> :: iterator sp;
226         
227         for (sp=all.begin(); sp!=all.end(); sp++)
228         {
229                 (*sp)->exec_value((*sp)->fwd_value);
230         }       
231         gdk_flush();
232 }
233
234 char * tX_seqpar :: get_vtt_name()
235 {       
236         if (vtt) return tt->name;
237         else return "Master Track";
238 }
239
240 void tX_seqpar :: restore_meta(xmlNodePtr node) {
241         char *buffer;
242         double temp;
243         
244         buffer=(char *) xmlGetProp(node, (xmlChar *) "id");
245         if (buffer) { sscanf(buffer, "%i", &persistence_id); }
246         else { tX_error("no ID for seqpar %s", this->get_name()); }
247         
248         buffer=(char *) xmlGetProp(node, (xmlChar *) "midiUpperBound");
249         if (buffer) {
250                 sscanf(buffer, "%lf", &temp);
251                 set_upper_midi_bound(temp);
252         }
253
254         buffer=(char *) xmlGetProp(node, (xmlChar *) "midiLowerBound");
255         if (buffer) {
256                 sscanf(buffer, "%lf", &temp);
257                 set_lower_midi_bound(temp);
258         }
259         
260         buffer=(char *) xmlGetProp(node, (xmlChar *) "midiType");
261         if (buffer) {
262                 if (strcmp("cc", buffer)==0) {
263                         bound_midi_event.type=tX_midievent::CC;
264                 } else if (strcmp("note", buffer)==0) {
265                         bound_midi_event.type=tX_midievent::NOTE;
266                 } else if (strcmp("pitchbend", buffer)==0) {
267                         bound_midi_event.type=tX_midievent::PITCHBEND;
268                 } else if (strcmp("cc14", buffer)==0) {
269                         bound_midi_event.type=tX_midievent::CC14;
270                 } else if (strcmp("rpn", buffer)==0) {
271                         bound_midi_event.type=tX_midievent::RPN;
272                 } else if (strcmp("nrpn", buffer)==0) {
273                         bound_midi_event.type=tX_midievent::NRPN;
274                 } else {
275                         tX_error("unknown midiType \"%s\" for seqpar %s", buffer, this->get_name());
276                 }
277                 
278                 buffer=(char *) xmlGetProp(node, (xmlChar *) "midiChannel");
279                 if (buffer) { sscanf(buffer, "%i", &bound_midi_event.channel); }
280                 else { tX_error("no midiChannel for seqpar %s", this->get_name()); }
281                         
282                 buffer=(char *) xmlGetProp(node, (xmlChar *) "midiNumber");
283                 if (buffer) { sscanf(buffer, "%i", &bound_midi_event.number); }
284                 else { tX_error("no midiNumber for seqpar %s", this->get_name()); }
285         } 
286         /* else: no MIDI init.... */
287 }
288
289 void tX_seqpar :: store_meta(FILE *rc, gzFile rz) {
290         char buffer[512];
291         char buffer2[256];
292         
293         if (bound_midi_event.type!=tX_midievent::NONE) {
294                 char *type;
295                 
296                 switch (bound_midi_event.type) {
297                         case tX_midievent::NOTE: type="note"; break;
298                         case tX_midievent::CC: type="cc"; break;
299                         case tX_midievent::PITCHBEND: type="pitchbend"; break;
300                         case tX_midievent::CC14: type="cc14"; break;
301                         case tX_midievent::RPN: type="rpn"; break;
302                         case tX_midievent::NRPN: type="nrpn"; break;
303                         default: type="error";
304                 }
305                 sprintf(buffer, "id=\"%i\" midiType=\"%s\" midiChannel=\"%i\" midiNumber=\"%i\"", persistence_id, type, bound_midi_event.channel, bound_midi_event.number);
306         } else {
307                 sprintf(buffer, "id=\"%i\"", persistence_id);
308         }
309         
310         if (midi_upper_bound_set) {
311                 sprintf(buffer2, " midiUpperBound=\"%lf\"", midi_upper_bound);
312                 strcat(buffer, buffer2);
313         }
314
315         if (midi_lower_bound_set) {
316                 sprintf(buffer2, " midiLowerBound=\"%lf\"", midi_lower_bound);
317                 strcat(buffer, buffer2);
318         }
319         
320         tX_store(buffer);
321 }
322
323
324 const char * tX_seqpar :: get_name()
325 {
326         return "This string means trouble!";
327 }
328
329 float tX_seqpar :: get_value()
330 {
331         printf("Ooops. tX_seqpar::get_value() called. Trouble.");
332         return 0.0;     
333 }
334
335 void tX_seqpar :: update_graphics()
336 {
337         gui_active=0;
338         do_update_graphics();
339         while (gtk_events_pending()) gtk_main_iteration();      /* gtk_flush */
340         gui_active=1;
341 }
342
343 void tX_seqpar :: update_all_graphics()
344 {
345         list <tX_seqpar *> :: iterator sp;
346
347         pthread_mutex_lock(&update_lock);
348
349         if (!update.size())
350         {
351                 pthread_mutex_unlock(&update_lock);
352                 return; 
353         }
354         
355         while (gtk_events_pending()) gtk_main_iteration();      
356         for (sp=update.begin(); sp!=update.end(); sp++)
357         {
358                 (*sp)->update_graphics();
359         }
360         update.erase(update.begin(), update.end());
361         pthread_mutex_unlock(&update_lock);
362 }
363
364 void tX_seqpar :: init_all_graphics()
365 {
366         list <tX_seqpar *> :: iterator sp;
367
368         pthread_mutex_lock(&update_lock);
369         
370         for (sp=all.begin(); sp!=all.end(); sp++)
371         {
372                 (*sp)->update_graphics();
373         }
374         while (gtk_events_pending()) gtk_main_iteration();      
375
376         pthread_mutex_unlock(&update_lock);
377 }
378
379 void tX_seqpar_update :: exec_value(const float value)
380 {
381         do_exec(value);
382         pthread_mutex_lock(&update_lock);
383         update.push_front(this);
384         pthread_mutex_unlock(&update_lock);
385 }
386
387 void tX_seqpar_no_update :: exec_value(const float value)
388 {
389         do_exec(value);
390 }
391
392 void tX_seqpar_no_update :: do_update_graphics()
393 {
394         /* NOP */
395 }
396
397
398 void tX_seqpar_no_update_active_forward :: receive_forward_value(const float value)
399 {
400         fwd_value=value;
401         do_exec(value);
402 }       
403
404 void tX_seqpar_update_active_forward :: receive_forward_value(const float value)
405 {
406         fwd_value=value;
407         do_exec(value);
408 }
409
410 /* "real" classes */
411
412 /**** Sequencable Parameter: MASTER VOLUME ****/
413
414 tX_seqpar_master_volume :: tX_seqpar_master_volume() 
415 {
416         set_mapping_parameters(2.5, 0, 0.1, 0);
417 }
418
419 void tX_seqpar_master_volume :: do_exec(const float value)
420 {
421         vtt_class :: set_master_volume(value);
422 }
423
424 void tX_seqpar_master_volume :: do_update_graphics ()
425 {
426         gtk_adjustment_set_value(volume_adj, vtt_class::master_volume);
427 }
428
429 const char * tX_seqpar_master_volume :: get_name()
430 {
431         return "Master Volume";
432 }
433
434 /**** Sequencable Parameter: MASTER PITCH ****/
435
436 tX_seqpar_master_pitch :: tX_seqpar_master_pitch()
437 {
438         set_mapping_parameters(3.0, -3.0, 0.1, 0);
439 }
440
441 void tX_seqpar_master_pitch :: do_exec(const float value)
442 {
443         vtt_class :: set_master_pitch(value);
444 }
445
446 void tX_seqpar_master_pitch :: do_update_graphics ()
447 {
448         gtk_adjustment_set_value(pitch_adj, globals.pitch);
449 }
450
451 const char * tX_seqpar_master_pitch :: get_name()
452 {
453         return "Master Pitch";
454 }
455
456 /**** Sequencable Parameter: TURNTABLE SPEED ****/
457
458 tX_seqpar_vtt_speed :: tX_seqpar_vtt_speed()
459 {
460         // min max scale are not required for this parameter
461         set_mapping_parameters(3.0, -3.0, 0.1, 1);
462 }
463
464 /* speed works differently so we need an extra input-handler */
465
466 void tX_seqpar_vtt_speed :: handle_mouse_input(float adjustment)
467 {
468         if (tt->do_scratch) tt->sp_speed.receive_input_value(adjustment);
469         tt->sense_cycles=globals.sense_cycles;
470 }
471
472 void tX_seqpar_vtt_speed :: do_exec(const float value)
473 {
474         tt->speed=value*tt->audiofile_pitch_correction;
475 }
476
477 const char * tX_seqpar_vtt_speed :: get_name()
478 {
479         return "Speed (Scratching)";
480 }
481
482 /**** Sequencable Parameter: TURNTABLE SPIN ****/
483
484 tX_seqpar_spin :: tX_seqpar_spin()
485 {
486         set_mapping_parameters(1, 0, 0, 0);
487 }
488
489 void tX_seqpar_spin :: do_exec(const float value)
490 {
491         if (value > 0) tt->speed=tt->res_pitch;
492         else tt->speed=0;
493 }
494
495 const char * tX_seqpar_spin :: get_name()
496 {
497         return "Motor Spin (On/Off)";
498 }
499
500 /**** Sequencable Parameter: TURNTABLE VOLUME ****/
501
502 tX_seqpar_vtt_volume :: tX_seqpar_vtt_volume()
503 {
504         set_mapping_parameters(2.0, 0, TX_SEQPAR_DEFAULT_SCALE, 1);
505 }
506
507 float tX_seqpar_vtt_volume :: get_value(){ return tt->rel_volume; }
508
509 void tX_seqpar_vtt_volume :: do_exec(const float value)
510 {
511         tt->set_volume(value);
512 }
513
514 void tX_seqpar_vtt_volume :: do_update_graphics ()
515 {
516         gtk_adjustment_set_value(tt->gui.volume, 2.0-tt->rel_volume);
517 }
518
519 const char * tX_seqpar_vtt_volume :: get_name()
520 {
521         return "Volume";
522 }
523
524 /**** Sequencable Parameter : Pan ****/
525
526 tX_seqpar_vtt_pan :: tX_seqpar_vtt_pan()
527 {
528         set_mapping_parameters(1.0, -1.0, TX_SEQPAR_DEFAULT_SCALE, 1);
529 }
530
531 float tX_seqpar_vtt_pan :: get_value(){ return tt->pan; }
532
533 void tX_seqpar_vtt_pan :: do_exec(const float value)
534 {
535         tt->set_pan(value);
536 }
537
538 void tX_seqpar_vtt_pan :: do_update_graphics ()
539 {
540         gtk_adjustment_set_value(tt->gui.pan, tt->pan);
541 }
542
543 const char * tX_seqpar_vtt_pan :: get_name()
544 {
545         return "Pan";
546 }
547
548 /**** Sequencable Parameter: TURNTABLE PITCH ****/
549
550 tX_seqpar_vtt_pitch :: tX_seqpar_vtt_pitch()
551 {
552         set_mapping_parameters(3.0, -3.0, TX_SEQPAR_DEFAULT_SCALE, 1);
553 }
554
555 float tX_seqpar_vtt_pitch :: get_value(){ return tt->rel_pitch; }
556
557 void tX_seqpar_vtt_pitch :: do_exec(const float value)
558 {
559         tt->set_pitch(value);
560 }
561
562 void tX_seqpar_vtt_pitch :: do_update_graphics ()
563 {
564         gtk_adjustment_set_value(tt->gui.pitch, tt->rel_pitch);
565 }
566
567 const char * tX_seqpar_vtt_pitch :: get_name()
568 {
569         return "Pitch";
570 }
571
572 /**** Sequencable Parameter: TURNTABLE TRIGGER ****/
573
574 tX_seqpar_vtt_trigger :: tX_seqpar_vtt_trigger()
575 {
576         set_mapping_parameters(0.01, 0, 1, 1);
577         is_boolean=true;
578 }
579
580 void tX_seqpar_vtt_trigger :: do_exec(const float value)
581 {
582         if (value > 0) tt->trigger();
583         else tt->stop();
584 }
585
586 const char * tX_seqpar_vtt_trigger :: get_name()
587 {
588         return "Trigger (Start/Stop)";
589 }
590
591 /**** Sequencable Parameter: TURNTABLE LOOP ****/
592
593 tX_seqpar_vtt_loop :: tX_seqpar_vtt_loop()
594 {
595         set_mapping_parameters(0, 0, 0, 0);
596         
597         is_boolean=true;
598 }
599
600 void tX_seqpar_vtt_loop :: do_exec(const float value)
601 {
602         tt->set_loop(value>0);
603 }
604
605 const char * tX_seqpar_vtt_loop :: get_name()
606 {
607         return "Loop (On/Off)";
608 }
609
610 void tX_seqpar_vtt_loop :: do_update_graphics ()
611 {
612         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tt->gui.loop), tt->loop);
613 }
614
615 /**** Sequencable Parameter: TURNTABLE SYNC CLIENT ****/
616
617 tX_seqpar_vtt_sync_client :: tX_seqpar_vtt_sync_client()
618 {
619         set_mapping_parameters(0,0,0,0);
620         is_boolean=true;
621 }
622
623 void tX_seqpar_vtt_sync_client :: do_exec(const float value)
624 {
625         tt->set_sync_client((value>0), tt->sync_cycles);
626 }
627
628 void tX_seqpar_vtt_sync_client :: do_update_graphics ()
629 {
630         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tt->gui.sync_client), tt->is_sync_client);
631 }
632
633 const char * tX_seqpar_vtt_sync_client :: get_name()
634 {
635         return "Sync Client (On/Off)";
636 }
637
638 /**** Sequencable Parameter: TURNTABLE SYNC CYCLES ****/
639
640 tX_seqpar_vtt_sync_cycles :: tX_seqpar_vtt_sync_cycles()
641 {
642         set_mapping_parameters(0,0,0,0);
643 }
644
645 void tX_seqpar_vtt_sync_cycles :: do_exec(const float value)
646 {
647         tt->set_sync_client(tt->is_sync_client, (int) value);
648 }
649
650 void tX_seqpar_vtt_sync_cycles :: do_update_graphics ()
651 {
652         gtk_adjustment_set_value(tt->gui.cycles, tt->sync_cycles);
653 }
654
655 const char * tX_seqpar_vtt_sync_cycles :: get_name()
656 {
657         return "Sync Cycles";
658 }
659
660 /**** Sequencable Parameter: TURNTABLE LP ENABLE ****/
661
662 tX_seqpar_vtt_lp_enable :: tX_seqpar_vtt_lp_enable()
663 {
664         set_mapping_parameters(0.01,0,1,1);
665         is_boolean=true;
666 }
667
668 void tX_seqpar_vtt_lp_enable :: do_exec(const float value)
669 {
670         tt->lp_set_enable(value>0);
671 }
672
673 void tX_seqpar_vtt_lp_enable :: do_update_graphics ()
674 {
675         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tt->gui.lp_enable), tt->lp_enable);
676 }
677
678 const char * tX_seqpar_vtt_lp_enable :: get_name()
679 {
680         return "Lowpass: Enable (On/Off)";
681 }
682
683 /**** Sequencable Parameter: TURNTABLE LP GAIN ****/
684
685 tX_seqpar_vtt_lp_gain :: tX_seqpar_vtt_lp_gain()
686 {
687         set_mapping_parameters(2.0,0, TX_SEQPAR_DEFAULT_SCALE, 1);
688 }
689
690 float tX_seqpar_vtt_lp_gain :: get_value() { return tt->lp_gain; }
691
692 void tX_seqpar_vtt_lp_gain :: do_exec(const float value)
693 {
694         tt->lp_set_gain(value);
695 }
696
697 const char * tX_seqpar_vtt_lp_gain :: get_name()
698 {
699         return "Lowpass: Input Gain";
700 }
701
702 void tX_seqpar_vtt_lp_gain :: do_update_graphics ()
703 {
704         gtk_adjustment_set_value(tt->gui.lp_gain, tt->lp_gain);
705 }
706
707 /**** Sequencable Parameter: TURNTABLE LP RESO ****/
708
709 tX_seqpar_vtt_lp_reso :: tX_seqpar_vtt_lp_reso()
710 {
711         set_mapping_parameters(0.99, 0, TX_SEQPAR_DEFAULT_SCALE, 1);
712 }
713
714 float tX_seqpar_vtt_lp_reso :: get_value() { return tt->lp_reso; }
715
716 void tX_seqpar_vtt_lp_reso :: do_exec(const float value)
717 {
718         tt->lp_set_reso(value);
719 }
720
721 void tX_seqpar_vtt_lp_reso :: do_update_graphics ()
722 {
723         gtk_adjustment_set_value(tt->gui.lp_reso, tt->lp_reso);
724 }
725
726 const char * tX_seqpar_vtt_lp_reso :: get_name()
727 {
728         return "Lowpass: Resonance";
729 }
730
731 /**** Sequencable Parameter: TURNTABLE LP FREQUENCY ****/
732
733 tX_seqpar_vtt_lp_freq :: tX_seqpar_vtt_lp_freq()
734 {
735         set_mapping_parameters(0.99, 0, TX_SEQPAR_DEFAULT_SCALE, 1);
736 }
737
738 float tX_seqpar_vtt_lp_freq :: get_value() { return tt->lp_freq; }
739
740 void tX_seqpar_vtt_lp_freq :: do_exec(const float value)
741 {
742         tt->lp_set_freq(value);
743 }
744
745 const char * tX_seqpar_vtt_lp_freq :: get_name()
746 {
747         return "Lowpass: Cutoff Frequency";
748 }
749
750 void tX_seqpar_vtt_lp_freq :: do_update_graphics ()
751 {
752         gtk_adjustment_set_value(tt->gui.lp_freq, tt->lp_freq);
753 }
754
755 /**** Sequencable Parameter: TURNTABLE ECHO ENABLE ****/
756
757 tX_seqpar_vtt_ec_enable :: tX_seqpar_vtt_ec_enable()
758 {
759         set_mapping_parameters(0.01,0,1,1);
760         is_boolean=true;
761 }
762
763 void tX_seqpar_vtt_ec_enable :: do_exec(const float value)
764 {
765         tt->ec_set_enable(value>0);
766 }
767
768 void tX_seqpar_vtt_ec_enable :: do_update_graphics ()
769 {
770         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tt->gui.ec_enable), tt->ec_enable);
771 }
772
773 const char * tX_seqpar_vtt_ec_enable :: get_name()
774 {
775         return "Echo: Enable (On/Off)";
776 }
777
778 /**** Sequencable Parameter: TURNTABLE ECHO LENGTH ****/
779
780 tX_seqpar_vtt_ec_length :: tX_seqpar_vtt_ec_length()
781 {
782         set_mapping_parameters(1.0, 0, TX_SEQPAR_DEFAULT_SCALE, 1);
783 }
784
785 float tX_seqpar_vtt_ec_length :: get_value() { return tt->ec_length; }
786
787 void tX_seqpar_vtt_ec_length :: do_exec(const float value)
788 {
789         tt->ec_set_length(value);
790 }
791
792 void tX_seqpar_vtt_ec_length :: do_update_graphics ()
793 {
794         gtk_adjustment_set_value(tt->gui.ec_length, tt->ec_length);
795 }
796
797 const char * tX_seqpar_vtt_ec_length :: get_name()
798 {
799         return "Echo: Duration";
800 }
801
802 /**** Sequencable Parameter: TURNTABLE ECHO FEEDBACK ****/
803
804 tX_seqpar_vtt_ec_feedback :: tX_seqpar_vtt_ec_feedback()
805 {
806         set_mapping_parameters(1.0, 0, TX_SEQPAR_DEFAULT_SCALE, 1);
807 }
808
809 float tX_seqpar_vtt_ec_feedback :: get_value() { return tt->ec_feedback; }
810
811 void tX_seqpar_vtt_ec_feedback :: do_exec(const float value)
812 {
813         tt->ec_set_feedback(value);
814 }
815
816 void tX_seqpar_vtt_ec_feedback :: do_update_graphics ()
817 {
818         gtk_adjustment_set_value(tt->gui.ec_feedback, tt->ec_feedback);
819 }
820
821 const char * tX_seqpar_vtt_ec_feedback :: get_name()
822 {
823         return "Echo: Feedback";
824 }
825
826 /**** Sequencable Parameter: TURNTABLE ECHO PAN ****/
827
828 tX_seqpar_vtt_ec_pan :: tX_seqpar_vtt_ec_pan()
829 {
830         set_mapping_parameters(1.0, -1.0, TX_SEQPAR_DEFAULT_SCALE, 1);
831 }
832
833 float tX_seqpar_vtt_ec_pan :: get_value() { return tt->ec_pan; }
834
835 void tX_seqpar_vtt_ec_pan :: do_exec(const float value)
836 {
837         tt->ec_set_pan(value);
838 }
839
840 void tX_seqpar_vtt_ec_pan :: do_update_graphics ()
841 {
842         gtk_adjustment_set_value(tt->gui.ec_pan, tt->ec_pan);
843 }
844
845 const char * tX_seqpar_vtt_ec_pan :: get_name()
846 {
847         return "Echo: Pan";
848 }
849
850 /**** Sequencable Parameter: TURNTABLE ECHO VOLUME ****/
851
852 tX_seqpar_vtt_ec_volume :: tX_seqpar_vtt_ec_volume()
853 {
854         set_mapping_parameters(0.0, 3.0, TX_SEQPAR_DEFAULT_SCALE, 1);
855 }
856
857 float tX_seqpar_vtt_ec_volume :: get_value() { return tt->ec_volume; }
858
859 void tX_seqpar_vtt_ec_volume :: do_exec(const float value)
860 {
861         tt->ec_set_volume(value);
862 }
863
864 void tX_seqpar_vtt_ec_volume :: do_update_graphics ()
865 {
866         gtk_adjustment_set_value(tt->gui.ec_volume, tt->ec_volume);
867 }
868
869 const char * tX_seqpar_vtt_ec_volume :: get_name()
870 {
871         return "Echo: Volume";
872 }
873
874
875 /**** Sequencable Parameter: TURNTABLE MUTE ****/
876
877 tX_seqpar_vtt_mute :: tX_seqpar_vtt_mute()
878 {
879         set_mapping_parameters(0.01,0,1,1);
880         is_boolean=true;
881 }
882
883 void tX_seqpar_vtt_mute :: do_exec(const float value)
884 {
885         tt->set_mute(value>0);
886 }
887
888 const char * tX_seqpar_vtt_mute :: get_name()
889 {
890         return "Mute (On/Off)";
891 }
892
893 /** LADSPA fx parameters **/
894
895 tX_seqpar_vttfx :: tX_seqpar_vttfx()
896 {
897         fx_value=(float *) malloc(sizeof(float));
898         *fx_value=0;
899         set_mapping_parameters(0,0,0,0);        
900 }
901
902 tX_seqpar_vttfx :: ~tX_seqpar_vttfx()
903 {
904         free(fx_value);
905 }
906
907 void tX_seqpar_vttfx :: set_name(const char *n, const char *sn)
908 {
909         strcpy(name, n);
910         strcpy(label_name, sn);
911         create_widget();
912 }
913
914 float tX_seqpar_vttfx :: get_value()
915 {
916         return *fx_value;
917 }
918
919 void tX_seqpar_vttfx :: create_widget()
920 {
921         fprintf(stderr, "tX: Ooops. create_widget() for tX_seqpar_vttfx.\n");
922 }
923
924 const char * tX_seqpar_vttfx :: get_name()
925 {
926         return name;    
927 }
928
929 void tX_seqpar_vttfx_float :: create_widget()
930 {
931         float tmp=max_value - min_value/1000;
932
933         *fx_value=min_value;
934         //myadj=GTK_ADJUSTMENT(gtk_adjustment_new(*fx_value, min_value+tmp/10, max_value-tmp/10, tmp, tmp, tmp));
935         myadj=GTK_ADJUSTMENT(gtk_adjustment_new(*fx_value, min_value, max_value, tmp, tmp, tmp));
936         mydial=new tX_extdial(label_name, myadj, this);
937         g_signal_connect(G_OBJECT(myadj), "value_changed", (GtkSignalFunc) tX_seqpar_vttfx_float :: gtk_callback, this);
938         widget = mydial->get_widget();  
939 }
940
941 tX_seqpar_vttfx_float :: ~tX_seqpar_vttfx_float()
942 {
943         delete mydial;  
944 }
945
946 void tX_seqpar_vttfx_float :: do_exec(const float value)
947 {
948         *fx_value=value;
949 }
950
951 void tX_seqpar_vttfx_float :: do_update_graphics()
952 {
953         gtk_adjustment_set_value(myadj, *fx_value);
954 }
955
956 GtkSignalFunc tX_seqpar_vttfx_float :: gtk_callback(GtkWidget* w, tX_seqpar_vttfx_float *sp)
957 {
958         sp->receive_gui_value(sp->myadj->value);        
959         return NULL;    
960 }
961
962 #define WID_DYN TRUE, TRUE, 0
963 #define WID_FIX FALSE, FALSE, 0
964
965 void tX_seqpar_vttfx_int :: create_widget()
966 {
967         float tmp=max_value - min_value/1000;
968         GtkWidget *tmpwid;
969
970         *fx_value=min_value;
971         myadj=GTK_ADJUSTMENT(gtk_adjustment_new(*fx_value, min_value, max_value, 1, 10, tmp));
972         GtkWidget *box=gtk_vbox_new(FALSE, 2);
973         
974         tmpwid=gtk_spin_button_new(myadj,1.0,0);
975         gtk_widget_show(tmpwid);
976         gtk_box_pack_start(GTK_BOX(box), tmpwid, WID_DYN);
977         g_signal_connect(G_OBJECT(tmpwid), "button_press_event", (GtkSignalFunc) tX_seqpar::tX_seqpar_press, this);
978         
979         g_signal_connect(G_OBJECT(myadj), "value_changed", (GtkSignalFunc) tX_seqpar_vttfx_int :: gtk_callback, this);
980
981     tmpwid=gtk_label_new(label_name);
982         gtk_widget_show(tmpwid);
983         gtk_box_pack_start(GTK_BOX(box), tmpwid, WID_FIX);
984         
985         gtk_widget_show(box);
986         
987         widget=gtk_event_box_new();
988         g_signal_connect(G_OBJECT(widget), "button_press_event", (GtkSignalFunc) tX_seqpar::tX_seqpar_press, this);
989         
990         gtk_container_add(GTK_CONTAINER(widget), box);
991 }
992
993 tX_seqpar_vttfx_int :: ~tX_seqpar_vttfx_int()
994 {
995         gtk_widget_destroy(widget);
996 }
997
998 void tX_seqpar_vttfx_int :: do_exec(const float value)
999 {
1000         *fx_value=value;
1001 }
1002
1003 void tX_seqpar_vttfx_int :: do_update_graphics()
1004 {
1005         gtk_adjustment_set_value(myadj, *fx_value);
1006 }
1007
1008 GtkSignalFunc tX_seqpar_vttfx_int :: gtk_callback(GtkWidget* w, tX_seqpar_vttfx_int *sp)
1009 {
1010         sp->receive_gui_value(sp->myadj->value);        
1011         return NULL;
1012 }
1013
1014 void tX_seqpar_vttfx_bool :: create_widget()
1015 {
1016         *fx_value=min_value;
1017         widget=gtk_check_button_new_with_label(label_name);
1018         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), 0);
1019         g_signal_connect(G_OBJECT(widget), "button_press_event", (GtkSignalFunc) tX_seqpar::tX_seqpar_press, this);
1020         g_signal_connect(G_OBJECT(widget), "clicked", (GtkSignalFunc) tX_seqpar_vttfx_bool :: gtk_callback, this);
1021 }
1022
1023 tX_seqpar_vttfx_bool :: ~tX_seqpar_vttfx_bool()
1024 {
1025         gtk_widget_destroy(widget);
1026 }
1027
1028 void tX_seqpar_vttfx_bool :: do_exec(const float value)
1029 {
1030         *fx_value=value;
1031 }
1032
1033 GtkSignalFunc tX_seqpar_vttfx_bool :: gtk_callback(GtkWidget* w, tX_seqpar_vttfx_bool *sp)
1034 {
1035         sp->receive_gui_value(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sp->widget)));     
1036         return NULL;
1037 }
1038
1039 void tX_seqpar_vttfx_bool :: do_update_graphics()
1040 {
1041         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), *fx_value==max_value);
1042 }
1043
1044 gboolean tX_seqpar::tX_seqpar_press(GtkWidget *widget, GdkEventButton *event, gpointer data) {
1045         tX_seqpar *sp=(tX_seqpar *) data;
1046         
1047         if (event->button==3) {
1048                 GtkWidget *menu=gtk_menu_new();
1049                 
1050                 GtkWidget *item=gtk_menu_item_new_with_label(sp->get_name());
1051                 gtk_widget_set_sensitive(item, FALSE);
1052                 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1053                 gtk_widget_show(item);
1054                 
1055                 item = gtk_menu_item_new();
1056                 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1057                 gtk_widget_set_sensitive (item, FALSE);
1058                 gtk_widget_show (item);
1059                 
1060                 item = gtk_menu_item_new_with_label("MIDI Learn");
1061                 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1062                 gtk_widget_show(item);
1063 #ifdef USE_ALSA_MIDI_IN
1064                 g_signal_connect(item, "activate", (GCallback) tX_seqpar::learn_midi_binding, sp);              
1065 #else
1066                 gtk_widget_set_sensitive(item, FALSE);
1067 #endif
1068                 
1069                 item = gtk_menu_item_new_with_label("Remove MIDI Binding");
1070                 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1071                 gtk_widget_show(item);          
1072
1073                 if (sp->bound_midi_event.type==tX_midievent::NONE) {
1074                         gtk_widget_set_sensitive(item, FALSE);
1075                 }
1076 #ifdef USE_ALSA_MIDI_IN
1077                 g_signal_connect(item, "activate", (GCallback) tX_seqpar::remove_midi_binding, sp);             
1078 #else
1079                 gtk_widget_set_sensitive(item, FALSE);
1080 #endif
1081                 if (!sp->is_boolean) {
1082                         item = gtk_menu_item_new();
1083                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1084                         gtk_widget_set_sensitive(item, FALSE);
1085                         gtk_widget_show(item);
1086                         
1087                         item = gtk_menu_item_new_with_label("Set Upper MIDI Bound");
1088                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1089                         gtk_widget_show(item);
1090                         
1091 #ifdef USE_ALSA_MIDI_IN
1092                         g_signal_connect(item, "activate", (GCallback) tX_seqpar::set_midi_upper_bound, sp);            
1093 #else
1094                         gtk_widget_set_sensitive(item, FALSE);
1095 #endif
1096                         
1097                         item = gtk_menu_item_new_with_label("Reset Upper MIDI Bound");
1098                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1099                         gtk_widget_show(item);
1100 #ifdef USE_ALSA_MIDI_IN
1101                         g_signal_connect(item, "activate", (GCallback) tX_seqpar::reset_midi_upper_bound, sp);          
1102 #else
1103                         gtk_widget_set_sensitive(item, FALSE);
1104 #endif
1105                         
1106                         if (!sp->midi_upper_bound_set) {
1107                                 gtk_widget_set_sensitive(item, FALSE);                          
1108                         }
1109                         
1110                         item = gtk_menu_item_new_with_label("Set Lower MIDI Bound");
1111                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1112                         gtk_widget_show(item);
1113 #ifdef USE_ALSA_MIDI_IN
1114                         g_signal_connect(item, "activate", (GCallback) tX_seqpar::set_midi_lower_bound, sp);                                    
1115 #else
1116                         gtk_widget_set_sensitive(item, FALSE);
1117 #endif
1118                         
1119                         item = gtk_menu_item_new_with_label("Reset Lower MIDI Bound");
1120                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1121                         gtk_widget_show(item);
1122 #ifdef USE_ALSA_MIDI_IN
1123                         g_signal_connect(item, "activate", (GCallback) tX_seqpar::reset_midi_lower_bound, sp);          
1124 #else
1125                         gtk_widget_set_sensitive(item, FALSE);
1126 #endif
1127
1128                         if (!sp->midi_lower_bound_set) {
1129                                 gtk_widget_set_sensitive(item, FALSE);                          
1130                         }                       
1131                 }
1132                 
1133                 item = gtk_menu_item_new();
1134                 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1135                 gtk_widget_set_sensitive (item, FALSE);
1136                 gtk_widget_show (item);
1137                 
1138                 item = gtk_menu_item_new_with_label("Delete Sequencer Events");
1139                 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1140                 gtk_widget_show(item);
1141                 g_signal_connect(item, "activate", (GCallback) menu_delete_all_events_for_sp, sp);              
1142                                 
1143                 gtk_widget_show(menu);
1144                 
1145                 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, event->button, event->time);
1146                 //gtk_grab_remove(gtk_grab_get_current());
1147
1148                 return TRUE;
1149         } 
1150         
1151         return FALSE;
1152 }
1153
1154 #ifdef USE_ALSA_MIDI_IN
1155
1156 gboolean tX_seqpar::remove_midi_binding(GtkWidget *widget, gpointer data) {
1157         tX_seqpar *sp=(tX_seqpar *) data;
1158         
1159         sp->bound_midi_event.type=tX_midievent::NONE;
1160         sp->bound_midi_event.number=0;
1161         sp->bound_midi_event.channel=0;
1162         
1163         return TRUE;
1164 }
1165
1166 gboolean tX_seqpar::learn_midi_binding(GtkWidget *widget, gpointer data) {
1167         tX_seqpar *sp=(tX_seqpar *) data;
1168
1169         tX_engine::get_instance()->get_midi()->set_midi_learn_sp(sp);
1170         
1171         return TRUE;
1172 }
1173
1174 gboolean tX_seqpar::set_midi_upper_bound(GtkWidget *widget, gpointer data) {
1175         tX_seqpar *sp=(tX_seqpar *) data;
1176         sp->set_upper_midi_bound(sp->get_value());
1177         
1178         return TRUE;
1179 }
1180
1181 gboolean tX_seqpar::reset_midi_upper_bound(GtkWidget *widget, gpointer data) {
1182         tX_seqpar *sp=(tX_seqpar *) data;
1183         sp->reset_upper_midi_bound();
1184         
1185         return TRUE;
1186 }
1187
1188 gboolean tX_seqpar::set_midi_lower_bound(GtkWidget *widget, gpointer data) {
1189         tX_seqpar *sp=(tX_seqpar *) data;
1190         sp->set_lower_midi_bound(sp->get_value());
1191         
1192         return TRUE;
1193 }
1194
1195 gboolean tX_seqpar::reset_midi_lower_bound(GtkWidget *widget, gpointer data) {
1196         tX_seqpar *sp=(tX_seqpar *) data;
1197         sp->reset_lower_midi_bound();
1198         
1199         return TRUE;
1200 }
1201
1202 #endif // USE_ALSA_MIDI_IN