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