Adds support for LADSPA-Integer Hint and some docs updates. 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 <malloc.h>
32
33 #define TX_SEQPAR_DEFAULT_SCALE 0.05
34
35 list <tX_seqpar *> tX_seqpar :: all;
36 list <tX_seqpar *> tX_seqpar :: update;
37 pthread_mutex_t tX_seqpar :: update_lock = PTHREAD_MUTEX_INITIALIZER;
38
39 #define tt ((vtt_class *) vtt)
40
41 void tX_seqpar :: default_constructor()
42 {
43         touched=0;
44         gui_active=1;
45         vtt=NULL;
46         max_value=0;
47         min_value=0;
48         scale_value=0;
49         is_mappable=1;
50         all.push_back(this);
51         last_event_recorded=NULL;
52 }
53
54 tX_seqpar :: tX_seqpar ()
55 {
56         default_constructor();
57 }
58
59 /*
60 tX_seqpar :: tX_seqpar (void * mytt)
61 {
62         default_constructor();
63         vtt=mytt;
64 }
65
66 tX_seqpar :: tX_seqpar (float max, float min, float scale, int mappable)
67 {
68         default_constructor();
69         max_value=max;
70         min_value=min;
71         scale_value=scale;
72         is_mappable=mappable;
73 }*/
74
75 void tX_seqpar :: set_mapping_parameters(float max, float min, float scale, int mappable)
76 {
77         max_value=max;
78         min_value=min;
79         scale_value=scale;
80         is_mappable=mappable;
81 }
82
83 /*
84 tX_seqpar :: tX_seqpar (void *mytt, float max, float min, float scale, int mappable)
85 {
86         default_constructor();
87         vtt=mytt;
88         max_value=max;
89         min_value=min;
90         scale_value=scale;
91         is_mappable=mappable;   
92 }
93 */
94
95 void tX_seqpar :: handle_mouse_input(float adjustment)
96 {
97         float tmpvalue;
98         
99         tmpvalue=get_value()+adjustment*scale_value;
100         if (tmpvalue>max_value) tmpvalue=max_value;
101         if (tmpvalue<min_value) tmpvalue=min_value;
102         
103         /*printf("Handling %s, max %f, min %f, scale %f,  val: %f\n", get_name(), max_value, min_value, scale_value, tmpvalue);*/
104         
105         receive_input_value(tmpvalue);
106 }
107
108 void tX_seqpar :: set_vtt (void *mytt)
109 {
110         vtt=mytt;
111 }
112
113 tX_seqpar :: ~tX_seqpar()
114 {
115         pthread_mutex_lock(&update_lock);
116         update.remove(this);
117         pthread_mutex_unlock(&update_lock);
118         sequencer.delete_all_events_for_sp(this);
119         all.remove(this);
120 }
121
122 void tX_seqpar :: do_touch()
123 {
124         if (sequencer.is_recording())
125         {
126                 touched=1;
127                 touch_timestamp=sequencer.get_timestamp();
128         }
129 }
130
131 void tX_seqpar :: untouch_all()
132 {
133         list <tX_seqpar *> :: iterator sp;
134         
135         for (sp=all.begin(); sp!=all.end(); sp++)
136         {
137                 (*sp)->untouch();
138         }
139 }
140
141 void tX_seqpar :: create_persistence_ids()
142 {
143         list <tX_seqpar *> :: iterator sp;
144         int pid=0;
145         
146         for (sp=all.begin(); sp!=all.end(); sp++)
147         {
148                 pid++;
149                 (*sp)->set_persistence_id(pid);
150         }
151 }
152
153 tX_seqpar* tX_seqpar :: get_sp_by_persistence_id(int pid)
154 {
155         list <tX_seqpar *> :: iterator sp;
156         
157         for (sp=all.begin(); sp!=all.end(); sp++)
158         {
159                 if ((*sp)->get_persistence_id()==pid) return ((*sp));
160         }
161         
162         fprintf (stderr, "oops: failed to lookup persistence id [%i].\n", pid); 
163         return (NULL);
164 }
165
166
167 void tX_seqpar :: record_value(const float value)
168 {
169 #define last_event ((tX_event *) last_event_recorded)
170
171         /* recording more than one event per seqpar for
172           one timestamp doesn't make sense... so if the 
173           last_event_recorded was for the current timestamp
174           we simply set that event's value to the current one.
175         */
176         if ((last_event) && (last_event->get_timestamp() == sequencer.get_timestamp()))
177         {
178                 last_event->set_value(value);
179         }
180         else last_event_recorded=(void *) sequencer.record(this, value);
181 }
182
183 void tX_seqpar :: receive_gui_value(const float value)
184 {
185         if (gui_active)
186         {
187                 touch();
188                 do_exec(value);
189                 record_value(value);
190         }
191 }
192
193 void tX_seqpar :: receive_input_value(const float value)
194 {
195         touch();
196         exec_value(value);
197         record_value(value);
198 }
199
200 void tX_seqpar :: receive_forward_value(const float value)
201 {
202         fwd_value=value;
203 }
204
205 void tX_seqpar :: materialize_forward_values()
206 {
207         list <tX_seqpar *> :: iterator sp;
208         
209         for (sp=all.begin(); sp!=all.end(); sp++)
210         {
211                 (*sp)->exec_value((*sp)->fwd_value);
212         }       
213         gdk_flush();
214 }
215
216 char * tX_seqpar :: get_vtt_name()
217 {       
218         if (vtt) return tt->name;
219         else return "Master Track";
220 }
221
222 const char * tX_seqpar :: get_name()
223 {
224         return "This string means trouble!";
225 }
226
227 float tX_seqpar :: get_value()
228 {
229         printf("Ooops. tX_seqpar::get_value() called. Trouble.");
230 }
231
232 void tX_seqpar :: do_exec(const float value)
233 {
234         fprintf(stderr, "oops: called do_exec() of tX_seqpar.\n");
235 }
236
237 void tX_seqpar :: exec_value(const float value)
238 {
239         fprintf(stderr, "oops: called exec_value() of tX_seqpar.\n");
240 }
241
242 void tX_seqpar :: do_update_graphics()
243 {
244         fprintf(stderr, "oops: called do_update_graphics() of tX_seqpar.\n");
245 }
246
247 void tX_seqpar :: update_graphics()
248 {
249         gui_active=0;
250         do_update_graphics();
251         while (gtk_events_pending()) gtk_main_iteration();      /* gtk_flush */
252         gui_active=1;
253 }
254
255 void tX_seqpar :: update_all_graphics()
256 {
257         list <tX_seqpar *> :: iterator sp;
258
259         pthread_mutex_lock(&update_lock);
260
261         if (!update.size())
262         {
263                 pthread_mutex_unlock(&update_lock);
264                 return; 
265         }
266         
267         while (gtk_events_pending()) gtk_main_iteration();      
268         for (sp=update.begin(); sp!=update.end(); sp++)
269         {
270                 (*sp)->update_graphics();
271         }
272         update.erase(update.begin(), update.end());
273         pthread_mutex_unlock(&update_lock);
274 }
275
276 void tX_seqpar :: init_all_graphics()
277 {
278         list <tX_seqpar *> :: iterator sp;
279
280         pthread_mutex_lock(&update_lock);
281         
282         for (sp=all.begin(); sp!=all.end(); sp++)
283         {
284                 (*sp)->update_graphics();
285         }
286         while (gtk_events_pending()) gtk_main_iteration();      
287
288         pthread_mutex_unlock(&update_lock);
289 }
290
291 void tX_seqpar_update :: exec_value(const float value)
292 {
293         do_exec(value);
294         pthread_mutex_lock(&update_lock);
295         update.push_front(this);
296         pthread_mutex_unlock(&update_lock);
297 }
298
299 void tX_seqpar_no_update :: exec_value(const float value)
300 {
301         do_exec(value);
302 }
303
304 void tX_seqpar_no_update :: do_update_graphics()
305 {
306         /* NOP */
307 }
308
309
310 void tX_seqpar_no_update_active_forward :: receive_forward_value(const float value)
311 {
312         fwd_value=value;
313         do_exec(value);
314 }       
315
316 void tX_seqpar_update_active_forward :: receive_forward_value(const float value)
317 {
318         fwd_value=value;
319         do_exec(value);
320 }
321
322 /* "real" classes */
323
324 /**** Sequencable Parameter: MASTER VOLUME ****/
325
326 tX_seqpar_master_volume :: tX_seqpar_master_volume()
327 {
328         set_mapping_parameters(2.5, 0, 0.1, 0);
329 }
330
331 void tX_seqpar_master_volume :: do_exec(const float value)
332 {
333         vtt_class :: set_master_volume(value);
334 }
335
336 void tX_seqpar_master_volume :: do_update_graphics ()
337 {
338         gtk_adjustment_set_value(volume_adj, vtt_class::master_volume);
339 }
340
341 const char * tX_seqpar_master_volume :: get_name()
342 {
343         return "Master Volume";
344 }
345
346 /**** Sequencable Parameter: MASTER PITCH ****/
347
348 tX_seqpar_master_pitch :: tX_seqpar_master_pitch()
349 {
350         set_mapping_parameters(3.0, -3.0, 0.1, 0);
351 }
352
353 void tX_seqpar_master_pitch :: do_exec(const float value)
354 {
355         vtt_class :: set_master_pitch(value);
356 }
357
358 void tX_seqpar_master_pitch :: do_update_graphics ()
359 {
360         gtk_adjustment_set_value(pitch_adj, globals.pitch);
361 }
362
363 const char * tX_seqpar_master_pitch :: get_name()
364 {
365         return "Master Pitch";
366 }
367
368 /**** Sequencable Parameter: TURNTABLE SPEED ****/
369
370 tX_seqpar_vtt_speed :: tX_seqpar_vtt_speed()
371 {
372         // min max scale are not required for this parameter
373         set_mapping_parameters(3.0, -3.0, 0.1, 1);
374 }
375
376 /* speed works differently so we need an extra input-handler */
377
378 void tX_seqpar_vtt_speed :: handle_mouse_input(float adjustment)
379 {
380         if (tt->do_scratch) tt->sp_speed.receive_input_value(adjustment);
381         tt->sense_cycles=globals.sense_cycles;
382 }
383
384 void tX_seqpar_vtt_speed :: do_exec(const float value)
385 {
386         tt->speed=value;
387 }
388
389 const char * tX_seqpar_vtt_speed :: get_name()
390 {
391         return "Speed (Scratching)";
392 }
393
394 /**** Sequencable Parameter: TURNTABLE SPIN ****/
395
396 tX_seqpar_spin :: tX_seqpar_spin()
397 {
398         set_mapping_parameters(1, 0, 0, 0);
399 }
400
401 void tX_seqpar_spin :: do_exec(const float value)
402 {
403         if (value > 0) tt->speed=tt->res_pitch;
404         else tt->speed=0;
405 }
406
407 const char * tX_seqpar_spin :: get_name()
408 {
409         return "Motor Spin (On/Off)";
410 }
411
412 /**** Sequencable Parameter: TURNTABLE VOLUME ****/
413
414 tX_seqpar_vtt_volume :: tX_seqpar_vtt_volume()
415 {
416         set_mapping_parameters(2.0, 0, TX_SEQPAR_DEFAULT_SCALE, 1);
417 }
418
419 float tX_seqpar_vtt_volume :: get_value(){ return tt->rel_volume; }
420
421 void tX_seqpar_vtt_volume :: do_exec(const float value)
422 {
423         tt->set_volume(value);
424 }
425
426 void tX_seqpar_vtt_volume :: do_update_graphics ()
427 {
428         gtk_adjustment_set_value(tt->gui.volume, 2.0-tt->rel_volume);
429 }
430
431 const char * tX_seqpar_vtt_volume :: get_name()
432 {
433         return "Volume";
434 }
435
436 /**** Sequencable Parameter: TURNTABLE PITCH ****/
437
438 tX_seqpar_vtt_pitch :: tX_seqpar_vtt_pitch()
439 {
440         set_mapping_parameters(3.0, -3.0, TX_SEQPAR_DEFAULT_SCALE, 1);
441 }
442
443 float tX_seqpar_vtt_pitch :: get_value(){ return tt->rel_pitch; }
444
445 void tX_seqpar_vtt_pitch :: do_exec(const float value)
446 {
447         tt->set_pitch(value);
448 }
449
450 void tX_seqpar_vtt_pitch :: do_update_graphics ()
451 {
452         gtk_adjustment_set_value(tt->gui.pitch, tt->rel_pitch);
453 }
454
455 const char * tX_seqpar_vtt_pitch :: get_name()
456 {
457         return "Pitch";
458 }
459
460 /**** Sequencable Parameter: TURNTABLE TRIGGER ****/
461
462 tX_seqpar_vtt_trigger :: tX_seqpar_vtt_trigger()
463 {
464         set_mapping_parameters(0, 0, 0, 0);
465 }
466
467 void tX_seqpar_vtt_trigger :: do_exec(const float value)
468 {
469         if (value > 0) tt->trigger();
470         else tt->stop();
471 }
472
473 const char * tX_seqpar_vtt_trigger :: get_name()
474 {
475         return "Trigger (Start/Stop)";
476 }
477
478 /**** Sequencable Parameter: TURNTABLE LOOP ****/
479
480 tX_seqpar_vtt_loop :: tX_seqpar_vtt_loop()
481 {
482         set_mapping_parameters(0, 0, 0, 0);
483 }
484
485 void tX_seqpar_vtt_loop :: do_exec(const float value)
486 {
487         tt->set_loop(value>0);
488 }
489
490 const char * tX_seqpar_vtt_loop :: get_name()
491 {
492         return "Loop (On/Off)";
493 }
494
495 void tX_seqpar_vtt_loop :: do_update_graphics ()
496 {
497         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tt->gui.loop), tt->loop);
498 }
499
500 /**** Sequencable Parameter: TURNTABLE SYNC CLIENT ****/
501
502 tX_seqpar_vtt_sync_client :: tX_seqpar_vtt_sync_client()
503 {
504         set_mapping_parameters(0,0,0,0);
505 }
506
507 void tX_seqpar_vtt_sync_client :: do_exec(const float value)
508 {
509         tt->set_sync_client((value>0), tt->sync_cycles);
510 }
511
512 void tX_seqpar_vtt_sync_client :: do_update_graphics ()
513 {
514         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tt->gui.sync_client), tt->is_sync_client);
515 }
516
517 const char * tX_seqpar_vtt_sync_client :: get_name()
518 {
519         return "Sync Client (On/Off)";
520 }
521
522 /**** Sequencable Parameter: TURNTABLE SYNC CYCLES ****/
523
524 tX_seqpar_vtt_sync_cycles :: tX_seqpar_vtt_sync_cycles()
525 {
526         set_mapping_parameters(0,0,0,0);
527 }
528
529 void tX_seqpar_vtt_sync_cycles :: do_exec(const float value)
530 {
531         tt->set_sync_client(tt->is_sync_client, (int) value);
532 }
533
534 void tX_seqpar_vtt_sync_cycles :: do_update_graphics ()
535 {
536         gtk_adjustment_set_value(tt->gui.cycles, tt->sync_cycles);
537 }
538
539 const char * tX_seqpar_vtt_sync_cycles :: get_name()
540 {
541         return "Sync Cycles";
542 }
543
544 /**** Sequencable Parameter: TURNTABLE LP ENABLE ****/
545
546 tX_seqpar_vtt_lp_enable :: tX_seqpar_vtt_lp_enable()
547 {
548         set_mapping_parameters(0,0,0,0);
549 }
550
551 void tX_seqpar_vtt_lp_enable :: do_exec(const float value)
552 {
553         tt->lp_set_enable(value>0);
554 }
555
556 void tX_seqpar_vtt_lp_enable :: do_update_graphics ()
557 {
558         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tt->gui.lp_enable), tt->lp_enable);
559 }
560
561 const char * tX_seqpar_vtt_lp_enable :: get_name()
562 {
563         return "Lowpass: Enable (On/Off)";
564 }
565
566 /**** Sequencable Parameter: TURNTABLE LP GAIN ****/
567
568 tX_seqpar_vtt_lp_gain :: tX_seqpar_vtt_lp_gain()
569 {
570         set_mapping_parameters(2.0,0, TX_SEQPAR_DEFAULT_SCALE, 1);
571 }
572
573 float tX_seqpar_vtt_lp_gain :: get_value() { return tt->lp_gain; }
574
575 void tX_seqpar_vtt_lp_gain :: do_exec(const float value)
576 {
577         tt->lp_set_gain(value);
578 }
579
580 const char * tX_seqpar_vtt_lp_gain :: get_name()
581 {
582         return "Lowpass: Input Gain";
583 }
584
585 void tX_seqpar_vtt_lp_gain :: do_update_graphics ()
586 {
587         gtk_adjustment_set_value(tt->gui.lp_gain, tt->lp_gain);
588 }
589
590 /**** Sequencable Parameter: TURNTABLE LP RESO ****/
591
592 tX_seqpar_vtt_lp_reso :: tX_seqpar_vtt_lp_reso()
593 {
594         set_mapping_parameters(0.99, 0, TX_SEQPAR_DEFAULT_SCALE, 1);
595 }
596
597 float tX_seqpar_vtt_lp_reso :: get_value() { return tt->lp_reso; }
598
599 void tX_seqpar_vtt_lp_reso :: do_exec(const float value)
600 {
601         tt->lp_set_reso(value);
602 }
603
604 void tX_seqpar_vtt_lp_reso :: do_update_graphics ()
605 {
606         gtk_adjustment_set_value(tt->gui.lp_reso, tt->lp_reso);
607 }
608
609 const char * tX_seqpar_vtt_lp_reso :: get_name()
610 {
611         return "Lowpass: Resonance";
612 }
613
614 /**** Sequencable Parameter: TURNTABLE LP FREQUENCY ****/
615
616 tX_seqpar_vtt_lp_freq :: tX_seqpar_vtt_lp_freq()
617 {
618         set_mapping_parameters(1.0, 0, TX_SEQPAR_DEFAULT_SCALE, 1);
619 }
620
621 float tX_seqpar_vtt_lp_freq :: get_value() { return tt->lp_freq; }
622
623 void tX_seqpar_vtt_lp_freq :: do_exec(const float value)
624 {
625         tt->lp_set_freq(value);
626 }
627
628 const char * tX_seqpar_vtt_lp_freq :: get_name()
629 {
630         return "Lowpass: Cutoff Frequency";
631 }
632
633 void tX_seqpar_vtt_lp_freq :: do_update_graphics ()
634 {
635         gtk_adjustment_set_value(tt->gui.lp_freq, tt->lp_freq);
636 }
637
638 /**** Sequencable Parameter: TURNTABLE ECHO ENABLE ****/
639
640 tX_seqpar_vtt_ec_enable :: tX_seqpar_vtt_ec_enable()
641 {
642         set_mapping_parameters(1.0, 0, 0, 0);
643 }
644
645 void tX_seqpar_vtt_ec_enable :: do_exec(const float value)
646 {
647         tt->ec_set_enable(value>0);
648 }
649
650 void tX_seqpar_vtt_ec_enable :: do_update_graphics ()
651 {
652         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tt->gui.ec_enable), tt->ec_enable);
653 }
654
655 const char * tX_seqpar_vtt_ec_enable :: get_name()
656 {
657         return "Echo: Enable (On/Off)";
658 }
659
660 /**** Sequencable Parameter: TURNTABLE ECHO LENGTH ****/
661
662 tX_seqpar_vtt_ec_length :: tX_seqpar_vtt_ec_length()
663 {
664         set_mapping_parameters(1.0, 0, TX_SEQPAR_DEFAULT_SCALE, 1);
665 }
666
667 float tX_seqpar_vtt_ec_length :: get_value() { return tt->ec_length; }
668
669 void tX_seqpar_vtt_ec_length :: do_exec(const float value)
670 {
671         tt->ec_set_length(value);
672 }
673
674 void tX_seqpar_vtt_ec_length :: do_update_graphics ()
675 {
676         gtk_adjustment_set_value(tt->gui.ec_length, tt->ec_length);
677 }
678
679 const char * tX_seqpar_vtt_ec_length :: get_name()
680 {
681         return "Echo: Duration";
682 }
683
684 /**** Sequencable Parameter: TURNTABLE ECHO FEEDBACK ****/
685
686 tX_seqpar_vtt_ec_feedback :: tX_seqpar_vtt_ec_feedback()
687 {
688         set_mapping_parameters(1.0, 0, TX_SEQPAR_DEFAULT_SCALE, 1);
689 }
690
691 float tX_seqpar_vtt_ec_feedback :: get_value() { return tt->ec_feedback; }
692
693 void tX_seqpar_vtt_ec_feedback :: do_exec(const float value)
694 {
695         tt->ec_set_feedback(value);
696 }
697
698 void tX_seqpar_vtt_ec_feedback :: do_update_graphics ()
699 {
700         gtk_adjustment_set_value(tt->gui.ec_feedback, tt->ec_feedback);
701 }
702
703 const char * tX_seqpar_vtt_ec_feedback :: get_name()
704 {
705         return "Echo: Feedback";
706 }
707
708 /**** Sequencable Parameter: TURNTABLE MUTE ****/
709
710 tX_seqpar_vtt_mute :: tX_seqpar_vtt_mute()
711 {
712         set_mapping_parameters(0,0,0,0);
713 }
714
715 void tX_seqpar_vtt_mute :: do_exec(const float value)
716 {
717         tt->set_mute(value>0);
718 }
719
720 const char * tX_seqpar_vtt_mute :: get_name()
721 {
722         return "Mute (On/Off)";
723 }
724
725 /** LADSPA fx parameters **/
726
727 tX_seqpar_vttfx :: tX_seqpar_vttfx()
728 {
729         fx_value=(float *) malloc(sizeof(float));
730         *fx_value=0;
731         set_mapping_parameters(0,0,0,0);        
732 }
733
734 tX_seqpar_vttfx :: ~tX_seqpar_vttfx()
735 {
736         free(fx_value);
737 }
738
739 void tX_seqpar_vttfx :: set_name(const char *n, const char *sn)
740 {
741         strcpy(name, n);
742         strcpy(label_name, sn);
743         create_widget();
744 }
745
746 float tX_seqpar_vttfx :: get_value()
747 {
748         return *fx_value;
749 }
750
751 void tX_seqpar_vttfx :: create_widget()
752 {
753         fprintf(stderr, "tX: Ooops. create_widget() for tX_seqpar_vttfx.\n");
754 }
755
756 const char * tX_seqpar_vttfx :: get_name()
757 {
758         return name;    
759 }
760
761 void tX_seqpar_vttfx_float :: create_widget()
762 {
763         float tmp=max_value - min_value/1000;
764
765         *fx_value=min_value;
766         myadj=GTK_ADJUSTMENT(gtk_adjustment_new(*fx_value, min_value, max_value, tmp, tmp, tmp));
767         mydial=new tX_extdial(label_name, myadj);
768         gtk_signal_connect(GTK_OBJECT(myadj), "value_changed", (GtkSignalFunc) tX_seqpar_vttfx_float :: gtk_callback, this);
769         widget = mydial->get_widget();  
770 }
771
772 tX_seqpar_vttfx_float :: ~tX_seqpar_vttfx_float()
773 {
774         delete mydial;  
775 }
776
777 void tX_seqpar_vttfx_float :: do_exec(const float value)
778 {
779         *fx_value=value;
780 }
781
782 void tX_seqpar_vttfx_float :: do_update_graphics()
783 {
784         gtk_adjustment_set_value(myadj, *fx_value);
785 }
786
787 GtkSignalFunc tX_seqpar_vttfx_float :: gtk_callback(GtkWidget* w, tX_seqpar_vttfx_float *sp)
788 {
789         sp->receive_gui_value(sp->myadj->value);        
790 }
791
792 #define WID_DYN TRUE, TRUE, 0
793 #define WID_FIX FALSE, FALSE, 0
794
795 void tX_seqpar_vttfx_int :: create_widget()
796 {
797         float tmp=max_value - min_value/1000;
798         GtkWidget *tmpwid;
799
800         *fx_value=min_value;
801         myadj=GTK_ADJUSTMENT(gtk_adjustment_new(*fx_value, min_value, max_value, tmp, tmp, tmp));
802         widget=gtk_hbox_new(FALSE, 2);
803         tmpwid=gtk_label_new(label_name);
804         gtk_widget_show(tmpwid);
805         gtk_box_pack_start(GTK_BOX(widget), tmpwid, WID_FIX);
806
807         tmpwid=gtk_spin_button_new(myadj,1.0,0);
808         gtk_widget_show(tmpwid);
809         gtk_box_pack_start(GTK_BOX(widget), tmpwid, WID_DYN);
810         
811         gtk_signal_connect(GTK_OBJECT(myadj), "value_changed", (GtkSignalFunc) tX_seqpar_vttfx_int :: gtk_callback, this);
812 }
813
814 tX_seqpar_vttfx_int :: ~tX_seqpar_vttfx_int()
815 {
816         gtk_widget_destroy(widget);
817 }
818
819 void tX_seqpar_vttfx_int :: do_exec(const float value)
820 {
821         *fx_value=value;
822 }
823
824 void tX_seqpar_vttfx_int :: do_update_graphics()
825 {
826         gtk_adjustment_set_value(myadj, *fx_value);
827 }
828
829 GtkSignalFunc tX_seqpar_vttfx_int :: gtk_callback(GtkWidget* w, tX_seqpar_vttfx_int *sp)
830 {
831         sp->receive_gui_value(sp->myadj->value);        
832 }
833
834 void tX_seqpar_vttfx_bool :: create_widget()
835 {
836         *fx_value=min_value;
837         widget=gtk_check_button_new_with_label(label_name);
838         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), 0);
839         gtk_signal_connect(GTK_OBJECT(widget), "clicked", (GtkSignalFunc) tX_seqpar_vttfx_bool :: gtk_callback, this);
840 }
841
842 tX_seqpar_vttfx_bool :: ~tX_seqpar_vttfx_bool()
843 {
844         gtk_widget_destroy(widget);
845 }
846
847 void tX_seqpar_vttfx_bool :: do_exec(const float value)
848 {
849         *fx_value=value;
850 }
851
852 GtkSignalFunc tX_seqpar_vttfx_bool :: gtk_callback(GtkWidget* w, tX_seqpar_vttfx_bool *sp)
853 {
854         sp->receive_gui_value(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sp->widget)));     
855 }
856
857 void tX_seqpar_vttfx_bool :: do_update_graphics()
858 {
859         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), *fx_value==max_value);
860 }