Fixed bug that crashed on saving after importing.
[epichord.git] / src / trackmodule.cpp
blob2828225fc4faa966c3e6805592bf381ced757b46
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 strncpy(t->name,gm_names[prog],64);
72 ui->track_info->update();
76 void bankcb(fltk::Widget* w, long i){
77 //fltk::ValueInput* o = (fltk::ValueInput*)w;
78 Gauge* o = (Gauge*)w;
79 track* t = tracks[i];
80 int bank = (int)o->value;
81 t->bank = bank;
82 midi_bank_controller(i, bank);
85 void namecb(fltk::Widget* w, long i){
86 fltk::Input* o = (fltk::Input*)w;
87 track* t = tracks[i];
88 strcpy(t->name,o->text());
89 free(t->name);
90 t->name = (char*)malloc(strlen(o->text())+1);
91 strcpy(t->name,o->text());
94 void mutecb(fltk::Widget* w, long i){
95 Toggle* o = (Toggle*)w;
96 track* t = tracks[i];
98 if(t->mute == 0){
99 t->mute = 1;
100 midi_track_off(i);
101 o->set(1);
103 else{
104 t->mute = 0;
105 o->set(0);
107 o->redraw();
110 void solocb(fltk::Widget* w, long i){
111 Toggle* o = (Toggle*)w;
112 track* t = tracks[i];
113 if(t->solo == 0){
114 ui->track_info->unset_solo();
115 t->solo = 1;
116 set_solo(1);
117 all_notes_off();
118 o->set(1);
120 else{
121 t->solo = 0;
122 set_solo(0);
123 o->set(0);
125 o->redraw();
128 void reccb(fltk::Widget* w, long i){
129 Toggle* o = (Toggle*)w;
130 track* t = tracks[i];
131 if(o->state == 0){
132 ui->track_info->set_rec(i);
133 ui->keyboard->cur_chan = t->chan;
134 ui->keyboard->cur_port = t->port;
135 set_rec_track(i);
137 o->redraw();
140 void volcb(fltk::Widget* w, long i){
141 Gauge* o = (Gauge*)w;
142 track* t = tracks[i];
144 t->vol = o->value;
145 midi_volume_controller(i, t->vol);
146 //perhaps record this
149 void pancb(fltk::Widget* w, long i){
150 Gauge* o = (Gauge*)w;
151 track* t = tracks[i];
153 t->pan = o->value;
154 midi_pan_controller(i, t->pan);
157 TrackModule::TrackModule(int x, int y, int w, int h, int i, const char* label) :
158 fltk::Group(x, y, w, h, label),
159 rec(5,5,20,20),
160 name(25,5,145,20),
161 volume(170,5,20,20),
162 pan(190,5,20,20),
163 solo(210,5,20,20),
164 mute(230,5,20,20),
165 port(230,5,20,20),
166 chan(210,5,20,20),
167 prog(170,5,20,20),
168 bank(190,5,20,20)
171 port.hide();
172 chan.hide();
173 prog.hide();
174 bank.hide();
176 prog.r = 0x3b;
177 prog.g = 0x5a;
178 prog.b = 0x88;
179 prog.R = 0x94;
180 prog.G = 0xbf;
181 prog.B = 0xff;
182 prog.value = 0;
183 prog.last_value = 0;
184 prog.label_always = 1;
185 prog.gauge_off = 1;
186 prog.tooltip("program");
188 bank.r = 0x2c;
189 bank.g = 0x40;
190 bank.b = 0x5b;
191 bank.R = 0x5a;
192 bank.G = 0x83;
193 bank.B = 0xba;
194 bank.value = 0;
195 bank.last_value = 0;
196 bank.label_always = 1;
197 bank.gauge_off = 1;
198 bank.tooltip("bank");
200 chan.r = 0x8c;
201 chan.g = 0xaf;
202 chan.b = 0xb6;
203 chan.R = 0xeb;
204 chan.G = 0xef;
205 chan.B = 0xf0;
206 chan.max = 15;
207 chan.label_always = 1;
208 chan.label_plusone = 1;
209 chan.label_hex = 0;
210 chan.gauge_off = 1;
211 chan.tooltip("channel");
213 port.r = 0xc0;
214 port.g = 0xc0;
215 port.b = 0xc0;
216 port.R = 0xff;
217 port.G = 0xff;
218 port.B = 0xff;
219 port.max = 7;
220 port.value = 0;
221 port.last_value = 0;
222 port.label_always = 1;
223 port.gauge_off = 1;
224 port.tooltip("port");
227 port.callback(portcb, i);
228 chan.callback(chancb, i);
229 prog.callback(progcb, i);
230 bank.callback(bankcb, i);
231 rec.callback(reccb, i);
232 name.callback(namecb, i);
233 volume.callback(volcb, i);
234 pan.callback(pancb, i);
235 solo.callback(solocb, i);
236 mute.callback(mutecb, i);
238 rec.tooltip("record on this track");
239 volume.tooltip("volume");
240 pan.tooltip("pan");
241 solo.tooltip("solo");
242 mute.tooltip("mute");
244 rec.key_flag = 1;
245 solo.c[0] = '1';
246 solo.r = 127;
247 solo.g = 0;
248 solo.b = 127;
249 solo.R = 255;
250 solo.G = 0;
251 solo.B = 255;
252 mute.c[0] = '.';
253 mute.c[1] = '.';
254 mute.c[2] = '.';
255 mute.c[3] = '\0';
256 mute.r = 0;
257 mute.g = 0;
258 mute.b = 127;
259 mute.R = 0;
260 mute.G = 0;
261 mute.B = 255;
263 begin();
265 add(rec);//toggle recording
266 add(name);//change track name
268 add(volume);//set track volume
269 add(pan);//set track pan
270 add(solo);//set solo to this track
271 add(mute);//mute or unmute track
273 add(port);//change track port
274 add(chan);//change track channel
275 add(prog);//change track program
276 add(bank);
278 end();
280 index = i;
281 settings_shown = 0;
285 int TrackModule::handle(int e){
286 return fltk::Group::handle(e);
289 void TrackModule::toggle(){
290 if(!settings_shown){
291 volume.hide();
292 pan.hide();
293 solo.hide();
294 mute.hide();
295 port.show();
296 chan.show();
297 prog.show();
298 bank.show();
299 settings_shown = 1;
301 else{
302 volume.show();
303 pan.show();
304 solo.show();
305 mute.show();
306 port.hide();
307 chan.hide();
308 prog.hide();
309 bank.hide();
310 settings_shown = 0;
315 void TrackModule::set_channel(int i){
316 chan.value = i;
317 chan.last_value = i;
320 void TrackModule::unset_solo(){
321 if(tracks[index]->solo){
322 tracks[index]->solo = 0;
323 solo.set(0);
324 solo.redraw();
328 void TrackModule::unset_rec(){
329 rec.set(0);
330 rec.redraw();
333 void TrackModule::set_rec(){
334 rec.set(1);
335 rec.redraw();
339 void TrackModule::update(){
340 track* t = tracks[index];
341 name.text(t->name);
342 port.value = t->port;
343 chan.value = t->chan;
344 prog.value = t->prog;
345 bank.value = t->bank;
347 if(t->mute){
348 mute.set(1);
350 else{
351 mute.set(0);
354 if(t->solo){
355 solo.set(1);
357 else{
358 solo.set(0);
361 mute.redraw();
362 solo.redraw();
367 void gauge_temp_cb(void* v){
368 Gauge* g = (Gauge*)v;
370 if(g->label_temp==0){
371 return;
373 g->label_temp--;
374 if(g->label_temp==0){
375 g->redraw();
377 else{
378 //fltk::repeat_timeout(0.5, gauge_temp_cb, v);
382 Gauge::Gauge(int x, int y, int w, int h, const char* label) :
383 fltk::Widget(x, y, w, h, label){
384 max = 127;
385 value = 64;
386 last_value = 64;
387 label_flag = 0;
388 label_always = 0;
389 label_plusone = 0;
390 label_hex = 1;
391 gauge_off = 0;
392 label_temp=0;
393 sens=1;
396 VGauge::VGauge(int x, int y, int w, int h, const char* label) :
397 Gauge(x, y, w, h, label){
398 r = 127;
399 g = 0;
400 b = 0;
401 R = 255;
402 G = 0;
403 B = 0;
405 int last;
406 int VGauge::handle(int e){
407 if(e == fltk::MOUSEWHEEL){
408 value-=fltk::event_dy();
409 if(value > max){value = max;}
410 if(value < 0){value = 0;}
411 last_value = value;
412 label_temp++;
413 fltk::add_timeout(1,gauge_temp_cb,this);
414 do_callback();
415 redraw();
416 return 1;
418 if(e == fltk::PUSH){
419 last = fltk::event_y();
420 label_flag = 1;
421 redraw();
422 return 1;
424 if(e == fltk::DRAG){
425 value += (last - fltk::event_y());
426 if(value > max){value = max;}
427 if(value < 0){value = 0;}
428 if(value != last_value){
429 last_value = value;
430 do_callback();
432 last = fltk::event_y();
433 redraw();
434 return 1;
436 if(e == fltk::RELEASE){
437 label_flag = 0;
438 redraw();
440 return fltk::Widget::handle(e);
444 HGauge::HGauge(int x, int y, int w, int h, const char* label) :
445 Gauge(x, y, w, h, label){
446 r = 0;
447 g = 127;
448 b = 0;
449 R = 0;
450 G = 255;
451 B = 0;
454 int HGauge::handle(int e){
455 if(e == fltk::MOUSEWHEEL){
456 value-=fltk::event_dy();
457 if(value > max){value = max;}
458 if(value < 0){value = 0;}
459 last_value = value;
460 label_temp++;
461 fltk::add_timeout(1,gauge_temp_cb,this);
462 do_callback();
463 redraw();
464 return 1;
466 if(e == fltk::PUSH){
467 last = fltk::event_x();
468 label_flag = 1;
469 redraw();
470 return 1;
472 if(e == fltk::DRAG){
473 value += fltk::event_x() - last;
474 if(value > max){value = max;}
475 if(value < 0){value = 0;}
476 if(value != last_value){
477 last_value = value;
478 do_callback();
480 last = fltk::event_x();
481 redraw();
482 return 1;
484 if(e == fltk::RELEASE){
485 label_flag = 0;
486 redraw();
488 return fltk::Widget::handle(e);
491 void VGauge::draw(){
492 draw_box();
493 fltk::setcolor(fltk::color(r,g,b));
494 fltk::fillrect(2,2,w()-4,h()-4);
496 if(!gauge_off){
497 fltk::setcolor(fltk::color(R,G,B));
499 int H = value * (h()-4) / max;
500 fltk::fillrect(2,h()-2-H,w()-4,H);
502 if(label_flag || label_always || label_temp){
503 char buf[3];
504 int V = label_plusone ? value + 1 : value;
505 if(label_hex){
506 snprintf(buf,3,"%x",V);
508 else{
509 snprintf(buf,3,"%d",V);
513 fltk::push_clip(2,2,w()-4,h()-4 - H);
514 fltk::setcolor(fltk::color(R,G,B));
515 fltk::setfont(fltk::HELVETICA,12);
516 int W = (int)fltk::getwidth(buf);
517 fltk::drawtext(buf,(w()-W)/2,h()-fltk::getascent()/2);
518 fltk::pop_clip();
521 fltk::push_clip(2,h()-2-H,w()-4,H);
522 if(!gauge_off){
523 fltk::setcolor(fltk::color(r,g,b));
525 fltk::setfont(fltk::HELVETICA,12);
526 fltk::drawtext(buf,(w()-W)/2,h()-fltk::getascent()/2);
527 fltk::pop_clip();
531 void HGauge::draw(){
532 draw_box();
533 fltk::setcolor(fltk::color(r,g,b));
534 fltk::fillrect(2,2,w()-4,h()-4);
536 fltk::setcolor(fltk::color(R,G,B));
537 int V = value * (h()-4) / max;
538 fltk::fillrect(2,2,V,h()-4);
540 if(label_flag || label_always || label_temp){
541 char buf[3];
542 snprintf(buf,3,"%x",value);
544 fltk::push_clip(V+2,2,w()-4-V,h()-4);
545 fltk::setcolor(fltk::color(R,G,B));
546 fltk::setfont(fltk::HELVETICA,12);
547 int W = (int)fltk::getwidth(buf);
548 fltk::drawtext(buf,(w()-W)/2,h()-fltk::getascent()/2);
549 fltk::pop_clip();
551 fltk::push_clip(2,2,V,h()-4);
552 fltk::setcolor(fltk::color(r,g,b));
553 fltk::setfont(fltk::HELVETICA,12);
554 fltk::drawtext(buf,(w()-W)/2,h()-fltk::getascent()/2);
555 fltk::pop_clip();
559 Toggle::Toggle(int x, int y, int w, int h, const char* label) :
560 fltk::Button(x, y, w, h, label){
561 buttonbox(fltk::DOWN_BOX);
562 when(fltk::WHEN_NEVER);
563 c[0] = 'A';
564 c[1] = '\0';
565 r = 127;
566 g = 0;
567 b = 0;
568 R = 255;
569 G = 0;
570 B = 0;
571 state = 0;
572 key_flag = 0;
575 int Toggle::handle(int e){
576 if(e==fltk::PUSH){
577 do_callback();
578 return 1;
580 return fltk::Button::handle(e);
583 void Toggle::draw(){
584 draw_box();
586 if(key_flag){ //instead of drawing normally do something completely different
587 //redirect complaints to /dev/null
588 if(state){
589 fltk::setcolor(fltk::BLACK);
590 fltk::fillrect(2,h()-3,w()-4,1);
591 fltk::fillrect(w()-3,2,1,h()-4);
592 fltk::fillrect(1,1,w()-4,1);
593 fltk::fillrect(1,1,1,h()-4);
595 fltk::fillrect(6,2,1,h()-4);
596 fltk::fillrect(12,2,1,h()-4);
598 fltk::fillrect(5,2,3,9);
599 fltk::fillrect(11,2,3,9);
601 else{
602 fltk::Button::draw(0);
604 return;
607 if(state){
608 fltk::setcolor(fltk::color(R,G,B));
610 else{
611 fltk::setcolor(fltk::color(r,g,b));
613 fltk::fillrect(2,2,w()-4,h()-4);
615 fltk::setcolor(fltk::BLACK);
616 fltk::setfont(fltk::HELVETICA,12);
617 int W = (int)fltk::getwidth(c);
618 fltk::drawtext(c,(w()-W)/2,h()-fltk::getascent()/2);
622 void Toggle::set(int s){
623 state = s;