OSDN Git Service

Import unkotim227
[timidity41/timidity41.git] / interface / gtk_c.c
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     motif_ctl.c: written by Vincent Pagel (pagel@loria.fr) 10/4/95
21
22     A motif interface for TIMIDITY: to prevent X redrawings from
23     interfering with the audio computation, I don't use the XtAppAddWorkProc
24
25     I create a pipe between the timidity process and a Motif interface
26     process forked from the 1st one
27
28     Copied the Motif file to create a Gtk+ interface.
29         - Glenn Trigg 29 Oct 1998
30
31     Modified for TiMidity++
32         - Isaku Yamahata 03 Dec 1998
33 */
34
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif /* HAVE_CONFIG_H*/
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <unistd.h>
42 #include <stdarg.h>
43 #include "_string.h"
44 #include "timidity.h"
45 #include "common.h"
46 #include "instrum.h"
47 #include "playmidi.h"
48 #include "output.h"
49 #include "controls.h"
50 #include "gtk_h.h"
51 #include "readmidi.h"
52
53 static int ctl_open(int using_stdin, int using_stdout);
54 static void ctl_close(void);
55 static int ctl_pass_playing_list(int number_of_files, char *list_of_files[]);
56 static int ctl_read(ptr_size_t *valp);
57 static int cmsg(int type, int verbosity_level, const char *fmt, ...);
58 static void ctl_event(CtlEvent *e);
59
60 static void ctl_refresh(void);
61 static void ctl_total_time(int tt);
62 static void ctl_master_volume(int mv);
63 static void ctl_file_name(char *name);
64 static void ctl_current_time(int secs, int voices);
65 static void ctl_note(int status, int channel, int note, int velocity);
66 static void ctl_program(int ch, int val, char *vp);
67 static void ctl_volume(int channel, int val);
68 static void ctl_expression(int channel, int val);
69 static void ctl_panning(int channel, int val);
70 static void ctl_sustain(int channel, int val);
71 static void ctl_pitch_bend(int channel, int val);
72 static void ctl_reset(void);
73 static void ctl_lyric(int);
74
75
76 /**********************************************/
77 /* export the interface functions */
78
79 #define ctl gtk_control_mode
80 ControlMode ctl =
81 {
82     "gtk+ interface", 'g',
83     "gtk",
84     1,0,0,
85     0,
86     ctl_open,
87     ctl_close,
88     ctl_pass_playing_list,
89     ctl_read,
90     NULL,
91     cmsg,
92     ctl_event
93 };
94
95 static uint32 cuepoint = 0;
96 static int cuepoint_pending = 0;
97
98
99 /***********************************************************************/
100 /* Put controls on the pipe                                            */
101 /***********************************************************************/
102 static int
103 cmsg(int type, int verbosity_level, const char *fmt, ...)
104 {
105     char local[255];
106
107     va_list ap;
108     if ((type==CMSG_TEXT || type==CMSG_INFO || type==CMSG_WARNING) &&
109         ctl.verbosity<verbosity_level)
110         return 0;
111
112     va_start(ap, fmt);
113     if (!ctl.opened) {
114         vfprintf(stderr, fmt, ap);
115         fprintf(stderr, "\n");
116     }
117     else {
118         vsnprintf(local, sizeof(local), fmt, ap);
119         gtk_pipe_int_write(CMSG_MESSAGE);
120         gtk_pipe_int_write(type);
121         gtk_pipe_string_write(local);
122     }
123     va_end(ap);
124     return 0;
125 }
126
127
128 /*
129   ctl_event is stolen from ncurses_c.c
130  */
131 static void ctl_event(CtlEvent *e)
132 {
133     switch (e->type)
134     {
135       case CTLE_NOW_LOADING:
136         ctl_file_name((char*) e->v1);
137         break;
138       case CTLE_LOADING_DONE:
139         break;
140       case CTLE_PLAY_START:
141         ctl_total_time((int) e->v1);
142         break;
143       case CTLE_PLAY_END:
144         break;
145       case CTLE_CUEPOINT:
146         cuepoint = e->v1;
147         cuepoint_pending = 1;
148         break;
149       case CTLE_TEMPO:
150         break;
151       case CTLE_METRONOME:
152         break;
153       case CTLE_CURRENT_TIME:
154         ctl_current_time((int) e->v1, (int) e->v2);
155         break;
156       case CTLE_NOTE:
157         ctl_note((int) e->v1, (int) e->v2, (int) e->v3, (int) e->v4);
158         break;
159       case CTLE_MASTER_VOLUME:
160         ctl_master_volume((int) e->v1);
161         break;
162       case CTLE_PROGRAM:
163         ctl_program((int) e->v1, (int) e->v2, (char*) e->v3);
164         break;
165       case CTLE_VOLUME:
166         ctl_volume((int) e->v1, (int) e->v2);
167         break;
168       case CTLE_EXPRESSION:
169         ctl_expression((int) e->v1, (int) e->v2);
170         break;
171       case CTLE_PANNING:
172         ctl_panning((int) e->v1, (int) e->v2);
173         break;
174       case CTLE_SUSTAIN:
175         ctl_sustain((int) e->v1, (int) e->v2);
176         break;
177       case CTLE_PITCH_BEND:
178         ctl_pitch_bend((int) e->v1, (int) e->v2);
179         break;
180       case CTLE_MOD_WHEEL:
181         ctl_pitch_bend((int) e->v1, e->v2);
182         break;
183       case CTLE_CHORUS_EFFECT:
184         break;
185       case CTLE_REVERB_EFFECT:
186         break;
187       case CTLE_LYRIC:
188         ctl_lyric((int) e->v1);
189         break;
190       case CTLE_REFRESH:
191         ctl_refresh();
192         break;
193       case CTLE_RESET:
194         ctl_reset();
195         break;
196       case CTLE_SPEANA:
197         break;
198     }
199 }
200
201 static void
202 ctl_refresh(void)
203 {
204     /* gtk_pipe_int_write(REFRESH_MESSAGE); */
205 }
206
207 static void
208 ctl_total_time(int tt)
209 {
210     gtk_pipe_int_write(TOTALTIME_MESSAGE);
211     gtk_pipe_int_write(tt);
212 }
213
214 static void
215 ctl_master_volume(int mv)
216 {
217     gtk_pipe_int_write(MASTERVOL_MESSAGE);
218     gtk_pipe_int_write(mv);
219 }
220
221 static void
222 ctl_file_name(char *name)
223 {
224     gtk_pipe_int_write(FILENAME_MESSAGE);
225     gtk_pipe_string_write(name);
226 }
227
228 static void
229 ctl_current_time(int secs, int voices)
230 {
231     gtk_pipe_int_write(CURTIME_MESSAGE);
232     gtk_pipe_int_write(secs);
233     gtk_pipe_int_write(voices);
234 }
235
236 static void
237 ctl_note(int status, int channel, int note, int velocity)
238 {
239     /*   int xl;
240     if (!ctl.trace_playing)
241         return;
242     xl=voice[v].note%(COLS-24);
243     wmove(dftwin, 8+voice[v].channel,xl+3);
244     switch (voice[v].status)
245         {
246         case VOICE_DIE:
247             waddch(dftwin, ',');
248             break;
249         case VOICE_FREE:
250             waddch(dftwin, '.');
251             break;
252         case VOICE_ON:
253             wattron(dftwin, A_BOLD);
254             waddch(dftwin, '0'+(10*voice[v].velocity)/128);
255             wattroff(dftwin, A_BOLD);
256             break;
257         case VOICE_OFF:
258         case VOICE_SUSTAINED:
259             waddch(dftwin, '0'+(10*voice[v].velocity)/128);
260             break;
261         }
262         */
263 }
264
265 static void
266 ctl_program(int ch, int val, char *vp)
267 {
268 /*  if (!ctl.trace_playing)
269     return;
270   wmove(dftwin, 8+ch, COLS-20);
271   if (ISDRUMCHANNEL(ch))
272     {
273       wattron(dftwin, A_BOLD);
274       wprintw(dftwin, "%03d", val);
275       wattroff(dftwin, A_BOLD);
276     }
277   else
278     wprintw(dftwin, "%03d", val);
279     */
280 }
281
282 static void
283 ctl_volume(int channel, int val)
284 {
285     /*
286       if (!ctl.trace_playing)
287     return;
288   wmove(dftwin, 8+channel, COLS-16);
289   wprintw(dftwin, "%3d", (val*100)/127);
290   */
291 }
292
293 static void
294 ctl_expression(int channel, int val)
295 {
296 /*  if (!ctl.trace_playing)
297     return;
298   wmove(dftwin, 8+channel, COLS-12);
299   wprintw(dftwin, "%3d", (val*100)/127);
300   */
301 }
302
303 static void
304 ctl_panning(int channel, int val)
305 {
306 /*  if (!ctl.trace_playing)
307     return;
308
309   if (val==NO_PANNING)
310     waddstr(dftwin, "   ");
311   else if (val<5)
312     waddstr(dftwin, " L ");
313   else if (val>123)
314     waddstr(dftwin, " R ");
315   else if (val>60 && val<68)
316     waddstr(dftwin, " C ");
317     */
318 }
319
320 static void
321 ctl_sustain(int channel, int val)
322 {
323 /*
324   if (!ctl.trace_playing)
325     return;
326
327   if (val) waddch(dftwin, 'S');
328   else waddch(dftwin, ' ');
329   */
330 }
331
332 static void
333 ctl_pitch_bend(int channel, int val)
334 {
335 /*  if (!ctl.trace_playing)
336     return;
337
338   if (val>0x2000) waddch(dftwin, '+');
339   else if (val<0x2000) waddch(dftwin, '-');
340   else waddch(dftwin, ' ');
341   */
342 }
343
344 static void
345 ctl_reset(void)
346 {
347 /*  int i,j;
348   if (!ctl.trace_playing)
349     return;
350   for (i=0; i<16; i++)
351     {
352         ctl_program(i, channel[i].program);
353         ctl_volume(i, channel[i].volume);
354         ctl_expression(i, channel[i].expression);
355         ctl_panning(i, channel[i].panning);
356         ctl_sustain(i, channel[i].sustain);
357         ctl_pitch_bend(i, channel[i].pitchbend);
358     }
359   ctl_refresh();
360   */
361 }
362
363 static void
364 ctl_lyric(int lyricid)
365 {
366     const char  *lyric;
367     static char lyric_buf[300];
368
369     lyric = event2string(lyricid);
370     if (lyric != NULL)
371     {
372         if (lyric[0] == ME_KARAOKE_LYRIC)
373         {
374             if (!lyric[1])
375                 return;
376             if (lyric[1] == '/' || lyric[1] == '\\')
377             {
378                 snprintf(lyric_buf, sizeof(lyric_buf), "\n%s", lyric + 2);
379                 gtk_pipe_int_write(LYRIC_MESSAGE);
380                 gtk_pipe_string_write(lyric_buf);
381             }
382             else if (lyric[1] == '@')
383             {
384                 if (lyric[2] == 'L')
385                     snprintf(lyric_buf, sizeof(lyric_buf), "Language: %s\n", lyric + 3);
386                 else if (lyric[2] == 'T')
387                     snprintf(lyric_buf, sizeof(lyric_buf), "Title: %s\n", lyric + 3);
388                 else
389                     snprintf(lyric_buf, sizeof(lyric_buf), "%s\n", lyric + 1);
390                 gtk_pipe_int_write(LYRIC_MESSAGE);
391                 gtk_pipe_string_write(lyric_buf);
392             }
393             else
394             {
395                 strncpy(lyric_buf, lyric + 1, sizeof(lyric_buf) - 1);
396                 gtk_pipe_int_write(LYRIC_MESSAGE);
397                 gtk_pipe_string_write(lyric_buf);
398             }
399         }
400         else
401         {
402             strncpy(lyric_buf, lyric + 1, sizeof(lyric_buf) - 1);
403             gtk_pipe_int_write(LYRIC_MESSAGE);
404             gtk_pipe_string_write(lyric_buf);
405         }
406     }
407 }
408
409 /***********************************************************************/
410 /* OPEN THE CONNECTION                                                */
411 /***********************************************************************/
412 static int
413 ctl_open(int using_stdin, int using_stdout)
414 {
415     ctl.opened=1;
416
417     /* The child process won't come back from this call  */
418     gtk_pipe_open();
419
420     return 0;
421 }
422
423 /* Tells the window to disapear */
424 static void
425 ctl_close(void)
426 {
427     if (ctl.opened) {
428         gtk_pipe_int_write(CLOSE_MESSAGE);
429         ctl.opened=0;
430     }
431 }
432
433
434 /*
435  * Read information coming from the window in a BLOCKING way
436  */
437 static int
438 ctl_blocking_read(ptr_size_t *valp)
439 {
440     int command;
441     int new_volume;
442     int new_centiseconds;
443
444     gtk_pipe_int_read(&command);
445
446     while (1)    /* Loop after pause sleeping to treat other buttons! */
447     {
448
449         switch (command) {
450         case GTK_CHANGE_VOLUME:
451             gtk_pipe_int_read(&new_volume);
452             *valp= new_volume - output_amplification;
453             return RC_CHANGE_VOLUME;
454
455         case GTK_CHANGE_LOCATOR:
456             gtk_pipe_int_read(&new_centiseconds);
457             *valp= new_centiseconds*(play_mode->rate / 100);
458             return RC_JUMP;
459
460         case GTK_QUIT:
461             return RC_QUIT;
462
463         case GTK_PLAY_FILE:
464             return RC_LOAD_FILE;
465
466         case GTK_NEXT:
467             return RC_NEXT;
468
469         case GTK_PREV:
470             return RC_REALLY_PREVIOUS;
471
472         case GTK_RESTART:
473             return RC_RESTART;
474
475         case GTK_FWD:
476             *valp=play_mode->rate;
477             return RC_FORWARD;
478
479         case GTK_RWD:
480             *valp=play_mode->rate;
481             return RC_BACK;
482
483         case GTK_KEYUP:
484             *valp = 1;
485             return RC_KEYUP;
486
487         case GTK_KEYDOWN:
488             *valp = -1;
489             return RC_KEYDOWN;
490
491         case GTK_SLOWER:
492             *valp = 1;
493             return RC_SPEEDDOWN;
494
495         case GTK_FASTER:
496             *valp = 1;
497             return RC_SPEEDUP;
498         }
499
500
501         if (command==GTK_PAUSE) {
502             gtk_pipe_int_read(&command); /* Blocking reading => Sleep ! */
503             if (command==GTK_PAUSE)
504                 return RC_NONE; /* Resume where we stopped */
505         }
506         else {
507             fprintf(stderr,"gtk UNKNOWN RC_MESSAGE %i" NLS,command);
508             return RC_NONE;
509         }
510     }
511 }
512
513 /*
514  * Read information coming from the window in a non blocking way
515  */
516 static int ctl_read(ptr_size_t *valp)
517 {
518     int num;
519
520     /* We don't wan't to lock on reading  */
521     num = gtk_pipe_read_ready();
522
523     if (num==0)
524         return RC_NONE;
525
526     return(ctl_blocking_read(valp));
527 #if 0
528     num = ctl_blocking_read(valp);
529     fprintf (stderr, "cmd=%i", num);
530     return num;
531 #endif
532 }
533
534 static int
535 ctl_pass_playing_list(int number_of_files, char *list_of_files[])
536 {
537     int i=0;
538     char file_to_play[1000];
539     int command;
540     int32 val;
541
542     if ( number_of_files > 0 ) {
543         /* Pass the list to the interface */
544         gtk_pipe_int_write(FILE_LIST_MESSAGE);
545         gtk_pipe_int_write(number_of_files);
546         for (i=0;i<number_of_files;i++)
547             gtk_pipe_string_write(list_of_files[i]);
548
549         /* Ask the interface for a filename to play -> begin to play automatically */
550         gtk_pipe_int_write(NEXT_FILE_MESSAGE);
551     }
552
553     command = ctl_blocking_read(&val);
554
555     /* Main Loop */
556     for (;;) {
557         if (command==RC_LOAD_FILE) {
558             /* Read a LoadFile command */
559             gtk_pipe_string_read(file_to_play);
560             command=play_midi_file(file_to_play);
561         }
562         else {
563             if (command==RC_QUIT)
564                 return 0;
565             if (command==RC_ERROR)
566                 command=RC_TUNE_END; /* Launch next file */
567
568
569             switch (command) {
570             case RC_NEXT:
571                 gtk_pipe_int_write(NEXT_FILE_MESSAGE);
572                 break;
573             case RC_REALLY_PREVIOUS:
574                 gtk_pipe_int_write(PREV_FILE_MESSAGE);
575                 break;
576             case RC_TUNE_END:
577                 gtk_pipe_int_write(TUNE_END_MESSAGE);
578                 break;
579             default:
580                 printf("PANIC !!! OTHER COMMAND ERROR ?!?! %i" NLS,command);
581             }
582
583             command = ctl_blocking_read(&val);
584         }
585     }
586     return 0;
587 }
588
589 /*
590  * interface_<id>_loader();
591  */
592 ControlMode *interface_g_loader(void)
593 {
594     return &ctl;
595 }