3
TiMidity -- Experimental MIDI to WAVE converter
4
Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
6
This program is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2 of the License, or
9
(at your option) any later version.
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
GNU General Public License for more details.
16
You should have received a copy of the GNU General Public License
17
along with this program; if not, write to the Free Software
18
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32
#ifdef HAVE_NCURSES_CURSES_H
33
#include <ncurses/curses.h>
55
static void ctl_refresh(void);
56
static void ctl_help_mode(void);
57
static void ctl_total_time(uint32 tt);
58
static void ctl_master_volume(int mv);
59
static void ctl_file_name(char *name);
60
static void ctl_current_time(uint32 ct);
61
static void ctl_note(int v);
62
static void ctl_note_display(void);
63
static void ctl_program(int ch, int val, const char *name);
64
static void ctl_volume(int ch, int val);
65
static void ctl_expression(int ch, int val);
66
static void ctl_panning(int ch, int val);
67
static void ctl_sustain(int ch, int val);
68
static void ctl_pitch_bend(int ch, int val);
69
static void ctl_reset(void);
70
static int ctl_open(int using_stdin, int using_stdout);
71
static void ctl_close(void);
72
static int ctl_read(int32 *valp);
73
static int cmsg(int type, int verbosity_level, const char *fmt, ...);
75
/**********************************************/
76
/* export the interface functions */
79
#define ctl ncurses_control_mode
83
"ncurses interface", 'n',
85
ctl_open,dumb_pass_playing_list, ctl_close, ctl_read, cmsg,
86
ctl_refresh, ctl_reset, ctl_file_name, ctl_total_time, ctl_current_time,
88
ctl_master_volume, ctl_program, ctl_volume,
89
ctl_expression, ctl_panning, ctl_sustain, ctl_pitch_bend
93
/***********************************************************************/
94
/* foreground/background checks disabled since switching to curses */
95
/* static int in_foreground=1; */
96
static int ctl_helpmode=0;
97
static int maxy, maxx;
98
static int save_master_volume;
99
static int save_total_time;
100
static char save_file_name[50];
101
static int screen_bugfix = 0;
102
static uint32 current_centiseconds = 0;
103
static int songoffset = 0, current_voices = 0;
105
extern MidiEvent *current_event;
108
uint8 status, channel, note, velocity, voices;
111
#define MAX_OLD_NOTES 500
112
static OldVoice old_note[MAX_OLD_NOTES];
113
static int leading_pointer=0, trailing_pointer=0;
115
static int tr_lm, tr_nw;
117
static char patch_name[16][MAX_PNW];
119
static char short_cfg_names[4][6];
121
static int my_bg = COLOR_BLACK;
123
static void set_color(WINDOW *win, chtype color)
129
pairs = (bool *)calloc(COLORS+1, sizeof(bool));
131
init_pair(n, color, my_bg);
134
wattroff(win, A_COLOR);
135
wattron(win, COLOR_PAIR(n));
139
static void unset_color(WINDOW *win)
142
wattrset(win, COLOR_PAIR(0));
146
static WINDOW *dftwin=0, *msgwin=0;
148
static void _ctl_refresh(void)
154
static void ctl_refresh(void)
156
if (ctl.trace_playing)
161
wprintw(dftwin, (char *)"%2d", current_voices);
166
/* This is taken from TiMidity++. */
167
static void re_init_screen(void)
173
wprintw(dftwin, (char *)"patchset: %-20s interpolation: %-8s",
174
cfg_names[cfg_select]? cfg_names[cfg_select] : "?",
175
current_interpolation? ((current_interpolation==1)? "C-spline":"LaGrange") : "linear" );
185
static void ctl_help_mode(void)
187
static WINDOW *helpwin;
198
/* And here I thought the point of curses was that you could put
199
stuff on windows without having to worry about whether this
200
one is overlapping that or the other way round... */
201
helpwin=newwin(2,maxx,0,0);
202
wattron(helpwin, A_REVERSE);
205
"V/Up=Louder b/Left=Skip back "
206
"n/Next=Next file r/Home=Restart file");
209
"v/Down=Softer f/Right=Skip forward "
210
"p/Prev=Previous file q/End=Quit program");
211
wattroff(helpwin, A_REVERSE);
216
static void ctl_total_time(uint32 tt)
218
int mins, secs=(int)tt/play_mode->rate;
219
save_total_time = tt;
223
wmove(dftwin, 4,6+6+3);
224
wattron(dftwin, A_BOLD);
225
wprintw(dftwin, (char *)"%3d:%02d", mins, secs);
226
wattroff(dftwin, A_BOLD);
230
current_centiseconds = 0;
231
for (secs=0; secs<16; secs++) patch_name[secs][0] = '\0';
234
static void ctl_master_volume(int mv)
236
save_master_volume = mv;
237
wmove(dftwin, 4,maxx-5);
238
wattron(dftwin, A_BOLD);
239
wprintw(dftwin, (char *)"%3d%%", mv);
240
wattroff(dftwin, A_BOLD);
244
static void ctl_file_name(char *name)
246
strncpy(save_file_name, name, 50);
247
save_file_name[49] = '\0';
250
wattron(dftwin, A_BOLD);
251
waddstr(dftwin, name);
252
wattroff(dftwin, A_BOLD);
256
static void ctl_current_time(uint32 ct)
258
int centisecs, realct;
261
if (!ctl.trace_playing)
264
realct = play_mode->output_count(ct);
265
if (realct < 0) realct = 0;
266
else realct += songoffset;
267
centisecs = realct / (play_mode->rate/100);
268
current_centiseconds = (uint32)centisecs;
274
if (has_colors()) set_color(dftwin, COLOR_GREEN);
275
else wattron(dftwin, A_BOLD);
276
wprintw(dftwin, (char *)"%3d:%02d", mins, secs);
277
if (has_colors()) unset_color(dftwin);
278
else wattroff(dftwin, A_BOLD);
282
static void ctl_note(int v)
285
if (!ctl.trace_playing)
287
if (voice[v].clone_type != 0) return;
289
old_note[leading_pointer].status = voice[v].status;
290
old_note[leading_pointer].channel = voice[v].channel;
291
old_note[leading_pointer].note = voice[v].note;
292
old_note[leading_pointer].velocity = voice[v].velocity;
293
old_note[leading_pointer].time = current_event->time / (play_mode->rate/100);
297
if (voice[i].status!=VOICE_FREE) n++;
298
old_note[leading_pointer].voices = n;
300
if (leading_pointer == MAX_OLD_NOTES) leading_pointer = 0;
307
static void ctl_note_display(void)
309
int v = trailing_pointer;
312
if (tr_nw < 10) return;
314
then = old_note[v].time;
316
while (then <= current_centiseconds && v != leading_pointer)
319
new_note = old_note[v].note - LOW_CLIP;
320
if (new_note < 0) new_note = 0;
321
if (new_note > HIGH_CLIP) new_note = HIGH_CLIP;
322
xl = (new_note * tr_nw) / (HIGH_CLIP+1);
323
wmove(dftwin, 8+(old_note[v].channel & 0x0f),xl + tr_lm);
324
switch(old_note[v].status)
327
waddch(dftwin, ACS_CKBOARD);
330
waddch(dftwin, ACS_BULLET);
335
if (channel[old_note[v].channel].kit) set_color(dftwin, COLOR_YELLOW);
336
else set_color(dftwin, COLOR_RED);
338
else wattron(dftwin, A_BOLD);
339
waddch(dftwin, '0'+(10*old_note[v].velocity)/128);
340
if (has_colors()) unset_color(dftwin);
341
else wattroff(dftwin, A_BOLD);
344
case VOICE_SUSTAINED:
345
if (has_colors()) set_color(dftwin, COLOR_GREEN);
346
waddch(dftwin, '0'+(10*old_note[v].velocity)/128);
347
if (has_colors()) unset_color(dftwin);
350
current_voices = old_note[v].voices;
352
if (v == MAX_OLD_NOTES) v = 0;
353
then = old_note[v].time;
355
trailing_pointer = v;
358
static void ctl_program(int ch, int val, const char *name)
361
if (!ctl.trace_playing)
365
if (name && realch<16)
367
strncpy(patch_name[ch], name, MAX_PNW);
368
patch_name[ch][MAX_PNW-1] = '\0';
372
wmove(dftwin, 8+ch, 3);
373
if (patch_name[ch][0])
374
wprintw(dftwin, (char *)"%-12s", patch_name[ch]);
375
else waddstr(dftwin, " ");
378
wmove(dftwin, 8+ch, maxx-20);
381
if (has_colors()) set_color(dftwin, COLOR_YELLOW);
382
else wattron(dftwin, A_BOLD);
383
wprintw(dftwin, (char *)"%03d", val);
384
if (has_colors()) unset_color(dftwin);
385
else wattroff(dftwin, A_BOLD);
388
wprintw(dftwin, (char *)"%03d", val);
391
static void ctl_volume(int ch, int val)
393
if (!ctl.trace_playing)
396
wmove(dftwin, 8+ch, maxx-16);
397
wprintw(dftwin, (char *)"%3d", (val*100)/127);
400
static void ctl_expression(int ch, int val)
402
if (!ctl.trace_playing)
405
wmove(dftwin, 8+ch, maxx-12);
406
wprintw(dftwin, (char *)"%3d", (val*100)/127);
409
static void ctl_panning(int ch, int val)
411
if (!ctl.trace_playing)
414
wmove(dftwin, 8+ch, maxx-8);
415
if (val != NO_PANNING && has_colors())
417
if (val <= 60) set_color(dftwin, COLOR_CYAN);
418
if (val >= 68) set_color(dftwin, COLOR_GREEN);
421
waddstr(dftwin, " ");
423
waddstr(dftwin, " L ");
425
waddstr(dftwin, " R ");
426
else if (val>60 && val<68)
427
waddstr(dftwin, " C ");
430
/* wprintw(dftwin, "%+02d", (100*(val-64))/64); */
431
val = (100*(val-64))/64; /* piss on curses */
437
else waddch(dftwin, '+');
438
wprintw(dftwin, (char *)"%02d", val);
440
if (val != NO_PANNING && has_colors())
446
static void ctl_sustain(int ch, int val)
448
if (!ctl.trace_playing)
451
wmove(dftwin, 8+ch, maxx-4);
452
if (val) waddch(dftwin, 'S');
453
else waddch(dftwin, ' ');
456
static void ctl_pitch_bend(int ch, int val)
458
if (!ctl.trace_playing)
461
wmove(dftwin, 8+ch, maxx-2);
462
if (val>0x2000) waddch(dftwin, '+');
463
else if (val<0x2000) waddch(dftwin, '-');
464
else waddch(dftwin, ' ');
467
static void ctl_reset(void)
470
if (!ctl.trace_playing)
475
wmove(dftwin, 8+i, tr_lm);
477
for (j=0; j<tr_nw; j++) waddch(dftwin, ACS_BULLET);
478
ctl_program(i, channel[i].program, 0);
479
ctl_volume(i, channel[i].volume);
480
ctl_expression(i, channel[i].expression);
481
ctl_panning(i, channel[i].panning);
482
ctl_sustain(i, channel[i].sustain);
483
ctl_pitch_bend(i, channel[i].pitchbend);
485
for (i=0; i<MAX_OLD_NOTES; i++)
487
old_note[i].time = 0;
489
leading_pointer = trailing_pointer = current_voices = 0;
493
/***********************************************************************/
495
/*#define CURSED_REDIR_HACK*/
497
#ifdef CURSED_REDIR_HACK
498
static SCREEN *oldscr;
501
static void draw_windows(void)
506
if (tr_nw > MAX_PNW + 1 + 20)
508
tr_nw -= MAX_PNW + 1;
509
tr_lm += MAX_PNW + 1;
513
waddstr(dftwin, "TiMidity v" TIMID_VERSION);
514
wmove(dftwin, 0,maxx-52);
515
waddstr(dftwin, "(C) 1995 Tuukka Toivonen <toivonen@clinet.fi>");
518
waddstr(dftwin, "Press 'h' for help with keys, or 'q' to quit.");
521
wprintw(dftwin, (char *)"patchset: %-20s interpolation: %-8s",
522
cfg_names[cfg_select]? cfg_names[cfg_select] : "?",
523
current_interpolation? ((current_interpolation==1)? "C-spline":"LaGrange") : "linear" );
525
waddstr(dftwin, "File:");
527
if (ctl.trace_playing)
529
waddstr(dftwin, "Time:");
530
wmove(dftwin, 4,6+6+1);
533
wprintw(dftwin, (char *)"Voices: / %d", voices);
537
waddstr(dftwin, "Playing time:");
539
wmove(dftwin, 4,maxx-20);
540
waddstr(dftwin, "Master volume:");
541
if (save_master_volume) ctl_master_volume(save_master_volume);
542
if (save_total_time) ctl_total_time(save_total_time);
543
if (save_file_name[0]) ctl_file_name(save_file_name);
545
for (i=0; i<maxx; i++)
546
waddch(dftwin, ACS_HLINE);
547
if (ctl.trace_playing)
550
waddstr(dftwin, "Ch");
551
wmove(dftwin, 6,maxx-20);
552
waddstr(dftwin, "Prg Vol Exp Pan S B");
554
for (i=0; i<maxx; i++)
555
waddch(dftwin, ACS_HLINE);
558
wmove(dftwin, 8+i, 0);
559
wprintw(dftwin, (char *)"%02d", i+1);
564
if (msgwin) wresize(msgwin, maxy-6, maxx);
567
msgwin=newwin(maxy-6,maxx,6,0);
568
scrollok(msgwin, TRUE);
579
static int ctl_open(int using_stdin, int using_stdout)
582
#ifdef CURSED_REDIR_HACK
583
FILE *infp=stdin, *outfp=stdout;
586
/* This doesn't work right */
587
if (using_stdin && using_stdout)
591
setvbuf(stderr, 0, _IOFBF, BUFSIZ);
593
else if (using_stdout)
597
setvbuf(stderr, 0, _IOFBF, BUFSIZ);
599
else if (using_stdin)
603
setvbuf(stdout, 0, _IOFBF, BUFSIZ);
607
dftscr=newterm(0, outfp, infp);
610
oldscr=set_term(dftscr);
622
/*leaveok(stdscr, 1);*/
624
keypad(stdscr, TRUE);
630
#ifdef HAVE_USE_DEFAULT_COLORS
631
if (use_default_colors() == OK)
637
getmaxyx(stdscr,maxy,maxx);
640
if (ctl.trace_playing)
643
dftwin=newwin(6,maxx,0,0);
645
slk_set(1, "Help", 1);
646
slk_set(2, "Lnear", 1);
647
slk_set(3, "Cspln", 1);
648
slk_set(4, "Lgrng", 1);
652
if (cfg_names[i]) strncpy(short_cfg_names[i], cfg_names[i], 5);
653
else strcpy(short_cfg_names[i], "(nne)");
654
short_cfg_names[i][5] = '\0';
655
slk_set(i+5, short_cfg_names[i], 1);
658
slk_set(10, "Quit", 1);
659
if (opt_dry) slk_set(11, "Dry", 1);
660
else slk_set(11, "Wet", 1);
667
static void ctl_close(void)
678
static int ctl_read(int32 *valp)
688
while ((c=getch())!=ERR)
703
return RC_CHANGE_VOLUME;
707
return RC_CHANGE_VOLUME;
717
return RC_REALLY_PREVIOUS;
725
*valp=play_mode->rate;
730
*valp=play_mode->rate;
731
if (songoffset<0) songoffset=0;
735
getmaxyx(stdscr,maxy,maxx);
741
current_interpolation = 0;
746
current_interpolation = 1;
751
current_interpolation = 2;
759
return RC_PATCHCHANGE;
764
return RC_PATCHCHANGE;
769
return RC_PATCHCHANGE;
774
return RC_PATCHCHANGE;
779
slk_set(11, "Dry", 1);
784
slk_set(11, "Wet", 1);
791
return RC_TOGGLE_PAUSE; */
799
static int cmsg(int type, int verbosity_level, const char *fmt, ...)
803
if ((type==CMSG_TEXT || type==CMSG_INFO || type==CMSG_WARNING) &&
804
ctl.verbosity<verbosity_level)
814
vfprintf(stderr, fmt, ap);
815
fprintf(stderr, "\n");
817
else if (ctl.trace_playing)
821
/* Pretty pointless to only have one line for messages, but... */
827
if (has_colors()) set_color(dftwin, COLOR_YELLOW);
828
else wattron(dftwin, A_REVERSE);
829
vwprintw(dftwin, (char *)fmt, ap);
830
if (has_colors()) unset_color(dftwin);
831
else wattroff(dftwin, A_REVERSE);
833
if (type==CMSG_WARNING)
834
sleep(1); /* Don't you just _HATE_ it when programs do this... */
848
vwprintw(msgwin, (char *)fmt, ap);
849
if (flagnl) waddch(msgwin, '\n');
853
if (has_colors()) set_color(msgwin, COLOR_YELLOW);
854
else wattron(msgwin, A_BOLD);
855
vwprintw(msgwin, (char *)fmt, ap);
856
if (has_colors()) unset_color(msgwin);
857
else wattroff(msgwin, A_BOLD);
858
waddch(msgwin, '\n');
863
if (has_colors()) set_color(msgwin, COLOR_RED);
864
else wattron(msgwin, A_REVERSE);
865
vwprintw(msgwin, (char *)fmt, ap);
866
if (has_colors()) unset_color(msgwin);
867
else wattroff(msgwin, A_REVERSE);
868
waddch(msgwin, '\n');
869
if (type==CMSG_FATAL)