4 Copyright 1999 by Daisuke Nagano <breeze.nagano@nifty.ne.jp>
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28 /* ------------------------------------------------------------------- */
33 #endif /* HAVE_CONFIG_H */
47 # define strrchr rindex
51 #ifdef TIME_WITH_SYS_TIME
52 # include <sys/time.h>
55 # ifdef HAVE_SYS_TIME_H
56 # include <sys/time.h>
64 #ifdef _POSIX_PRIORITY_SCHEDULING
68 # include <sys/mman.h>
74 #include "gettext_wrapper.h"
78 # define timercmp(tvp, uvp, cmp)\
79 ((tvp)->tv_sec cmp (uvp)->tv_sec ||\
80 (tvp)->tv_sec == (uvp)->tv_sec &&\
81 (tvp)->tv_usec cmp (uvp)->tv_usec)
85 # define SMFPLAY_WAIT_INTERVAL 1 /* (ms) */
88 # define SMFPLAY_WAIT_INTERVAL 2 /* (ms) */
90 # define SMFPLAY_WAIT_INTERVAL 10 /* (ms) */
94 /* ------------------------------------------------------------------- */
96 /* player's functions */
98 static int set_signals( void );
99 static int put_event( SMF_DATA *, int );
100 static int priority_init( void );
102 static int smf_init_track_buffer( SMF_DATA * );
103 static int read_smf_header( SMF_DATA * );
104 static int set_new_event( SMF_DATA *, int );
105 static long get_smf_number( SMF_DATA *, int );
107 static int is_player_alive;
109 inline long timerdiff( struct timeval *st, struct timeval *et ) {
111 retl = st->tv_usec - et->tv_usec;
112 reth = st->tv_sec - et->tv_sec;
117 return (reth*1000*1000)+retl;
120 /* ------------------------------------------------------------------- */
122 /* SMF player engine */
123 int smfplay( SMF_DATA *smf ) {
125 struct timeval st,et;
128 if ( smf_init_track_buffer( smf ) != 0 ) return 1;
129 if ( read_smf_header( smf ) != 0 ) return 1;
131 /* prepare for output device (/dev/midi, /dev/ttyS0, etc) */
133 if ( smf->output_device == NULL ) {
134 fprintf(stderr,_("No output device is specified.\n"));
137 if ( open_midi_device( smf->output_device, smf->is_buffered ) ) {
138 /* Cannot open midi device */
139 fprintf(stderr,_("Cannot open midi device\n"));
143 /* prepare for signal */
147 /* prepare for priority ('setuid root' is required) */
154 myusleep( 50 * 1000 );
156 /* get first current time */
157 gettimeofday( &st, NULL );
159 if ( smf->is_send_rtm == FLAG_TRUE ) {
162 smf->rtm_delta = smf->timebase / 24;
164 is_player_alive = FLAG_TRUE;
165 while( is_player_alive == FLAG_TRUE ) {
167 int is_all_tracks_finished;
169 /* wait a delta time */
171 st.tv_usec += smf->tempo_delta;
172 while ( st.tv_usec >= 1000*1000 ) {
173 st.tv_usec-=1000*1000;
178 if ( smf->rtm_delta <= 0 ) {
179 if ( smf->is_send_rtm == FLAG_TRUE ) {
180 send_rtm_timingclock();
182 smf->rtm_delta = smf->timebase / 24;
188 gettimeofday( &et, NULL );
189 s = timerdiff( &st, &et );
190 if ( s > SMFPLAY_WAIT_INTERVAL*1000 ) {
192 gettimeofday( &et, NULL );
195 if ( et.tv_sec - st.tv_sec > 1 ) {
196 st.tv_sec = et.tv_sec;
197 st.tv_usec = et.tv_usec;
200 is_all_tracks_finished = FLAG_TRUE;
204 for ( track=0 ; track < smf->tracks ; track++ ) {
205 /* Have the track finished ? */
206 if ( smf->track[track].finished == FLAG_TRUE )
209 is_all_tracks_finished = FLAG_FALSE;
211 /* checks whether the step time is expired */
212 smf->track[track].delta_step++;
213 smf->track[track].total_step++;
214 smf->track[track].step--;
216 while ( smf->track[track].step == 0 ) {
217 if ( smf->track[track].finished == FLAG_TRUE ) break;
218 set_new_event( smf, track );
219 put_event( smf, track );
222 if ( is_all_tracks_finished == FLAG_TRUE ) break;
226 if ( smf->is_send_rtm == FLAG_TRUE ) {
230 #ifdef _POSIX_PRIORITY_SCHEDULING
233 #ifdef _POSIX_MEMLOCK
242 /* ------------------------------------------------------------------- */
244 static int put_event( SMF_DATA *smf, int track ) {
247 static int current_port = -1;
249 if ( smf->result[0] == SMF_TERM ) return 0;
251 /* is the track disabled ? */
252 if ( smf->track[track].enabled == FLAG_FALSE &&
253 smf->result[0] != MIDI_NOTEOFF ) {
257 /* flushing MIDI data */
259 if ( current_port != smf->track[track].port ) {
260 change_midi_port( smf->track[track].port );
261 current_port = smf->track[track].port;
265 while ( smf->result[i] != SMF_TERM ) {
266 put_midi(smf->result[i++]);
269 switch( smf->result[0]&0xf0 ) {
271 smf->track[track].notes[smf->result[1]]=0;
275 smf->track[track].notes[smf->result[1]]=smf->result[2];
282 smf->track[track].delta_step = 0;
285 smf->result[0] = SMF_TERM;
290 static int set_new_event( SMF_DATA *smf, int t ) {
298 ptr = smf->track[t].current_ptr;
300 if ( ptr >= smf->track[t].top + smf->track[t].size ) {
301 smf->track[t].finished = FLAG_TRUE;
305 if ( data[ptr+0] < 0x80 )
306 smf->result[0] = smf->track[t].last_event;
308 smf->track[t].last_event = data[ptr+0];
309 smf->result[0] = data[ptr+0];
313 switch ( smf->result[0]&0xf0 ) {
319 smf->result[1] = data[ptr++];
320 smf->result[2] = data[ptr++];
321 smf->result[3] = SMF_TERM;
326 smf->result[1] = data[ptr++];
327 smf->result[2] = SMF_TERM;
330 default: /* exclusive & meta event */
331 switch ( smf->result[0] ) {
338 smf->result[i++] = 0xf0;
339 size = get_smf_number( smf, ptr );
340 while( data[ptr++] >= 0x80 ){};
341 while ( size>0 && i < SMF_MAX_RESULT_SMF_SIZE ) {
342 smf->result[i++] = data[ptr++];
345 smf->result[i] = SMF_TERM;
350 size = get_smf_number( smf, ptr );
351 while( data[ptr++] >= 0x80 ){};
352 while ( size>0 && i < SMF_MAX_RESULT_SMF_SIZE ) {
353 smf->result[i++] = data[ptr++];
356 smf->result[i] = SMF_TERM;
360 smf->result[0]=SMF_TERM;
362 size = get_smf_number( smf, ptr );
363 while( data[ptr++] >= 0x80 );
367 smf->tempo = (data[ptr+0]<<16) + (data[ptr+1]<<8) + data[ptr+2];
368 smf->tempo_delta = smf->tempo / smf->timebase;
372 smf->track[t].port = data[ptr];
376 smf->track[t].finished = FLAG_TRUE;
381 if ( i>0x80 ) i = 255-i;
382 if ( data[ptr] == 1 ) i+=16;
397 while ( i<size && i<SMF_MAX_MESSAGE_SIZE-1 ) {
398 smf->track[t].message[i] = data[ptr+i];
401 smf->track[t].message[i] = '\0';
423 if ( smf->track[t].finished == FLAG_FALSE ) {
424 smf->track[t].step = get_smf_number( smf, ptr );
425 while( data[ptr++] >= 0x80 );
428 smf->track[t].step = 0;
431 smf->track[t].current_ptr = ptr;
435 /* ------------------------------------------------------------------- */
437 static long get_smf_number( SMF_DATA *smf, int ptr ) {
445 while( *p >= 0x80 ) {
446 ret = (ret<<7) + (*p&0x7f);
454 /* ------------------------------------------------------------------- */
456 static int smf_init_track_buffer( SMF_DATA *smf ) {
461 smf->result[0] = SMF_TERM;
462 smf->tempo = 1000*1000*16;
464 for ( track=0 ; track<SMF_MAX_TRACKS ; track++ ) {
465 smf->track[track].enabled = FLAG_FALSE;
466 smf->track[track].finished = FLAG_FALSE;
468 smf->track[track].step = 1;
469 smf->track[track].delta_step = -1; /* initial value should be -1 */
470 smf->track[track].total_step = -1;
472 smf->track[track].current_ptr = 0;
474 smf->track[track].last_event = 0;
475 smf->track[track].port = 0;
477 for ( n=0 ; n<SMF_MAX_NOTES ; n++ )
478 smf->track[track].notes[n] = 0;
479 smf->track[track].all_notes_expired = FLAG_TRUE;
485 static int read_smf_header( SMF_DATA *smf ) {
488 unsigned char *data, *ptr;
492 /* check 1st header */
494 if ( strncmp( data, SMF_HEADER_STRING, 4 ) !=0 ) {
495 if ( strncmp( data+128, SMF_HEADER_STRING, 4 ) !=0 ) { /* Mac binary */
504 smf->format = (data[0x08] << 8) + data[0x09];
505 if ( smf->format != 0 && smf->format != 1 )
506 return 1; /* Only supports format 0 and 1 */
508 smf->tracks = (data[0x0a] << 8) + data[0x0b];
509 smf->timebase = (data[0x0c] << 8) + data[0x0d];
510 smf->rtm_delta = smf->timebase / 24;
511 if ( data[0x0c] > 0x7f )
512 return 1; /* Not supports SMPTE format */
514 ptr = data+8+ (data[0x04]<<24) + (data[0x05]<<16) + (data[0x06]<<8) + data[0x07];
518 for ( t=0 ; t<smf->tracks ; t++ ) {
522 if ( ptr+8 > smf->data + smf->length )
525 if ( strncmp( ptr, SMF_TRACK_STRING, 4 ) !=0 ) {
529 smf->track[t].enabled = FLAG_TRUE;
531 size = (ptr[0x04]<<24) + (ptr[0x05]<<16) + (ptr[0x06]<<8) + ptr[0x07];
532 smf->track[t].top = (ptr+8 - smf->data);
533 smf->track[t].size = size;
535 smf->track[t].step = get_smf_number( smf, smf->track[t].top )+1;
537 while( *(p++) >= 0x80 );
538 smf->track[t].current_ptr = (long)(p-smf->data);
546 /* ------------------------------------------------------------------- */
548 /* Signals configuration */
550 static RETSIGTYPE sigexit( int num ) {
554 #ifdef _POSIX_PRIORITY_SCHEDULING
557 #ifdef _POSIX_MEMLOCK
561 fprintf(stderr,"Signal caught : %d\n", num);
565 static RETSIGTYPE sig_stop_play( int num ) {
569 signal( SIGINT, SIG_DFL );
570 is_player_alive = FLAG_FALSE;
575 static const int signals[]={SIGHUP,SIGQUIT,SIGILL,SIGABRT,SIGFPE,
576 SIGBUS,SIGSEGV,SIGPIPE,SIGTERM,0};
578 static int set_signals( void ) {
582 for ( i=0 ; signals[i]!=0 ; i++ )
583 signal( signals[i], sigexit );
585 signal( SIGINT, sig_stop_play );
590 /* priority configuration : only when program is setuid root-ed */
592 static int priority_init( void ) {
594 #ifdef _POSIX_PRIORITY_SCHEDULING
595 struct sched_param ptmp, *priority_param;
598 priority_param=&ptmp;
599 i=sched_get_priority_max( SCHED_FIFO );
600 priority_param->sched_priority = i/2; /* no means */
601 sched_setscheduler( 0, SCHED_FIFO, priority_param );
603 #ifdef _POSIX_MEMLOCK
604 mlockall(MCL_CURRENT);