Fixed one segfault during undo.
[epichord.git] / src / trackmodule.cpp
blobd4adf8f74a0b8cf6f1fff06cc3d85dd64ca5ad90
1 /*
2 Epichord - a midi sequencer
3 Copyright (C) 2008 Evan Rinehart
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
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.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to
18 The Free Software Foundation, Inc.
19 51 Franklin Street, Fifth Floor
20 Boston, MA 02110-1301, USA
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <fltk/Group.h>
27 #include <fltk/Widget.h>
29 #include <fltk/draw.h>
30 #include <fltk/run.h>
32 #include <vector>
34 #include "ui.h"
35 #include "backend.h"
36 #include "uihelper.h"
38 extern std::vector<track*> tracks;
39 extern UI* ui;
41 extern char gm_names[128][64];
43 extern struct conf config;
45 void portcb(fltk::Widget* w, long i){
46 //fltk::ValueInput* o = (fltk::ValueInput*)w;
47 Gauge* o = (Gauge*)w;
48 track* t = tracks[i];
49 int old_port = t->port;
50 t->port = (int)o->value;
51 midi_channel_off(t->chan,old_port);
54 void chancb(fltk::Widget* w, long i){
55 //fltk::ValueInput* o = (fltk::ValueInput*)w;
56 Gauge* o = (Gauge*)w;
57 track* t = tracks[i];
58 int old_chan = t->chan;
59 t->chan = (int)o->value;
60 midi_channel_off(old_chan,t->port);
63 void progcb(fltk::Widget* w, long i){
64 //fltk::ValueInput* o = (fltk::ValueInput*)w;
65 Gauge* o = (Gauge*)w;
66 track* t = tracks[i];
67 int prog = (int)o->value;
68 t->prog = prog;
69 program_change(i, prog);
70 if(config.autotrackname){
71 free(t->name);
72 t->name = (char*)malloc(64);
73 strncpy(t->name,gm_names[prog],64);
74 ui->track_info->update();
78 void bankcb(fltk::Widget* w, long i){
79 //fltk::ValueInput* o = (fltk::ValueInput*)w;
80 Gauge* o = (Gauge*)w;
81 track* t = tracks[i];
82 int bank = (int)o->value;
83 t->bank = bank;
84 midi_bank_controller(i, bank);
87 void namecb(fltk::Widget* w, long i){
88 fltk::Input* o = (fltk::Input*)w;
89 track* t = tracks[i];
90 strcpy(t->name,o->text());
91 free(t->name);
92 t->name = (char*)malloc(strlen(o->text())+1);
93 strcpy(t->name,o->text());
96 void mutecb(fltk::Widget* w, long i){
97 Toggle* o = (Toggle*)w;
98 track* t = tracks[i];
100 if(t->mute == 0){
101 t->mute = 1;
102 midi_track_off(i);
103 o->set(1);
105 else{
106 t->mute = 0;
107 o->set(0);
109 o->redraw();
112 void solocb(fltk::Widget* w, long i){
113 Toggle* o = (Toggle*)w;
114 track* t = tracks[i];
115 if(t->solo == 0){
116 ui->track_info->unset_solo();
117 t->solo = 1;
118 set_solo(1);
119 all_notes_off();
120 o->set(1);
122 else{
123 t->solo = 0;
124 set_solo(0);
125 o->set(0);
127 o->redraw();
130 void reccb(fltk::Widget* w, long i){
131 Toggle* o = (Toggle*)w;
132 track* t = tracks[i];
133 if(o->state == 0){
134 ui->track_info->set_rec(i);
135 ui->keyboard->cur_chan = t->chan;
136 ui->keyboard->cur_port = t->port;
137 set_rec_track(i);
139 o->redraw();
142 void volcb(fltk::Widget* w, long i){
143 Gauge* o = (Gauge*)w;
144 track* t = tracks[i];
146 t->vol = o->value;
147 midi_volume_controller(i, t->vol);
148 //perhaps record this
151 void pancb(fltk::Widget* w, long i){
152 Gauge* o = (Gauge*)w;
153 track* t = tracks[i];
155 t->pan = o->value;
156 midi_pan_controller(i, t->pan);
159 TrackModule::TrackModule(int x, int y, int w, int h, int i, const char* label) :
160 fltk::Group(x, y, w, h, label),
161 rec(5,5,20,20),
162 name(25,5,145,20),
163 volume(170,5,20,20),
164 pan(190,5,20,20),
165 solo(210,5,20,20),
166 mute(230,5,20,20),
167 port(230,5,20,20),
168 chan(210,5,20,20),
169 prog(170,5,20,20),
170 bank(190,5,20,20)
173 port.hide();
174 chan.hide();
175 prog.hide();
176 bank.hide();
178 prog.r = 0x3b;
179 prog.g = 0x5a;
180 prog.b = 0x88;
181 prog.R = 0x94;
182 prog.G = 0xbf;
183 prog.B = 0xff;
184 prog.value = 0;
185 prog.last_value = 0;
186 prog.label_always = 1;
187 prog.gauge_off = 1;
188 prog.tooltip("program");
190 bank.r = 0x2c;
191 bank.g = 0x40;
192 bank.b = 0x5b;
193 bank.R = 0x5a;
194 bank.G = 0x83;
195 bank.B = 0xba;
196 bank.value = 0;
197 bank.last_value = 0;
198 bank.label_always = 1;
199 bank.gauge_off = 1;
200 bank.tooltip("bank");
202 chan.r = 0x8c;
203 chan.g = 0xaf;
204 chan.b = 0xb6;
205 chan.R = 0xeb;
206 chan.G = 0xef;
207 chan.B = 0xf0;
208 chan.max = 15;
209 chan.label_always = 1;
210 chan.label_plusone = 1;
211 chan.label_hex = 0;
212 chan.gauge_off = 1;
213 chan.tooltip("channel");
215 port.r = 0xc0;
216 port.g = 0xc0;
217 port.b = 0xc0;
218 port.R = 0xff;
219 port.G = 0xff;
220 port.B = 0xff;
221 port.max = 7;
222 port.value = 0;
223 port.last_value = 0;
224 port.label_always = 1;
225 port.gauge_off = 1;
226 port.tooltip("port");
229 port.callback(portcb, i);
230 chan.callback(chancb, i);
231 prog.callback(progcb, i);
232 bank.callback(bankcb, i);
233 rec.callback(reccb, i);
234 name.callback(namecb, i);
235 volume.callback(volcb, i);
236 pan.callback(pancb, i);
237 solo.callback(solocb, i);
238 mute.callback(mutecb, i);
240 rec.tooltip("record on this track");
241 volume.tooltip("volume");
242 pan.tooltip("pan");
243 solo.tooltip("solo");
244 mute.tooltip("mute");
246 rec.key_flag = 1;
247 solo.c[0] = '1';
248 solo.r = 127;
249 solo.g = 0;
250 solo.b = 127;
251 solo.R = 255;
252 solo.G = 0;
253 solo.B = 255;
254 mute.c[0] = '.';
255 mute.c[1] = '.';
256 mute.c[2] = '.';
257 mute.c[3] = '\0';
258 mute.r = 0;
259 mute.g = 0;
260 mute.b = 127;
261 mute.R = 0;
262 mute.G = 0;
263 mute.B = 255;
265 begin();
267 add(rec);//toggle recording
268 add(name);//change track name
270 add(volume);//set track volume
271 add(pan);//set track pan
272 add(solo);//set solo to this track
273 add(mute);//mute or unmute track
275 add(port);//change track port
276 add(chan);//change track channel
277 add(prog);//change track program
278 add(bank);
280 end();
282 index = i;
283 settings_shown = 0;
287 int TrackModule::handle(int e){
288 return fltk::Group::handle(e);
291 void TrackModule::toggle(){
292 if(!settings_shown){
293 volume.hide();
294 pan.hide();
295 solo.hide();
296 mute.hide();
297 port.show();
298 chan.show();
299 prog.show();
300 bank.show();
301 settings_shown = 1;
303 else{
304 volume.show();
305 pan.show();
306 solo.show();
307 mute.show();
308 port.hide();
309 chan.hide();
310 prog.hide();
311 bank.hide();
312 settings_shown = 0;
317 void TrackModule::set_channel(int i){
318 chan.value = i;
319 chan.last_value = i;
322 void TrackModule::unset_solo(){
323 if(tracks[index]->solo){
324 tracks[index]->solo = 0;
325 solo.set(0);
326 solo.redraw();
330 void TrackModule::unset_rec(){
331 rec.set(0);
332 rec.redraw();
335 void TrackModule::set_rec(){
336 rec.set(1);
337 rec.redraw();
341 void TrackModule::update(){
342 track* t = tracks[index];
343 name.text(t->name);
344 port.value = t->port;
345 chan.value = t->chan;
346 prog.value = t->prog;
347 bank.value = t->bank;
349 if(t->mute){
350 mute.set(1);
352 else{
353 mute.set(0);
356 if(t->solo){
357 solo.set(1);
359 else{
360 solo.set(0);
363 mute.redraw();
364 solo.redraw();
369 void gauge_temp_cb(void* v){
370 Gauge* g = (Gauge*)v;
372 if(g->label_temp==0){
373 return;
375 g->label_temp--;
376 if(g->label_temp==0){
377 g->redraw();
379 else{
380 //fltk::repeat_timeout(0.5, gauge_temp_cb, v);
384 Gauge::Gauge(int x, int y, int w, int h, const char* label) :
385 fltk::Widget(x, y, w, h, label){
386 max = 127;
387 value = 64;
388 last_value = 64;
389 label_flag = 0;
390 label_always = 0;
391 label_plusone = 0;
392 label_hex = 1;
393 gauge_off = 0;
394 label_temp=0;
395 sens=1;
398 VGauge::VGauge(int x, int y, int w, int h, const char* label) :
399 Gauge(x, y, w, h, label){
400 r = 127;
401 g = 0;
402 b = 0;
403 R = 255;
404 G = 0;
405 B = 0;
407 int last;
408 int VGauge::handle(int e){
409 if(e == fltk::MOUSEWHEEL){
410 value-=fltk::event_dy();
411 if(value > max){value = max;}
412 if(value < 0){value = 0;}
413 last_value = value;
414 label_temp++;
415 fltk::add_timeout(1,gauge_temp_cb,this);
416 do_callback();
417 redraw();
418 return 1;
420 if(e == fltk::PUSH){
421 last = fltk::event_y();
422 label_flag = 1;
423 redraw();
424 return 1;
426 if(e == fltk::DRAG){
427 value += (last - fltk::event_y());
428 if(value > max){value = max;}
429 if(value < 0){value = 0;}
430 if(value != last_value){
431 last_value = value;
432 do_callback();
434 last = fltk::event_y();
435 redraw();
436 return 1;
438 if(e == fltk::RELEASE){
439 label_flag = 0;
440 redraw();
442 return fltk::Widget::handle(e);
446 HGauge::HGauge(int x, int y, int w, int h, const char* label) :
447 Gauge(x, y, w, h, label){
448 r = 0;
449 g = 127;
450 b = 0;
451 R = 0;
452 G = 255;
453 B = 0;
456 int HGauge::handle(int e){
457 if(e == fltk::MOUSEWHEEL){
458 value-=fltk::event_dy();
459 if(value > max){value = max;}
460 if(value < 0){value = 0;}
461 last_value = value;
462 label_temp++;
463 fltk::add_timeout(1,gauge_temp_cb,this);
464 do_callback();
465 redraw();
466 return 1;
468 if(e == fltk::PUSH){
469 last = fltk::event_x();
470 label_flag = 1;
471 redraw();
472 return 1;
474 if(e == fltk::DRAG){
475 value += fltk::event_x() - last;
476 if(value > max){value = max;}
477 if(value < 0){value = 0;}
478 if(value != last_value){
479 last_value = value;
480 do_callback();
482 last = fltk::event_x();
483 redraw();
484 return 1;
486 if(e == fltk::RELEASE){
487 label_flag = 0;
488 redraw();
490 return fltk::Widget::handle(e);
493 void VGauge::draw(){
494 draw_box();
495 fltk::setcolor(fltk::color(r,g,b));
496 fltk::fillrect(2,2,w()-4,h()-4);
498 if(!gauge_off){
499 fltk::setcolor(fltk::color(R,G,B));
501 int H = value * (h()-4) / max;
502 fltk::fillrect(2,h()-2-H,w()-4,H);
504 if(label_flag || label_always || label_temp){
505 char buf[3];
506 int V = label_plusone ? value + 1 : value;
507 if(label_hex){
508 snprintf(buf,3,"%x",V);
510 else{
511 snprintf(buf,3,"%d",V);
515 fltk::push_clip(2,2,w()-4,h()-4 - H);
516 fltk::setcolor(fltk::color(R,G,B));
517 fltk::setfont(fltk::HELVETICA,12);
518 int W = (int)fltk::getwidth(buf);
519 fltk::drawtext(buf,(w()-W)/2,h()-fltk::getascent()/2);
520 fltk::pop_clip();
523 fltk::push_clip(2,h()-2-H,w()-4,H);
524 if(!gauge_off){
525 fltk::setcolor(fltk::color(r,g,b));
527 fltk::setfont(fltk::HELVETICA,12);
528 fltk::drawtext(buf,(w()-W)/2,h()-fltk::getascent()/2);
529 fltk::pop_clip();
533 void HGauge::draw(){
534 draw_box();
535 fltk::setcolor(fltk::color(r,g,b));
536 fltk::fillrect(2,2,w()-4,h()-4);
538 fltk::setcolor(fltk::color(R,G,B));
539 int V = value * (h()-4) / max;
540 fltk::fillrect(2,2,V,h()-4);
542 if(label_flag || label_always || label_temp){
543 char buf[3];
544 snprintf(buf,3,"%x",value);
546 fltk::push_clip(V+2,2,w()-4-V,h()-4);
547 fltk::setcolor(fltk::color(R,G,B));
548 fltk::setfont(fltk::HELVETICA,12);
549 int W = (int)fltk::getwidth(buf);
550 fltk::drawtext(buf,(w()-W)/2,h()-fltk::getascent()/2);
551 fltk::pop_clip();
553 fltk::push_clip(2,2,V,h()-4);
554 fltk::setcolor(fltk::color(r,g,b));
555 fltk::setfont(fltk::HELVETICA,12);
556 fltk::drawtext(buf,(w()-W)/2,h()-fltk::getascent()/2);
557 fltk::pop_clip();
561 Toggle::Toggle(int x, int y, int w, int h, const char* label) :
562 fltk::Button(x, y, w, h, label){
563 buttonbox(fltk::DOWN_BOX);
564 when(fltk::WHEN_NEVER);
565 c[0] = 'A';
566 c[1] = '\0';
567 r = 127;
568 g = 0;
569 b = 0;
570 R = 255;
571 G = 0;
572 B = 0;
573 state = 0;
574 key_flag = 0;
577 int Toggle::handle(int e){
578 if(e==fltk::PUSH){
579 do_callback();
580 return 1;
582 return fltk::Button::handle(e);
585 void Toggle::draw(){
586 draw_box();
588 if(key_flag){ //instead of drawing normally do something completely different
589 //redirect complaints to /dev/null
590 if(state){
591 fltk::setcolor(fltk::BLACK);
592 fltk::fillrect(2,h()-3,w()-4,1);
593 fltk::fillrect(w()-3,2,1,h()-4);
594 fltk::fillrect(1,1,w()-4,1);
595 fltk::fillrect(1,1,1,h()-4);
597 fltk::fillrect(6,2,1,h()-4);
598 fltk::fillrect(12,2,1,h()-4);
600 fltk::fillrect(5,2,3,9);
601 fltk::fillrect(11,2,3,9);
603 else{
604 fltk::Button::draw(0);
606 return;
609 if(state){
610 fltk::setcolor(fltk::color(R,G,B));
612 else{
613 fltk::setcolor(fltk::color(r,g,b));
615 fltk::fillrect(2,2,w()-4,h()-4);
617 fltk::setcolor(fltk::BLACK);
618 fltk::setfont(fltk::HELVETICA,12);
619 int W = (int)fltk::getwidth(c);
620 fltk::drawtext(c,(w()-W)/2,h()-fltk::getascent()/2);
624 void Toggle::set(int s){
625 state = s;