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