f58840e62eede8bad27685f1c8b6d037a2a4d1e9
[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, tX_sequencer::DELETE_ALL);
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 *rc, gzFile rz) {
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         tX_store(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 :: update_graphics()
291 {
292         gui_active=0;
293         do_update_graphics();
294         while (gtk_events_pending()) gtk_main_iteration();      /* gtk_flush */
295         gui_active=1;
296 }
297
298 void tX_seqpar :: update_all_graphics()
299 {
300         list <tX_seqpar *> :: iterator sp;
301
302         pthread_mutex_lock(&update_lock);
303
304         if (!update.size())
305         {
306                 pthread_mutex_unlock(&update_lock);
307                 return; 
308         }
309         
310         while (gtk_events_pending()) gtk_main_iteration();      
311         for (sp=update.begin(); sp!=update.end(); sp++)
312         {
313                 (*sp)->update_graphics();
314         }
315         update.erase(update.begin(), update.end());
316         pthread_mutex_unlock(&update_lock);
317 }
318
319 void tX_seqpar :: init_all_graphics()
320 {
321         list <tX_seqpar *> :: iterator sp;
322
323         pthread_mutex_lock(&update_lock);
324         
325         for (sp=all.begin(); sp!=all.end(); sp++)
326         {
327                 (*sp)->update_graphics();
328         }
329         while (gtk_events_pending()) gtk_main_iteration();      
330
331         pthread_mutex_unlock(&update_lock);
332 }
333
334 void tX_seqpar_update :: exec_value(const float value)
335 {
336         do_exec(value);
337         pthread_mutex_lock(&update_lock);
338         update.push_front(this);
339         pthread_mutex_unlock(&update_lock);
340 }
341
342 void tX_seqpar_no_update :: exec_value(const float value)
343 {
344         do_exec(value);
345 }
346
347 void tX_seqpar_no_update :: do_update_graphics()
348 {
349         /* NOP */
350 }
351
352
353 void tX_seqpar_no_update_active_forward :: receive_forward_value(const float value)
354 {
355         fwd_value=value;
356         do_exec(value);
357 }       
358
359 void tX_seqpar_update_active_forward :: receive_forward_value(const float value)
360 {
361         fwd_value=value;
362         do_exec(value);
363 }
364
365 /* "real" classes */
366
367 /**** Sequencable Parameter: MASTER VOLUME ****/
368
369 tX_seqpar_master_volume :: tX_seqpar_master_volume() 
370 {
371         set_mapping_parameters(2.5, 0, 0.1, 0);
372 }
373
374 void tX_seqpar_master_volume :: do_exec(const float value)
375 {
376         vtt_class :: set_master_volume(value);
377 }
378
379 void tX_seqpar_master_volume :: do_update_graphics ()
380 {
381         gtk_adjustment_set_value(volume_adj, 2.0-vtt_class::master_volume);
382 }
383
384 const char * tX_seqpar_master_volume :: get_name()
385 {
386         return "Master Volume";
387 }
388
389 /**** Sequencable Parameter: MASTER PITCH ****/
390
391 tX_seqpar_master_pitch :: tX_seqpar_master_pitch()
392 {
393         set_mapping_parameters(3.0, -3.0, 0.1, 0);
394 }
395
396 void tX_seqpar_master_pitch :: do_exec(const float value)
397 {
398         vtt_class :: set_master_pitch(value);
399 }
400
401 void tX_seqpar_master_pitch :: do_update_graphics ()
402 {
403         gtk_adjustment_set_value(pitch_adj, globals.pitch);
404 }
405
406 const char * tX_seqpar_master_pitch :: get_name()
407 {
408         return "Master Pitch";
409 }
410
411 /**** Sequencable Parameter: TURNTABLE SPEED ****/
412
413 tX_seqpar_vtt_speed :: tX_seqpar_vtt_speed()
414 {
415         // min max scale are not required for this parameter
416         set_mapping_parameters(3.0, -3.0, 0.1, 1);
417 }
418
419 /* speed works differently so we need an extra input-handler */
420
421 void tX_seqpar_vtt_speed :: handle_mouse_input(float adjustment)
422 {
423         if (tt->do_scratch) tt->sp_speed.receive_input_value(adjustment);
424         tt->sense_cycles=globals.sense_cycles;
425 }
426
427 void tX_seqpar_vtt_speed :: do_exec(const float value)
428 {
429         tt->speed=value*tt->audiofile_pitch_correction;
430 }
431
432 const char * tX_seqpar_vtt_speed :: get_name()
433 {
434         return "Speed (Scratching)";
435 }
436
437 /**** Sequencable Parameter: TURNTABLE SPIN ****/
438
439 tX_seqpar_spin :: tX_seqpar_spin()
440 {
441         set_mapping_parameters(1, 0, 0, 0);
442 }
443
444 void tX_seqpar_spin :: do_exec(const float value)
445 {
446         if (value > 0) tt->speed=tt->res_pitch;
447         else tt->speed=0;
448 }
449
450 const char * tX_seqpar_spin :: get_name()
451 {
452         return "Motor Spin (On/Off)";
453 }
454
455 /**** Sequencable Parameter: TURNTABLE VOLUME ****/
456
457 tX_seqpar_vtt_volume :: tX_seqpar_vtt_volume()
458 {
459         set_mapping_parameters(2.0, 0, TX_SEQPAR_DEFAULT_SCALE, 1);
460 }
461
462 float tX_seqpar_vtt_volume :: get_value(){ return tt->rel_volume; }
463
464 void tX_seqpar_vtt_volume :: do_exec(const float value)
465 {
466         tt->set_volume(value);
467 }
468
469 void tX_seqpar_vtt_volume :: do_update_graphics ()
470 {
471         gtk_adjustment_set_value(tt->gui.volume, 2.0-tt->rel_volume);
472 }
473
474 const char * tX_seqpar_vtt_volume :: get_name()
475 {
476         return "Volume";
477 }
478
479 /**** Sequencable Parameter : Pan ****/
480
481 tX_seqpar_vtt_pan :: tX_seqpar_vtt_pan()
482 {
483         set_mapping_parameters(1.0, -1.0, TX_SEQPAR_DEFAULT_SCALE, 1);
484 }
485
486 float tX_seqpar_vtt_pan :: get_value(){ return tt->pan; }
487
488 void tX_seqpar_vtt_pan :: do_exec(const float value)
489 {
490         tt->set_pan(value);
491 }
492
493 void tX_seqpar_vtt_pan :: do_update_graphics ()
494 {
495         gtk_adjustment_set_value(tt->gui.pan, tt->pan);
496 }
497
498 const char * tX_seqpar_vtt_pan :: get_name()
499 {
500         return "Pan";
501 }
502
503 /**** Sequencable Parameter: TURNTABLE PITCH ****/
504
505 tX_seqpar_vtt_pitch :: tX_seqpar_vtt_pitch()
506 {
507         set_mapping_parameters(3.0, -3.0, TX_SEQPAR_DEFAULT_SCALE, 1);
508 }
509
510 float tX_seqpar_vtt_pitch :: get_value(){ return tt->rel_pitch; }
511
512 void tX_seqpar_vtt_pitch :: do_exec(const float value)
513 {
514         tt->set_pitch(value);
515 }
516
517 void tX_seqpar_vtt_pitch :: do_update_graphics ()
518 {
519         gtk_adjustment_set_value(tt->gui.pitch, tt->rel_pitch);
520 }
521
522 const char * tX_seqpar_vtt_pitch :: get_name()
523 {
524         return "Pitch";
525 }
526
527 /**** Sequencable Parameter: TURNTABLE TRIGGER ****/
528
529 tX_seqpar_vtt_trigger :: tX_seqpar_vtt_trigger()
530 {
531         set_mapping_parameters(0.01, 0, 1, 1);
532         is_boolean=true;
533 }
534
535 void tX_seqpar_vtt_trigger :: do_exec(const float value)
536 {
537         if (value > 0) tt->trigger();
538         else tt->stop();
539 }
540
541 const char * tX_seqpar_vtt_trigger :: get_name()
542 {
543         return "Trigger (Start/Stop)";
544 }
545
546 /**** Sequencable Parameter: TURNTABLE LOOP ****/
547
548 tX_seqpar_vtt_loop :: tX_seqpar_vtt_loop()
549 {
550         set_mapping_parameters(0, 0, 0, 0);
551         
552         is_boolean=true;
553 }
554
555 void tX_seqpar_vtt_loop :: do_exec(const float value)
556 {
557         tt->set_loop(value>0);
558 }
559
560 const char * tX_seqpar_vtt_loop :: get_name()
561 {
562         return "Loop (On/Off)";
563 }
564
565 void tX_seqpar_vtt_loop :: do_update_graphics ()
566 {
567         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tt->gui.loop), tt->loop);
568 }
569
570 /**** Sequencable Parameter: TURNTABLE SYNC CLIENT ****/
571
572 tX_seqpar_vtt_sync_client :: tX_seqpar_vtt_sync_client()
573 {
574         set_mapping_parameters(0,0,0,0);
575 }
576
577 void tX_seqpar_vtt_sync_client :: do_exec(const float value)
578 {
579         tt->set_sync_client((value>0), tt->sync_cycles);
580 }
581
582 void tX_seqpar_vtt_sync_client :: do_update_graphics ()
583 {
584         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tt->gui.sync_client), tt->is_sync_client);
585 }
586
587 const char * tX_seqpar_vtt_sync_client :: get_name()
588 {
589         return "Sync Client (On/Off)";
590 }
591
592 /**** Sequencable Parameter: TURNTABLE SYNC CYCLES ****/
593
594 tX_seqpar_vtt_sync_cycles :: tX_seqpar_vtt_sync_cycles()
595 {
596         set_mapping_parameters(0,0,0,0);
597 }
598
599 void tX_seqpar_vtt_sync_cycles :: do_exec(const float value)
600 {
601         tt->set_sync_client(tt->is_sync_client, (int) value);
602 }
603
604 void tX_seqpar_vtt_sync_cycles :: do_update_graphics ()
605 {
606         gtk_adjustment_set_value(tt->gui.cycles, tt->sync_cycles);
607 }
608
609 const char * tX_seqpar_vtt_sync_cycles :: get_name()
610 {
611         return "Sync Cycles";
612 }
613
614 /**** Sequencable Parameter: TURNTABLE LP ENABLE ****/
615
616 tX_seqpar_vtt_lp_enable :: tX_seqpar_vtt_lp_enable()
617 {
618         set_mapping_parameters(0.01,0,1,1);
619         is_boolean=true;
620 }
621
622 void tX_seqpar_vtt_lp_enable :: do_exec(const float value)
623 {
624         tt->lp_set_enable(value>0);
625 }
626
627 void tX_seqpar_vtt_lp_enable :: do_update_graphics ()
628 {
629         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tt->gui.lp_enable), tt->lp_enable);
630 }
631
632 const char * tX_seqpar_vtt_lp_enable :: get_name()
633 {
634         return "Lowpass: Enable (On/Off)";
635 }
636
637 /**** Sequencable Parameter: TURNTABLE LP GAIN ****/
638
639 tX_seqpar_vtt_lp_gain :: tX_seqpar_vtt_lp_gain()
640 {
641         set_mapping_parameters(2.0,0, TX_SEQPAR_DEFAULT_SCALE, 1);
642 }
643
644 float tX_seqpar_vtt_lp_gain :: get_value() { return tt->lp_gain; }
645
646 void tX_seqpar_vtt_lp_gain :: do_exec(const float value)
647 {
648         tt->lp_set_gain(value);
649 }
650
651 const char * tX_seqpar_vtt_lp_gain :: get_name()
652 {
653         return "Lowpass: Input Gain";
654 }
655
656 void tX_seqpar_vtt_lp_gain :: do_update_graphics ()
657 {
658         gtk_adjustment_set_value(tt->gui.lp_gain, tt->lp_gain);
659 }
660
661 /**** Sequencable Parameter: TURNTABLE LP RESO ****/
662
663 tX_seqpar_vtt_lp_reso :: tX_seqpar_vtt_lp_reso()
664 {
665         set_mapping_parameters(0.99, 0, TX_SEQPAR_DEFAULT_SCALE, 1);
666 }
667
668 float tX_seqpar_vtt_lp_reso :: get_value() { return tt->lp_reso; }
669
670 void tX_seqpar_vtt_lp_reso :: do_exec(const float value)
671 {
672         tt->lp_set_reso(value);
673 }
674
675 void tX_seqpar_vtt_lp_reso :: do_update_graphics ()
676 {
677         gtk_adjustment_set_value(tt->gui.lp_reso, tt->lp_reso);
678 }
679
680 const char * tX_seqpar_vtt_lp_reso :: get_name()
681 {
682         return "Lowpass: Resonance";
683 }
684
685 /**** Sequencable Parameter: TURNTABLE LP FREQUENCY ****/
686
687 tX_seqpar_vtt_lp_freq :: tX_seqpar_vtt_lp_freq()
688 {
689         set_mapping_parameters(0.99, 0, TX_SEQPAR_DEFAULT_SCALE, 1);
690 }
691
692 float tX_seqpar_vtt_lp_freq :: get_value() { return tt->lp_freq; }
693
694 void tX_seqpar_vtt_lp_freq :: do_exec(const float value)
695 {
696         tt->lp_set_freq(value);
697 }
698
699 const char * tX_seqpar_vtt_lp_freq :: get_name()
700 {
701         return "Lowpass: Cutoff Frequency";
702 }
703
704 void tX_seqpar_vtt_lp_freq :: do_update_graphics ()
705 {
706         gtk_adjustment_set_value(tt->gui.lp_freq, tt->lp_freq);
707 }
708
709 /**** Sequencable Parameter: TURNTABLE ECHO ENABLE ****/
710
711 tX_seqpar_vtt_ec_enable :: tX_seqpar_vtt_ec_enable()
712 {
713         set_mapping_parameters(0.01,0,1,1);
714         is_boolean=true;
715 }
716
717 void tX_seqpar_vtt_ec_enable :: do_exec(const float value)
718 {
719         tt->ec_set_enable(value>0);
720 }
721
722 void tX_seqpar_vtt_ec_enable :: do_update_graphics ()
723 {
724         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tt->gui.ec_enable), tt->ec_enable);
725 }
726
727 const char * tX_seqpar_vtt_ec_enable :: get_name()
728 {
729         return "Echo: Enable (On/Off)";
730 }
731
732 /**** Sequencable Parameter: TURNTABLE ECHO LENGTH ****/
733
734 tX_seqpar_vtt_ec_length :: tX_seqpar_vtt_ec_length()
735 {
736         set_mapping_parameters(1.0, 0, TX_SEQPAR_DEFAULT_SCALE, 1);
737 }
738
739 float tX_seqpar_vtt_ec_length :: get_value() { return tt->ec_length; }
740
741 void tX_seqpar_vtt_ec_length :: do_exec(const float value)
742 {
743         tt->ec_set_length(value);
744 }
745
746 void tX_seqpar_vtt_ec_length :: do_update_graphics ()
747 {
748         gtk_adjustment_set_value(tt->gui.ec_length, tt->ec_length);
749 }
750
751 const char * tX_seqpar_vtt_ec_length :: get_name()
752 {
753         return "Echo: Duration";
754 }
755
756 /**** Sequencable Parameter: TURNTABLE ECHO FEEDBACK ****/
757
758 tX_seqpar_vtt_ec_feedback :: tX_seqpar_vtt_ec_feedback()
759 {
760         set_mapping_parameters(1.0, 0, TX_SEQPAR_DEFAULT_SCALE, 1);
761 }
762
763 float tX_seqpar_vtt_ec_feedback :: get_value() { return tt->ec_feedback; }
764
765 void tX_seqpar_vtt_ec_feedback :: do_exec(const float value)
766 {
767         tt->ec_set_feedback(value);
768 }
769
770 void tX_seqpar_vtt_ec_feedback :: do_update_graphics ()
771 {
772         gtk_adjustment_set_value(tt->gui.ec_feedback, tt->ec_feedback);
773 }
774
775 const char * tX_seqpar_vtt_ec_feedback :: get_name()
776 {
777         return "Echo: Feedback";
778 }
779
780 /**** Sequencable Parameter: TURNTABLE ECHO PAN ****/
781
782 tX_seqpar_vtt_ec_pan :: tX_seqpar_vtt_ec_pan()
783 {
784         set_mapping_parameters(1.0, -1.0, TX_SEQPAR_DEFAULT_SCALE, 1);
785 }
786
787 float tX_seqpar_vtt_ec_pan :: get_value() { return tt->ec_pan; }
788
789 void tX_seqpar_vtt_ec_pan :: do_exec(const float value)
790 {
791         tt->ec_set_pan(value);
792 }
793
794 void tX_seqpar_vtt_ec_pan :: do_update_graphics ()
795 {
796         gtk_adjustment_set_value(tt->gui.ec_pan, tt->ec_pan);
797 }
798
799 const char * tX_seqpar_vtt_ec_pan :: get_name()
800 {
801         return "Echo: Pan";
802 }
803
804 /**** Sequencable Parameter: TURNTABLE ECHO VOLUME ****/
805
806 tX_seqpar_vtt_ec_volume :: tX_seqpar_vtt_ec_volume()
807 {
808         set_mapping_parameters(0.0, 3.0, TX_SEQPAR_DEFAULT_SCALE, 1);
809 }
810
811 float tX_seqpar_vtt_ec_volume :: get_value() { return tt->ec_volume; }
812
813 void tX_seqpar_vtt_ec_volume :: do_exec(const float value)
814 {
815         tt->ec_set_volume(value);
816 }
817
818 void tX_seqpar_vtt_ec_volume :: do_update_graphics ()
819 {
820         gtk_adjustment_set_value(tt->gui.ec_volume, tt->ec_volume);
821 }
822
823 const char * tX_seqpar_vtt_ec_volume :: get_name()
824 {
825         return "Echo: Volume";
826 }
827
828
829 /**** Sequencable Parameter: TURNTABLE MUTE ****/
830
831 tX_seqpar_vtt_mute :: tX_seqpar_vtt_mute()
832 {
833         set_mapping_parameters(0.01,0,1,1);
834         is_boolean=true;
835 }
836
837 void tX_seqpar_vtt_mute :: do_exec(const float value)
838 {
839         tt->set_mute(value>0);
840 }
841
842 const char * tX_seqpar_vtt_mute :: get_name()
843 {
844         return "Mute (On/Off)";
845 }
846
847 /** LADSPA fx parameters **/
848
849 tX_seqpar_vttfx :: tX_seqpar_vttfx()
850 {
851         fx_value=(float *) malloc(sizeof(float));
852         *fx_value=0;
853         set_mapping_parameters(0,0,0,0);        
854 }
855
856 tX_seqpar_vttfx :: ~tX_seqpar_vttfx()
857 {
858         free(fx_value);
859 }
860
861 void tX_seqpar_vttfx :: set_name(const char *n, const char *sn)
862 {
863         strcpy(name, n);
864         strcpy(label_name, sn);
865         create_widget();
866 }
867
868 float tX_seqpar_vttfx :: get_value()
869 {
870         return *fx_value;
871 }
872
873 void tX_seqpar_vttfx :: create_widget()
874 {
875         fprintf(stderr, "tX: Ooops. create_widget() for tX_seqpar_vttfx.\n");
876 }
877
878 const char * tX_seqpar_vttfx :: get_name()
879 {
880         return name;    
881 }
882
883 void tX_seqpar_vttfx_float :: create_widget()
884 {
885         float tmp=max_value - min_value/1000;
886
887         *fx_value=min_value;
888         myadj=GTK_ADJUSTMENT(gtk_adjustment_new(*fx_value, min_value, max_value, tmp, tmp, tmp));
889         mydial=new tX_extdial(label_name, myadj);
890         gtk_signal_connect(GTK_OBJECT(myadj), "value_changed", (GtkSignalFunc) tX_seqpar_vttfx_float :: gtk_callback, this);
891         widget = mydial->get_widget();  
892 }
893
894 tX_seqpar_vttfx_float :: ~tX_seqpar_vttfx_float()
895 {
896         delete mydial;  
897 }
898
899 void tX_seqpar_vttfx_float :: do_exec(const float value)
900 {
901         *fx_value=value;
902 }
903
904 void tX_seqpar_vttfx_float :: do_update_graphics()
905 {
906         gtk_adjustment_set_value(myadj, *fx_value);
907 }
908
909 GtkSignalFunc tX_seqpar_vttfx_float :: gtk_callback(GtkWidget* w, tX_seqpar_vttfx_float *sp)
910 {
911         sp->receive_gui_value(sp->myadj->value);        
912         return NULL;    
913 }
914
915 #define WID_DYN TRUE, TRUE, 0
916 #define WID_FIX FALSE, FALSE, 0
917
918 void tX_seqpar_vttfx_int :: create_widget()
919 {
920         float tmp=max_value - min_value/1000;
921         GtkWidget *tmpwid;
922
923         *fx_value=min_value;
924         myadj=GTK_ADJUSTMENT(gtk_adjustment_new(*fx_value, min_value, max_value, 1, 10, tmp));
925         widget=gtk_vbox_new(FALSE, 2);
926
927         tmpwid=gtk_spin_button_new(myadj,1.0,0);
928         gtk_widget_show(tmpwid);
929         gtk_box_pack_start(GTK_BOX(widget), tmpwid, WID_DYN);
930         
931         gtk_signal_connect(GTK_OBJECT(myadj), "value_changed", (GtkSignalFunc) tX_seqpar_vttfx_int :: gtk_callback, this);
932
933     tmpwid=gtk_label_new(label_name);
934         gtk_widget_show(tmpwid);
935         gtk_box_pack_start(GTK_BOX(widget), tmpwid, WID_FIX);
936 }
937
938 tX_seqpar_vttfx_int :: ~tX_seqpar_vttfx_int()
939 {
940         gtk_widget_destroy(widget);
941 }
942
943 void tX_seqpar_vttfx_int :: do_exec(const float value)
944 {
945         *fx_value=value;
946 }
947
948 void tX_seqpar_vttfx_int :: do_update_graphics()
949 {
950         gtk_adjustment_set_value(myadj, *fx_value);
951 }
952
953 GtkSignalFunc tX_seqpar_vttfx_int :: gtk_callback(GtkWidget* w, tX_seqpar_vttfx_int *sp)
954 {
955         sp->receive_gui_value(sp->myadj->value);        
956         return NULL;
957 }
958
959 void tX_seqpar_vttfx_bool :: create_widget()
960 {
961         *fx_value=min_value;
962         widget=gtk_check_button_new_with_label(label_name);
963         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), 0);
964         gtk_signal_connect(GTK_OBJECT(widget), "clicked", (GtkSignalFunc) tX_seqpar_vttfx_bool :: gtk_callback, this);
965 }
966
967 tX_seqpar_vttfx_bool :: ~tX_seqpar_vttfx_bool()
968 {
969         gtk_widget_destroy(widget);
970 }
971
972 void tX_seqpar_vttfx_bool :: do_exec(const float value)
973 {
974         *fx_value=value;
975 }
976
977 GtkSignalFunc tX_seqpar_vttfx_bool :: gtk_callback(GtkWidget* w, tX_seqpar_vttfx_bool *sp)
978 {
979         sp->receive_gui_value(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sp->widget)));     
980         return NULL;
981 }
982
983 void tX_seqpar_vttfx_bool :: do_update_graphics()
984 {
985         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), *fx_value==max_value);
986 }