OSDN Git Service

最初のコミット
[winaudioj/stedx.git] / smfplay.cpp
1 /*
2   SMF player engine
3
4   Copyright 1999 by Daisuke Nagano <breeze.nagano@nifty.ne.jp>
5   Jan.29.2000
6   Oct.16.2002
7
8
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:
15
16   The above copyright notice and this permission notice shall be included in
17   all copies or substantial portions of the Software.
18
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
25   THE SOFTWARE.
26 */
27
28 /* ------------------------------------------------------------------- */
29 #include "stdafx.h"
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif /* HAVE_CONFIG_H */
34
35 #include <stdio.h>
36 #include <stdlib.h>
37
38 #ifdef HAVE_UNISTD_H
39 # include <unistd.h>
40 #endif
41
42 #ifdef STDC_HEADERS
43 # include <string.h>
44 #else
45 # ifdef HAVE_STRCHR
46 #  define strchr index
47 #  define strrchr rindex
48 # endif
49 #endif
50
51 #ifdef TIME_WITH_SYS_TIME
52 # include <sys/time.h>
53 # include <time.h>
54 #else
55 # ifdef HAVE_SYS_TIME_H
56 #  include <sys/time.h>
57 # else
58 #  include <time.h>
59 # endif
60 #endif
61
62 #include <signal.h>
63
64 #ifdef _POSIX_PRIORITY_SCHEDULING
65 # include <sched.h>
66 #endif
67 #ifdef _POSIX_MEMLOCK
68 # include <sys/mman.h>
69 #endif
70
71 #include "smfplay.h"
72 #include "smf.h"
73 #include "mididev.h"
74 #include "gettext_wrapper.h"
75 #include "version.h"
76
77 #ifndef timercmp
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)
82 #endif
83
84 #ifdef HAVE_DEV_RTC
85 # define SMFPLAY_WAIT_INTERVAL  1 /* (ms) */
86 #else
87 # if (HZ>100)
88 #  define SMFPLAY_WAIT_INTERVAL 2  /* (ms) */
89 # else
90 #  define SMFPLAY_WAIT_INTERVAL 10  /* (ms) */
91 # endif
92 #endif
93
94 /* ------------------------------------------------------------------- */
95
96 /* player's functions */
97
98 static int set_signals( void );
99 static int put_event( SMF_DATA *, int );
100 static int priority_init( void );
101
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 );
106
107 static int is_player_alive;
108
109 inline long timerdiff( struct timeval *st, struct timeval *et ) {
110   long reth, retl;
111   retl = st->tv_usec - et->tv_usec;
112   reth = st->tv_sec - et->tv_sec;
113   if ( retl < 0 ) {
114     reth--;
115     retl+=(1000*1000);
116   }
117   return (reth*1000*1000)+retl;
118 }
119
120 /* ------------------------------------------------------------------- */
121
122 /* SMF player engine */
123 int smfplay( SMF_DATA *smf ) {
124
125   struct timeval st,et;
126   int rtm_delta=0;
127
128   if ( smf_init_track_buffer( smf ) != 0 ) return 1;
129   if ( read_smf_header( smf )   != 0 ) return 1;
130
131   /* prepare for output device (/dev/midi, /dev/ttyS0, etc) */
132
133   if ( smf->output_device == NULL ) {
134     fprintf(stderr,_("No output device is specified.\n"));
135     return 1;
136   }
137   if ( open_midi_device( smf->output_device, smf->is_buffered ) ) {
138     /* Cannot open midi device */
139     fprintf(stderr,_("Cannot open midi device\n"));
140     return 1;
141   }
142
143   /* prepare for signal */
144
145   set_signals();
146
147   /* prepare for priority ('setuid root' is required) */
148
149   priority_init();
150
151   /* start playing */
152
153   send_midi_reset();
154   myusleep( 50 * 1000 );
155
156   /* get first current time */
157   gettimeofday( &st, NULL );
158
159   if ( smf->is_send_rtm == FLAG_TRUE ) {
160     send_rtm_start();
161   }
162   smf->rtm_delta = smf->timebase / 24;
163
164   is_player_alive = FLAG_TRUE;
165   while( is_player_alive == FLAG_TRUE ) {
166     int track;
167     int is_all_tracks_finished;
168
169     /* wait a delta time */
170
171     st.tv_usec += smf->tempo_delta;
172     while ( st.tv_usec >= 1000*1000 ) {
173       st.tv_usec-=1000*1000;
174       st.tv_sec++;
175     }
176
177     smf->rtm_delta--;
178     if ( smf->rtm_delta <= 0 ) {
179       if ( smf->is_send_rtm == FLAG_TRUE ) {
180         send_rtm_timingclock();
181       }
182       smf->rtm_delta = smf->timebase / 24;
183     }
184
185     {
186       long s;
187       flush_midi();
188       gettimeofday( &et, NULL );
189       s = timerdiff( &st, &et );
190       if ( s > SMFPLAY_WAIT_INTERVAL*1000 ) {
191         myusleep(s);
192         gettimeofday( &et, NULL );
193       }
194     }
195     if ( et.tv_sec - st.tv_sec > 1 ) {
196       st.tv_sec  = et.tv_sec;
197       st.tv_usec = et.tv_usec;
198     }
199
200     is_all_tracks_finished = FLAG_TRUE;
201
202     smf->step++;
203
204     for ( track=0 ; track < smf->tracks ; track++ ) {
205       /* Have the track finished ? */
206       if ( smf->track[track].finished == FLAG_TRUE )
207         continue;
208
209       is_all_tracks_finished = FLAG_FALSE;
210
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--;
215
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 );
220       }
221     }
222     if ( is_all_tracks_finished == FLAG_TRUE ) break;
223
224   }
225
226   if ( smf->is_send_rtm == FLAG_TRUE ) {
227     send_rtm_stop();
228   }
229
230 #ifdef _POSIX_PRIORITY_SCHEDULING
231   sched_yield();
232 #endif
233 #ifdef _POSIX_MEMLOCK
234   munlockall();
235 #endif
236
237   close_midi_device();
238
239   return 0;
240 }
241
242 /* ------------------------------------------------------------------- */
243
244 static int put_event( SMF_DATA *smf, int track ) {
245
246   int i;
247   static int current_port = -1;
248
249   if ( smf->result[0] == SMF_TERM ) return 0;
250
251   /* is the track disabled ? */
252   if ( smf->track[track].enabled == FLAG_FALSE && 
253        smf->result[0] != MIDI_NOTEOFF ) {
254     goto put_event_end;
255   }
256   
257   /* flushing MIDI data */
258   
259   if ( current_port != smf->track[track].port ) {
260     change_midi_port( smf->track[track].port );
261     current_port = smf->track[track].port;
262   }
263
264   i=0;
265   while ( smf->result[i] != SMF_TERM ) {
266     put_midi(smf->result[i++]);
267   }
268
269   switch( smf->result[0]&0xf0 ) {
270   case 0x80:
271     smf->track[track].notes[smf->result[1]]=0;
272     break;
273
274   case 0x90:
275     smf->track[track].notes[smf->result[1]]=smf->result[2];
276     break;
277
278   default:
279     break;
280   }
281
282   smf->track[track].delta_step = 0;
283   
284 put_event_end:
285   smf->result[0] = SMF_TERM;
286
287   return 0;
288 }
289
290 static int set_new_event( SMF_DATA *smf, int t ) {
291
292   int ptr;
293   unsigned char *data;
294   int ret;
295
296   ret = 0;
297   data = smf->data;
298   ptr  = smf->track[t].current_ptr;
299
300   if ( ptr >= smf->track[t].top + smf->track[t].size ) {
301     smf->track[t].finished = FLAG_TRUE;
302     return 1;
303   }
304
305   if ( data[ptr+0] < 0x80 )
306     smf->result[0] = smf->track[t].last_event;
307   else {
308     smf->track[t].last_event = data[ptr+0];
309     smf->result[0] = data[ptr+0];
310     ptr++;
311   }
312
313   switch ( smf->result[0]&0xf0 ) {
314   case 0x80:
315   case 0x90:
316   case 0xa0:
317   case 0xb0:
318   case 0xe0:
319     smf->result[1] = data[ptr++];
320     smf->result[2] = data[ptr++];
321     smf->result[3] = SMF_TERM;
322     break;
323
324   case 0xc0:
325   case 0xd0:
326     smf->result[1] = data[ptr++];
327     smf->result[2] = SMF_TERM;
328     break;
329
330   default: /* exclusive & meta event */
331     switch ( smf->result[0] ) {
332       int size;
333       int type;
334       int i;
335
336     case 0xf0:
337       i=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++];
343         size--;
344       }
345       smf->result[i] = SMF_TERM;
346       break;
347
348     case 0xf7:
349       i=0;
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++];
354         size--;
355       }
356       smf->result[i] = SMF_TERM;
357       break;
358
359     case 0xff:
360       smf->result[0]=SMF_TERM;
361       type = data[ptr++];
362       size = get_smf_number( smf, ptr );
363       while( data[ptr++] >= 0x80 );
364
365       switch(type) {
366       case META_TEMPO:
367         smf->tempo = (data[ptr+0]<<16) + (data[ptr+1]<<8) + data[ptr+2];
368         smf->tempo_delta = smf->tempo / smf->timebase;
369         break;
370
371       case META_PORT:
372         smf->track[t].port = data[ptr];
373         break;
374
375       case META_EOT:
376         smf->track[t].finished = FLAG_TRUE;
377         break;
378
379       case META_KEYSIG:
380         i = data[ptr];
381         if ( i>0x80 ) i = 255-i;
382         if ( data[ptr] == 1 ) i+=16;
383         smf->key = i;
384         break;
385
386       case META_TIMESIG:
387         break;
388
389       case META_TEXT:
390       case META_COPYRIGHT:
391       case META_SEQNAME:
392       case META_INSTNAME:
393       case META_LYRIC:
394       case META_MARKER:
395       case META_CUEPT:
396         i=0;
397         while ( i<size && i<SMF_MAX_MESSAGE_SIZE-1 ) {
398           smf->track[t].message[i] = data[ptr+i];
399           i++;
400         }
401         smf->track[t].message[i] = '\0';
402         break;
403
404       default:
405         break;
406       }
407       ptr+=size;
408       break;
409
410     case 0xf1:
411     case 0xf2:
412     case 0xf3:
413     case 0xf5:
414       ptr++;
415       break;
416
417     default:
418       break;
419     }
420     break;
421   }
422
423   if ( smf->track[t].finished == FLAG_FALSE ) {
424     smf->track[t].step = get_smf_number( smf, ptr );
425     while( data[ptr++] >= 0x80 );
426   }
427   else {
428     smf->track[t].step = 0;
429   }
430
431   smf->track[t].current_ptr = ptr;
432   return 0;
433 }
434
435 /* ------------------------------------------------------------------- */
436
437 static long get_smf_number( SMF_DATA *smf, int ptr ) {
438
439   long ret;
440   unsigned char *p;
441
442   p = smf->data+ptr;
443
444   ret = 0;
445   while( *p >= 0x80 ) {
446     ret = (ret<<7) + (*p&0x7f);
447     p++;
448   }
449   ret = (ret<<7) + *p;
450
451   return ret;
452 }
453
454 /* ------------------------------------------------------------------- */
455
456 static int smf_init_track_buffer( SMF_DATA *smf ) {
457
458   int track,n;
459
460   smf->step            = -1;
461   smf->result[0]       = SMF_TERM;
462   smf->tempo           = 1000*1000*16;
463
464   for ( track=0 ; track<SMF_MAX_TRACKS ; track++ ) {
465     smf->track[track].enabled      = FLAG_FALSE;
466     smf->track[track].finished     = FLAG_FALSE;
467
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;
471
472     smf->track[track].current_ptr  = 0;
473
474     smf->track[track].last_event   = 0;
475     smf->track[track].port         = 0;
476
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;
480   }
481
482   return 0;
483 }
484
485 static int read_smf_header( SMF_DATA *smf ) {
486
487   int t;
488   unsigned char *data, *ptr;
489
490   data = smf->data;
491
492   /* check 1st header */
493
494   if ( strncmp( data, SMF_HEADER_STRING, 4 ) !=0 ) {
495     if ( strncmp( data+128, SMF_HEADER_STRING, 4 ) !=0 ) { /* Mac binary */
496       return 1;
497     } else {
498       data+=128;
499     }
500   }
501
502   /* Header chunk */
503
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 */
507
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 */
513
514   ptr = data+8+ (data[0x04]<<24) + (data[0x05]<<16) + (data[0x06]<<8) + data[0x07];
515
516   /* Track chunk */
517
518   for ( t=0 ; t<smf->tracks ; t++ ) {
519     long size;
520     unsigned char *p;
521
522     if ( ptr+8 > smf->data + smf->length )
523       break;
524
525     if ( strncmp( ptr, SMF_TRACK_STRING, 4 ) !=0 ) {
526       return 1;
527     }
528
529     smf->track[t].enabled    = FLAG_TRUE;
530
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;
534
535     smf->track[t].step = get_smf_number( smf, smf->track[t].top )+1;
536     p = ptr+8;
537     while( *(p++) >= 0x80 );
538     smf->track[t].current_ptr = (long)(p-smf->data);
539
540     ptr = ptr+8+size;
541   }
542
543   return 0;
544 }
545
546 /* ------------------------------------------------------------------- */
547
548 /* Signals configuration */
549
550 static RETSIGTYPE sigexit( int num ) {
551   send_rtm_stop();
552   send_midi_reset();
553
554 #ifdef _POSIX_PRIORITY_SCHEDULING
555   sched_yield();
556 #endif
557 #ifdef _POSIX_MEMLOCK
558   munlockall();
559 #endif
560
561   fprintf(stderr,"Signal caught : %d\n", num);
562   exit(1);
563 }
564
565 static RETSIGTYPE sig_stop_play( int num ) {
566   send_midi_reset();
567   send_rtm_stop();
568
569   signal( SIGINT, SIG_DFL );
570   is_player_alive = FLAG_FALSE;
571
572   return;
573 }
574
575 static const int signals[]={SIGHUP,SIGQUIT,SIGILL,SIGABRT,SIGFPE,
576                               SIGBUS,SIGSEGV,SIGPIPE,SIGTERM,0};
577
578 static int set_signals( void ) {
579
580   int i;
581
582   for ( i=0 ; signals[i]!=0 ; i++ )
583     signal( signals[i], sigexit );
584
585   signal( SIGINT, sig_stop_play );
586
587   return 0;
588 }
589
590 /* priority configuration : only when program is setuid root-ed */
591
592 static int priority_init( void ) {
593
594 #ifdef _POSIX_PRIORITY_SCHEDULING
595   struct sched_param ptmp, *priority_param;
596   int i;
597
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 );
602 #endif
603 #ifdef _POSIX_MEMLOCK
604   mlockall(MCL_CURRENT);
605 #endif
606
607   return 0;
608 }