1 /*
2 TiMidity++ -- MIDI to WAVE converter and player
3 Copyright (C) 1999-2004 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 slang_c.c, Riccardo Facchetti (riccardo@cdc8g5.cdc.polimi.it)
21
22 based on ncurses_ctl.c
23 slang library is more efficient than ncurses one.
24
25 04/04/1995
26 - Initial, working version.
27
28 15/04/1995
29 - Works with no-trace playing too; not the best way, but
30 it is the only way: slang 0.99.1 don't have a window management interface
31 and I don't want write one for it! :)
32 The problem is that I have set the no-scroll slang option so
33 when there are too much messages, the last ones are not displayed at
34 all. Tipically the last messages are warning for instruments not found
35 so this is no real problem (I hope :)
36 - Get the real size of screen we are running on
37
38 TiMidity++ release: Masanao Izumo <iz@onicos.co.jp>
39 */
40
41 #ifdef HAVE_CONFIG_H
42 #include "config.h"
43 #endif /* HAVE_CONFIG_H */
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <unistd.h>
47 #include <stdarg.h>
48 #include <termios.h>
49 #include <sys/ioctl.h>
50 #ifndef NO_STRING_H
51 #include <string.h>
52 #else
53 #include <strings.h>
54 #endif
55
56 #ifdef HAVE_SLANG_SLANG_H
57 #include <slang/slang.h>
58 #else
59 #include <slang.h>
60 #endif
61
62 #include "timidity.h"
63 #include "common.h"
64 #include "instrum.h"
65 #include "playmidi.h"
66 #include "readmidi.h"
67 #include "output.h"
68 #include "controls.h"
69 #include "miditrace.h"
70 #include "timer.h"
71
72 /*
73 * For the set_color pairs (so called 'objects')
74 * see the ctl_open()
75 */
76 #define SLsmg_normal() SLsmg_set_color(20)
77 #define SLsmg_bold() SLsmg_set_color(21)
78 #define SLsmg_reverse() SLsmg_set_color(22)
79
80 #define SCRMODE_OUT_THRESHOLD 10.0
81 #define CHECK_NOTE_SLEEP_TIME 5.0
82 #define INDICATOR_UPDATE_TIME 0.2
83
84 static struct
85 {
86 int prog;
87 int disp_cnt;
88 double last_note_on;
89 char *comm;
90 } instr_comment[MAX_CHANNELS];
91
92 enum indicator_mode_t
93 {
94 INDICATOR_DEFAULT,
95 INDICATOR_LYRIC
96 };
97
98 static int indicator_width = 78;
99 static char *comment_indicator_buffer = NULL;
100 static char *current_indicator_message = NULL;
101 static char *indicator_msgptr = NULL;
102 static int current_indicator_chan = 0;
103 static int next_indicator_chan = -1;
104 static double indicator_last_update;
105 static int indicator_mode = INDICATOR_DEFAULT;
106
107 static void update_indicator(void);
108 static void reset_indicator(void);
109 static void display_lyric(char *lyric, int sep);
110 static void display_title(char *title);
111 static void init_lyric(char *lang);
112
113 #define LYRIC_WORD_NOSEP 0
114 #define LYRIC_WORD_SEP ' '
115
116 static void ctl_refresh(void);
117 static void ctl_help_mode(void);
118 static void ctl_total_time(int tt);
119 static void ctl_master_volume(int mv);
120 static void ctl_file_name(char *name);
121 static void ctl_current_time(int secs, int v);
122 static void ctl_note(int status, int ch, int note, int vel);
123 static void ctl_program(int ch, int val);
124 static void ctl_volume(int channel, int val);
125 static void ctl_expression(int channel, int val);
126 static void ctl_panning(int channel, int val);
127 static void ctl_sustain(int channel, int val);
128 static void ctl_pitch_bend(int channel, int val);
129 static void ctl_reset(void);
130 static int ctl_open(int using_stdin, int using_stdout);
131 static void ctl_close(void);
132 static int ctl_read(int32 *valp);
133 static int ctl_write(char *valp, int32 size);
134 static void ctl_lyric(int valp);
135 static int cmsg(int type, int verbosity_level, char *fmt, ...);
136 static void ctl_event(CtlEvent *e);
137
138 /**********************************************/
139 /* export the interface functions */
140
141 #define ctl slang_control_mode
142
143 ControlMode ctl=
144 {
145 "slang interface", 's',
146 "slang",
147 1,0,0,
148 0,
149 ctl_open,
150 ctl_close,
151 dumb_pass_playing_list,
152 ctl_read,
153 ctl_write,
154 cmsg,
155 ctl_event
156 };
157
158 static uint32 cuepoint = 0;
159 static int cuepoint_pending = 0;
160
161 /***********************************************************************/
162 /* foreground/background checks disabled since switching to curses */
163 /* static int in_foreground=1; */
164 static int ctl_helpmode=0;
165 static int lyric_row = 6;
166 static int title_row = 6;
167 static int msg_row = 0;
168
_ctl_refresh(void)169 static void _ctl_refresh(void)
170 {
171 SLsmg_gotorc(0,0);
172 SLsmg_refresh();
173 }
174
SLsmg_printfrc(int r,int c,char * fmt,...)175 static void SLsmg_printfrc( int r, int c, char *fmt, ...) {
176 char p[1000];
177 va_list ap;
178
179 SLsmg_gotorc( r, c);
180 va_start(ap, fmt);
181 vsnprintf(p, sizeof(p), fmt, ap);
182 va_end(ap);
183
184 SLsmg_write_string (p);
185 }
186
ctl_head(void)187 static void ctl_head(void)
188 {
189 SLsmg_printfrc(0, 0, "TiMidity++ %s%s",
190 (strcmp(timidity_version, "current")) ? "v" : "", timidity_version);
191 SLsmg_printfrc(0,SLtt_Screen_Cols-45, "(C) 1995 Tuukka Toivonen <toivonen@clinet.fi>");
192 SLsmg_printfrc(1,0, "Press 'h' for help with keys, or 'q' to quit.");
193 }
ctl_refresh(void)194 static void ctl_refresh(void)
195 {
196 if (ctl.trace_playing)
197 _ctl_refresh();
198 }
199
ctl_help_mode(void)200 static void ctl_help_mode(void)
201 {
202 if (ctl_helpmode)
203 {
204 ctl_helpmode=0;
205
206 /*
207 * Clear the head zone and reprint head message.
208 */
209 SLsmg_gotorc(0,0);
210 SLsmg_erase_eol();
211 SLsmg_gotorc(1,0);
212 SLsmg_erase_eol();
213 ctl_head();
214 _ctl_refresh();
215 }
216 else
217 {
218 ctl_helpmode=1;
219 SLsmg_reverse();
220 SLsmg_gotorc(0,0);
221 SLsmg_erase_eol();
222 SLsmg_write_string(
223 "V=Louder b=Skip back "
224 "n=Next file r=Restart file");
225
226 SLsmg_gotorc(1,0);
227 SLsmg_erase_eol();
228 SLsmg_write_string(
229 "v=Softer f=Skip forward "
230 "p=Previous file q=Quit program");
231 SLsmg_normal();
232 _ctl_refresh();
233 }
234 }
235
ctl_total_time(int tt)236 static void ctl_total_time(int tt)
237 {
238 int mins, secs=tt/play_mode->rate;
239 mins=secs/60;
240 secs-=mins*60;
241
242 SLsmg_gotorc(4,6+6+3);
243 SLsmg_bold();
244 SLsmg_printf("%3d:%02d", mins, secs);
245 SLsmg_normal();
246 _ctl_refresh();
247 }
248
ctl_master_volume(int mv)249 static void ctl_master_volume(int mv)
250 {
251 SLsmg_gotorc(4,SLtt_Screen_Cols-5);
252 SLsmg_bold();
253 SLsmg_printf("%03d %%", mv);
254 SLsmg_normal();
255 _ctl_refresh();
256 }
257
ctl_file_name(char * name)258 static void ctl_file_name(char *name)
259 {
260 SLsmg_gotorc(3,6);
261 SLsmg_erase_eol();
262 SLsmg_bold();
263 SLsmg_write_string(name);
264 SLsmg_normal();
265 _ctl_refresh();
266 }
267
ctl_current_time(int secs,int v)268 static void ctl_current_time(int secs, int v)
269 {
270 int mins;
271 static int last_voices=-1,last_secs=-1;
272
273 if(1/*last_secs!=secs*/)
274 {
275 last_secs=secs;
276 mins=secs/60;
277 secs-=mins*60;
278 SLsmg_gotorc(4,6);
279 SLsmg_bold();
280 SLsmg_printf("%3d:%02d", mins, secs);
281 _ctl_refresh();
282 }
283 if(!ctl.trace_playing||midi_trace.flush_flag)
284 {
285 SLsmg_normal();
286 return;
287 }
288
289 if(last_voices!=voices)
290 {
291 last_voices=voices;
292 SLsmg_gotorc(4,48);
293 SLsmg_printf("%2d", v);
294 SLsmg_normal();
295 _ctl_refresh();
296 }
297 }
298
ctl_note(int status,int channel,int note,int velocity)299 static void ctl_note(int status, int channel, int note, int velocity)
300 {
301 int xl;
302 if(channel >= 16)
303 return;
304 if (!ctl.trace_playing)
305 return;
306 xl=note%(SLtt_Screen_Cols-24);
307 SLsmg_gotorc(8+channel,xl+3);
308 switch(status)
309 {
310 case VOICE_DIE:
311 SLsmg_write_char(',');
312 break;
313 case VOICE_FREE:
314 SLsmg_write_char('.');
315 break;
316 case VOICE_ON:
317 SLsmg_bold();
318 SLsmg_write_char('0'+(10*velocity)/128);
319 SLsmg_normal();
320 break;
321 case VOICE_OFF:
322 case VOICE_SUSTAINED:
323 SLsmg_write_char('0'+(10*velocity)/128);
324 break;
325 }
326 }
327
ctl_program(int ch,int val)328 static void ctl_program(int ch, int val)
329 {
330 if(ch >= 16)
331 return;
332 if (!ctl.trace_playing)
333 return;
334 if(channel[ch].special_sample)
335 val = channel[ch].special_sample;
336 else
337 val += progbase;
338 SLsmg_gotorc(8+ch, SLtt_Screen_Cols-20);
339 if (ISDRUMCHANNEL(ch))
340 {
341 SLsmg_bold();
342 SLsmg_printf("%03d", val);
343 SLsmg_normal();
344 }
345 else
346 SLsmg_printf("%03d", val);
347 }
348
ctl_volume(int ch,int val)349 static void ctl_volume(int ch, int val)
350 {
351 if(ch >= 16)
352 return;
353 if (!ctl.trace_playing)
354 return;
355 SLsmg_gotorc(8+ch, SLtt_Screen_Cols-16);
356 SLsmg_printf("%3d", (val*100)/127);
357 }
358
ctl_expression(int ch,int val)359 static void ctl_expression(int ch, int val)
360 {
361 if(ch >= 16)
362 return;
363 if (!ctl.trace_playing)
364 return;
365 SLsmg_gotorc(8+ch, SLtt_Screen_Cols-12);
366 SLsmg_printf("%3d", (val*100)/127);
367 }
368
ctl_panning(int ch,int val)369 static void ctl_panning(int ch, int val)
370 {
371 if(ch >= 16)
372 return;
373 if (!ctl.trace_playing)
374 return;
375 SLsmg_gotorc(8+ch, SLtt_Screen_Cols-8);
376 if (val==NO_PANNING)
377 SLsmg_write_string(" ");
378 else if (val<5)
379 SLsmg_write_string(" L ");
380 else if (val>123)
381 SLsmg_write_string(" R ");
382 else if (val>60 && val<68)
383 SLsmg_write_string(" C ");
384 else
385 {
386 /* wprintw(dftwin, "%+02d", (100*(val-64))/64); */
387 val = (100*(val-64))/64; /* piss on curses */
388 if (val<0)
389 {
390 SLsmg_write_char('-');
391 val=-val;
392 }
393 else SLsmg_write_char('+');
394 SLsmg_printf("%02d", val);
395 }
396 }
397
ctl_sustain(int ch,int val)398 static void ctl_sustain(int ch, int val)
399 {
400 if(ch >= 16)
401 return;
402 if (!ctl.trace_playing)
403 return;
404 SLsmg_gotorc(8+ch, SLtt_Screen_Cols-4);
405 if (val) SLsmg_write_char('S');
406 else SLsmg_write_char(' ');
407 }
408
ctl_pitch_bend(int ch,int val)409 static void ctl_pitch_bend(int ch, int val)
410 {
411 if(ch >= 16)
412 return;
413 if (!ctl.trace_playing)
414 return;
415 SLsmg_gotorc(8+ch, SLtt_Screen_Cols-2);
416 if (val==-1) SLsmg_write_char('=');
417 else if (val>0x2000) SLsmg_write_char('+');
418 else if (val<0x2000) SLsmg_write_char('-');
419 else SLsmg_write_char(' ');
420 }
421
ctl_reset(void)422 static void ctl_reset(void)
423 {
424 int i,j;
425 if (!ctl.trace_playing)
426 return;
427 for (i=0; i<16; i++)
428 {
429 SLsmg_gotorc(8+i, 3);
430 for (j=0; j<SLtt_Screen_Cols-24; j++)
431 SLsmg_write_char('.');
432 if(ISDRUMCHANNEL(i))
433 ctl_program(i, channel[i].bank);
434 else
435 ctl_program(i, channel[i].program);
436 ctl_volume(i, channel[i].volume);
437 ctl_expression(i, channel[i].expression);
438 ctl_panning(i, channel[i].panning);
439 ctl_sustain(i, channel[i].sustain);
440 if(channel[i].pitchbend == 0x2000 && channel[i].mod.val > 0)
441 ctl_pitch_bend(i, -1);
442 else
443 ctl_pitch_bend(i, channel[i].pitchbend);
444 }
445 _ctl_refresh();
446 }
447
448 /***********************************************************************/
449
450 /*ARGSUSED*/
ctl_open(int using_stdin,int using_stdout)451 static int ctl_open(int using_stdin, int using_stdout)
452 {
453 #ifdef TIOCGWINSZ
454 struct winsize size;
455 #endif
456 int i;
457 int save_lines, save_cols;
458
459 SLtt_get_terminfo();
460 /*
461 * Save the terminfo values for lines and cols
462 * then detect the real values.
463 */
464 save_lines = SLtt_Screen_Rows;
465 save_cols = SLtt_Screen_Cols;
466 #ifdef TIOCGWINSZ
467 if (!ioctl(0, TIOCGWINSZ, &size)) {
468 SLtt_Screen_Cols=size.ws_col;
469 SLtt_Screen_Rows=size.ws_row;
470 } else
471 #endif
472 {
473 SLtt_Screen_Cols=atoi(getenv("COLUMNS"));
474 SLtt_Screen_Rows=atoi(getenv("LINES"));
475 }
476 if (!SLtt_Screen_Cols || !SLtt_Screen_Rows) {
477 SLtt_Screen_Rows = save_lines;
478 SLtt_Screen_Cols = save_cols;
479 }
480 SLang_init_tty(7, 0, 0);
481 SLsmg_init_smg();
482 SLtt_set_color (20, "Normal", "lightgray", "black");
483 SLtt_set_color (21, "HighLight", "white", "black");
484 SLtt_set_color (22, "Reverse", "black", "white");
485 SLtt_Use_Ansi_Colors = 1;
486 SLtt_Term_Cannot_Scroll = 1;
487
488 ctl.opened=1;
489
490 SLsmg_cls();
491
492 ctl_head();
493
494 SLsmg_printfrc(3,0, "File:");
495 if (ctl.trace_playing)
496 {
497 SLsmg_printfrc(4,0, "Time:");
498 SLsmg_gotorc(4,6+6+1);
499 SLsmg_write_char('/');
500 SLsmg_gotorc(4,40);
501 SLsmg_printf("Voices: / %d", voices);
502 }
503 else
504 {
505 SLsmg_printfrc(4,0, "Time:");
506 SLsmg_printfrc(4,13, "/");
507 }
508 SLsmg_printfrc(4,SLtt_Screen_Cols-20, "Master volume:");
509 SLsmg_gotorc(5,0);
510 for (i=0; i<SLtt_Screen_Cols; i++)
511 SLsmg_write_char('_');
512 if (ctl.trace_playing)
513 {
514 SLsmg_printfrc(6,0, "Ch");
515 SLsmg_printfrc(6,SLtt_Screen_Cols-20, "Prg Vol Exp Pan S B");
516 SLsmg_gotorc(7,0);
517 for (i=0; i<SLtt_Screen_Cols; i++)
518 SLsmg_write_char('-');
519 for (i=0; i<16; i++)
520 {
521 SLsmg_printfrc(8+i, 0, "%02d", i+1);
522 }
523 set_trace_loop_hook(update_indicator);
524 indicator_width=SLtt_Screen_Cols-2;
525 if(indicator_width<40)
526 indicator_width=40;
527 lyric_row=2;
528 }
529 else
530 msg_row = 6;
531 memset(comment_indicator_buffer =
532 (char *)safe_malloc(indicator_width), 0, indicator_width);
533 memset(current_indicator_message =
534 (char *)safe_malloc(indicator_width), 0, indicator_width);
535 _ctl_refresh();
536
537 return 0;
538 }
539
ctl_close(void)540 static void ctl_close(void)
541 {
542 if (ctl.opened)
543 {
544 SLsmg_normal();
545 SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
546 SLsmg_refresh();
547 SLsmg_reset_smg();
548 SLang_reset_tty();
549 ctl.opened=0;
550 }
551 }
552
ctl_read(int32 * valp)553 static int ctl_read(int32 *valp)
554 {
555 int c;
556
557 if (cuepoint_pending) {
558 *valp = cuepoint;
559 cuepoint_pending = 0;
560 return RC_FORWARD;
561 }
562
563 if (!SLang_input_pending(0))
564 return RC_NONE;
565
566 c=SLang_getkey();
567 switch(c)
568 {
569 case 'h':
570 case '?':
571 ctl_help_mode();
572 return RC_NONE;
573
574 case 'V':
575 *valp=10;
576 return RC_CHANGE_VOLUME;
577 case 'v':
578 *valp=-10;
579 return RC_CHANGE_VOLUME;
580 case 'q':
581 return RC_QUIT;
582 case 'n':
583 return RC_NEXT;
584 case 'p':
585 return RC_REALLY_PREVIOUS;
586 case 'r':
587 return RC_RESTART;
588
589 case 'f':
590 *valp=play_mode->rate;
591 return RC_FORWARD;
592 case 'b':
593 *valp=play_mode->rate;
594 return RC_BACK;
595 case 's':
596 return RC_TOGGLE_PAUSE;
597 }
598 return RC_NONE;
599 }
600
ctl_write(char * valp,int32 size)601 static int ctl_write(char *valp, int32 size)
602 {
603 static int warned = 0;
604 if (!warned) {
605 fprintf(stderr, "Warning: using stdout with slang interface will not\n"
606 "give the desired effect.\n");
607 warned = 1;
608 }
609 return write(STDOUT_FILENO, valp, size);
610 }
611
612 /*ARGSUSED*/
ctl_lyric(int lyricid)613 static void ctl_lyric(int lyricid)
614 {
615 char *lyric;
616
617 lyric = event2string(lyricid);
618 if(lyric != NULL)
619 {
620 if(*lyric == ME_KARAOKE_LYRIC)
621 {
622 if(lyric[1] == '/')
623 {
624 display_lyric("\n", LYRIC_WORD_NOSEP);
625 display_lyric(lyric + 2, LYRIC_WORD_NOSEP);
626 }
627 else if(lyric[1] == '\\')
628 {
629 display_lyric("\r", LYRIC_WORD_NOSEP);
630 display_lyric(lyric + 2, LYRIC_WORD_NOSEP);
631 }
632 else if(lyric[1] == '@' && lyric[2] == 'T')
633 {
634 if(ctl.trace_playing)
635 {
636 display_lyric("\n", LYRIC_WORD_NOSEP);
637 display_lyric(lyric + 3, LYRIC_WORD_SEP);
638 }
639 else
640 display_title(lyric + 3);
641 }
642 else if(lyric[1] == '@' && lyric[2] == 'L')
643 {
644 init_lyric(lyric + 3);
645 }
646 else
647 display_lyric(lyric + 1, LYRIC_WORD_NOSEP);
648 }
649 else
650 {
651 if(*lyric == ME_CHORUS_TEXT || *lyric == ME_INSERT_TEXT)
652 display_lyric("\r", LYRIC_WORD_SEP);
653 display_lyric(lyric + 1, LYRIC_WORD_SEP);
654 }
655 }
656 }
657
cmsg(int type,int verbosity_level,char * fmt,...)658 static int cmsg(int type, int verbosity_level, char *fmt, ...)
659 {
660 va_list ap;
661 char p[1000];
662 if ((type==CMSG_TEXT || type==CMSG_INFO || type==CMSG_WARNING) &&
663 ctl.verbosity<verbosity_level)
664 return 0;
665 va_start(ap, fmt);
666 if (!ctl.opened)
667 {
668 vfprintf(stderr, fmt, ap);
669 fprintf(stderr, "\n");
670 }
671 else if (ctl.trace_playing)
672 {
673 switch(type)
674 {
675 /* Pretty pointless to only have one line for messages, but... */
676 case CMSG_WARNING:
677 case CMSG_ERROR:
678 case CMSG_FATAL:
679 SLsmg_gotorc(2,0);
680 SLsmg_erase_eol();
681 SLsmg_bold();
682 vsnprintf(p, sizeof(p), fmt, ap);
683 SLsmg_write_string(p);
684 SLsmg_normal();
685 _ctl_refresh();
686 if (type==CMSG_WARNING)
687 sleep(1); /* Don't you just _HATE_ it when programs do this... */
688 else
689 sleep(2);
690 SLsmg_gotorc(2,0);
691 SLsmg_erase_eol();
692 _ctl_refresh();
693 break;
694 }
695 }
696 else
697 {
698 SLsmg_gotorc(msg_row++,0);
699 if(msg_row==SLtt_Screen_Rows){
700 int i;
701 msg_row=6;
702 for(i=6;i<=SLtt_Screen_Rows;i++){
703 SLsmg_gotorc(i,0);
704 SLsmg_erase_eol();
705 }
706 }
707 switch(type)
708 {
709 default:
710 vsnprintf(p, sizeof(p), fmt, ap);
711 SLsmg_write_string(p);
712 _ctl_refresh();
713 break;
714
715 case CMSG_WARNING:
716 SLsmg_bold();
717 vsnprintf(p, sizeof(p), fmt, ap);
718 SLsmg_write_string(p);
719 SLsmg_normal();
720 _ctl_refresh();
721 break;
722
723 case CMSG_ERROR:
724 case CMSG_FATAL:
725 SLsmg_bold();
726 vsnprintf(p, sizeof(p), fmt, ap);
727 SLsmg_write_string(p);
728 SLsmg_normal();
729 _ctl_refresh();
730 if (type==CMSG_FATAL)
731 sleep(2);
732 break;
733 }
734 }
735
736 va_end(ap);
737 return 0;
738 }
739
740 /* Indicator */
741
reset_indicator(void)742 static void reset_indicator(void)
743 {
744 int i;
745
746 memset(comment_indicator_buffer, ' ', indicator_width - 1);
747 comment_indicator_buffer[indicator_width - 1] = '\0';
748
749 next_indicator_chan = -1;
750 indicator_last_update = get_current_calender_time();
751 indicator_mode = INDICATOR_DEFAULT;
752 indicator_msgptr = NULL;
753
754 for(i = 0; i < MAX_CHANNELS; i++)
755 {
756 instr_comment[i].last_note_on = 0.0;
757 instr_comment[i].comm = channel_instrum_name(i);
758 }
759 }
760
update_indicator(void)761 static void update_indicator(void)
762 {
763 double t;
764 int i;
765 char c;
766
767 t = get_current_calender_time();
768 if(indicator_mode != INDICATOR_DEFAULT)
769 {
770 int save_chan;
771 if(indicator_last_update + SCRMODE_OUT_THRESHOLD > t)
772 return;
773 save_chan = next_indicator_chan;
774 reset_indicator();
775 next_indicator_chan = save_chan;
776 }
777 else
778 {
779 if(indicator_last_update + INDICATOR_UPDATE_TIME > t)
780 return;
781 }
782 indicator_last_update = t;
783
784 if(indicator_msgptr != NULL && *indicator_msgptr == '\0')
785 indicator_msgptr = NULL;
786
787 if(indicator_msgptr == NULL)
788 {
789 if(next_indicator_chan >= 0 &&
790 instr_comment[next_indicator_chan].comm != NULL &&
791 *instr_comment[next_indicator_chan].comm)
792 {
793 current_indicator_chan = next_indicator_chan;
794 }
795 else
796 {
797 int prog;
798
799 prog = instr_comment[current_indicator_chan].prog;
800 for(i = 0; i < MAX_CHANNELS; i++)
801 {
802 current_indicator_chan++;
803 if(current_indicator_chan == MAX_CHANNELS)
804 current_indicator_chan = 0;
805
806
807 if(instr_comment[current_indicator_chan].comm != NULL &&
808 *instr_comment[current_indicator_chan].comm &&
809 instr_comment[current_indicator_chan].prog != prog &&
810 (instr_comment[current_indicator_chan].last_note_on + CHECK_NOTE_SLEEP_TIME > t ||
811 instr_comment[current_indicator_chan].disp_cnt == 0))
812 break;
813 }
814
815 if(i == MAX_CHANNELS)
816 return;
817 }
818 next_indicator_chan = -1;
819
820 if(instr_comment[current_indicator_chan].comm == NULL ||
821 *instr_comment[current_indicator_chan].comm == '\0')
822 return;
823
824 snprintf(current_indicator_message, indicator_width, "%03d:%s ",
825 instr_comment[current_indicator_chan].prog,
826 instr_comment[current_indicator_chan].comm);
827 instr_comment[current_indicator_chan].disp_cnt++;
828 indicator_msgptr = current_indicator_message;
829 }
830
831 c = *indicator_msgptr++;
832
833 for(i = 0; i < indicator_width - 2; i++)
834 comment_indicator_buffer[i] = comment_indicator_buffer[i + 1];
835 comment_indicator_buffer[indicator_width - 2] = c;
836 SLsmg_printfrc(2,0,comment_indicator_buffer);
837 ctl_refresh();
838 }
839
display_lyric(char * lyric,int sep)840 static void display_lyric(char *lyric, int sep)
841 {
842 char *p;
843 int len, idlen, sepoffset;
844 static int crflag = 0;
845
846 if(lyric == NULL)
847 {
848 indicator_last_update = get_current_calender_time();
849 crflag = 0;
850 return;
851 }
852
853 if(indicator_mode != INDICATOR_LYRIC || crflag)
854 {
855 memset(comment_indicator_buffer, 0, indicator_width);
856 SLsmg_gotorc(lyric_row,0);
857 SLsmg_erase_eol();
858 ctl_refresh();
859 indicator_mode = INDICATOR_LYRIC;
860 crflag = 0;
861 }
862
863 if(*lyric == '\0')
864 {
865 indicator_last_update = get_current_calender_time();
866 return;
867 }
868 else if(*lyric == '\n')
869 {
870 if(!ctl.trace_playing)
871 {
872 crflag = 1;
873 lyric_row++;
874 SLsmg_gotorc(0,lyric_row);
875 return;
876 }
877 else
878 lyric = " / ";
879 }
880
881 if(strchr(lyric, '\r') != NULL)
882 {
883 crflag = 1;
884 if(!ctl.trace_playing)
885 {
886 int i;
887 for(i = title_row+1; i <= lyric_row; i++)
888 {
889 SLsmg_gotorc(i,0);
890 SLsmg_erase_eol();
891 }
892 lyric_row = title_row+1;
893 }
894 if(lyric[0] == '\r' && lyric[1] == '\0')
895 {
896 indicator_last_update = get_current_calender_time();
897 return;
898 }
899 }
900
901 idlen = strlen(comment_indicator_buffer);
902 len = strlen(lyric);
903
904 if(sep)
905 {
906 while(idlen > 0 && comment_indicator_buffer[idlen - 1] == ' ')
907 comment_indicator_buffer[--idlen] = '\0';
908 while(len > 0 && lyric[len - 1] == ' ')
909 len--;
910 }
911
912 if(len == 0)
913 {
914 /* update time stamp */
915 indicator_last_update = get_current_calender_time();
916 reuse_mblock(&tmpbuffer);
917 return;
918 }
919
920 sepoffset = (sep != 0);
921
922 if(len >= indicator_width - 2)
923 {
924 memcpy(comment_indicator_buffer, lyric, indicator_width - 1);
925 comment_indicator_buffer[indicator_width - 1] = '\0';
926 }
927 else if(idlen == 0)
928 {
929 memcpy(comment_indicator_buffer, lyric, len);
930 comment_indicator_buffer[len] = '\0';
931 }
932 else if(len + idlen + 2 < indicator_width)
933 {
934 if(sep)
935 comment_indicator_buffer[idlen] = sep;
936 memcpy(comment_indicator_buffer + idlen + sepoffset, lyric, len);
937 comment_indicator_buffer[idlen + sepoffset + len] = '\0';
938 }
939 else
940 {
941 int spaces;
942 p = comment_indicator_buffer;
943 spaces = indicator_width - idlen - 2;
944
945 while(spaces < len)
946 {
947 char *q;
948
949 /* skip one word */
950 if((q = strchr(p, ' ')) == NULL)
951 {
952 p = NULL;
953 break;
954 }
955
956 do q++; while(*q == ' ');
957 spaces += (q - p);
958 p = q;
959 }
960
961 if(p == NULL)
962 {
963 SLsmg_gotorc(lyric_row,0);
964 SLsmg_erase_eol();
965 memcpy(comment_indicator_buffer, lyric, len);
966 comment_indicator_buffer[len] = '\0';
967 }
968 else
969 {
970 int d, l, r, i, j;
971
972 d = (p - comment_indicator_buffer);
973 l = strlen(p);
974 r = len - (indicator_width - 2 - l - d);
975
976 j = d - r;
977 for(i = 0; i < j; i++)
978 comment_indicator_buffer[i] = ' ';
979 for(i = 0; i < l; i++)
980 comment_indicator_buffer[j + i] =
981 comment_indicator_buffer[d + i];
982 if(sep)
983 comment_indicator_buffer[j + i] = sep;
984 memcpy(comment_indicator_buffer + j + i + sepoffset, lyric, len);
985 comment_indicator_buffer[j + i + sepoffset + len] = '\0';
986 }
987 }
988
989 SLsmg_printfrc(lyric_row,0,"%s",comment_indicator_buffer);
990 ctl_refresh();
991 reuse_mblock(&tmpbuffer);
992 indicator_last_update = get_current_calender_time();
993 }
994
display_title(char * title)995 static void display_title(char *title)
996 {
997 SLsmg_printfrc(title_row,0,"Title:");
998 SLsmg_bold();
999 SLsmg_printfrc(title_row++,7,"%s", title);
1000 SLsmg_normal();
1001 lyric_row = title_row + 1;
1002 }
1003
init_lyric(char * lang)1004 static void init_lyric(char *lang)
1005 {
1006 int i;
1007
1008 if(ctl.trace_playing)
1009 return;
1010 for(i=6;i<=SLtt_Screen_Rows;i++){
1011 SLsmg_gotorc(i,0);
1012 SLsmg_erase_eol();
1013 }
1014 }
1015
ctl_event(CtlEvent * e)1016 static void ctl_event(CtlEvent *e)
1017 {
1018 switch(e->type)
1019 {
1020 case CTLE_NOW_LOADING:
1021 ctl_file_name((char *)e->v1);
1022 break;
1023 case CTLE_LOADING_DONE:
1024 break;
1025 case CTLE_PLAY_START:
1026 ctl_total_time((int)e->v1);
1027 break;
1028 case CTLE_PLAY_END:
1029 break;
1030 case CTLE_CUEPOINT:
1031 cuepoint = e->v1;
1032 cuepoint_pending = 1;
1033 break;
1034 case CTLE_TEMPO:
1035 break;
1036 case CTLE_METRONOME:
1037 /* update_indicator(); */
1038 break;
1039 case CTLE_CURRENT_TIME:
1040 ctl_current_time((int)e->v1, (int)e->v2);
1041 break;
1042 case CTLE_NOTE:
1043 ctl_note((int)e->v1, (int)e->v2, (int)e->v3, (int)e->v4);
1044 break;
1045 case CTLE_MASTER_VOLUME:
1046 ctl_master_volume((int)e->v1);
1047 break;
1048 case CTLE_PROGRAM:
1049 ctl_program((int)e->v1, (int)e->v2);
1050 break;
1051 case CTLE_VOLUME:
1052 ctl_volume((int)e->v1, (int)e->v2);
1053 break;
1054 case CTLE_EXPRESSION:
1055 ctl_expression((int)e->v1, (int)e->v2);
1056 break;
1057 case CTLE_PANNING:
1058 ctl_panning((int)e->v1, (int)e->v2);
1059 break;
1060 case CTLE_SUSTAIN:
1061 ctl_sustain((int)e->v1, (int)e->v2);
1062 break;
1063 case CTLE_PITCH_BEND:
1064 ctl_pitch_bend((int)e->v1, (int)e->v2);
1065 break;
1066 case CTLE_MOD_WHEEL:
1067 ctl_pitch_bend((int)e->v1, e->v2 ? -1 : 0x2000);
1068 break;
1069 case CTLE_CHORUS_EFFECT:
1070 break;
1071 case CTLE_REVERB_EFFECT:
1072 break;
1073 case CTLE_LYRIC:
1074 ctl_lyric((int)e->v1);
1075 break;
1076 case CTLE_REFRESH:
1077 ctl_refresh();
1078 break;
1079 case CTLE_RESET:
1080 ctl_reset();
1081 break;
1082 }
1083 }
1084
1085 /*
1086 * interface_<id>_loader();
1087 */
interface_s_loader(void)1088 ControlMode *interface_s_loader(void)
1089 {
1090 return &ctl;
1091 }
1092