1 /*
2     TiMidity++ -- MIDI to WAVE converter and player
3     Copyright (C) 1999-2018 Masanao Izumo <iz@onicos.co.jp>
4     Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
5 
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.
10 
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.
15 
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 
20     ncurs_c.c: written by Masanao Izumo <iz@onicos.co.jp>
21                       and Aoki Daisuke <dai@y7.net>.
22     This version is merged with title list mode from Aoki Daisuke.
23 */
24 
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif /* HAVE_CONFIG_H */
28 #ifdef __POCC__
29 #include <sys/types.h>
30 #endif //for off_t
31 #include <stdio.h>
32 #if defined(__W32__)  && !defined(STDOUT_FILENO)
33 #define STDOUT_FILENO 1
34 #endif
35 
36 #if defined(__MINGW32__) && defined(USE_PDCURSES)
37 #define _NO_OLDNAMES 1	/* avoid type mismatch of beep() */
38 #ifndef sleep
39 extern void sleep(unsigned long);
40 #endif /* sleep */
41 #include <stdlib.h>
42 #undef _NO_OLDNAMES
43 #else /* USE_PDCURSES */
44 #include <stdlib.h>
45 #endif
46 
47 #include <stdarg.h>
48 #include <ctype.h>
49 #ifndef NO_STRING_H
50 #include <string.h>
51 #else
52 #include <strings.h>
53 #endif
54 #include <math.h>
55 
56 #ifdef HAVE_UNISTD_H
57 #include <unistd.h>
58 #endif /* HAVE_UNISTD_H */
59 
60 #ifdef __W32__
61 #include <windows.h>
62 #ifdef MOUSE_MOVED
63 #undef MOUSE_MOVED
64 #endif
65 #endif /* __W32__ */
66 
67 #ifdef HAVE_NCURSES_H
68 #include <ncurses.h>
69 #elif defined(HAVE_NCURSES_CURSES_H)
70 #include <ncurses/curses.h>
71 #else
72 #include <curses.h>
73 #endif
74 
75 #include "timidity.h"
76 #include "common.h"
77 #include "instrum.h"
78 #include "playmidi.h"
79 #include "readmidi.h"
80 #include "output.h"
81 #include "controls.h"
82 #include "miditrace.h"
83 #include "timer.h"
84 #include "bitset.h"
85 #include "arc.h"
86 #include "aq.h"
87 
88 #ifdef USE_PDCURSES
89 int PDC_set_ctrl_break(bool setting);
90 #endif /* USE_PDCURSES */
91 
92 #define SCREEN_BUGFIX 1 /* FIX the old ncurses bug */
93 
94 /* Define WREFRESH_CACHED if wrefresh isn't clear the internal cache */
95 #define WREFRESH_CACHED 1
96 
97 #ifdef JAPANESE
98 #define MULTIBUTE_CHAR_BUGFIX 1 /* Define to fix multibute overwrite bug */
99 #endif /* JAPANESE */
100 
101 #define MIDI_TITLE
102 #define DISPLAY_MID_MODE
103 #define COMMAND_BUFFER_SIZE 4096
104 #define MINI_BUFF_MORE_C '$'
105 #define LYRIC_OUT_THRESHOLD 10.0
106 #define CHECK_NOTE_SLEEP_TIME 5.0
107 #define NCURS_MIN_LINES 8
108 
109 #define CTL_STATUS_UPDATE -98
110 #define CTL_STATUS_INIT -99
111 
112 #ifndef MIDI_TITLE
113 #undef DISPLAY_MID_MODE
114 #endif /* MIDI_TITLE */
115 
116 #ifdef DISPLAY_MID_MODE
117 #if defined(JAPANESE) && !defined(__WATCOMC__)
118 #include "mid-j.defs"
119 #else
120 #include "mid.defs"
121 #endif /* JAPANESE */
122 #endif /* DISPLAY_MID_MODE */
123 
124 #define MAX_U_PREFIX 256
125 
126 /* GS LCD */
127 #define GS_LCD_MARK_ON		-1
128 #define GS_LCD_MARK_OFF		-2
129 #define GS_LCD_MARK_CLEAR	-3
130 #define GS_LCD_MARK_CHAR '$'
131 static double gslcd_last_display_time;
132 static int gslcd_displayed_flag = 0;
133 #define GS_LCD_CLEAR_TIME 10.0
134 #define GS_LCD_WIDTH 40
135 
136 extern int set_extension_modes(char *flag);
137 
138 static struct
139 {
140     int mute, bank, bank_lsb, bank_msb, prog;
141     int tt, vol, exp, pan, sus, pitch, wheel;
142     int is_drum;
143     int bend_mark;
144 
145     double last_note_on;
146     char *comm;
147 } ChannelStatus[MAX_CHANNELS];
148 
149 enum indicator_mode_t
150 {
151     INDICATOR_DEFAULT,
152     INDICATOR_LYRIC,
153     INDICATOR_CMSG
154 };
155 
156 static int indicator_width = 78;
157 static char *comment_indicator_buffer = NULL;
158 static char *current_indicator_message = NULL;
159 static char *indicator_msgptr = NULL;
160 static int current_indicator_chan = 0;
161 static double indicator_last_update;
162 static int indicator_mode = INDICATOR_DEFAULT;
163 static int display_velocity_flag = 0;
164 static int display_channels = 16;
165 
166 static Bitset channel_program_flags[MAX_CHANNELS];
167 static Bitset gs_lcd_bits[MAX_CHANNELS];
168 static int is_display_lcd = 1;
169 static int scr_modified_flag = 1; /* delay flush for trace mode */
170 
171 
172 static void update_indicator(void);
173 static void reset_indicator(void);
174 static void indicator_chan_update(int ch);
175 static void display_lyric(char *lyric, int sep);
176 static void display_play_system(int mode);
177 static void display_intonation(int mode);
178 static void display_aq_ratio(void);
179 
180 #define LYRIC_WORD_NOSEP	0
181 #define LYRIC_WORD_SEP		' '
182 
183 
184 static int ctl_open(int using_stdin, int using_stdout);
185 static void ctl_close(void);
186 static int ctl_pass_playing_list(int number_of_files, char *list_of_files[]);
187 static int ctl_read(int32 *valp);
188 static int ctl_write(char *valp, int32 size);
189 static int cmsg(int type, int verbosity_level, char *fmt, ...);
190 static void ctl_event(CtlEvent *e);
191 
192 static void ctl_refresh(void);
193 static void ctl_help_mode(void);
194 static void ctl_list_mode(int type);
195 static void ctl_total_time(int tt);
196 static void ctl_master_volume(int mv);
197 static void ctl_metronome(int meas, int beat);
198 static void ctl_keysig(int8 k, int ko);
199 static void ctl_tempo(int t, int tr);
200 static void ctl_file_name(char *name);
201 static void ctl_current_time(int ct, int nv);
202 static const char note_name_char[12] =
203 {
204     'c', 'C', 'd', 'D', 'e', 'f', 'F', 'g', 'G', 'a', 'A', 'b'
205 };
206 
207 static void ctl_note(int status, int ch, int note, int vel);
208 static void ctl_temper_keysig(int8 tk, int ko);
209 static void ctl_temper_type(int ch, int8 tt);
210 static void ctl_mute(int ch, int mute);
211 static void ctl_drumpart(int ch, int is_drum);
212 static void ctl_program(int ch, int prog, char *vp, unsigned int banks);
213 static void ctl_volume(int channel, int val);
214 static void ctl_expression(int channel, int val);
215 static void ctl_panning(int channel, int val);
216 static void ctl_sustain(int channel, int val);
217 static void update_bend_mark(int ch);
218 static void ctl_pitch_bend(int channel, int val);
219 static void ctl_mod_wheel(int channel, int wheel);
220 static void ctl_lyric(int lyricid);
221 static void ctl_gslcd(int id);
222 static void ctl_reset(void);
223 
224 /**********************************************/
225 
226 /* define (LINE,ROW) */
227 #ifdef MIDI_TITLE
228 #define VERSION_LINE 0
229 #define HELP_LINE 1
230 #define FILE_LINE 2
231 #define FILE_TITLE_LINE 3
232 #define TIME_LINE 4
233 #define VOICE_LINE 4
234 #define SEPARATE1_LINE 5
235 #define TITLE_LINE 6
236 #define NOTE_LINE 7
237 #else
238 #define VERSION_LINE 0
239 #define HELP_LINE 1
240 #define FILE_LINE 2
241 #define TIME_LINE  3
242 #define VOICE_LINE 3
243 #define SEPARATE1_LINE 4
244 #define TITLE_LINE 5
245 #define SEPARATE2_LINE 6
246 #define NOTE_LINE 7
247 #endif
248 
249 #define LIST_TITLE_LINES (LINES - TITLE_LINE - 1)
250 
251 /**********************************************/
252 /* export the interface functions */
253 
254 #define ctl ncurses_control_mode
255 
256 ControlMode ctl=
257 {
258     "ncurses interface", 'n',
259     "ncurses",
260     1,0,0,
261     0,
262     ctl_open,
263     ctl_close,
264     ctl_pass_playing_list,
265     ctl_read,
266     ctl_write,
267     cmsg,
268     ctl_event
269 };
270 
271 static uint32 cuepoint = 0;
272 static int cuepoint_pending = 0;
273 
274 
275 /***********************************************************************/
276 /* foreground/background checks disabled since switching to curses */
277 /* static int in_foreground=1; */
278 
279 enum ctl_ncurs_mode_t
280 {
281     /* Major modes */
282     NCURS_MODE_NONE,	/* None */
283     NCURS_MODE_MAIN,	/* Normal mode */
284     NCURS_MODE_TRACE,	/* Trace mode */
285     NCURS_MODE_HELP,	/* Help mode */
286     NCURS_MODE_LIST,	/* MIDI list mode */
287     NCURS_MODE_DIR,	/* Directory list mode */
288 
289     /* Minor modes */
290     /* Command input mode */
291     NCURS_MODE_CMD_J,	/* Jump */
292     NCURS_MODE_CMD_L,	/* Load file */
293     NCURS_MODE_CMD_E,	/* Extensional mode */
294     NCURS_MODE_CMD_FSEARCH,	/* forward search MIDI file */
295     NCURS_MODE_CMD_D,	/* Change drum channel */
296     NCURS_MODE_CMD_S,	/* Save as */
297     NCURS_MODE_CMD_R	/* Change sample rate */
298 };
299 static int ctl_ncurs_mode = NCURS_MODE_MAIN; /* current mode */
300 static int ctl_ncurs_back = NCURS_MODE_MAIN; /* prev mode to back from help */
301 static int ctl_cmdmode = 0;
302 static int ctl_mode_L_dispstart = 0;
303 static char ctl_mode_L_lastenter[COMMAND_BUFFER_SIZE];
304 static char ctl_mode_SEARCH_lastenter[COMMAND_BUFFER_SIZE];
305 
306 struct double_list_string
307 {
308     char *string;
309     struct double_list_string *next, *prev;
310 };
311 static struct double_list_string *ctl_mode_L_histh = NULL; /* head */
312 static struct double_list_string *ctl_mode_L_histc = NULL; /* current */
313 
314 static void ctl_ncurs_mode_init(void);
315 static void init_trace_window_chan(int ch);
316 static void init_chan_status(void);
317 static void ctl_cmd_J_move(int diff);
318 static int ctl_cmd_J_enter(void);
319 static void ctl_cmd_L_dir(int move);
320 static int ctl_cmd_L_enter(void);
321 
322 static int selected_channel = -1;
323 
324 /* list_mode */
325 typedef struct _MFnode
326 {
327     char *file;
328 #ifdef MIDI_TITLE
329     char *title;
330 #endif /* MIDI_TITLE */
331     struct midi_file_info *infop;
332     struct _MFnode *next;
333 } MFnode;
334 
335 static struct _file_list {
336   int number;
337   MFnode *MFnode_head;
338   MFnode *MFnode_tail;
339 } file_list;
340 
341 static MFnode *MFnode_nth_cdr(MFnode *p, int n);
342 static MFnode *current_MFnode = NULL;
343 
344 #define NC_LIST_MAX 512
345 static int ctl_listmode=1;
346 static int ctl_listmode_max=1;	/* > 1 */
347 static int ctl_listmode_play=1;	/* > 1 */
348 static int ctl_list_select[NC_LIST_MAX];
349 static int ctl_list_from[NC_LIST_MAX];
350 static int ctl_list_to[NC_LIST_MAX];
351 static void ctl_list_table_init(void);
352 static MFnode *make_new_MFnode_entry(char *file);
353 static void insert_MFnode_entrys(MFnode *mfp, int pos);
354 
355 #define NC_LIST_NEW 1
356 #define NC_LIST_NOW 2
357 #define NC_LIST_PLAY 3
358 #define NC_LIST_SELECT 4
359 #define NC_LIST_NEXT 5
360 #define NC_LIST_PREV 6
361 #define NC_LIST_UP 7
362 #define NC_LIST_DOWN 8
363 #define NC_LIST_UPPAGE 9
364 #define NC_LIST_DOWNPAGE 10
365 
366 /* playing files */
367 static int nc_playfile=0;
368 
369 typedef struct MiniBuffer
370 {
371     char *buffer;	/* base buffer */
372     int size;		/* size of base buffer */
373     char *text;		/* pointer to buffer + (prompt length) */
374     int maxlen;		/* max text len */
375     int len;		/* [0..maxlen] */
376     int cur;		/* cursor pos [0..len] */
377     int uflag;		/* update flag */
378     int cflag;		/* for file completion flag */
379     MFnode *files;	/* completed files */
380     char *lastcmpl;	/* last completed pathname */
381     MBlockList pool;	/* memory pool */
382 
383     WINDOW *bufwin;	/* buffer window */
384     int x, y;		/* window position */
385     int w, h;		/* window size */
386 } MiniBuffer;
387 
388 static MiniBuffer *command_buffer = NULL; /* command buffer */
389 
390 static MiniBuffer *mini_buff_new(int size);
391 static void mini_buff_set(MiniBuffer *b,
392 			  WINDOW *bufwin, int line, char *prompt);
393 static void mini_buff_clear(MiniBuffer *b);
394 static void mini_buff_refresh(MiniBuffer *b);
395 static int mini_buff_forward(MiniBuffer *b);
396 static int mini_buff_backward(MiniBuffer *b);
397 static int mini_buff_insertc(MiniBuffer *b, int c);
398 static int mini_buff_inserts(MiniBuffer *b, char *s);
399 static int mini_buff_delc(MiniBuffer *b);
400 static char *mini_buff_gets(MiniBuffer *b);
401 static void mini_buff_sets(MiniBuffer *b, char *s);
402 static int mini_buff_len(MiniBuffer *b);
403 static int mini_buff_completion(MiniBuffer *b);
404 
405 static WINDOW *dftwin=0, *msgwin=0, *listwin=0;
406 
407 
N_ctl_refresh(void)408 static void N_ctl_refresh(void)
409 {
410   if(!ctl.opened)
411     return;
412 
413   if(ctl_cmdmode)
414       wmove(dftwin, command_buffer->y, command_buffer->x);
415   else
416       wmove(dftwin, 0,0);
417   wrefresh(dftwin);
418   scr_modified_flag = 0;
419 }
420 
N_ctl_clrtoeol(int row)421 static void N_ctl_clrtoeol(int row)
422 {
423     int i;
424 
425     wmove(dftwin, row, 0);
426     for(i = 0; i < COLS; i++)
427 	waddch(dftwin, ' ');
428     wmove(dftwin, row, 0);
429     wrefresh(dftwin);
430 }
431 
432 /* werase() is not collectly work if multibyte font is displayed. */
N_ctl_werase(WINDOW * w)433 static void N_ctl_werase(WINDOW *w)
434 {
435 #ifdef WREFRESH_CACHED
436     int x, y, xsize, ysize;
437     getmaxyx(w, ysize, xsize);
438     for(y = 0; y < ysize; y++)
439     {
440 	wmove(w, y, 0);
441 	for(x = 0; x < xsize; x++)
442 	    waddch(w, ' ');
443     }
444 #else
445     werase(w);
446 #endif /* WREFRESH_CACHED */
447     wmove(w, 0, 0);
448     wrefresh(w);
449 }
450 
N_ctl_scrinit(void)451 static void N_ctl_scrinit(void)
452 {
453     int i;
454 
455     N_ctl_werase(dftwin);
456     wmove(dftwin, VERSION_LINE,0);
457     waddstr(dftwin, "TiMidity++ ");
458     if (strcmp(timidity_version, "current"))
459     	waddch(dftwin, 'v');
460     waddstr(dftwin, timidity_version);
461     wmove(dftwin, VERSION_LINE,COLS-51);
462     waddstr(dftwin, "(C) 1995,1999-2018 Tuukka Toivonen, Masanao Izumo");
463     wmove(dftwin, FILE_LINE,0);
464     waddstr(dftwin, "File:");
465 #ifdef MIDI_TITLE
466     wmove(dftwin, FILE_TITLE_LINE,0);
467     waddstr(dftwin, "Title:");
468     for(i = 0; i < COLS - 6; i++)
469 	waddch(dftwin, ' ');
470 #endif
471     wmove(dftwin, TIME_LINE,0);
472     waddstr(dftwin, "Time:");
473     wmove(dftwin, TIME_LINE,6 + 6);
474     waddch(dftwin, '/');
475     wmove(dftwin, VOICE_LINE,40);
476     wprintw(dftwin, "Voices:     / %3d", voices);
477     wmove(dftwin, VOICE_LINE, COLS-20);
478     waddstr(dftwin, "Master volume:");
479     wmove(dftwin, SEPARATE1_LINE, 0);
480     for(i = 0; i < COLS; i++)
481 #ifdef MIDI_TITLE
482 	waddch(dftwin, '-');
483 #else
484     waddch(dftwin, '_');
485 #endif
486     wmove(dftwin, SEPARATE1_LINE, 0);
487     waddstr(dftwin, "Meas: ");
488     wmove(dftwin, SEPARATE1_LINE, 37);
489     waddstr(dftwin, " Key: ");
490     wmove(dftwin, SEPARATE1_LINE, 58);
491     waddstr(dftwin, " Tempo: ");
492 
493     indicator_width = COLS - 2;
494     if(indicator_width < 40)
495 	indicator_width = 40;
496     if(comment_indicator_buffer != NULL)
497 	free(comment_indicator_buffer);
498     if(current_indicator_message != NULL)
499 	free(current_indicator_message);
500     memset(comment_indicator_buffer =
501 	   (char *)safe_malloc(indicator_width), 0, indicator_width);
502     memset(current_indicator_message =
503 	   (char *)safe_malloc(indicator_width), 0, indicator_width);
504 
505     if(ctl.trace_playing)
506     {
507 	int o;
508 
509 	wmove(dftwin, TITLE_LINE, 0);
510 	waddstr(dftwin, "Ch ");
511 	o = (COLS - 28) / 12;
512 	for(i = 0; i < o; i++)
513 	{
514 	    int j;
515 	    for(j = 0; j < 12; j++)
516 	    {
517 		int c;
518 		c = note_name_char[j];
519 		if(islower(c))
520 		    waddch(dftwin, c);
521 		else
522 		    waddch(dftwin, ' ');
523 	    }
524 	}
525 	wmove(dftwin, TITLE_LINE, COLS - 20);
526 	waddstr(dftwin, "Prg Vol Exp Pan S B");
527 #ifndef MIDI_TITLE
528 	wmove(dftwin, SEPARATE2_LINE, 0);
529 	for(i = 0; i < COLS; i++)
530 	    waddch(dftwin, '-');
531 #endif
532 	for(i = 0; i < MAX_CHANNELS; i++)
533 	{
534 	    init_bitset(channel_program_flags + i, 128);
535 	    init_bitset(gs_lcd_bits + i, 128);
536 	}
537     }
538     N_ctl_refresh();
539 }
540 
ctl_refresh(void)541 static void ctl_refresh(void)
542 {
543   if (scr_modified_flag)
544     N_ctl_refresh();
545 }
546 
init_trace_window_chan(int ch)547 static void init_trace_window_chan(int ch)
548 {
549     int i, c;
550 
551     if(ch >= display_channels)
552 	return;
553 
554     N_ctl_clrtoeol(NOTE_LINE + ch);
555     ctl_mute(ch, CTL_STATUS_UPDATE);
556     waddch(dftwin, ' ');
557     if(ch != selected_channel)
558     {
559 	c = (COLS - 28) / 12 * 12;
560 	if(c <= 0)
561 	    c = 1;
562 	for(i = 0; i < c; i++)
563 	    waddch(dftwin, '.');
564 	ctl_temper_type(ch, CTL_STATUS_UPDATE);
565 	ctl_program(ch, CTL_STATUS_UPDATE, NULL, 0);
566 	ctl_volume(ch, CTL_STATUS_UPDATE);
567 	ctl_expression(ch, CTL_STATUS_UPDATE);
568 	ctl_panning(ch, CTL_STATUS_UPDATE);
569 	ctl_sustain(ch, CTL_STATUS_UPDATE);
570 	update_bend_mark(ch);
571 	clear_bitset(channel_program_flags + ch, 0, 128);
572     }
573     else
574     {
575 	ToneBankElement *prog;
576 	ToneBank *bank;
577 	int b, type, pr;
578 
579 	b = ChannelStatus[ch].bank;
580 	pr = ChannelStatus[ch].prog;
581 	bank = tonebank[b];
582 	if(bank == NULL || bank->tone[pr].instrument == NULL)
583 	{
584 	    b = 0;
585 	    bank = tonebank[0];
586 	}
587 
588 	if(ChannelStatus[ch].is_drum)
589 	{
590 	    wprintw(dftwin, "Drumset Bank %d=>%d",
591 		    ChannelStatus[ch].bank + progbase, b + progbase);
592 	}
593 	else
594 	{
595 	    if(IS_CURRENT_MOD_FILE)
596 	    {
597 		wprintw(dftwin, "MOD %d (%s)",
598 			ChannelStatus[ch].prog,
599 			ChannelStatus[ch].comm ? ChannelStatus[ch].comm :
600 			"Not installed");
601 	    }
602 	    else
603 	    {
604 		prog = &bank->tone[pr];
605 
606 		if(prog->instrument != NULL &&
607 		   !IS_MAGIC_INSTRUMENT(prog->instrument))
608 		{
609 		    type = prog->instrument->type;
610 		    /* check instrument alias */
611 		    if(b != 0 &&
612 		       tonebank[0]->tone[pr].instrument == prog->instrument)
613 		    {
614 			b = 0;
615 			bank = tonebank[0];
616 			prog = &bank->tone[pr];
617 		    }
618 		}
619 		else
620 		    type = -1;
621 
622 		wprintw(dftwin, "%d Bank %d/%d=>%d Prog %d",
623 			type,
624 			ChannelStatus[ch].bank_msb,
625 			ChannelStatus[ch].bank_lsb,
626 			b,
627 			ChannelStatus[ch].prog + progbase);
628 
629 		if(type == INST_GUS)
630 		{
631 		    if(prog->name)
632 		    {
633 			waddch(dftwin, ' ');
634 			waddstr(dftwin, prog->name);
635 		    }
636 		    if(prog->comment != NULL)
637 			wprintw(dftwin, "(%s)", prog->comment);
638 		}
639 		else if(type == INST_SF2)
640 		{
641 		    char *name, *fn;
642 
643 		    waddstr(dftwin, " (SF ");
644 
645 		    if(prog->instype == 1)
646 		    {
647 			/* Restore original one */
648 			b = prog->font_bank;
649 			pr = prog->font_preset;
650 		    }
651 
652 		    name = soundfont_preset_name(b, pr, -1, &fn);
653 		    if(name == NULL && b != 0)
654 		    {
655 			if((name = soundfont_preset_name(0, pr, -1, &fn)) != NULL)
656 			    b = 0;
657 		    }
658 
659 		    wprintw(dftwin, "%d,%d", b, pr + progbase);
660 
661 		    if(name != NULL)
662 		    {
663 			char *p;
664 			if((p = pathsep_strrchr(fn)) != NULL)
665 			    p++;
666 			else
667 			    p = fn;
668 			wprintw(dftwin, ",%s", name, p);
669 		    }
670 		    waddch(dftwin, ')');
671 		}
672 	    }
673 	}
674     }
675 }
676 
init_chan_status(void)677 static void init_chan_status(void)
678 {
679     int ch;
680 
681     for(ch = 0; ch < MAX_CHANNELS; ch++)
682     {
683 	ChannelStatus[ch].mute = temper_type_mute & 1;
684 	ChannelStatus[ch].bank = 0;
685 	ChannelStatus[ch].bank_msb = 0;
686 	ChannelStatus[ch].bank_lsb = 0;
687 	ChannelStatus[ch].prog = 0;
688 	ChannelStatus[ch].tt = 0;
689 	ChannelStatus[ch].is_drum = ISDRUMCHANNEL(ch);
690 	ChannelStatus[ch].vol = 0;
691 	ChannelStatus[ch].exp = 0;
692 	ChannelStatus[ch].pan = NO_PANNING;
693 	ChannelStatus[ch].sus = 0;
694 	ChannelStatus[ch].pitch = 0x2000;
695 	ChannelStatus[ch].wheel = 0;
696 	ChannelStatus[ch].bend_mark = ' ';
697 	ChannelStatus[ch].last_note_on = 0.0;
698 	ChannelStatus[ch].comm = NULL;
699     }
700 }
701 
display_play_system(int mode)702 static void display_play_system(int mode)
703 {
704     wmove(dftwin, TIME_LINE, 22);
705     switch(mode)
706     {
707       case GM_SYSTEM_MODE:
708 	waddstr(dftwin, "[GM] ");
709 	break;
710       case GS_SYSTEM_MODE:
711 	waddstr(dftwin, "[GS] ");
712 	break;
713       case XG_SYSTEM_MODE:
714 	waddstr(dftwin, "[XG] ");
715 	break;
716       case GM2_SYSTEM_MODE:
717 	waddstr(dftwin, "[GM2]");
718 	break;
719       default:
720 	waddstr(dftwin, "     ");
721 	break;
722     }
723     scr_modified_flag = 1;
724 }
725 
display_intonation(int mode)726 static void display_intonation(int mode)
727 {
728 	wmove(dftwin, TIME_LINE, 28);
729 	waddstr(dftwin, (mode == 1) ? "[PureInt]" : "         ");
730 	scr_modified_flag = 1;
731 }
732 
ctl_ncurs_mode_init(void)733 static void ctl_ncurs_mode_init(void)
734 {
735 	int i;
736 
737 	if (current_file_info != NULL)
738 		display_channels = (current_file_info->max_channel / 16) * 16 + 16;
739 	else
740 		display_channels = LINES - 8;
741 	if (display_channels > LINES - 8)
742 		display_channels = LINES - 8;
743 	display_play_system(play_system_mode);
744 	display_intonation(opt_pure_intonation);
745 	switch (ctl_ncurs_mode) {
746 	case NCURS_MODE_MAIN:
747 		touchwin(msgwin);
748 		wrefresh(msgwin);
749 		break;
750 	case NCURS_MODE_TRACE:
751 		touchwin(dftwin);
752 		for (i = 0; i < MAX_CHANNELS; i++)
753 			init_trace_window_chan(i);
754 		N_ctl_refresh();
755 		break;
756 	case NCURS_MODE_HELP:
757 		break;
758 	case NCURS_MODE_LIST:
759 		touchwin(listwin);
760 		ctl_list_mode(NC_LIST_NOW);
761 		break;
762 	case NCURS_MODE_DIR:
763 		ctl_cmd_L_dir(0);
764 		break;
765 	}
766 }
767 
display_key_helpmsg(void)768 static void display_key_helpmsg(void)
769 {
770     if(ctl_cmdmode || ctl_ncurs_mode == NCURS_MODE_HELP)
771     {
772 	if(!ctl.trace_playing)
773 	{
774 	    wmove(dftwin, HELP_LINE, 0);
775 	    waddstr(dftwin, "Press 'h' for help with keys, or 'q' to quit.");
776 	    N_ctl_refresh();
777 	}
778 	return;
779     }
780     N_ctl_clrtoeol(LINES - 1);
781 
782     if(!ctl.trace_playing)
783 	wmove(dftwin, HELP_LINE, 0);
784     waddstr(dftwin, "Press 'h' for help with keys, or 'q' to quit.");
785     N_ctl_refresh();
786 }
787 
ctl_help_mode(void)788 static void ctl_help_mode(void)
789 {
790     static WINDOW *helpwin;
791     if(ctl_ncurs_mode == NCURS_MODE_HELP)
792     {
793 	ctl_ncurs_mode = ctl_ncurs_back;
794 	touchwin(dftwin);
795 	delwin(helpwin);
796 	N_ctl_refresh();
797 	ctl_ncurs_mode_init();
798 	display_key_helpmsg();
799     }
800     else
801     {
802 	int i;
803 	static char *help_message_list[] =
804 	{
805 "V/Up=Louder    b/Left=Skip back      n/Next=Next file      r/Home=Restart file",
806 "v/Down=Softer  f/Right=Skip forward  p/Prev=Previous file  q/End=Quit program",
807 "h/?=Help mode  s=Toggle pause        E=ExtMode-Setting",
808 "+=Key up       -=Key down            >=Speed up            <=Speed down",
809 "O=Voices up    o=Voices down         c/j/C/k=Move channel  d=Toggle drum prt.",
810 "J=Jump         L=Load & play (TAB: File completion)        t=Toggle trace mode",
811 "%=Display velocity (toggle)          D=Drum change         S=Save as",
812 "R=Change rate  Space=Toggle ch. mute .=Solo ch. play       /=Clear ch. mute",
813 #ifdef SUPPORT_SOUNDSPEC
814 "g=Open sound spectrogram window",
815 #else
816 "",
817 #endif /* SUPPORT_SOUNDSPEC */
818 "",
819 "l/INS=List mode",
820 "k/Up=Cursor up         j/Down=Cursor down Space=Select and play",
821 "p=Previous file play   n=Next file play   RollUp=Page up   RollDown=Page down",
822 "/=Search file",
823 NULL
824 };
825 	ctl_ncurs_back = ctl_ncurs_mode;
826 	ctl_ncurs_mode = NCURS_MODE_HELP;
827 	helpwin = newwin(LIST_TITLE_LINES, COLS, TITLE_LINE, 0);
828 	N_ctl_werase(helpwin);
829 	wattron(helpwin, A_BOLD);
830 	waddstr(helpwin, "                 ncurses interface Help");
831 	wattroff(helpwin, A_BOLD);
832 
833 	for(i = 0; help_message_list[i]; i++)
834 	{
835 	    wmove(helpwin, i+1,0);
836 	    waddstr(helpwin, help_message_list[i]);
837 	}
838 	wmove(helpwin, i+2,0);
839 	wattron(helpwin, A_BOLD);
840 	waddstr(helpwin,
841 		"                   Type `h' to go to previous screen");
842 	wattroff(helpwin, A_BOLD);
843 	wrefresh(helpwin);
844 	N_ctl_clrtoeol(LINES - 1);
845 	N_ctl_refresh();
846     }
847 }
848 
MFnode_nth_cdr(MFnode * p,int n)849 static MFnode *MFnode_nth_cdr(MFnode *p, int n)
850 {
851     while(p != NULL && n-- > 0)
852 	p = p->next;
853     return p;
854 }
855 
ctl_list_MFnode_files(MFnode * mfp,int select_id,int play_id)856 static void ctl_list_MFnode_files(MFnode *mfp, int select_id, int play_id)
857 {
858     int i, mk;
859 #ifdef MIDI_TITLE
860     char *item, *f, *title;
861     int tlen, flen, mlen;
862 #ifdef DISPLAY_MID_MODE
863     char *mname;
864 #endif /* DISPLAY_MID_MODE */
865 #endif /* MIDI_TITLE */
866 
867     N_ctl_werase(listwin);
868     mk = 0;
869     for(i = 0; i < LIST_TITLE_LINES && mfp; i++, mfp = mfp->next)
870     {
871 	if(i == select_id || i == play_id)
872 	{
873 	    mk = 1;
874 	    wattron(listwin,A_REVERSE);
875 	}
876 
877 	wmove(listwin, i, 0);
878 	wprintw(listwin,"%03d%c",
879 		i + ctl_list_from[ctl_listmode],
880 		i == play_id ? '*' : ' ');
881 
882 #ifdef MIDI_TITLE
883 
884 	if((f = pathsep_strrchr(mfp->file)) != NULL)
885 	    f++;
886 	else
887 	    f = mfp->file;
888 	flen = strlen(f);
889 	title = mfp->title;
890 	if(title != NULL)
891 	{
892 	    while(*title == ' ')
893 		title++;
894 	    tlen = strlen(title) + 1;
895 	}
896 	else
897 	    tlen = 0;
898 
899 #ifdef DISPLAY_MID_MODE
900 	mname = mid2name(mfp->infop->mid);
901 	if(mname != NULL)
902 	    mlen = strlen(mname);
903 	else
904 	    mlen = 0;
905 #else
906 	mlen = 0;
907 #endif /* DISPLAY_MID_MODE */
908 
909 	item = (char *)new_segment(&tmpbuffer, tlen + flen + mlen + 4);
910 	if(title != NULL)
911 	{
912 	    strcpy(item, title);
913 	    strcat(item, " ");
914 	}
915 	else
916 	    item[0] = '\0';
917 	strcat(item, "(");
918 	strcat(item, f);
919 	strcat(item, ")");
920 
921 #ifdef DISPLAY_MID_MODE
922 	if(mlen)
923 	{
924 	    strcat(item, "/");
925 	    strcat(item, mname);
926 	}
927 #endif /* DISPLAY_MID_MODE */
928 
929 	waddnstr(listwin, item, COLS-6);
930 	reuse_mblock(&tmpbuffer);
931 #else
932 	waddnstr(listwin, mfp->file, COLS-6);
933 #endif
934 	if(mk)
935 	{
936 	    mk = 0;
937 	    wattroff(listwin,A_REVERSE);
938 	}
939     }
940 }
941 
ctl_list_mode(int type)942 static void ctl_list_mode(int type)
943 {
944   for(ctl_listmode_play=1;;ctl_listmode_play++) {
945     if(ctl_list_from[ctl_listmode_play]<=nc_playfile
946        &&nc_playfile<=ctl_list_to[ctl_listmode_play])
947       break;
948   }
949   switch(type){
950   case NC_LIST_PREV:
951     if(ctl_listmode<=1)
952       ctl_listmode=ctl_listmode_max;
953     else
954       ctl_listmode--;
955     break;
956   case NC_LIST_NEXT:
957     if(ctl_listmode>=ctl_listmode_max)
958       ctl_listmode=1;
959     else
960       ctl_listmode++;
961     break;
962   case NC_LIST_UP:
963     if(ctl_list_select[ctl_listmode]<=ctl_list_from[ctl_listmode]){
964       if(ctl_listmode<=1)
965 	ctl_listmode=ctl_listmode_max;
966       else
967 	ctl_listmode--;
968       ctl_list_select[ctl_listmode]=ctl_list_to[ctl_listmode];
969     } else
970       ctl_list_select[ctl_listmode]--;
971     break;
972   case NC_LIST_DOWN:
973     if(ctl_list_select[ctl_listmode]>=ctl_list_to[ctl_listmode]){
974       if(ctl_listmode>=ctl_listmode_max)
975 	ctl_listmode=1;
976       else
977 	ctl_listmode++;
978       ctl_list_select[ctl_listmode]=ctl_list_from[ctl_listmode];
979     } else
980 	ctl_list_select[ctl_listmode]++;
981     break;
982   case NC_LIST_UPPAGE:
983     if(ctl_listmode<=1)
984       ctl_listmode=ctl_listmode_max;
985     else
986 	ctl_listmode--;
987     ctl_list_select[ctl_listmode]=ctl_list_to[ctl_listmode];
988     break;
989   case NC_LIST_DOWNPAGE:
990     if(ctl_listmode>=ctl_listmode_max)
991       ctl_listmode=1;
992     else
993 	ctl_listmode++;
994     ctl_list_select[ctl_listmode]=ctl_list_from[ctl_listmode];
995     break;
996   case NC_LIST_PLAY:
997     if(ctl_ncurs_mode == NCURS_MODE_LIST)
998     {
999 	/* leave list mode */
1000 	if(ctl.trace_playing)
1001 	    ctl_ncurs_mode = NCURS_MODE_TRACE;
1002 	else
1003 	    ctl_ncurs_mode = NCURS_MODE_MAIN;
1004 	ctl_ncurs_mode_init();
1005     }
1006     else
1007     {
1008 	/* enter list mode */
1009 	ctl_ncurs_mode = NCURS_MODE_LIST;
1010     }
1011     ctl_ncurs_back = ctl_ncurs_mode;
1012     break;
1013   case NC_LIST_NEW:
1014     ctl_listmode=ctl_listmode_play;
1015     ctl_list_select[ctl_listmode]=nc_playfile;
1016     break;
1017   case NC_LIST_NOW:
1018     break;
1019   default:
1020     ;
1021   }
1022   if(ctl_ncurs_mode == NCURS_MODE_LIST)
1023     {
1024 	int i;
1025 	MFnode *mfp;
1026 
1027 	i = ctl_list_from[ctl_listmode];
1028 	mfp = MFnode_nth_cdr(file_list.MFnode_head, i);
1029 	ctl_list_MFnode_files(mfp, ctl_list_select[ctl_listmode] - i,
1030 			   nc_playfile - i);
1031 	wrefresh(listwin);
1032 	N_ctl_refresh();
1033     }
1034 }
1035 
redraw_all(void)1036 static void redraw_all(void)
1037 {
1038     N_ctl_scrinit();
1039     ctl_total_time(CTL_STATUS_UPDATE);
1040     ctl_master_volume(CTL_STATUS_UPDATE);
1041     ctl_metronome(CTL_STATUS_UPDATE, CTL_STATUS_UPDATE);
1042     ctl_keysig(CTL_STATUS_UPDATE, CTL_STATUS_UPDATE);
1043     ctl_tempo(CTL_STATUS_UPDATE, CTL_STATUS_UPDATE);
1044     ctl_temper_keysig(CTL_STATUS_UPDATE, CTL_STATUS_UPDATE);
1045     display_key_helpmsg();
1046     ctl_file_name(NULL);
1047     ctl_ncurs_mode_init();
1048 }
1049 
ctl_event(CtlEvent * e)1050 static void ctl_event(CtlEvent *e)
1051 {
1052     if(midi_trace.flush_flag)
1053 	return;
1054     switch(e->type)
1055     {
1056       case CTLE_NOW_LOADING:
1057 	ctl_file_name((char *)e->v1);
1058 	break;
1059       case CTLE_LOADING_DONE:
1060 	redraw_all();
1061 	break;
1062       case CTLE_PLAY_START:
1063 	init_chan_status();
1064 	ctl_ncurs_mode_init();
1065 	ctl_total_time((int)e->v1);
1066 	break;
1067       case CTLE_PLAY_END:
1068 	break;
1069 	case CTLE_CUEPOINT:
1070 		cuepoint = e->v1;
1071 		cuepoint_pending = 1;
1072 		break;
1073       case CTLE_CURRENT_TIME:
1074 	ctl_current_time((int)e->v1, (int)e->v2);
1075 	display_aq_ratio();
1076 	break;
1077       case CTLE_NOTE:
1078 	ctl_note((int)e->v1, (int)e->v2, (int)e->v3, (int)e->v4);
1079 	break;
1080       case CTLE_MASTER_VOLUME:
1081 	ctl_master_volume((int)e->v1);
1082 	break;
1083 	case CTLE_METRONOME:
1084 		ctl_metronome((int) e->v1, (int) e->v2);
1085 		update_indicator();
1086 		break;
1087 	case CTLE_KEYSIG:
1088 		ctl_keysig((int8) e->v1, CTL_STATUS_UPDATE);
1089 		break;
1090 	case CTLE_KEY_OFFSET:
1091 		ctl_keysig(CTL_STATUS_UPDATE, (int) e->v1);
1092 		ctl_temper_keysig(CTL_STATUS_UPDATE, (int) e->v1);
1093 		break;
1094 	case CTLE_TEMPO:
1095 		ctl_tempo((int) e->v1, CTL_STATUS_UPDATE);
1096 		break;
1097 	case CTLE_TIME_RATIO:
1098 		ctl_tempo(CTL_STATUS_UPDATE, (int) e->v1);
1099 		break;
1100 	case CTLE_TEMPER_KEYSIG:
1101 		ctl_temper_keysig((int8) e->v1, CTL_STATUS_UPDATE);
1102 		break;
1103 	case CTLE_TEMPER_TYPE:
1104 		ctl_temper_type((int) e->v1, (int8) e->v2);
1105 		break;
1106 	case CTLE_MUTE:
1107 		ctl_mute((int) e->v1, (int) e->v2);
1108 		break;
1109       case CTLE_PROGRAM:
1110 	ctl_program((int)e->v1, (int)e->v2, (char *)e->v3, (unsigned int)e->v4);
1111 	break;
1112       case CTLE_DRUMPART:
1113 	ctl_drumpart((int)e->v1, (int)e->v2);
1114 	break;
1115       case CTLE_VOLUME:
1116 	ctl_volume((int)e->v1, (int)e->v2);
1117 	break;
1118       case CTLE_EXPRESSION:
1119 	ctl_expression((int)e->v1, (int)e->v2);
1120 	break;
1121       case CTLE_PANNING:
1122 	ctl_panning((int)e->v1, (int)e->v2);
1123 	break;
1124       case CTLE_SUSTAIN:
1125 	ctl_sustain((int)e->v1, (int)e->v2);
1126 	break;
1127       case CTLE_PITCH_BEND:
1128 	ctl_pitch_bend((int)e->v1, (int)e->v2);
1129 	break;
1130       case CTLE_MOD_WHEEL:
1131 	ctl_mod_wheel((int)e->v1, (int)e->v2);
1132 	break;
1133       case CTLE_CHORUS_EFFECT:
1134 	break;
1135       case CTLE_REVERB_EFFECT:
1136 	break;
1137       case CTLE_LYRIC:
1138 	ctl_lyric((int)e->v1);
1139 	break;
1140       case CTLE_GSLCD:
1141 	if(is_display_lcd)
1142 	    ctl_gslcd((int)e->v1);
1143 	break;
1144       case CTLE_REFRESH:
1145 	ctl_refresh();
1146 	break;
1147       case CTLE_RESET:
1148 	ctl_reset();
1149 	break;
1150       case CTLE_SPEANA:
1151 	break;
1152       case CTLE_PAUSE:
1153 	ctl_current_time((int)e->v2, 0);
1154 	N_ctl_refresh();
1155 	break;
1156     }
1157 }
1158 
ctl_total_time(int tt)1159 static void ctl_total_time(int tt)
1160 {
1161     static int last_tt = CTL_STATUS_UPDATE;
1162     int mins, secs;
1163 
1164     if(tt == CTL_STATUS_UPDATE)
1165 	tt = last_tt;
1166     else
1167 	last_tt = tt;
1168     secs=tt/play_mode->rate;
1169     mins=secs/60;
1170     secs-=mins*60;
1171 
1172     wmove(dftwin, TIME_LINE,6+6+1);
1173     wattron(dftwin, A_BOLD);
1174     wprintw(dftwin, "%3d:%02d  ", mins, secs);
1175     wattroff(dftwin, A_BOLD);
1176     ctl_current_time(CTL_STATUS_INIT, 0); /* Init. */
1177     ctl_current_time(0, 0);
1178     N_ctl_refresh();
1179 }
1180 
ctl_master_volume(int mv)1181 static void ctl_master_volume(int mv)
1182 {
1183     static int lastvol = CTL_STATUS_UPDATE;
1184 
1185     if(mv == CTL_STATUS_UPDATE)
1186 	mv = lastvol;
1187     else
1188 	lastvol = mv;
1189     wmove(dftwin, VOICE_LINE,COLS-5);
1190     wattron(dftwin, A_BOLD);
1191     wprintw(dftwin, "%03d %%", mv);
1192     wattroff(dftwin, A_BOLD);
1193     N_ctl_refresh();
1194 }
1195 
ctl_metronome(int meas,int beat)1196 static void ctl_metronome(int meas, int beat)
1197 {
1198 	static int lastmeas = CTL_STATUS_UPDATE;
1199 	static int lastbeat = CTL_STATUS_UPDATE;
1200 
1201 	if (meas == CTL_STATUS_UPDATE)
1202 		meas = lastmeas;
1203 	else
1204 		lastmeas = meas;
1205 	if (beat == CTL_STATUS_UPDATE)
1206 		beat = lastbeat;
1207 	else
1208 		lastbeat = beat;
1209 	wmove(dftwin, SEPARATE1_LINE, 6);
1210 	wattron(dftwin, A_BOLD);
1211 	wprintw(dftwin, "%03d.%02d ", meas, beat);
1212 	wattroff(dftwin, A_BOLD);
1213 	N_ctl_refresh();
1214 }
1215 
ctl_keysig(int8 k,int ko)1216 static void ctl_keysig(int8 k, int ko)
1217 {
1218 	static int8 lastkeysig = CTL_STATUS_UPDATE;
1219 	static int lastoffset = CTL_STATUS_UPDATE;
1220 	static const char *keysig_name[] = {
1221 		"Cb", "Gb", "Db", "Ab", "Eb", "Bb", "F ", "C ",
1222 		"G ", "D ", "A ", "E ", "B ", "F#", "C#", "G#",
1223 		"D#", "A#"
1224 	};
1225 	int i, j;
1226 
1227 	if (k == CTL_STATUS_UPDATE)
1228 		k = lastkeysig;
1229 	else
1230 		lastkeysig = k;
1231 	if (ko == CTL_STATUS_UPDATE)
1232 		ko = lastoffset;
1233 	else
1234 		lastoffset = ko;
1235 	i = k + ((k < 8) ? 7 : -6);
1236 	if (ko > 0)
1237 		for (j = 0; j < ko; j++)
1238 			i += (i > 10) ? -5 : 7;
1239 	else
1240 		for (j = 0; j < abs(ko); j++)
1241 			i += (i < 7) ? 5 : -7;
1242 	wmove(dftwin, SEPARATE1_LINE, 43);
1243 	wattron(dftwin, A_BOLD);
1244 	wprintw(dftwin, "%s %s (%+03d) ",
1245 			keysig_name[i], (k < 8) ? "Maj" : "Min", ko);
1246 	wattroff(dftwin, A_BOLD);
1247 	N_ctl_refresh();
1248 }
1249 
ctl_tempo(int t,int tr)1250 static void ctl_tempo(int t, int tr)
1251 {
1252 	static int lasttempo = CTL_STATUS_UPDATE;
1253 	static int lastratio = CTL_STATUS_UPDATE;
1254 
1255 	if (t == CTL_STATUS_UPDATE)
1256 		t = lasttempo;
1257 	else
1258 		lasttempo = t;
1259 	if (tr == CTL_STATUS_UPDATE)
1260 		tr = lastratio;
1261 	else
1262 		lastratio = tr;
1263 	t = (int) (500000 / (double) t * 120 * (double) tr / 100 + 0.5);
1264 	wmove(dftwin, SEPARATE1_LINE, 66);
1265 	wattron(dftwin, A_BOLD);
1266 	wprintw(dftwin, "%3d (%03d %%) ", t, tr);
1267 	wattroff(dftwin, A_BOLD);
1268 	N_ctl_refresh();
1269 }
1270 
ctl_file_name(char * name)1271 static void ctl_file_name(char *name)
1272 {
1273     if(name == NULL)
1274     {
1275 	if(current_MFnode != NULL)
1276 	    name = current_MFnode->file;
1277 	else
1278 	    return;
1279     }
1280     N_ctl_clrtoeol(FILE_LINE);
1281     waddstr(dftwin, "File: ");
1282     wattron(dftwin, A_BOLD);
1283     waddnstr(dftwin, name, COLS - 8);
1284     wattroff(dftwin, A_BOLD);
1285 
1286 #ifdef MIDI_TITLE
1287     /* Display MIDI title */
1288     N_ctl_clrtoeol(FILE_TITLE_LINE);
1289     waddstr(dftwin, "Title: ");
1290     if(current_MFnode != NULL && current_MFnode->title != NULL)
1291 	waddnstr(dftwin, current_MFnode->title, COLS - 9);
1292 #endif
1293     N_ctl_refresh();
1294 }
1295 
ctl_current_time(int secs,int v)1296 static void ctl_current_time(int secs, int v)
1297 {
1298     int mins;
1299     static int last_voices = CTL_STATUS_INIT, last_v = CTL_STATUS_INIT;
1300     static int last_secs = CTL_STATUS_INIT;
1301 
1302     if(secs == CTL_STATUS_INIT)
1303     {
1304 	last_voices = last_v = last_secs = CTL_STATUS_INIT;
1305 	return;
1306     }
1307 
1308     if(last_secs != secs)
1309     {
1310 	last_secs = secs;
1311 	mins = secs/60;
1312 	secs -= mins*60;
1313 	wmove(dftwin, TIME_LINE, 5);
1314 	wattron(dftwin, A_BOLD);
1315 	wprintw(dftwin, "%3d:%02d", mins, secs);
1316 	wattroff(dftwin, A_BOLD);
1317 	scr_modified_flag = 1;
1318     }
1319 
1320     if(last_v != v)
1321     {
1322 	last_v = v;
1323 	wmove(dftwin, VOICE_LINE, 48);
1324 	wattron(dftwin, A_BOLD);
1325 	wprintw(dftwin, "%3d", v);
1326 	wattroff(dftwin, A_BOLD);
1327 	scr_modified_flag = 1;
1328     }
1329 
1330     if(last_voices != voices)
1331     {
1332 	last_voices = voices;
1333 	wmove(dftwin, VOICE_LINE, 54);
1334 	wprintw(dftwin, "%3d", voices);
1335 	scr_modified_flag = 1;
1336     }
1337 }
1338 
ctl_note(int status,int ch,int note,int vel)1339 static void ctl_note(int status, int ch, int note, int vel)
1340 {
1341     int n, c;
1342     unsigned int onoff = 0, check, prev_check;
1343     Bitset *bitset;
1344 
1345     if(ch >= display_channels || ctl_ncurs_mode != NCURS_MODE_TRACE ||
1346        selected_channel == ch)
1347 	return;
1348 
1349     scr_modified_flag = 1;
1350 
1351     if(display_velocity_flag)
1352 	n = '0' + (10 * vel) / 128;
1353     else
1354 	n = note_name_char[note % 12];
1355     c = (COLS - 28) / 12 * 12;
1356     if(c <= 0)
1357 	c = 1;
1358     note = note % c;
1359     wmove(dftwin, NOTE_LINE + ch, note + 3);
1360     bitset = channel_program_flags + ch;
1361 
1362     switch(status)
1363     {
1364       case VOICE_DIE:
1365 	waddch(dftwin, ',');
1366 	onoff = 0;
1367 	break;
1368       case VOICE_FREE:
1369 	if(get_bitset1(gs_lcd_bits + ch, note))
1370 	    waddch(dftwin, GS_LCD_MARK_CHAR);
1371 	else
1372 	    waddch(dftwin, '.');
1373 	onoff = 0;
1374 	break;
1375       case VOICE_ON:
1376 	wattron(dftwin, A_REVERSE);
1377 	waddch(dftwin, n);
1378 	wattroff(dftwin, A_REVERSE);
1379 	indicator_chan_update(ch);
1380 	onoff = 1;
1381 	break;
1382       case VOICE_SUSTAINED:
1383 	wattron(dftwin, A_BOLD);
1384 	waddch(dftwin, n);
1385 	wattroff(dftwin, A_BOLD);
1386 	onoff = 0;
1387 	break;
1388       case VOICE_OFF:
1389 	waddch(dftwin, n);
1390 	onoff = 0;
1391 	break;
1392       case GS_LCD_MARK_ON:
1393 	set_bitset1(gs_lcd_bits + ch, note, 1);
1394 	if(!get_bitset1(bitset, note))
1395 	    waddch(dftwin, GS_LCD_MARK_CHAR);
1396 	return;
1397       case GS_LCD_MARK_OFF:
1398 	set_bitset1(gs_lcd_bits + ch, note, 0);
1399 	if(!get_bitset1(bitset, note))
1400 	    waddch(dftwin, '.');
1401 	return;
1402     }
1403 
1404     prev_check = has_bitset(bitset);
1405     set_bitset1(bitset, note, onoff);
1406     if(prev_check == onoff)
1407     {
1408 	/* Not change program mark */
1409 	return;
1410     }
1411 
1412     check = has_bitset(bitset);
1413     if(prev_check ^ check)
1414     {
1415 	wmove(dftwin, NOTE_LINE + ch, COLS - 21);
1416 	if(check)
1417 	{
1418 	    wattron(dftwin, A_BOLD);
1419 	    waddch(dftwin, '*');
1420 	    wattroff(dftwin, A_BOLD);
1421 	}
1422 	else
1423 	{
1424 	    waddch(dftwin, ' ');
1425 	}
1426     }
1427 }
1428 
ctl_temper_keysig(int8 tk,int ko)1429 static void ctl_temper_keysig(int8 tk, int ko)
1430 {
1431 	static int8 lastkeysig = CTL_STATUS_UPDATE;
1432 	static int lastoffset = CTL_STATUS_UPDATE;
1433 	static const char *keysig_name[] = {
1434 		"Cb", "Gb", "Db", "Ab", "Eb", "Bb", " F", " C",
1435 		" G", " D", " A", " E", " B", "F#", "C#", "G#",
1436 		"D#", "A#"
1437 	};
1438 	int adj, i, j;
1439 
1440 	if (tk == CTL_STATUS_UPDATE)
1441 		tk = lastkeysig;
1442 	else
1443 		lastkeysig = tk;
1444 	if (ko == CTL_STATUS_UPDATE)
1445 		ko = lastoffset;
1446 	else
1447 		lastoffset = ko;
1448 	if (ctl_ncurs_mode != NCURS_MODE_TRACE)
1449 		return;
1450 	adj = (tk + 8) & 0x20, tk = (tk + 8) % 32 - 8;
1451 	i = tk + ((tk < 8) ? 7 : -6);
1452 	if (ko > 0)
1453 		for (j = 0; j < ko; j++)
1454 			i += (i > 10) ? -5 : 7;
1455 	else
1456 		for (j = 0; j < abs(ko); j++)
1457 			i += (i < 7) ? 5 : -7;
1458 	wmove(dftwin, TITLE_LINE, COLS - 24);
1459 	if (adj)
1460 		wattron(dftwin, A_BOLD);
1461 	wprintw(dftwin, "%s%c", keysig_name[i], (tk < 8) ? ' ' : 'm');
1462 	if (adj)
1463 		wattroff(dftwin, A_BOLD);
1464 	N_ctl_refresh();
1465 }
1466 
ctl_temper_type(int ch,int8 tt)1467 static void ctl_temper_type(int ch, int8 tt)
1468 {
1469 	if (ch >= display_channels)
1470 		return;
1471 	if (tt != CTL_STATUS_UPDATE) {
1472 		if (ChannelStatus[ch].tt == tt)
1473 			return;
1474 		ChannelStatus[ch].tt = tt;
1475 	} else
1476 		tt = ChannelStatus[ch].tt;
1477 	if (ctl_ncurs_mode != NCURS_MODE_TRACE || ch == selected_channel)
1478 		return;
1479 	wmove(dftwin, NOTE_LINE + ch, COLS - 23);
1480 	switch (tt) {
1481 	case 0:
1482 		waddch(dftwin, ' ');
1483 		break;
1484 	case 1:
1485 		waddch(dftwin, 'P');
1486 		break;
1487 	case 2:
1488 		waddch(dftwin, 'm');
1489 		break;
1490 	case 3:
1491 		wattron(dftwin, A_BOLD);
1492 		waddch(dftwin, 'p');
1493 		wattroff(dftwin, A_BOLD);
1494 		break;
1495 	case 64:
1496 		waddch(dftwin, '0');
1497 		break;
1498 	case 65:
1499 		waddch(dftwin, '1');
1500 		break;
1501 	case 66:
1502 		waddch(dftwin, '2');
1503 		break;
1504 	case 67:
1505 		waddch(dftwin, '3');
1506 		break;
1507 	}
1508 	scr_modified_flag = 1;
1509 }
1510 
ctl_mute(int ch,int mute)1511 static void ctl_mute(int ch, int mute)
1512 {
1513 	if (ch >= display_channels)
1514 		return;
1515 	if (mute != CTL_STATUS_UPDATE) {
1516 		if (ChannelStatus[ch].mute == mute)
1517 			return;
1518 		ChannelStatus[ch].mute = mute;
1519 	} else
1520 		mute = ChannelStatus[ch].mute;
1521 	if (ctl_ncurs_mode != NCURS_MODE_TRACE)
1522 		return;
1523 	wmove(dftwin, NOTE_LINE + ch, 0);
1524 	if (ch != selected_channel) {
1525 		wattron(dftwin, (mute) ? A_REVERSE : 0);
1526 		wprintw(dftwin, "%02d", ch + 1);
1527 		wattroff(dftwin, (mute) ? A_REVERSE : 0);
1528 	} else {
1529 		wattron(dftwin, A_BOLD | ((mute) ? A_REVERSE : 0));
1530 		wprintw(dftwin, "%02d", ch + 1);
1531 		wattroff(dftwin, A_BOLD | ((mute) ? A_REVERSE : 0));
1532 	}
1533 	scr_modified_flag = 1;
1534 }
1535 
ctl_drumpart(int ch,int is_drum)1536 static void ctl_drumpart(int ch, int is_drum)
1537 {
1538     if(ch >= display_channels)
1539 	return;
1540     ChannelStatus[ch].is_drum = is_drum;
1541 }
1542 
ctl_program(int ch,int prog,char * comm,unsigned int banks)1543 static void ctl_program(int ch, int prog, char *comm, unsigned int banks)
1544 {
1545     int val;
1546     int bank;
1547 
1548     if(ch >= display_channels)
1549 	return;
1550 
1551     if(prog != CTL_STATUS_UPDATE)
1552     {
1553 	bank = banks & 0xff;
1554 	ChannelStatus[ch].prog = prog;
1555 	ChannelStatus[ch].bank = bank;
1556 	ChannelStatus[ch].bank_lsb = (banks >> 8) & 0xff;
1557 	ChannelStatus[ch].bank_msb = (banks >> 16) & 0xff;
1558 	ChannelStatus[ch].comm = (comm ? comm : "");
1559     } else {
1560 	prog = ChannelStatus[ch].prog;
1561 	bank = ChannelStatus[ch].bank;
1562     }
1563     ChannelStatus[ch].last_note_on = 0.0;	/* reset */
1564 
1565     if(ctl_ncurs_mode != NCURS_MODE_TRACE)
1566 	return;
1567 
1568     if(selected_channel == ch)
1569     {
1570 	init_trace_window_chan(ch);
1571 	return;
1572     }
1573 
1574     if(ChannelStatus[ch].is_drum)
1575 	val = bank;
1576     else
1577 	val = prog;
1578     if(!IS_CURRENT_MOD_FILE)
1579 	val += progbase;
1580 
1581     wmove(dftwin, NOTE_LINE + ch, COLS - 21);
1582     if(ChannelStatus[ch].is_drum)
1583     {
1584 	wattron(dftwin, A_BOLD);
1585 	wprintw(dftwin, " %03d", val);
1586 	wattroff(dftwin, A_BOLD);
1587     }
1588     else
1589 	wprintw(dftwin, " %03d", val);
1590     scr_modified_flag = 1;
1591 }
1592 
ctl_volume(int ch,int vol)1593 static void ctl_volume(int ch, int vol)
1594 {
1595     if(ch >= display_channels)
1596 	return;
1597 
1598     if(vol != CTL_STATUS_UPDATE)
1599     {
1600 	if(ChannelStatus[ch].vol == vol)
1601 	    return;
1602 	ChannelStatus[ch].vol = vol;
1603     }
1604     else
1605 	vol = ChannelStatus[ch].vol;
1606 
1607     if(ctl_ncurs_mode != NCURS_MODE_TRACE || selected_channel == ch)
1608 	return;
1609 
1610     wmove(dftwin, NOTE_LINE + ch, COLS - 16);
1611     wprintw(dftwin, "%3d", vol);
1612     scr_modified_flag = 1;
1613 }
1614 
ctl_expression(int ch,int exp)1615 static void ctl_expression(int ch, int exp)
1616 {
1617     if(ch >= display_channels)
1618 	return;
1619 
1620     if(exp != CTL_STATUS_UPDATE)
1621     {
1622 	if(ChannelStatus[ch].exp == exp)
1623 	    return;
1624 	ChannelStatus[ch].exp = exp;
1625     }
1626     else
1627 	exp = ChannelStatus[ch].exp;
1628 
1629     if(ctl_ncurs_mode != NCURS_MODE_TRACE || selected_channel == ch)
1630 	return;
1631 
1632     wmove(dftwin, NOTE_LINE + ch, COLS - 12);
1633     wprintw(dftwin, "%3d", exp);
1634     scr_modified_flag = 1;
1635 }
1636 
ctl_panning(int ch,int pan)1637 static void ctl_panning(int ch, int pan)
1638 {
1639     if(ch >= display_channels)
1640 	return;
1641 
1642     if(pan != CTL_STATUS_UPDATE)
1643     {
1644 	if(pan == NO_PANNING)
1645 	    ;
1646 	else if(pan < 5)
1647 	    pan = 0;
1648 	else if(pan > 123)
1649 	    pan = 127;
1650 	else if(pan > 60 && pan < 68)
1651 	    pan = 64;
1652 	if(ChannelStatus[ch].pan == pan)
1653 	    return;
1654 	ChannelStatus[ch].pan = pan;
1655     }
1656     else
1657 	pan = ChannelStatus[ch].pan;
1658 
1659     if(ctl_ncurs_mode != NCURS_MODE_TRACE || selected_channel == ch)
1660 	return;
1661 
1662     wmove(dftwin, NOTE_LINE + ch, COLS - 8);
1663     switch(pan)
1664     {
1665       case NO_PANNING:
1666 	waddstr(dftwin, "   ");
1667 	break;
1668       case 0:
1669 	waddstr(dftwin, " L ");
1670 	break;
1671       case 64:
1672 	waddstr(dftwin, " C ");
1673 	break;
1674       case 127:
1675 	waddstr(dftwin, " R ");
1676 	break;
1677       default:
1678 	pan -= 64;
1679 	if(pan < 0)
1680 	{
1681 	    waddch(dftwin, '-');
1682 	    pan = -pan;
1683 	}
1684 	else
1685 	    waddch(dftwin, '+');
1686 	wprintw(dftwin, "%02d", pan);
1687 	break;
1688     }
1689     scr_modified_flag = 1;
1690 }
1691 
ctl_sustain(int ch,int sus)1692 static void ctl_sustain(int ch, int sus)
1693 {
1694     if(ch >= display_channels)
1695 	return;
1696 
1697     if(sus != CTL_STATUS_UPDATE)
1698     {
1699 	if(ChannelStatus[ch].sus == sus)
1700 	    return;
1701 	ChannelStatus[ch].sus = sus;
1702     }
1703     else
1704 	sus = ChannelStatus[ch].sus;
1705 
1706     if(ctl_ncurs_mode != NCURS_MODE_TRACE || selected_channel == ch)
1707 	return;
1708 
1709     wmove(dftwin, NOTE_LINE + ch, COLS - 4);
1710     if(sus)
1711 	waddch(dftwin, 'S');
1712     else
1713 	waddch(dftwin, ' ');
1714     scr_modified_flag = 1;
1715 }
1716 
update_bend_mark(int ch)1717 static void update_bend_mark(int ch)
1718 {
1719     wmove(dftwin, NOTE_LINE + ch, COLS - 2);
1720     waddch(dftwin, ChannelStatus[ch].bend_mark);
1721     scr_modified_flag = 1;
1722 }
1723 
ctl_pitch_bend(int ch,int pitch)1724 static void ctl_pitch_bend(int ch, int pitch)
1725 {
1726     int mark;
1727 
1728     if(ch >= display_channels)
1729 	return;
1730 
1731     ChannelStatus[ch].pitch = pitch;
1732 
1733     if(ctl_ncurs_mode != NCURS_MODE_TRACE || selected_channel == ch)
1734 	return;
1735 
1736     if(ChannelStatus[ch].wheel)
1737 	mark = '=';
1738     else if(pitch > 0x2000)
1739 	mark = '>';
1740     else if(pitch < 0x2000)
1741 	mark = '<';
1742     else
1743 	mark = ' ';
1744 
1745     if(ChannelStatus[ch].bend_mark == mark)
1746 	return;
1747     ChannelStatus[ch].bend_mark = mark;
1748     update_bend_mark(ch);
1749 }
1750 
ctl_mod_wheel(int ch,int wheel)1751 static void ctl_mod_wheel(int ch, int wheel)
1752 {
1753     int mark;
1754 
1755     if(ch >= display_channels)
1756 	return;
1757 
1758     ChannelStatus[ch].wheel = wheel;
1759 
1760     if(ctl_ncurs_mode != NCURS_MODE_TRACE || selected_channel == ch)
1761 	return;
1762 
1763     if(wheel)
1764 	mark = '=';
1765     else
1766     {
1767 	/* restore pitch bend mark */
1768 	if(ChannelStatus[ch].pitch > 0x2000)
1769 	    mark = '>';
1770 	else if(ChannelStatus[ch].pitch < 0x2000)
1771 	    mark = '<';
1772 	else
1773 	    mark = ' ';
1774     }
1775 
1776     if(ChannelStatus[ch].bend_mark == mark)
1777 	return;
1778     ChannelStatus[ch].bend_mark = mark;
1779     update_bend_mark(ch);
1780 }
1781 
ctl_lyric(int lyricid)1782 static void ctl_lyric(int lyricid)
1783 {
1784     char *lyric;
1785 
1786     lyric = event2string(lyricid);
1787     if(lyric != NULL)
1788     {
1789         /* EAW -- if not a true KAR lyric, ignore \r, treat \n as \r */
1790         if (*lyric != ME_KARAOKE_LYRIC) {
1791             while (strchr(lyric, '\r')) {
1792             	*(strchr(lyric, '\r')) = ' ';
1793             }
1794 	    if (ctl.trace_playing) {
1795 		while (strchr(lyric, '\n')) {
1796 		    *(strchr(lyric, '\n')) = '\r';
1797 		}
1798             }
1799         }
1800 
1801 	if(ctl.trace_playing)
1802 	{
1803 	    if(*lyric == ME_KARAOKE_LYRIC)
1804 	    {
1805 		if(lyric[1] == '/')
1806 		{
1807 		    display_lyric(" / ", LYRIC_WORD_NOSEP);
1808 		    display_lyric(lyric + 2, LYRIC_WORD_NOSEP);
1809 		}
1810 		else if(lyric[1] == '\\')
1811 		{
1812 		    display_lyric("\r", LYRIC_WORD_NOSEP);
1813 		    display_lyric(lyric + 2, LYRIC_WORD_NOSEP);
1814 		}
1815 		else if(lyric[1] == '@')
1816 		    display_lyric(lyric + 3, LYRIC_WORD_SEP);
1817 		else
1818 		    display_lyric(lyric + 1, LYRIC_WORD_NOSEP);
1819 	    }
1820 	    else
1821 	    {
1822 		if(*lyric == ME_CHORUS_TEXT || *lyric == ME_INSERT_TEXT)
1823 		    display_lyric("\r", LYRIC_WORD_SEP);
1824 		display_lyric(lyric + 1, LYRIC_WORD_SEP);
1825 	    }
1826 	}
1827 	else
1828 	    cmsg(CMSG_INFO, VERB_NORMAL, "%s", lyric + 1);
1829     }
1830 }
1831 
ctl_lcd_mark(int status,int x,int y)1832 static void ctl_lcd_mark(int status, int x, int y)
1833 {
1834     int w;
1835 
1836     if(!ctl.trace_playing)
1837     {
1838 	waddch(msgwin, status == GS_LCD_MARK_ON ? GS_LCD_MARK_CHAR : ' ');
1839 	return;
1840     }
1841 
1842     w = (COLS - 28) / 12 * 12;
1843     if(status == GS_LCD_MARK_CLEAR)
1844       {
1845 	int x, y;
1846 	for(y = 0; y < 16; y++)
1847 	  for(x = 0; x < 40; x++)
1848 	    ctl_note(GS_LCD_MARK_OFF, y, x + (w - 40) / 2, 0);
1849 	return;
1850       }
1851 
1852     if(w < GS_LCD_WIDTH)
1853     {
1854 	if(x < w)
1855 	    ctl_note(status, y, x, 0);
1856     }
1857     else
1858     {
1859 	ctl_note(status, y, x + (w - GS_LCD_WIDTH) / 2, 0);
1860     }
1861 }
1862 
ctl_gslcd(int id)1863 static void ctl_gslcd(int id)
1864 {
1865     char *lcd;
1866     int i, j, k, data, mask;
1867     char tmp[3];
1868 
1869     if((lcd = event2string(id)) == NULL)
1870 	return;
1871     if(lcd[0] != ME_GSLCD)
1872 	return;
1873     gslcd_last_display_time = get_current_calender_time();
1874     gslcd_displayed_flag = 1;
1875     lcd++;
1876     for(i = 0; i < 16; i++)
1877     {
1878 	for(j = 0; j < 4; j++)
1879 	{
1880 	    tmp[0]= lcd[2 * (j * 16 + i)];
1881 	    tmp[1]= lcd[2 * (j * 16 + i) + 1];
1882 	    if(sscanf(tmp, "%02X", &data) != 1)
1883 	    {
1884 		/* Invalid format */
1885 		return;
1886 	    }
1887 	    mask = 0x10;
1888 	    for(k = 0; k < 10; k += 2)
1889 	    {
1890 		if(data & mask)
1891 		{
1892  		    ctl_lcd_mark(GS_LCD_MARK_ON, j * 10 + k,     i);
1893 		    ctl_lcd_mark(GS_LCD_MARK_ON, j * 10 + k + 1, i);
1894 		}
1895 		else
1896 	        {
1897  		    ctl_lcd_mark(GS_LCD_MARK_OFF, j * 10 + k,     i);
1898 		    ctl_lcd_mark(GS_LCD_MARK_OFF, j * 10 + k + 1, i);
1899 		}
1900 		mask >>= 1;
1901 	    }
1902 	}
1903 	if(!ctl.trace_playing)
1904 	{
1905 	    waddch(msgwin, '\n');
1906 	    wrefresh(msgwin);
1907 	}
1908     }
1909 }
1910 
ctl_reset(void)1911 static void ctl_reset(void)
1912 {
1913     if(ctl.trace_playing)
1914 	reset_indicator();
1915     N_ctl_refresh();
1916     ctl_ncurs_mode_init();
1917 }
1918 
1919 /***********************************************************************/
1920 
1921 /* #define CURSED_REDIR_HACK */
1922 
1923 /*ARGSUSED*/
ctl_open(int using_stdin,int using_stdout)1924 static int ctl_open(int using_stdin, int using_stdout)
1925 {
1926     static int open_init_flag = 0;
1927 #ifdef CURSED_REDIR_HACK
1928     FILE *infp = stdin, *outfp = stdout;
1929     SCREEN *dftscr;
1930 #endif
1931 
1932 #ifdef USE_PDCURSES
1933     PDC_set_ctrl_break(1);
1934 #endif /* USE_PDCURSES */
1935 
1936     if(!open_init_flag)
1937     {
1938 #ifdef CURSED_REDIR_HACK
1939 	/* This doesn't work right */
1940 	if(using_stdin && using_stdout)
1941 	{
1942 	    infp = outfp = stderr;
1943 	    fflush(stderr);
1944 	    setvbuf(stderr, 0, _IOFBF, BUFSIZ);
1945 	}
1946 	else if(using_stdout)
1947 	{
1948 	    outfp = stderr;
1949 	    fflush(stderr);
1950 	    setvbuf(stderr, 0, _IOFBF, BUFSIZ);
1951 	}
1952 	else if(using_stdin)
1953 	{
1954 	    infp = stdout;
1955 	    fflush(stdout);
1956 	    setvbuf(stdout, 0, _IOFBF, BUFSIZ);
1957 	}
1958 	dftscr = newterm(0, outfp, infp);
1959 	if (!dftscr)
1960 	    return -1;
1961 #else
1962 	initscr();
1963 #endif /* CURSED_REDIR_HACK */
1964 
1965 	if(LINES < NCURS_MIN_LINES)
1966 	{
1967 	    endwin();
1968 	    cmsg(CMSG_FATAL, VERB_NORMAL, "Error: Screen is too small.");
1969 	    return 1;
1970 	}
1971 
1972 	cbreak();
1973 	noecho();
1974 	nonl();
1975 	nodelay(stdscr, 1);
1976 	scrollok(stdscr, 0);
1977 #ifndef USE_PDCURSES
1978 	idlok(stdscr, 1);
1979 #endif /* USE_PDCURSES */
1980 	keypad(stdscr, TRUE);
1981 	ctl.opened = 1;
1982 	init_chan_status();
1983     }
1984 
1985     open_init_flag = 1;
1986     dftwin=stdscr;
1987     if(ctl.trace_playing)
1988 	ctl_ncurs_mode = NCURS_MODE_TRACE;
1989     else
1990 	ctl_ncurs_mode = NCURS_MODE_MAIN;
1991 
1992     ctl_ncurs_back = ctl_ncurs_mode;
1993     N_ctl_scrinit();
1994 
1995     if(ctl.trace_playing)
1996     {
1997 	if(msgwin != NULL)
1998 	{
1999 	    delwin(msgwin);
2000 	    msgwin = NULL;
2001 	}
2002     }
2003     else
2004     {
2005 	set_trace_loop_hook(NULL);
2006 	msgwin = newwin(LINES - 6 - 1, COLS, 6, 0);
2007 	N_ctl_werase(msgwin);
2008 	scrollok(msgwin, 1);
2009 	wrefresh(msgwin);
2010     }
2011 
2012     if(command_buffer == NULL)
2013 	command_buffer = mini_buff_new(COMMAND_BUFFER_SIZE);
2014 
2015     N_ctl_refresh();
2016 
2017     return 0;
2018 }
2019 
ctl_close(void)2020 static void ctl_close(void)
2021 {
2022   if (ctl.opened)
2023     {
2024       endwin();
2025       ctl.opened=0;
2026     }
2027 }
2028 
2029 #if SCREEN_BUGFIX
re_init_screen(void)2030 static void re_init_screen(void)
2031 {
2032     static int screen_bugfix = 0;
2033     if(screen_bugfix)
2034 	return;
2035     screen_bugfix = 1;
2036     touchwin(dftwin);
2037     N_ctl_refresh();
2038     if(msgwin)
2039     {
2040 	touchwin(msgwin);
2041 	wrefresh(msgwin);
2042     }
2043 }
2044 #endif
2045 
move_select_channel(int diff)2046 static void move_select_channel(int diff)
2047 {
2048     if(selected_channel != -1)
2049     {
2050 	int prev_chan;
2051 	prev_chan = selected_channel;
2052 	selected_channel += diff;
2053 	init_trace_window_chan(prev_chan);
2054     }
2055     else
2056 	selected_channel += diff;
2057     while(selected_channel < 0)
2058 	selected_channel += display_channels + 1;
2059     while(selected_channel >= display_channels)
2060 	selected_channel -= display_channels + 1;
2061 
2062     if(selected_channel != -1)
2063     {
2064 	init_trace_window_chan(selected_channel);
2065 	current_indicator_chan = selected_channel;
2066     }
2067     N_ctl_refresh();
2068 }
2069 
ctl_cmd_dir_close(void)2070 static void ctl_cmd_dir_close(void)
2071 {
2072     if(ctl_ncurs_mode == NCURS_MODE_DIR)
2073     {
2074 	ctl_ncurs_mode = ctl_ncurs_back;
2075 	ctl_ncurs_mode_init();
2076     }
2077 }
2078 
ctl_cmd_J_move(int diff)2079 static void ctl_cmd_J_move(int diff)
2080 {
2081     int i;
2082     char num[16];
2083 
2084     i = atoi(mini_buff_gets(command_buffer)) + diff;
2085     if(i < 0)
2086 	i = 0;
2087     else if(i > file_list.number)
2088 	i = file_list.number;
2089     sprintf(num, "%d", i);
2090     mini_buff_sets(command_buffer, num);
2091 }
2092 
ctl_cmd_J_enter(void)2093 static int ctl_cmd_J_enter(void)
2094 {
2095     int i, rc;
2096     char *text;
2097 
2098     text = mini_buff_gets(command_buffer);
2099 
2100     if(*text == '\0')
2101 	rc = RC_NONE;
2102     else
2103     {
2104 	i = atoi(text);
2105 	if(i < 0 || i > file_list.number)
2106 	{
2107 	    beep();
2108 	    rc = RC_NONE;
2109 	}
2110 	else
2111 	{
2112 	    rc = RC_LOAD_FILE;
2113 	    ctl_listmode = 1 + i / LIST_TITLE_LINES;
2114 	    ctl_list_select[ctl_listmode] = i;
2115 	}
2116     }
2117 
2118     mini_buff_clear(command_buffer);
2119     ctl_cmdmode = 0;
2120     return rc;
2121 }
2122 
ctl_cmd_L_dir(int move)2123 static void ctl_cmd_L_dir(int move)
2124 {
2125     MFnode *mfp;
2126     int i;
2127 
2128     if(ctl_ncurs_mode != NCURS_MODE_DIR)
2129     {
2130 	ctl_ncurs_back = ctl_ncurs_mode;
2131 	ctl_ncurs_mode = NCURS_MODE_DIR;
2132 	move = 0;
2133     }
2134 
2135     N_ctl_werase(listwin);
2136 
2137     if(command_buffer->files == NULL)
2138     {
2139 	wmove(listwin, 0, 0);
2140 	waddstr(listwin, "No match");
2141 	wrefresh(listwin);
2142 	N_ctl_refresh();
2143 	ctl_mode_L_dispstart = 0;
2144 	return;
2145     }
2146 
2147     ctl_mode_L_dispstart += move * (LIST_TITLE_LINES-1);
2148     mfp = MFnode_nth_cdr(command_buffer->files, ctl_mode_L_dispstart);
2149     if(mfp == NULL)
2150     {
2151 	mfp = command_buffer->files;
2152 	ctl_mode_L_dispstart = 0;
2153     }
2154 
2155     N_ctl_werase(listwin);
2156     waddstr(listwin, "Possible completions are:");
2157     for(i = 0; i < LIST_TITLE_LINES - 1 && mfp; i++, mfp = mfp->next)
2158     {
2159 	wmove(listwin, i + 1, 0);
2160 	waddnstr(listwin, mfp->file, COLS - 6);
2161     }
2162     wrefresh(listwin);
2163     N_ctl_refresh();
2164 }
2165 
ctl_cmd_L_enter(void)2166 static int ctl_cmd_L_enter(void)
2167 {
2168     char *text;
2169     MFnode *mfp;
2170     int i, rc = RC_NONE;
2171     struct double_list_string *hist;
2172     int nfiles;
2173     char *files[1], **new_files;
2174     MFnode *tail, *head;
2175 
2176     ctl_cmd_dir_close();
2177     text = mini_buff_gets(command_buffer);
2178     if(*text == '\0')
2179 	goto end_enter;
2180 
2181     strncpy(ctl_mode_L_lastenter, text, COMMAND_BUFFER_SIZE - 1);
2182     ctl_mode_L_lastenter[COMMAND_BUFFER_SIZE - 1] = '\0';
2183 
2184     hist = (struct double_list_string *)
2185 	safe_malloc(sizeof(struct double_list_string));
2186     hist->string = safe_strdup(ctl_mode_L_lastenter);
2187     hist->prev = NULL;
2188     hist->next = ctl_mode_L_histh;
2189     if(ctl_mode_L_histh != NULL)
2190 	ctl_mode_L_histh->prev = hist;
2191     ctl_mode_L_histh = hist;
2192 
2193     i = strlen(ctl_mode_L_lastenter);
2194     while(i > 0 && !IS_PATH_SEP(ctl_mode_L_lastenter[i - 1]))
2195 	i--;
2196     ctl_mode_L_lastenter[i] = '\0';
2197 
2198 
2199     /* Add new files */
2200     files[0] = text;
2201     nfiles  = 1;
2202     new_files = expand_file_archives(files, &nfiles);
2203     if(new_files == NULL)
2204       {
2205 	rc = RC_NONE;
2206 	beep();
2207       }
2208     else
2209       {
2210 	head = tail = NULL;
2211 	for(i = 0; i < nfiles; i++)
2212 	{
2213 	    if((mfp = make_new_MFnode_entry(new_files[i])) != NULL)
2214 	    {
2215 		if(head == NULL)
2216 		    head = tail = mfp;
2217 		else
2218 		    tail = tail->next = mfp;
2219 	    }
2220 	}
2221 	mfp = head;
2222 	free(new_files[0]);
2223 	free(new_files);
2224 	if(mfp == NULL)
2225 	{
2226 	    rc = RC_NONE;
2227 	    beep();
2228 	    goto end_enter;
2229 	}
2230 	insert_MFnode_entrys(mfp, nc_playfile);
2231 	ctl_list_mode(NC_LIST_NEW);
2232 	rc = RC_NEXT;
2233     }
2234 
2235   end_enter:
2236     mini_buff_clear(command_buffer);
2237     ctl_cmdmode = 0;
2238     return rc;
2239 }
2240 
ctl_cmd_E_enter(int32 * val)2241 static int ctl_cmd_E_enter(int32 *val)
2242 {
2243     int rc = RC_NONE;
2244     char *text;
2245     int lastb;
2246 
2247     *val = 1;
2248     text = mini_buff_gets(command_buffer);
2249     if(*text)
2250     {
2251 	lastb = special_tonebank;
2252 	if(set_extension_modes(text))
2253 	    beep();
2254 	else
2255 	{
2256 	    if(lastb == special_tonebank)
2257 		rc = RC_SYNC_RESTART;
2258 	    else
2259 		rc = RC_RELOAD;
2260 	}
2261     }
2262     mini_buff_clear(command_buffer);
2263     ctl_cmdmode = 0;
2264     return rc;
2265 }
2266 
ctl_cmd_S_enter(void)2267 static int ctl_cmd_S_enter(void)
2268 {
2269     char *file;
2270 
2271     ctl_cmd_dir_close();
2272     file = mini_buff_gets(command_buffer);
2273     if(*file)
2274     {
2275 	if(midi_file_save_as(NULL, file) == -1)
2276 	    beep();
2277     }
2278 
2279     mini_buff_clear(command_buffer);
2280     ctl_cmdmode = 0;
2281     return RC_NONE;
2282 }
2283 
ctl_cmd_R_enter(int32 * valp)2284 static int ctl_cmd_R_enter(int32 *valp)
2285 {
2286     char *rateStr;
2287     int rc = RC_NONE;
2288 
2289     rateStr = mini_buff_gets(command_buffer);
2290     if(*rateStr)
2291     {
2292 	*valp = atoi(rateStr);
2293 	rc = RC_CHANGE_RATE;
2294     }
2295     mini_buff_clear(command_buffer);
2296     ctl_cmdmode = 0;
2297     return rc;
2298 }
2299 
ctl_cmd_D_enter(int32 * val)2300 static int ctl_cmd_D_enter(int32 *val)
2301 {
2302     int rc = RC_NONE, ch;
2303     char *text;
2304 
2305     text = mini_buff_gets(command_buffer);
2306     if(*text)
2307     {
2308 	if(*text == '+')
2309 	{
2310 	    ch = atoi(text + 1) - 1;
2311 	    if(ch >= 0 && ChannelStatus[ch].is_drum)
2312 	    {
2313 		*val = ch;
2314 		rc = RC_TOGGLE_DRUMCHAN;
2315 	    }
2316 	}
2317 	else if(*text == '-')
2318 	{
2319 	    ch = atoi(text + 1) - 1;
2320 	    if(ch >= 0 && ChannelStatus[ch].is_drum)
2321 	    {
2322 		*val = ch;
2323 		rc = RC_TOGGLE_DRUMCHAN;
2324 	    }
2325 	}
2326 	else
2327 	{
2328 	    *val = atoi(text) - 1;
2329 	    if(*val >= 0)
2330 		rc = RC_TOGGLE_DRUMCHAN;
2331 	}
2332     }
2333     mini_buff_clear(command_buffer);
2334     ctl_cmdmode = 0;
2335     return rc;
2336 }
2337 
2338 /* Previous history */
ctl_cmd_L_phist(void)2339 static void ctl_cmd_L_phist(void)
2340 {
2341     if(ctl_mode_L_histh == NULL ||
2342        (ctl_mode_L_histc != NULL && ctl_mode_L_histc->next == NULL))
2343     {
2344 	beep();
2345 	return;
2346     }
2347 
2348     if(ctl_mode_L_histc != NULL)
2349 	ctl_mode_L_histc = ctl_mode_L_histc->next;
2350     else
2351     {
2352 	strcpy(ctl_mode_L_lastenter, mini_buff_gets(command_buffer));
2353 	ctl_mode_L_lastenter[COMMAND_BUFFER_SIZE - 1] = '\0';
2354 	ctl_mode_L_histc = ctl_mode_L_histh;
2355     }
2356     mini_buff_sets(command_buffer, ctl_mode_L_histc->string);
2357 }
2358 
2359 /* Next history */
ctl_cmd_L_nhist(void)2360 static void ctl_cmd_L_nhist(void)
2361 {
2362     if(ctl_mode_L_histc == NULL)
2363     {
2364 	beep();
2365 	return;
2366     }
2367     ctl_mode_L_histc = ctl_mode_L_histc->prev;
2368     if(ctl_mode_L_histc != NULL)
2369 	mini_buff_sets(command_buffer, ctl_mode_L_histc->string);
2370     else
2371 	mini_buff_sets(command_buffer, ctl_mode_L_lastenter);
2372 }
2373 
ctl_cmd_forward_search(void)2374 static int ctl_cmd_forward_search(void)
2375 {
2376     MFnode *mfp;
2377     int i, n, found;
2378     char *ptn, *name;
2379 
2380     if(mini_buff_len(command_buffer) == 0)
2381     {
2382 	if(ctl_mode_SEARCH_lastenter[0] == 0)
2383 	{
2384 	    mini_buff_clear(command_buffer);
2385 	    ctl_cmdmode = 0;
2386 	    return 1;
2387 	}
2388 	mini_buff_sets(command_buffer, ctl_mode_SEARCH_lastenter);
2389     }
2390     else
2391 	strcpy(ctl_mode_SEARCH_lastenter, mini_buff_gets(command_buffer));
2392 
2393     /* Put '*' into buffer with first and last */
2394     while(mini_buff_backward(command_buffer))
2395 	;
2396     mini_buff_insertc(command_buffer, '*');
2397     while(mini_buff_forward(command_buffer))
2398 	;
2399     mini_buff_insertc(command_buffer, '*');
2400 
2401     ptn = mini_buff_gets(command_buffer);
2402     n = ctl_list_select[ctl_listmode] + 1;
2403     mfp = MFnode_nth_cdr(file_list.MFnode_head, n);
2404     found = 0;
2405     for(i = 0; i < file_list.number; i++, n++)
2406     {
2407 	if(mfp == NULL)
2408 	{
2409 	    mfp = file_list.MFnode_head;
2410 	    n = 0;
2411 	}
2412 	if((name = pathsep_strrchr(mfp->file)) == NULL)
2413 	    name = mfp->file;
2414 	else
2415 	    name++;
2416 	if(arc_wildmat(name, ptn))
2417 	{
2418 	    found = 1;
2419 	    break;
2420 	}
2421 	mfp = mfp->next;
2422     }
2423 
2424     mini_buff_clear(command_buffer);
2425     ctl_cmdmode = 0;
2426     if(found)
2427     {
2428 	ctl_listmode = n / LIST_TITLE_LINES + 1;
2429 	ctl_list_select[ctl_listmode] = n;
2430 	ctl_list_mode(NC_LIST_NOW);
2431     }
2432     else
2433     {
2434 	wmove(dftwin, LINES - 1, 0);
2435 	wattron(dftwin, A_REVERSE);
2436 	waddstr(dftwin, "Pattern not found");
2437 	wattroff(dftwin, A_REVERSE);
2438     }
2439 
2440     return found;
2441 }
2442 
ctl_read(int32 * valp)2443 static int ctl_read(int32 *valp)
2444 {
2445   int c, i;
2446   static int u_prefix = 1, u_flag = 1;
2447 
2448 	if (cuepoint_pending) {
2449 		*valp = cuepoint;
2450 		cuepoint_pending = 0;
2451 		return RC_FORWARD;
2452 	}
2453 
2454   if(ctl_cmdmode)
2455       mini_buff_refresh(command_buffer);
2456 
2457   while ((c=getch())!=ERR)
2458     {
2459 #if SCREEN_BUGFIX
2460       re_init_screen();
2461 #endif
2462 
2463       if(u_flag == 0)
2464       {
2465 	  u_prefix = 1;
2466 	  u_flag = 1;
2467       }
2468 
2469       if(ctl_ncurs_mode == NCURS_MODE_HELP)
2470       {
2471 	  switch(c)
2472 	  {
2473 	    case 'h':
2474 	    case '?':
2475 	    case KEY_F(1):
2476 	      ctl_help_mode();
2477 	      break;
2478 	    case 'q':
2479 	      return RC_QUIT;
2480 	  }
2481 	  u_prefix = 1;
2482 	  continue;
2483       }
2484 
2485       if(ctl_cmdmode && ' ' <= c && c < 256)
2486       {
2487 	  if(!mini_buff_insertc(command_buffer, c))
2488 	      beep();
2489 	  u_prefix = 1;
2490 	  continue;
2491       }
2492 
2493       if(!ctl_cmdmode && c == 21)
2494       {
2495 	  u_prefix <<= 1;
2496 	  if(u_prefix > MAX_U_PREFIX)
2497 	      u_prefix = MAX_U_PREFIX;
2498 	  u_flag = 1;
2499 	  continue;
2500       }
2501       else
2502 	  u_flag = 0;
2503 
2504       switch(c)
2505 	{
2506 	case 'h':
2507 	case '?':
2508 	case KEY_F(1):
2509 	  ctl_help_mode();
2510 	  continue;
2511 
2512 	case 'V':
2513  	  *valp = 10 * u_prefix;
2514 	  return RC_CHANGE_VOLUME;
2515 	case 'v':
2516 	  *valp = -10 * u_prefix;
2517  	  return RC_CHANGE_VOLUME;
2518 
2519 	case 16:
2520 	case 'P':
2521 	case KEY_UP:
2522 	  if(ctl_cmdmode == NCURS_MODE_CMD_J)
2523 	      ctl_cmd_J_move(1);
2524 	  else if(ctl_cmdmode == NCURS_MODE_CMD_L)
2525 	      ctl_cmd_L_phist();
2526 	  else if(ctl_ncurs_mode == NCURS_MODE_LIST)
2527 	      ctl_list_mode(NC_LIST_UP);
2528 	  else
2529 	  {
2530 	      *valp = 10 * u_prefix;
2531 	      return RC_CHANGE_VOLUME;
2532 	  }
2533 	  continue;
2534 
2535 	case 14:
2536 	case 'N':
2537 	case KEY_DOWN:
2538 	  if(ctl_cmdmode == NCURS_MODE_CMD_J)
2539 	      ctl_cmd_J_move(-1);
2540 	  else if(ctl_cmdmode == NCURS_MODE_CMD_L)
2541 	      ctl_cmd_L_nhist();
2542 	  else if(ctl_ncurs_mode == NCURS_MODE_LIST)
2543 	      ctl_list_mode(NC_LIST_DOWN);
2544 	  else
2545 	  {
2546 	      *valp = -10 * u_prefix;
2547 	      return RC_CHANGE_VOLUME;
2548 	  }
2549 	  continue;
2550 
2551 	case KEY_PPAGE:
2552 	  if(ctl_ncurs_mode == NCURS_MODE_LIST)
2553 	  {
2554 	      ctl_list_mode(NC_LIST_UPPAGE);
2555 	      continue;
2556 	  }
2557 	  else
2558 	      return RC_REALLY_PREVIOUS;
2559 
2560 	case 22: /* ^V */
2561 	case KEY_NPAGE:
2562 	  if(ctl_ncurs_mode == NCURS_MODE_LIST)
2563 	  {
2564 	      ctl_list_mode(NC_LIST_DOWNPAGE);
2565 	      continue;
2566 	  }
2567 	  else
2568 	      return RC_NEXT;
2569 #if 0
2570 	case '1':
2571 	case '2':
2572 	case '3':
2573 	  *valp = c - '2';
2574 	  return RC_CHANGE_REV_EFFB;
2575 	case '4':
2576 	case '5':
2577 	case '6':
2578 	  *valp = c - '5';
2579 	  return RC_CHANGE_REV_TIME;
2580 #endif
2581 	case 'q':
2582 	case 3: /* ^C */
2583 	case KEY_END:
2584 	  trace_flush();
2585 	  sleep(1);
2586 	  return RC_QUIT;
2587 	case 'n':
2588 	  return RC_NEXT;
2589 	case 'p':
2590 	  return RC_REALLY_PREVIOUS;
2591 	case 'r':
2592 	case KEY_HOME:
2593 	  return RC_RESTART;
2594 	case 'f':
2595 	case KEY_RIGHT:
2596 	case 6: /* ^F */
2597 	  if(ctl_cmdmode)
2598 	  {
2599 	      if(!mini_buff_forward(command_buffer))
2600 		  beep();
2601 	      continue;
2602 	  }
2603 	  *valp = play_mode->rate * u_prefix;
2604 	  return RC_FORWARD;
2605 	case 'b':
2606 	case KEY_LEFT:
2607 	case 2: /* ^B */
2608 	  if(ctl_cmdmode)
2609 	  {
2610 	      if(!mini_buff_backward(command_buffer))
2611 		  beep();
2612 	      continue;
2613 	  }
2614 	  *valp = play_mode->rate * u_prefix;
2615 	  return RC_BACK;
2616 	case 's':
2617 	  return RC_TOGGLE_PAUSE;
2618 	case 'l':
2619 	  display_key_helpmsg();
2620 	  ctl_list_mode(NC_LIST_PLAY);
2621 	  continue;
2622 	case ' ':
2623 	case KEY_ENTER:
2624 	case '\r':
2625 	case '\n':
2626 	  if(ctl_cmdmode == NCURS_MODE_CMD_J)
2627 	      return ctl_cmd_J_enter();
2628 	  if(ctl_cmdmode == NCURS_MODE_CMD_L)
2629 	      return ctl_cmd_L_enter();
2630 	  if(ctl_cmdmode == NCURS_MODE_CMD_D)
2631 	      return ctl_cmd_D_enter(valp);
2632 	  if(ctl_cmdmode == NCURS_MODE_CMD_E)
2633 	      return ctl_cmd_E_enter(valp);
2634 	  if(ctl_cmdmode == NCURS_MODE_CMD_S)
2635 	      return ctl_cmd_S_enter();
2636 	  if(ctl_cmdmode == NCURS_MODE_CMD_R)
2637 	      return ctl_cmd_R_enter(valp);
2638 	  if(ctl_cmdmode == NCURS_MODE_CMD_FSEARCH)
2639 	  {
2640 	      if(!ctl_cmd_forward_search())
2641 		  beep();
2642 	      continue;
2643 	  }
2644 	  if(ctl_ncurs_mode == NCURS_MODE_LIST)
2645 	  {
2646 	      /* ctl_list_mode(NC_LIST_SELECT); */
2647 	      return RC_LOAD_FILE;
2648 	  }
2649 		if (ctl_ncurs_mode == NCURS_MODE_TRACE && selected_channel != -1) {
2650 			*valp = selected_channel;
2651 			return RC_TOGGLE_MUTE;
2652 		}
2653 	  continue;
2654 	case '+':
2655 	  *valp = u_prefix;
2656 	  return RC_KEYUP;
2657 	case '-':
2658 	  *valp = -u_prefix;
2659 	  return RC_KEYDOWN;
2660 	case '>':
2661 	  *valp = u_prefix;
2662 	  return RC_SPEEDUP;
2663 	case '<':
2664 	  *valp = u_prefix;
2665 	  return RC_SPEEDDOWN;
2666 	case 'O':
2667 	  *valp = u_prefix;
2668 	  return RC_VOICEINCR;
2669 	case 'o':
2670 	  *valp = u_prefix;
2671 	  return RC_VOICEDECR;
2672 	case 'c':
2673 	  if(ctl_ncurs_mode == NCURS_MODE_TRACE)
2674 	  {
2675 	      move_select_channel(u_prefix);
2676 	      continue;
2677 	  }
2678 	  break;
2679 	case 'j':
2680 		if (ctl_ncurs_mode == NCURS_MODE_TRACE)
2681 			move_select_channel(u_prefix);
2682 		else if (ctl_ncurs_mode == NCURS_MODE_LIST)
2683 			ctl_list_mode(NC_LIST_DOWN);
2684 		continue;
2685 	case 'C':
2686 	  if(ctl_ncurs_mode == NCURS_MODE_TRACE)
2687 	  {
2688 	      move_select_channel(-u_prefix);
2689 	      continue;
2690 	  }
2691 	  break;
2692 	case 'k':
2693 		if (ctl_ncurs_mode == NCURS_MODE_TRACE)
2694 			move_select_channel(-u_prefix);
2695 		else if (ctl_ncurs_mode == NCURS_MODE_LIST)
2696 			ctl_list_mode(NC_LIST_UP);
2697 		continue;
2698 	case 'd':
2699 	  if(ctl_ncurs_mode == NCURS_MODE_TRACE && selected_channel != -1)
2700 	  {
2701 	      *valp = selected_channel;
2702 	      return RC_TOGGLE_DRUMCHAN;
2703 	  }
2704 	  break;
2705 	case '.':
2706 		if (ctl_ncurs_mode == NCURS_MODE_TRACE && selected_channel != -1) {
2707 			*valp = selected_channel;
2708 			return RC_SOLO_PLAY;
2709 		}
2710 		break;
2711 	case 'g':
2712 	  return RC_TOGGLE_SNDSPEC;
2713 	case 'G':
2714 	  return RC_TOGGLE_CTL_SPEANA;
2715 	case 't': /* toggle trace */
2716 	  if(ctl.trace_playing)
2717 	      trace_flush();
2718 	  ctl.trace_playing = (ctl.trace_playing) ? 0 : 1;
2719 	  if(ctl_open(0, 0))
2720 	      return RC_QUIT; /* Error */
2721 	  ctl_total_time(CTL_STATUS_UPDATE);
2722 	  ctl_master_volume(CTL_STATUS_UPDATE);
2723 	  ctl_metronome(CTL_STATUS_UPDATE, CTL_STATUS_UPDATE);
2724 	  ctl_keysig(CTL_STATUS_UPDATE, CTL_STATUS_UPDATE);
2725 	  ctl_tempo(CTL_STATUS_UPDATE, CTL_STATUS_UPDATE);
2726 	  ctl_file_name(NULL);
2727 	  display_key_helpmsg();
2728 	  if(ctl.trace_playing)
2729 	  {
2730 	      *valp = 0;
2731 	      return RC_SYNC_RESTART;
2732 	  }
2733 	  return RC_NONE;
2734 	case 7: /* ^G */
2735 	case 27: /* cancel */
2736 	  if(ctl_cmdmode)
2737 	  {
2738 	      mini_buff_clear(command_buffer);
2739 	      beep();
2740 	      ctl_cmdmode = 0;
2741 	      ctl_cmd_dir_close();
2742 	  }
2743 	  continue;
2744 	case 1: /* ^A */
2745 	  if(ctl_cmdmode)
2746 	  {
2747 	      while(mini_buff_backward(command_buffer))
2748 		  ;
2749 	  }
2750 	  continue;
2751 	case 4: /* ^D */
2752 	  if(ctl_cmdmode)
2753 	  {
2754 	      if(!mini_buff_delc(command_buffer))
2755 		  beep();
2756 	  }
2757 	  continue;
2758 	case 5: /* ^E */
2759 	  if(ctl_cmdmode)
2760 	  {
2761 	      while(mini_buff_forward(command_buffer))
2762 		  ;
2763 	  }
2764 	  continue;
2765 	case 9: /* TAB: file completion */
2766 	  if(ctl_cmdmode == NCURS_MODE_CMD_L ||
2767 	     ctl_cmdmode == NCURS_MODE_CMD_S)
2768 	  {
2769 	      if(!mini_buff_completion(command_buffer))
2770 	      {
2771 		  /* Completion failure */
2772 		  beep();
2773 		  ctl_cmd_L_dir(0);
2774 	      }
2775 	      if(command_buffer->cflag == 1)
2776 	      {
2777 		  ctl_mode_L_dispstart = 0;
2778 		  ctl_cmd_L_dir(0);
2779 	      }
2780 	      else if(command_buffer->cflag > 1)
2781 		  ctl_cmd_L_dir(1);
2782 	  }
2783 	  continue;
2784 	case 11: /* ^K */
2785 	  if(ctl_cmdmode)
2786 	  {
2787 	      while(mini_buff_delc(command_buffer))
2788 		  ;
2789 	  }
2790 	  continue;
2791 	case KEY_BACKSPACE:
2792 	case 8: /* ^H */
2793 	case 127: /* del */
2794 	  if(ctl_cmdmode)
2795 	  {
2796 	      if(mini_buff_backward(command_buffer))
2797 		  mini_buff_delc(command_buffer);
2798 	      else
2799 		  beep();
2800 	  }
2801 	  continue;
2802 	case 21: /* ^U */
2803 	  if(ctl_cmdmode)
2804 	  {
2805 	      while(mini_buff_backward(command_buffer))
2806 		  mini_buff_delc(command_buffer);
2807 	  }
2808 	  continue;
2809 	case'J':
2810 	  ctl_cmdmode = NCURS_MODE_CMD_J;
2811 	  mini_buff_set(command_buffer, dftwin, LINES - 1, "Jump: ");
2812 	  continue;
2813 	case'L':
2814 	  ctl_cmdmode = NCURS_MODE_CMD_L;
2815 	  mini_buff_set(command_buffer, dftwin, LINES - 1, "MIDI File: ");
2816 	  if(*ctl_mode_L_lastenter == '\0' && current_MFnode != NULL)
2817 	  {
2818 	      char *p;
2819 	      strncpy(ctl_mode_L_lastenter, current_MFnode->file,
2820 		      COMMAND_BUFFER_SIZE - 1);
2821 	      ctl_mode_L_lastenter[COMMAND_BUFFER_SIZE - 1] = '\0';
2822 	      if((p = strrchr(ctl_mode_L_lastenter, '#')) != NULL)
2823 		  i = p - ctl_mode_L_lastenter;
2824 	      else
2825 		  i = strlen(ctl_mode_L_lastenter);
2826 	      while(i > 0 && !IS_PATH_SEP(ctl_mode_L_lastenter[i - 1]))
2827 		  i--;
2828 	      ctl_mode_L_lastenter[i] = '\0';
2829 	  }
2830 	  mini_buff_sets(command_buffer, ctl_mode_L_lastenter);
2831 	  ctl_mode_L_histc = NULL;
2832 	  continue;
2833 	case 'D':
2834 	  ctl_cmdmode = NCURS_MODE_CMD_D;
2835 	  mini_buff_set(command_buffer, dftwin, LINES - 1, "DrumCh> ");
2836 	  continue;
2837 	case 'E':
2838 	  ctl_cmdmode = NCURS_MODE_CMD_E;
2839 	  mini_buff_set(command_buffer, dftwin, LINES - 1, "ExtMode> ");
2840 	  continue;
2841 	case 'S':
2842 	  ctl_cmdmode = NCURS_MODE_CMD_S;
2843 	  mini_buff_set(command_buffer, dftwin, LINES - 1, "SaveAs> ");
2844 	  if(*ctl_mode_L_lastenter == '\0' && current_MFnode != NULL)
2845 	  {
2846 	      int i;
2847 	      strncpy(ctl_mode_L_lastenter, current_MFnode->file,
2848 		      COMMAND_BUFFER_SIZE - 1);
2849 	      ctl_mode_L_lastenter[COMMAND_BUFFER_SIZE - 1] = '\0';
2850 	      i = strlen(ctl_mode_L_lastenter);
2851 	      while(i > 0 && !IS_PATH_SEP(ctl_mode_L_lastenter[i - 1]))
2852 		  i--;
2853 	      ctl_mode_L_lastenter[i] = '\0';
2854 	  }
2855 	  mini_buff_sets(command_buffer, ctl_mode_L_lastenter);
2856 	  continue;
2857 	case 'R': {
2858 	    char currentRate[16];
2859 	    ctl_cmdmode = NCURS_MODE_CMD_R;
2860 	    mini_buff_set(command_buffer, dftwin, LINES - 1, "Sample rate> ");
2861 	    sprintf(currentRate, "%d", (int)play_mode->rate);
2862 	    mini_buff_sets(command_buffer, currentRate);
2863 	    continue;
2864 	  }
2865 	case '%':
2866 	  display_velocity_flag = !display_velocity_flag;
2867 	  continue;
2868 	case '/':
2869 	  if(ctl_ncurs_mode == NCURS_MODE_LIST)
2870 	  {
2871 	      ctl_cmdmode = NCURS_MODE_CMD_FSEARCH;
2872 	      mini_buff_set(command_buffer, dftwin, LINES - 1, "/");
2873 	  }
2874 		if (ctl_ncurs_mode == NCURS_MODE_TRACE)
2875 			return RC_MUTE_CLEAR;
2876 	  continue;
2877 	case 12: /* ^L */
2878 	  redraw_all();
2879 	  continue;
2880 	default:
2881 	  beep();
2882 	  continue;
2883 	}
2884     }
2885 
2886 #if SCREEN_BUGFIX
2887   re_init_screen();
2888 #endif
2889 
2890   return RC_NONE;
2891 }
2892 
ctl_write(char * valp,int32 size)2893 static int ctl_write(char *valp, int32 size)
2894 {
2895   static int warned = 0;
2896   if (!warned) {
2897     fprintf(stderr, "Warning: using stdout with ncurses interface will not\n"
2898 		    "give the desired effect.\n");
2899     warned = 1;
2900   }
2901   return write(STDOUT_FILENO, valp, size);
2902 }
2903 
2904 #if defined(USE_PDCURSES) && !defined(HAVE_VWPRINTW)
vwprintw(WINDOW * w,char * fmt,va_list ap)2905 static void vwprintw(WINDOW *w, char *fmt, va_list ap)
2906 {
2907     char *buff;
2908     MBlockList pool;
2909 
2910     init_mblock(&pool);
2911     buff = (char *)new_segment(&pool, MIN_MBLOCK_SIZE);
2912     vsnprintf(buff, MIN_MBLOCK_SIZE, fmt, ap);
2913     waddstr(w, buff);
2914     reuse_mblock(&pool);
2915 }
2916 #endif /* defined(USE_PDCURSES) && !defined(HAVE_VWPRINTW) */
2917 
cmsg(int type,int verbosity_level,char * fmt,...)2918 static int cmsg(int type, int verbosity_level, char *fmt, ...)
2919 {
2920     va_list ap;
2921 
2922     if ((type==CMSG_TEXT || type==CMSG_INFO || type==CMSG_WARNING) &&
2923 	ctl.verbosity<verbosity_level)
2924 	return 0;
2925     indicator_mode = INDICATOR_CMSG;
2926     va_start(ap, fmt);
2927     if(!ctl.opened)
2928     {
2929 	vfprintf(stderr, fmt, ap);
2930 	fprintf(stderr, NLS);
2931     }
2932     else
2933     {
2934 #if defined( __BORLANDC__) || (defined(__W32__) && !defined(__CYGWIN32__))
2935 	nl();
2936 #endif
2937 	if(ctl.trace_playing)
2938 	{
2939 	    char *buff;
2940 	    int i;
2941 	    MBlockList pool;
2942 
2943 	    init_mblock(&pool);
2944 	    buff = (char *)new_segment(&pool, MIN_MBLOCK_SIZE);
2945 	    vsnprintf(buff, MIN_MBLOCK_SIZE, fmt, ap);
2946 	    for(i = 0; i < COLS - 1 && buff[i]; i++)
2947 		if(buff[i] == '\n' || buff[i] == '\r' || buff[i] == '\t')
2948 		    buff[i] = ' ';
2949 	    buff[i] = '\0';
2950 	    N_ctl_clrtoeol(HELP_LINE);
2951 
2952 	    switch(type)
2953 	    {
2954 		/* Pretty pointless to only have one line for messages, but... */
2955 	      case CMSG_WARNING:
2956 	      case CMSG_ERROR:
2957 	      case CMSG_FATAL:
2958 		wattron(dftwin, A_REVERSE);
2959 		waddstr(dftwin, buff);
2960 		wattroff(dftwin, A_REVERSE);
2961 		N_ctl_refresh();
2962 		if(type != CMSG_WARNING)
2963 		    sleep(2);
2964 		break;
2965 	      default:
2966 		waddstr(dftwin, buff);
2967 		N_ctl_refresh();
2968 		break;
2969 	    }
2970 	    reuse_mblock(&pool);
2971 	}
2972 	else
2973 	{
2974 	    switch(type)
2975 	    {
2976 	      default:
2977 		vwprintw(msgwin, fmt, ap);
2978 		wprintw(msgwin, "\n");
2979 		if(ctl_ncurs_mode == NCURS_MODE_MAIN)
2980 		    wrefresh(msgwin);
2981 		break;
2982 
2983 	      case CMSG_WARNING:
2984 		wattron(msgwin, A_BOLD);
2985 		vwprintw(msgwin, fmt, ap);
2986 		wprintw(msgwin, "\n");
2987 		wattroff(msgwin, A_BOLD);
2988 		if(ctl_ncurs_mode == NCURS_MODE_MAIN)
2989 		    wrefresh(msgwin);
2990 		break;
2991 
2992 	      case CMSG_ERROR:
2993 	      case CMSG_FATAL:
2994 		wattron(msgwin, A_REVERSE);
2995 		vwprintw(msgwin, fmt, ap);
2996 		wprintw(msgwin, "\n");
2997 		wattroff(msgwin, A_REVERSE);
2998 		if(ctl_ncurs_mode == NCURS_MODE_MAIN)
2999 		{
3000 		    wrefresh(msgwin);
3001 		    if(type==CMSG_FATAL)
3002 			sleep(2);
3003 		}
3004 		break;
3005 	    }
3006 	}
3007 #ifdef __BORLANDC__
3008 	nonl();
3009 #endif /* __BORLANDC__ */
3010     }
3011     va_end(ap);
3012     return 0;
3013 }
3014 
insert_MFnode_entrys(MFnode * mfp,int pos)3015 static void insert_MFnode_entrys(MFnode *mfp, int pos)
3016 {
3017     MFnode *q; /* tail pointer of mfp */
3018     int len;
3019 
3020     q = mfp;
3021     len = 1;
3022     while(q->next)
3023     {
3024 	q = q->next;
3025 	len++;
3026     }
3027 
3028     if(pos < 0) /* head */
3029     {
3030 	q->next = file_list.MFnode_head;
3031 	file_list.MFnode_head = mfp;
3032     }
3033     else
3034     {
3035 	MFnode *p;
3036 	p = MFnode_nth_cdr(file_list.MFnode_head, pos);
3037 
3038 	if(p == NULL)
3039 	    file_list.MFnode_tail = file_list.MFnode_tail->next = mfp;
3040 	else
3041 	{
3042 	    q->next = p->next;
3043 	    p->next = mfp;
3044 	}
3045     }
3046     file_list.number += len;
3047     ctl_list_table_init();
3048 }
3049 
ctl_list_table_init(void)3050 static void ctl_list_table_init(void)
3051 {
3052     for(;;) {
3053       ctl_list_from[ctl_listmode_max]=LIST_TITLE_LINES*(ctl_listmode_max-1);
3054       ctl_list_select[ctl_listmode_max]=ctl_list_from[ctl_listmode_max];
3055       ctl_list_to[ctl_listmode_max]=LIST_TITLE_LINES*ctl_listmode_max-1;
3056       if(ctl_list_to[ctl_listmode_max]>=file_list.number){
3057 	ctl_list_to[ctl_listmode_max]=file_list.number;
3058 	break;
3059       }
3060       ctl_listmode_max++;
3061     }
3062 }
3063 
make_new_MFnode_entry(char * file)3064 static MFnode *make_new_MFnode_entry(char *file)
3065 {
3066     struct midi_file_info *infop;
3067 #ifdef MIDI_TITLE
3068     char *title = NULL;
3069 #endif
3070 
3071     if(!strcmp(file, "-"))
3072 	infop = get_midi_file_info("-", 1);
3073     else
3074     {
3075 #ifdef MIDI_TITLE
3076 	title = get_midi_title(file);
3077 #else
3078 	if(check_midi_file(file) < 0)
3079 	    return NULL;
3080 #endif /* MIDI_TITLE */
3081 	infop = get_midi_file_info(file, 0);
3082     }
3083 
3084     if(!strcmp(file, "-") || (infop && infop->format >= 0))
3085     {
3086 	MFnode *mfp;
3087 	mfp = (MFnode *)safe_malloc(sizeof(MFnode));
3088 	memset(mfp, 0, sizeof(MFnode));
3089 #ifdef MIDI_TITLE
3090 	mfp->title = title;
3091 #endif /* MIDI_TITLE */
3092 	mfp->file = safe_strdup(url_unexpand_home_dir(file));
3093 	mfp->infop = infop;
3094 	return mfp;
3095     }
3096 
3097     cmsg(CMSG_WARNING, VERB_NORMAL, "%s: Not a midi file (Ignored)",
3098 	 url_unexpand_home_dir(file));
3099     return NULL;
3100 }
3101 
shuffle_list(void)3102 static void shuffle_list(void)
3103 {
3104     MFnode **nodeList;
3105     int i, j, n;
3106 
3107     n = file_list.number + 1;
3108     /* Move MFnode into nodeList */
3109     nodeList = (MFnode **)new_segment(&tmpbuffer, n * sizeof(MFnode));
3110     for(i = 0; i < n; i++)
3111     {
3112 	nodeList[i] = file_list.MFnode_head;
3113 	file_list.MFnode_head = file_list.MFnode_head->next;
3114     }
3115 
3116     /* Simple validate check */
3117     if(file_list.MFnode_head != NULL)
3118 	ctl.cmsg(CMSG_ERROR, VERB_NORMAL, "BUG: MFnode_head is corrupted");
3119 
3120     /* Construct randamized chain */
3121     file_list.MFnode_head = file_list.MFnode_tail = NULL;
3122     for(i = 0; i < n; i++)
3123     {
3124 	MFnode *tmp;
3125 
3126 	j = int_rand(n - i);
3127 	if(file_list.MFnode_head == NULL)
3128 	    file_list.MFnode_head = file_list.MFnode_tail = nodeList[j];
3129 	else
3130 	    file_list.MFnode_tail = file_list.MFnode_tail->next = nodeList[j];
3131 
3132 	/* nodeList[j] is used.  Swap out it */
3133 	tmp = nodeList[j];
3134 	nodeList[j] = nodeList[n - i - 1];
3135 	nodeList[n - i - 1] = tmp;
3136     }
3137     file_list.MFnode_tail->next = NULL;
3138     reuse_mblock(&tmpbuffer);
3139 }
3140 
ctl_pass_playing_list(int number_of_files,char * list_of_files[])3141 static int ctl_pass_playing_list(int number_of_files, char *list_of_files[])
3142 {
3143     int i;
3144     int act_number_of_files;
3145     int stdin_check;
3146 
3147     listwin=newwin(LIST_TITLE_LINES,COLS,TITLE_LINE,0);
3148     stdin_check = 0;
3149     act_number_of_files=0;
3150     for(i=0;i<number_of_files;i++){
3151 	MFnode *mfp;
3152 	if(!strcmp(list_of_files[i], "-"))
3153 	    stdin_check = 1;
3154 	mfp = make_new_MFnode_entry(list_of_files[i]);
3155 	if(mfp != NULL)
3156 	{
3157 	    if(file_list.MFnode_head == NULL)
3158 		file_list.MFnode_head = file_list.MFnode_tail = mfp;
3159 	    else
3160 		file_list.MFnode_tail = file_list.MFnode_tail->next = mfp;
3161 	    act_number_of_files++;
3162 	}
3163     }
3164 
3165     file_list.number=act_number_of_files-1;
3166 
3167     if (file_list.number<0) {
3168       cmsg(CMSG_FATAL, VERB_NORMAL, "No MIDI file to play!");
3169       return 1;
3170     }
3171 
3172     ctl_listmode_max=1;
3173     ctl_list_table_init();
3174     i=0;
3175     for (;;)
3176 	{
3177 	  int rc;
3178 	  current_MFnode = MFnode_nth_cdr(file_list.MFnode_head, i);
3179 	  display_key_helpmsg();
3180 	  switch((rc=play_midi_file(current_MFnode->file)))
3181 	    {
3182 	    case RC_REALLY_PREVIOUS:
3183 		if (i>0)
3184 		    i--;
3185 		else
3186 		{
3187 		    if(ctl.flags & CTLF_LIST_LOOP)
3188 			i = file_list.number;
3189 		    else
3190 		    {
3191 			ctl_reset();
3192 			break;
3193 		    }
3194 		    sleep(1);
3195 		}
3196 		nc_playfile=i;
3197 		ctl_list_mode(NC_LIST_NEW);
3198 		break;
3199 
3200 	    default: /* An error or something */
3201 	    case RC_TUNE_END:
3202 	    case RC_NEXT:
3203 		if (i<file_list.number)
3204 		    i++;
3205 		else
3206 		{
3207 		    if(!(ctl.flags & CTLF_LIST_LOOP) || stdin_check)
3208 		    {
3209 			aq_flush(0);
3210 			return 0;
3211 		    }
3212 		    i = 0;
3213 		    if(rc == RC_TUNE_END)
3214 			sleep(2);
3215 		    if(ctl.flags & CTLF_LIST_RANDOM)
3216 			shuffle_list();
3217 		}
3218 		nc_playfile=i;
3219 		ctl_list_mode(NC_LIST_NEW);
3220 		break;
3221 	    case RC_LOAD_FILE:
3222 		i=ctl_list_select[ctl_listmode];
3223 		nc_playfile=i;
3224 		break;
3225 
3226 		/* else fall through */
3227 	    case RC_QUIT:
3228 		return 0;
3229 	    }
3230 	  ctl_reset();
3231 	}
3232 }
3233 
reset_indicator(void)3234 static void reset_indicator(void)
3235 {
3236     int i;
3237 
3238     memset(comment_indicator_buffer, ' ', indicator_width - 1);
3239     comment_indicator_buffer[indicator_width - 1] = '\0';
3240 
3241     indicator_last_update = get_current_calender_time();
3242     indicator_mode = INDICATOR_DEFAULT;
3243     indicator_msgptr = NULL;
3244 
3245     for(i = 0; i < MAX_CHANNELS; i++)
3246     {
3247 	ChannelStatus[i].last_note_on = 0.0;
3248 	ChannelStatus[i].comm = channel_instrum_name(i);
3249     }
3250 }
3251 
display_aq_ratio(void)3252 static void display_aq_ratio(void)
3253 {
3254     static int last_rate = -1;
3255     int rate, devsiz;
3256 
3257     if((devsiz = aq_get_dev_queuesize()) <= 0)
3258 	return;
3259     rate = (int)(((double)(aq_filled() + aq_soft_filled()) /
3260 		  devsiz) * 100 + 0.5);
3261     if(rate > 9999)
3262 	rate = 10000;
3263 
3264     if(last_rate != rate)
3265     {
3266 	last_rate = rate;
3267 	wmove(dftwin, VOICE_LINE + 1, 15);
3268 	if(rate > 9999)
3269 	    wprintw(dftwin, " Audio queue: ****%% ");
3270 	else
3271 	    wprintw(dftwin, " Audio queue: %4d%% ", rate);
3272 	scr_modified_flag = 1;
3273     }
3274 }
3275 
update_indicator(void)3276 static void update_indicator(void)
3277 {
3278     double t;
3279     int i;
3280     char c;
3281     static int play_modeflag = 1;
3282 
3283 #if 0
3284     play_modeflag = 1;
3285     display_play_system(play_system_mode);
3286     display_intonation(opt_pure_intonation);
3287 #else
3288     if(midi_trace.flush_flag)
3289     {
3290 	play_modeflag = 1;
3291 	return;
3292     }
3293 
3294     if(gslcd_displayed_flag)
3295     {
3296 	t = get_current_calender_time();
3297 	if(t - gslcd_last_display_time > GS_LCD_CLEAR_TIME)
3298 	{
3299 	    ctl_lcd_mark(GS_LCD_MARK_CLEAR, 0, 0);
3300 	    gslcd_displayed_flag = 0;
3301 	}
3302     }
3303 
3304 	if (play_modeflag) {
3305 		display_play_system(play_system_mode);
3306 		display_intonation(opt_pure_intonation);
3307 	} else {
3308 		display_play_system(-1);
3309 		display_intonation(-1);
3310 	}
3311     play_modeflag = !play_modeflag;
3312 #endif /* __W32__ */
3313 
3314     t = get_current_calender_time();
3315     if(indicator_mode != INDICATOR_DEFAULT)
3316     {
3317 	if(indicator_last_update + LYRIC_OUT_THRESHOLD > t)
3318 	    return;
3319 	reset_indicator();
3320     }
3321     indicator_last_update = t;
3322 
3323     if(indicator_msgptr != NULL && *indicator_msgptr == '\0')
3324 	indicator_msgptr = NULL;
3325 
3326     if(indicator_msgptr == NULL)
3327     {
3328 	int i, prog, first_ch;
3329 
3330 	first_ch = -1;
3331 	prog = ChannelStatus[current_indicator_chan].prog;
3332 	/* Find next message */
3333 	for(i = 0; i < MAX_CHANNELS; i++,
3334 	    current_indicator_chan = (current_indicator_chan + 1) % MAX_CHANNELS)
3335 	{
3336 	    if(ChannelStatus[current_indicator_chan].is_drum ||
3337 	       ChannelStatus[current_indicator_chan].comm == NULL ||
3338 	       *ChannelStatus[current_indicator_chan].comm == '\0')
3339 		continue;
3340 
3341 	    if(first_ch == -1 &&
3342 	       ChannelStatus[current_indicator_chan].last_note_on > 0)
3343 		first_ch = current_indicator_chan;
3344 	    if(ChannelStatus[current_indicator_chan].prog != prog &&
3345 	       (ChannelStatus[current_indicator_chan].last_note_on
3346 		+ CHECK_NOTE_SLEEP_TIME > t))
3347 		break;
3348 	}
3349 
3350 	if(i == MAX_CHANNELS)
3351 	{
3352 	    if(first_ch == -1)
3353 		first_ch = 0;
3354 	    if(ChannelStatus[first_ch].comm == NULL ||
3355 	       *ChannelStatus[first_ch].comm == '\0')
3356 		return;
3357 	    current_indicator_chan = first_ch;
3358 	}
3359 
3360 	snprintf(current_indicator_message, indicator_width, "%03d:%s   ",
3361 		 ChannelStatus[current_indicator_chan].prog,
3362 		 ChannelStatus[current_indicator_chan].comm);
3363 	indicator_msgptr = current_indicator_message;
3364     }
3365 
3366     c = *indicator_msgptr++;
3367 
3368     for(i = 0; i < indicator_width - 2; i++)
3369 	comment_indicator_buffer[i] = comment_indicator_buffer[i + 1];
3370     comment_indicator_buffer[indicator_width - 2] = c;
3371     wmove(dftwin, HELP_LINE, 0);
3372     waddstr(dftwin, comment_indicator_buffer);
3373     scr_modified_flag = 1;
3374     N_ctl_refresh();
3375 }
3376 
indicator_chan_update(int ch)3377 static void indicator_chan_update(int ch)
3378 {
3379     ChannelStatus[ch].last_note_on = get_current_calender_time();
3380     if(ChannelStatus[ch].comm == NULL)
3381     {
3382 	if((ChannelStatus[ch].comm = default_instrument_name) == NULL)
3383 	{
3384 	    if(ChannelStatus[ch].is_drum)
3385 		ChannelStatus[ch].comm = "<Drum>";
3386 	    else
3387 		ChannelStatus[ch].comm = "<GrandPiano>";
3388 	}
3389     }
3390 }
3391 
display_lyric(char * lyric,int sep)3392 static void display_lyric(char *lyric, int sep)
3393 {
3394     char *p;
3395     int len, idlen, sepoffset;
3396     static int crflag = 0;
3397 
3398     if(lyric == NULL)
3399     {
3400 	indicator_last_update = get_current_calender_time();
3401 	crflag = 0;
3402 	return;
3403     }
3404 
3405     if(indicator_mode != INDICATOR_LYRIC || crflag)
3406     {
3407 	memset(comment_indicator_buffer, 0, indicator_width);
3408 	N_ctl_clrtoeol(HELP_LINE);
3409 	N_ctl_refresh();
3410 	indicator_mode = INDICATOR_LYRIC;
3411 	crflag = 0;
3412     }
3413 
3414     if(*lyric == '\0')
3415     {
3416 	indicator_last_update = get_current_calender_time();
3417 	return;
3418     }
3419 
3420     if(strchr(lyric, '\r') != NULL)
3421     {
3422 	crflag = 1;
3423 	if(lyric[0] == '\r' && lyric[1] == '\0')
3424 	{
3425 	    indicator_last_update = get_current_calender_time();
3426 	    return;
3427 	}
3428     }
3429 
3430     idlen = strlen(comment_indicator_buffer);
3431     len = strlen(lyric);
3432 
3433     if(sep)
3434     {
3435 	while(idlen > 0 && comment_indicator_buffer[idlen - 1] == ' ')
3436 	    comment_indicator_buffer[--idlen] = '\0';
3437 	while(len > 0 && lyric[len - 1] == ' ')
3438 	    len--;
3439     }
3440 
3441     if(len == 0)
3442     {
3443 	indicator_last_update = get_current_calender_time();
3444 	reuse_mblock(&tmpbuffer);
3445 	return;
3446     }
3447 
3448     sepoffset = (sep != 0);
3449 
3450     if(len >= indicator_width - 2)
3451     {
3452 	memcpy(comment_indicator_buffer, lyric, indicator_width - 1);
3453 	comment_indicator_buffer[indicator_width - 1] = '\0';
3454     }
3455     else if(idlen == 0)
3456     {
3457 	memcpy(comment_indicator_buffer, lyric, len);
3458 	comment_indicator_buffer[len] = '\0';
3459     }
3460     else if(len + idlen + 2 < indicator_width)
3461     {
3462 	if(sep)
3463 	    comment_indicator_buffer[idlen] = sep;
3464 	memcpy(comment_indicator_buffer + idlen + sepoffset, lyric, len);
3465 	comment_indicator_buffer[idlen + sepoffset + len] = '\0';
3466     }
3467     else
3468     {
3469 	int spaces;
3470 	p = comment_indicator_buffer;
3471 	spaces = indicator_width - idlen - 2;
3472 
3473 	while(spaces < len)
3474 	{
3475 	    char *q;
3476 
3477 	    /* skip one word */
3478 	    if((q = strchr(p, ' ')) == NULL)
3479 	    {
3480 		p = NULL;
3481 		break;
3482 	    }
3483 	    do q++; while(*q == ' ');
3484 	    spaces += (q - p);
3485 	    p = q;
3486 	}
3487 
3488 	if(p == NULL)
3489 	{
3490 	    N_ctl_clrtoeol(HELP_LINE);
3491 	    memcpy(comment_indicator_buffer, lyric, len);
3492 	    comment_indicator_buffer[len] = '\0';
3493 	}
3494 	else
3495 	{
3496 	    int d, l, r, i, j;
3497 
3498 	    d = (p - comment_indicator_buffer);
3499 	    l = strlen(p);
3500 	    r = len - (indicator_width - 2 - l - d);
3501 
3502 	    j = d - r;
3503 	    for(i = 0; i < j; i++)
3504 		comment_indicator_buffer[i] = ' ';
3505 	    for(i = 0; i < l; i++)
3506 		comment_indicator_buffer[j + i] =
3507 		    comment_indicator_buffer[d + i];
3508 	    if(sep)
3509 		comment_indicator_buffer[j + i] = sep;
3510 	    memcpy(comment_indicator_buffer + j + i + sepoffset, lyric, len);
3511 	    comment_indicator_buffer[j + i + sepoffset + len] = '\0';
3512 	}
3513     }
3514 
3515     wmove(dftwin, HELP_LINE, 0);
3516     waddstr(dftwin, comment_indicator_buffer);
3517     N_ctl_refresh();
3518     reuse_mblock(&tmpbuffer);
3519     indicator_last_update = get_current_calender_time();
3520 }
3521 
3522 
3523 /*
3524  * MiniBuffer functions
3525   */
3526 #include <sys/types.h>
3527 #include <sys/stat.h>
3528 
3529 #ifndef S_ISDIR
3530 #define S_ISDIR(mode)   (((mode)&0xF000) == 0x4000)
3531 #endif /* S_ISDIR */
3532 
3533 /* Allocate new buffer */
mini_buff_new(int size)3534 static MiniBuffer *mini_buff_new(int size)
3535 {
3536     MiniBuffer *b;
3537 
3538     b = (MiniBuffer *)safe_malloc(sizeof(MiniBuffer) + size + 1);
3539     memset(b, 0, sizeof(MiniBuffer) + size + 1);
3540     b->buffer = (char *)b + sizeof(MiniBuffer);
3541     b->size = size;
3542     mini_buff_set(b, NULL, 0, NULL);
3543     return b;
3544 }
3545 
3546 /* Initialize buffer */
mini_buff_set(MiniBuffer * b,WINDOW * bufwin,int line,char * prompt)3547 static void mini_buff_set(MiniBuffer *b, WINDOW *bufwin, int line,
3548 			  char *prompt)
3549 {
3550     int plen = 0;
3551 
3552     memset(b->buffer, 0, b->size);
3553 
3554     b->len = 0;
3555     b->cur = 0;
3556     b->bufwin = bufwin;
3557     b->cflag = 0;
3558     b->uflag = 0;
3559     reuse_mblock(&b->pool);
3560     b->files = NULL;
3561     b->lastcmpl = NULL;
3562 
3563     if(prompt)
3564     {
3565 	plen = strlen(prompt);
3566 	b->text = b->buffer + plen;
3567 	b->maxlen = b->size - plen;
3568 	memcpy(b->buffer, prompt, plen);
3569     }
3570     else
3571     {
3572 	b->text = b->buffer;
3573 	b->maxlen = b->size;
3574     }
3575 
3576     if(bufwin)
3577     {
3578 	b->x = 0;
3579 	b->y = line;
3580 	getmaxyx(bufwin, b->h, b->w);
3581 	N_ctl_clrtoeol(line);
3582 	if(prompt)
3583 	{
3584 	    waddstr(bufwin, prompt);
3585 	    b->x = plen;
3586 	}
3587 	wrefresh(b->bufwin);
3588     }
3589 }
3590 
3591 /* Clear buffer */
mini_buff_clear(MiniBuffer * b)3592 static void mini_buff_clear(MiniBuffer *b)
3593 {
3594     reuse_mblock(&b->pool);
3595     mini_buff_set(b, b->bufwin, b->y, NULL);
3596 }
3597 
3598 /* Refresh buffer window if modified */
mini_buff_refresh(MiniBuffer * b)3599 static void mini_buff_refresh(MiniBuffer *b)
3600 {
3601     if(b->uflag && b->bufwin)
3602     {
3603 	wmove(b->bufwin, b->y, b->x);
3604 	wrefresh(b->bufwin);
3605 	b->uflag = 0;
3606     }
3607 }
3608 
mb_disp_line(MiniBuffer * b,int offset,int view_start)3609 static void mb_disp_line(MiniBuffer *b, int offset, int view_start)
3610 {
3611     int rlen;
3612     int tlen;
3613 
3614     if(b->bufwin == NULL)
3615 	return;
3616 
3617     /* Note that: -prompt_length <= view_start <= b->maxlen */
3618 
3619     wmove(b->bufwin, b->y, offset);
3620     wclrtoeol(b->bufwin);
3621 
3622     rlen = b->w - offset;
3623     tlen = b->len - view_start - offset;
3624 
3625     if(tlen < rlen)
3626 	waddnstr(b->bufwin, b->text + view_start + offset, tlen);
3627     else
3628     {
3629 	waddnstr(b->bufwin, b->text + view_start + offset, rlen - 1);
3630 	waddch(b->bufwin, MINI_BUFF_MORE_C);
3631     }
3632 }
3633 
3634 /* Forward one character */
mini_buff_forward(MiniBuffer * b)3635 static int mini_buff_forward(MiniBuffer *b)
3636 {
3637     if(b->cur == b->len)
3638 	return 0;
3639     b->cur++;
3640     b->x++;
3641 
3642     if(b->cur == b->len && b->x == b->w)
3643     {
3644 	/* turn the line */
3645 	mb_disp_line(b, 0, b->cur - 1);
3646 	b->x = 0;
3647     }
3648     else if(b->x == b->w - 1)
3649     {
3650 	/* turn the line */
3651 	mb_disp_line(b, 0, b->cur);
3652 	b->x = 0;
3653     }
3654     b->uflag = 1;
3655     return 1;
3656 }
3657 
3658 /* Forward one character */
mini_buff_backward(MiniBuffer * b)3659 static int mini_buff_backward(MiniBuffer *b)
3660 {
3661     if(b->cur == 0)
3662 	return 0;
3663     b->cur--;
3664     b->x--;
3665 
3666     if(b->x < 0)
3667     {
3668 	/* restore the prev line */
3669 	b->x = b->w - 2;
3670 	mb_disp_line(b, 0, b->cur - b->x);
3671     }
3672     b->uflag = 1;
3673     return 1;
3674 }
3675 
3676 /* Insert a character */
mini_buff_insertc(MiniBuffer * b,int c)3677 static int mini_buff_insertc(MiniBuffer *b, int c)
3678 {
3679     if(b->cur == b->maxlen || c == 0)
3680 	return 0;
3681 
3682     /* insert */
3683     if(b->cur == b->len)
3684     {
3685 	/* end of buffer */
3686 	b->text[b->cur] = c;
3687 	b->cur++;
3688 	b->len++;
3689 	b->x++;
3690 	if(b->x == b->w)
3691 	{
3692 	    mb_disp_line(b, 0, b->cur - 1);
3693 	    b->x = 1;
3694 	}
3695 	else
3696 	{
3697 	    if(b->bufwin)
3698 	    {
3699 		wmove(b->bufwin, b->y, b->x - 1);
3700 		waddch(b->bufwin, c);
3701 	    }
3702 	}
3703     }
3704     else
3705     {
3706 	/* not end of buffer */
3707 	int i;
3708 	for(i = b->len; i > b->cur; i--)
3709 	    b->text[i] = b->text[i - 1];
3710 	b->text[i] = c;
3711 	b->cur++;
3712 	b->len++;
3713 	b->x++;
3714 	if(b->x == b->w - 1)
3715 	{
3716 	    mb_disp_line(b, 0, b->cur);
3717 	    b->x = 0;
3718 	}
3719 	else
3720 	{
3721 	    mb_disp_line(b, b->x - 1, b->cur - b->x);
3722 	}
3723     }
3724     b->uflag = 1;
3725     return 1;
3726 }
3727 
3728 /* Insert a string */
mini_buff_inserts(MiniBuffer * b,char * s)3729 static int mini_buff_inserts(MiniBuffer *b, char *s)
3730 {
3731     unsigned char *c = (unsigned char *)s;
3732 
3733     while(*c)
3734 	if(!mini_buff_insertc(b, *c++))
3735 	    return 0;
3736     return 1;
3737 }
3738 
3739 /* Delete a character */
mini_buff_delc(MiniBuffer * b)3740 static int mini_buff_delc(MiniBuffer *b)
3741 {
3742     int i, c;
3743 
3744     if(b->cur == b->len)
3745 	return 0;
3746 
3747     c = (int)(unsigned char)b->text[b->cur];
3748     for(i = b->cur; i < b->len - 1; i++)
3749 	b->text[i] = b->text[i + 1];
3750     b->len--;
3751     if(b->x > 0 || b->cur != b->len || b->cur == 0)
3752 	mb_disp_line(b, b->x, b->cur - b->x);
3753     else
3754     {
3755 	mb_disp_line(b, 0, b->cur - b->w + 1);
3756 	b->x = b->w - 1;
3757     }
3758     b->uflag = 1;
3759     return c;
3760 }
3761 
3762 /* Get buffer string */
mini_buff_gets(MiniBuffer * b)3763 static char *mini_buff_gets(MiniBuffer *b)
3764 {
3765     b->text[b->len] = '\0';
3766     return b->text;
3767 }
3768 
3769 /* Set buffer string */
mini_buff_sets(MiniBuffer * b,char * s)3770 static void mini_buff_sets(MiniBuffer *b, char *s)
3771 {
3772     while(mini_buff_backward(b))
3773 	;
3774     while(mini_buff_delc(b))
3775 	;
3776     mini_buff_inserts(b, s);
3777 }
3778 
mini_buff_len(MiniBuffer * b)3779 static int mini_buff_len(MiniBuffer *b)
3780 {
3781     return b->len;
3782 }
3783 
is_directory(char * pathname)3784 static int is_directory(char *pathname)
3785 {
3786     struct stat stb;
3787 
3788     pathname = url_expand_home_dir(pathname);
3789     if(stat(pathname, &stb) < 0)
3790 	return 0;
3791     return S_ISDIR(stb.st_mode);
3792 }
3793 
MFnode_insert_node(MFnode * list,MFnode * node)3794 static MFnode *MFnode_insert_node(MFnode *list, MFnode *node)
3795 {
3796     MFnode *cur, *prev;
3797 
3798     prev = NULL;
3799     for(cur = list; cur; prev = cur, cur = cur->next)
3800 	if(strcmp(cur->file, node->file) >= 0)
3801 	    break;
3802     if(cur == list)
3803     {
3804 	node->next = list;
3805 	return node;
3806     }
3807     prev->next = node;
3808     node->next = cur;
3809     return list;
3810 }
3811 
3812 /* Completion as file name */
mini_buff_completion(MiniBuffer * b)3813 static int mini_buff_completion(MiniBuffer *b)
3814 {
3815     char *text, *dir, *file, *pr;
3816     URL url;
3817     char buff[BUFSIZ];
3818     int dirlen, prefix;
3819 
3820     text = mini_buff_gets(b);
3821     if(b->lastcmpl != NULL && strcmp(b->lastcmpl, text) == 0)
3822     {
3823 	/* same */
3824 	b->cflag++;
3825 	return 1;
3826     }
3827 
3828     /* make new completion list */
3829 
3830     /* fix the path */
3831     pr = text;
3832     for(;;)
3833     {
3834 	pr = pathsep_strchr(pr);
3835 	if(pr == NULL)
3836 	    break;
3837 	pr++;
3838 #ifdef TILD_SCHEME_ENABLE
3839 	if(*pr == '~')
3840 	    break;
3841 #endif /* TILD_SCHEME_ENABLE */
3842 	if(IS_PATH_SEP(*pr))
3843 	{
3844 	    do
3845 		pr++;
3846 	    while(IS_PATH_SEP(*pr))
3847 		;
3848 	    pr--;
3849 	    break;
3850 	}
3851     }
3852     if(pr != NULL)
3853     {
3854 	int pos;
3855 
3856 	pos = pr - text;
3857 	/* goto pos */
3858 	while(b->cur < pos)
3859 	    mini_buff_forward(b);
3860 	while(b->cur > pos)
3861 	    mini_buff_backward(b);
3862 	/* del */
3863 	while(mini_buff_backward(b))
3864 	    mini_buff_delc(b);
3865     }
3866     text = mini_buff_gets(b);
3867 
3868     reuse_mblock(&b->pool);
3869     b->lastcmpl = NULL;
3870     b->files = NULL;
3871     b->cflag = 0;
3872 
3873     /* split dir and file name */
3874     if((file = pathsep_strrchr(text)) != NULL)
3875     {
3876 	file++;
3877 	dirlen = file - text;
3878 	dir = (char *)new_segment(&b->pool, dirlen + 1);
3879 	memcpy(dir, text, dirlen);
3880 	dir[dirlen] = '\0';
3881     }
3882     else
3883     {
3884 	file = text;
3885 	dir = ""; /* "" means current directory */
3886 	dirlen = 0;
3887     }
3888 
3889     /* open directory */
3890     url = url_dir_open(dir);
3891 
3892     if(url == NULL) /* No completion */
3893     {
3894 	reuse_mblock(&b->pool);
3895 	return 0;
3896     }
3897 
3898     /* scan and match each files */
3899     prefix = -1;
3900     pr = NULL;
3901     while(url_gets(url, buff, sizeof(buff)))
3902     {
3903 	char *path;
3904 	MFnode *mfp;
3905 	int i;
3906 
3907 	if(!strcmp(buff, ".") || !strcmp(buff, "..") ||
3908 	   (*buff == '.' && *file != '.'))
3909 	    continue;
3910 
3911 	/* check prefix */
3912 	for(i = 0; file[i]; i++)
3913 	    if(file[i] != buff[i])
3914 		break;
3915 
3916 	if(file[i] == '\0') /* matched */
3917 	{
3918 	    int flen;
3919 	    flen = strlen(buff);
3920 	    path = (char *)new_segment(&b->pool, dirlen + flen + 1);
3921 	    memcpy(path, dir, dirlen);
3922 	    memcpy(path + dirlen, buff, flen + 1);
3923 	    mfp = (MFnode *)new_segment(&b->pool, sizeof(MFnode));
3924 	    mfp->file = path;
3925 	    b->files = MFnode_insert_node(b->files, mfp);
3926 
3927 	    if(prefix == -1)
3928 	    {
3929 		prefix = flen;
3930 		pr = path + dirlen;
3931 	    }
3932 	    else
3933 	    {
3934 		int j;
3935 		for(j = i; j < prefix && pr[j]; j++)
3936 		    if(pr[j] != buff[j])
3937 			break;
3938 		prefix = j;
3939 	    }
3940 	}
3941     }
3942     url_close(url);
3943 
3944     prefix -= strlen(file);
3945 
3946     if(b->files == NULL)
3947     {
3948 	reuse_mblock(&b->pool);
3949 	b->files = NULL;
3950 	return 0;
3951     }
3952 
3953     /* go to end of buffer */
3954     while(mini_buff_forward(b))
3955 	;
3956 
3957     if(b->files->next == NULL) /* Sole completed */
3958     {
3959 	char *p;
3960 	p = b->files->file + strlen(text);
3961 	while(*p)
3962 	    mini_buff_insertc(b, *p++);
3963 	if(is_directory(mini_buff_gets(b)))
3964 	{
3965 	    /* Enter in the new directory. */
3966 	    mini_buff_insertc(b, PATH_SEP);
3967 	    reuse_mblock(&b->pool);
3968 	    b->lastcmpl = NULL;
3969 	    b->files = NULL;
3970 	}
3971 	else
3972 	    b->lastcmpl = strdup_mblock(&b->pool, mini_buff_gets(b));
3973     }
3974     else if(prefix > 0) /* partial completed */
3975     {
3976 	char *p;
3977 	int i;
3978 
3979 	p = b->files->file + strlen(text);
3980 	for(i = 0; i < prefix; i++)
3981 	    mini_buff_insertc(b, p[i]);
3982 	b->lastcmpl = strdup_mblock(&b->pool, mini_buff_gets(b));
3983     }
3984     else
3985     {
3986 	b->cflag++;
3987 	b->lastcmpl = strdup_mblock(&b->pool, mini_buff_gets(b));
3988     }
3989 
3990     return 1;
3991 }
3992 
3993 
3994 /*
3995  * interface_<id>_loader();
3996  */
interface_n_loader(void)3997 ControlMode *interface_n_loader(void)
3998 {
3999     return &ctl;
4000 }
4001