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