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 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
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif /* HAVE_CONFIG_H */
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <stdarg.h>
36 #ifndef NO_STRING_H
37 #include <string.h>
38 #else
39 #include <strings.h>
40 #endif
41
42 #include "timidity.h"
43 #include "common.h"
44 #include "instrum.h"
45 #include "playmidi.h"
46 #include "readmidi.h"
47 #include "output.h"
48 #include "controls.h"
49 #include "motif.h"
50 #include "miditrace.h"
51
52 static void ctl_refresh(void);
53 static void ctl_total_time(int tt);
54 static void ctl_master_volume(int mv);
55 static void ctl_file_name(char *name);
56 static void ctl_current_time(int secs, int v);
57 static void ctl_lyric(int lyricid);
58 static int ctl_open(int using_stdin, int using_stdout);
59 static void ctl_close(void);
60 static int ctl_read(int32 *valp);
61 static int cmsg(int type, int verbosity_level, char *fmt, ...);
62 static int ctl_pass_playing_list(int number_of_files, char *list_of_files[]);
63 static void ctl_event(CtlEvent *e);
64
65 static int motif_ready = 0;
66
67 /**********************************************/
68 /* export the interface functions */
69
70 #define ctl motif_control_mode
71
72 ControlMode ctl=
73 {
74 "motif interface", 'm',
75 "motif",
76 1,0,0,
77 0,
78 ctl_open,
79 ctl_close,
80 ctl_pass_playing_list,
81 ctl_read,
82 NULL,
83 cmsg,
84 ctl_event
85 };
86
87 static uint32 cuepoint = 0;
88 static int cuepoint_pending = 0;
89
90
91 /***********************************************************************/
92 /* Put controls on the pipe */
93 /***********************************************************************/
cmsg(int type,int verbosity_level,char * fmt,...)94 static int cmsg(int type, int verbosity_level, char *fmt, ...)
95 {
96 char local[255];
97
98 va_list ap;
99 if ((type==CMSG_TEXT || type==CMSG_INFO || type==CMSG_WARNING) &&
100 ctl.verbosity<verbosity_level)
101 return 0;
102
103 va_start(ap, fmt);
104 if (!motif_ready)
105 {
106 vfprintf(stderr, fmt, ap);
107 fprintf(stderr, NLS);
108 }
109 else
110 {
111 vsnprintf(local, sizeof(local), fmt, ap);
112 m_pipe_int_write(CMSG_MESSAGE);
113 m_pipe_int_write(type);
114 m_pipe_string_write(local);
115 }
116 va_end(ap);
117 return 0;
118 }
119
120
_ctl_refresh(void)121 static void _ctl_refresh(void)
122 {
123 /* m_pipe_int_write(REFRESH_MESSAGE); */
124 }
125
ctl_refresh(void)126 static void ctl_refresh(void)
127 {
128 if (ctl.trace_playing)
129 _ctl_refresh();
130 }
131
ctl_total_time(int tt)132 static void ctl_total_time(int tt)
133 {
134 int secs=tt/play_mode->rate;
135
136 m_pipe_int_write(TOTALTIME_MESSAGE);
137 m_pipe_int_write(secs);
138 }
139
ctl_master_volume(int mv)140 static void ctl_master_volume(int mv)
141 {
142 m_pipe_int_write(MASTERVOL_MESSAGE);
143 m_pipe_int_write(mv);
144 }
145
ctl_file_name(char * name)146 static void ctl_file_name(char *name)
147 {
148 m_pipe_int_write(FILENAME_MESSAGE);
149 m_pipe_string_write(name);
150 }
151
ctl_current_time(int secs,int v)152 static void ctl_current_time(int secs, int v)
153 {
154 m_pipe_int_write(CURTIME_MESSAGE);
155 m_pipe_int_write(secs);
156 m_pipe_int_write(v);
157 }
158
ctl_lyric(int lyricid)159 static void ctl_lyric(int lyricid)
160 {
161 char *lyric;
162 static char lyric_buf[300];
163
164 lyric = event2string(lyricid);
165 if(lyric != NULL)
166 {
167 if(lyric[0] == ME_KARAOKE_LYRIC)
168 {
169 if(!lyric[1])
170 return;
171 if(lyric[1] == '/' || lyric[1] == '\\')
172 {
173 snprintf(lyric_buf, sizeof(lyric_buf), "\n%s", lyric + 2);
174 m_pipe_int_write(LYRIC_MESSAGE);
175 m_pipe_string_write(lyric_buf);
176 }
177 else if(lyric[1] == '@')
178 {
179 if(lyric[2] == 'L')
180 snprintf(lyric_buf, sizeof(lyric_buf), "Language: %s\n", lyric + 3);
181 else if(lyric[2] == 'T')
182 snprintf(lyric_buf, sizeof(lyric_buf), "Title: %s\n", lyric + 3);
183 else
184 snprintf(lyric_buf, sizeof(lyric_buf), "%s\n", lyric + 1);
185 m_pipe_int_write(LYRIC_MESSAGE);
186 m_pipe_string_write(lyric_buf);
187 }
188 else
189 {
190 strncpy(lyric_buf, lyric + 1, sizeof(lyric_buf) - 1);
191 m_pipe_int_write(LYRIC_MESSAGE);
192 m_pipe_string_write(lyric_buf);
193 }
194 }
195 else
196 {
197 strncpy(lyric_buf, lyric + 1, sizeof(lyric_buf) - 1);
198 m_pipe_int_write(LYRIC_MESSAGE);
199 m_pipe_string_write(lyric_buf);
200 }
201 }
202 }
203
ctl_event(CtlEvent * e)204 static void ctl_event(CtlEvent *e)
205 {
206 switch(e->type)
207 {
208 case CTLE_NOW_LOADING:
209 ctl_file_name((char *)e->v1);
210 break;
211 case CTLE_PLAY_START:
212 ctl_total_time((int)e->v1);
213 break;
214 case CTLE_CUEPOINT:
215 cuepoint = e->v1;
216 cuepoint_pending = 1;
217 break;
218 case CTLE_CURRENT_TIME:
219 ctl_current_time((int)e->v1, (int)e->v2);
220 break;
221 case CTLE_MASTER_VOLUME:
222 ctl_master_volume((int)e->v1);
223 break;
224 case CTLE_LYRIC:
225 ctl_lyric((int)e->v1);
226 break;
227 case CTLE_REFRESH:
228 ctl_refresh();
229 break;
230 }
231 }
232
233
234 /***********************************************************************/
235 /* OPEN THE CONNECTION */
236 /***********************************************************************/
237 /*ARGSUSED*/
ctl_open(int using_stdin,int using_stdout)238 static int ctl_open(int using_stdin, int using_stdout)
239 {
240 ctl.opened=1;
241 #if 0
242 ctl.trace_playing=1; /* Default mode with Motif interface */
243 #endif
244
245 /* The child process won't come back from this call */
246 m_pipe_open();
247
248 return 0;
249 }
250
251 /* Tells the window to disapear */
ctl_close(void)252 static void ctl_close(void)
253 {
254 if (ctl.opened)
255 {
256 m_pipe_int_write(CLOSE_MESSAGE);
257 ctl.opened=0;
258 motif_ready = 0;
259 }
260 }
261
262
263 /*
264 * Read information coming from the window in a BLOCKING way
265 */
ctl_blocking_read(int32 * valp)266 static int ctl_blocking_read(int32 *valp)
267 {
268 int command;
269 int new_volume;
270 int new_secs;
271 int i=0, nfiles;
272 char buf[256][256];
273 char **ret, *files[256];
274
275 m_pipe_int_read(&command);
276
277 for(;;) /* Loop after pause sleeping to treat other buttons! */
278 {
279
280 switch(command)
281 {
282 case MOTIF_CHANGE_VOLUME:
283 m_pipe_int_read(&new_volume);
284 *valp= new_volume - amplification ;
285 return RC_CHANGE_VOLUME;
286
287 case MOTIF_CHANGE_LOCATOR:
288 m_pipe_int_read(&new_secs);
289 *valp= new_secs * play_mode->rate;
290 return RC_JUMP;
291
292 case MOTIF_QUIT:
293 return RC_QUIT;
294
295 case MOTIF_PLAY_FILE:
296 return RC_LOAD_FILE;
297
298 case MOTIF_NEXT:
299 return RC_NEXT;
300
301 case MOTIF_PREV:
302 return RC_REALLY_PREVIOUS;
303
304 case MOTIF_RESTART:
305 return RC_RESTART;
306
307 case MOTIF_FWD:
308 *valp=play_mode->rate;
309 return RC_FORWARD;
310
311 case MOTIF_RWD:
312 *valp=play_mode->rate;
313 return RC_BACK;
314
315 case MOTIF_EXPAND:
316 m_pipe_int_read(&nfiles);
317 for (i=0;i<nfiles;i++)
318 {
319 m_pipe_string_read(buf[i]);
320 files[i] = buf[i];
321 }
322 ret = expand_file_archives(files, &nfiles);
323 m_pipe_int_write(FILE_LIST_MESSAGE);
324 m_pipe_int_write(nfiles);
325 for (i=0;i<nfiles;i++)
326 m_pipe_string_write(ret[i]);
327 if(ret != files)
328 free(ret);
329 return RC_NONE;
330
331 case MOTIF_PAUSE:
332 return RC_TOGGLE_PAUSE;
333
334 default:
335 fprintf(stderr,"UNKNOWN RC_MESSAGE %d" NLS, command);
336 return RC_NONE;
337 }
338 }
339 }
340
341 /*
342 * Read information coming from the window in a non blocking way
343 */
ctl_read(int32 * valp)344 static int ctl_read(int32 *valp)
345 {
346 int num;
347
348 if (cuepoint_pending) {
349 *valp = cuepoint;
350 cuepoint_pending = 0;
351 return RC_FORWARD;
352 }
353
354 /* We don't wan't to lock on reading */
355 num=m_pipe_read_ready();
356
357 if (num==0)
358 return RC_NONE;
359
360 return(ctl_blocking_read(valp));
361 }
362
ctl_pass_playing_list(int number_of_files,char * list_of_files[])363 static int ctl_pass_playing_list(int number_of_files, char *list_of_files[])
364 {
365 int i=0;
366 char file_to_play[1000];
367 int command;
368 int32 val;
369 int retval;
370
371 motif_ready = 1;
372
373 m_pipe_int_write(MASTERVOL_MESSAGE);
374 m_pipe_int_write(amplification);
375
376 /* Pass the list to the interface */
377 m_pipe_int_write(FILE_LIST_MESSAGE);
378 m_pipe_int_write(number_of_files);
379 for (i=0;i<number_of_files;i++)
380 m_pipe_string_write(list_of_files[i]);
381
382 /* Ask the interface for a filename to play -> begin to play automatically */
383 m_pipe_int_write(NEXT_FILE_MESSAGE);
384
385 command = ctl_blocking_read(&val);
386
387 /* Main Loop */
388 for (;;)
389 {
390 if (command==RC_LOAD_FILE)
391 {
392 /* Read a LoadFile command */
393 m_pipe_string_read(file_to_play);
394 command=play_midi_file(file_to_play);
395 }
396 else
397 {
398 if (command==RC_QUIT)
399 return 0;
400
401 switch(command)
402 {
403 case RC_ERROR:
404 m_pipe_int_write(ERROR_MESSAGE);
405 retval=1;
406 break;
407 case RC_NONE:
408 break;
409 case RC_NEXT:
410 m_pipe_int_write(NEXT_FILE_MESSAGE);
411 break;
412 case RC_REALLY_PREVIOUS:
413 m_pipe_int_write(PREV_FILE_MESSAGE);
414 break;
415 case RC_TUNE_END:
416 m_pipe_int_write(TUNE_END_MESSAGE);
417 break;
418 case RC_CHANGE_VOLUME:
419 amplification += val;
420 break;
421 default:
422 fprintf(stderr,
423 "PANIC !!! OTHER COMMAND ERROR ?!?! %i"
424 NLS, command);
425 }
426
427 command = ctl_blocking_read(&val);
428 }
429 }
430 return retval;
431 }
432
433 /*
434 * interface_<id>_loader();
435 */
interface_m_loader(void)436 ControlMode *interface_m_loader(void)
437 {
438 return &ctl;
439 }
440