]> icculus.org git repositories - btb/d2x.git/blob - arch/linux/hmiplay.c
use the orientation parameter of g3_draw_bitmap
[btb/d2x.git] / arch / linux / hmiplay.c
1 /*
2  * HMI midi playing routines by Jani Frilander
3  *
4  * External device support by Patrick McCarthy
5  *
6  * Ported to d1x/sdl_threads by Matthew Mueller
7  *
8  */
9
10 #include <errno.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <signal.h>
16 #include <linux/soundcard.h>
17 #include <sys/ioctl.h>
18 #include <fcntl.h>
19 #include <sys/types.h>
20 #include <sys/ipc.h>
21 #include <sys/msg.h>
22 #include "music.h"
23 #include "cfile.h"
24 #include "args.h"
25
26 #include <SDL/SDL_thread.h>
27
28 //#define WANT_AWE32 1
29
30 #ifdef WANT_AWE32
31 #include <linux/awe_voice.h>
32 #endif
33
34 //#define WANT_MPU401 1
35
36 #ifdef WANT_MPU401
37
38 unsigned char reset_genmidi[5] =
39         { 0x7e, 0x7f, 0x09, 0x01, 0xf7 };
40
41 #define MIDI_RESET {                            \
42         SEQ_MIDIOUT(synth_dev,MIDI_SYSTEM_PREFIX);  \
43         SEQ_MIDIOUT(synth_dev,reset_genmidi[0]);    \
44         SEQ_MIDIOUT(synth_dev,reset_genmidi[1]);    \
45         SEQ_MIDIOUT(synth_dev,reset_genmidi[2]);    \
46         SEQ_MIDIOUT(synth_dev,reset_genmidi[3]);    \
47         SEQ_MIDIOUT(synth_dev,reset_genmidi[4]);    \
48 }
49
50 #define MIDI_MESSAGE2(a,b) {            \
51         SEQ_MIDIOUT(synth_dev,a);       \
52         SEQ_MIDIOUT(synth_dev,b);       \
53 }
54
55 #define MIDI_MESSAGE3(a,b,c) {          \
56         SEQ_MIDIOUT(synth_dev,a);       \
57         SEQ_MIDIOUT(synth_dev,b);       \
58         SEQ_MIDIOUT(synth_dev,c);       \
59 }
60 #endif
61
62 SEQ_DEFINEBUF(1024);
63
64 int drumflag = 1<<9;
65 int seqfd;
66 int synth_dev;
67 int program[16];
68 int stop;
69 double volume=1;
70
71 int ipc_queue_id = -1;
72 struct msgbuf *snd;
73
74 SDL_Thread *player_thread=NULL;
75
76 Voice_info *voices;
77 unsigned char *data=NULL;
78 char digi_last_midi_song[16] = "";
79
80 struct synth_info card_info;
81
82 void seqbuf_dump()
83 {
84         if (_seqbufptr)
85         {
86                 if (write(seqfd, _seqbuf, _seqbufptr) == -1)
87                 {
88                         perror ("Error writing sequencer device");
89                         SDL_KillThread(player_thread);
90                 }
91         }
92         _seqbufptr = 0;
93 }
94               
95 void my_quit()
96 {
97 //      printf("goodbye\n");//#####
98 //      exit(0);
99 }
100
101 int seq_init()
102 {
103         int nrmidis,nrsynths,i;
104         
105         if ((seqfd = open(SEQ_DEV, O_WRONLY, 0)) < 0)
106         {
107                 perror ("Error opening sequencer device");
108                 return (-1);
109         }
110         
111         if (ioctl(seqfd, SNDCTL_SEQ_NRSYNTHS, &nrsynths) == -1)
112         {
113                 perror ("There is no soundcard");
114                 return (-1);
115         }
116         
117         if (ioctl(seqfd, SNDCTL_SEQ_NRMIDIS, &nrmidis) == -1)
118         {
119                 perror ("There is no soundcard");
120                 return (-1);
121         }
122         
123         
124         if(nrsynths < 1 && nrmidis < 1)
125         {
126                 printf("No synth or midi device!\n");
127                 return -1;
128         }
129         
130         synth_dev = 0;
131         
132         //Check if we have wavetable synth device
133         for (i=0; i < nrsynths; i++)
134         {
135                 card_info.device = i;
136                 if (ioctl(seqfd, SNDCTL_SYNTH_INFO, &card_info) == -1)
137                 {
138                         perror("cannot get info on soundcard");
139                         return (-1);
140                 }
141                 
142                 if (card_info.synth_type == SYNTH_TYPE_SAMPLE)
143                 {    
144                         synth_dev = i;
145                         break;
146                 }
147         }
148         
149 #ifdef WANT_AWE32
150         for (i=0; i < nrsynths; i++)
151         {
152                 card_info.device = i;
153                 if (ioctl(seqfd, SNDCTL_SYNTH_INFO, &card_info) == -1)
154                 {
155                         perror("cannot get info on soundcard");
156                         return (-1);
157                 }
158                 
159                 if (card_info.synth_type==SYNTH_TYPE_SAMPLE
160                     &&card_info.synth_subtype==SAMPLE_TYPE_AWE32) {
161                         synth_dev = i;
162                         break;
163                 }
164         }
165 #endif
166         
167 #ifdef WANT_MPU401
168         for (i=0; i < nrmidis; i++)
169         {
170                 struct midi_info cinfo;
171                 cinfo.device = i;
172                 if (ioctl(seqfd, SNDCTL_MIDI_INFO, &cinfo) == -1)
173                 {
174                         perror("cannot get info on soundcard");
175                         return (-1);
176                 }
177                 
178                 // Just take first available for now.
179                 card_info.synth_type=SYNTH_TYPE_MIDI;
180                 card_info.device=i;
181                 synth_dev=i;
182                 break;
183         }
184         
185         if (card_info.synth_type!=SYNTH_TYPE_MIDI) {
186 #endif
187                 
188                 card_info.device = synth_dev;
189                 if (ioctl(seqfd, SNDCTL_SYNTH_INFO, &card_info) == -1)
190                 {
191                         perror("cannot get info on soundcard");
192                         return (-1);
193                 }
194                 
195 #ifdef WANT_MPU401
196         }
197         
198         if (card_info.synth_type==SYNTH_TYPE_MIDI) {
199                 MIDI_RESET;
200                 SEQ_DUMPBUF();
201         } else
202 #endif
203 #ifdef WANT_AWE32    
204           if (card_info.synth_type == SYNTH_TYPE_SAMPLE
205               && card_info.synth_subtype == SAMPLE_TYPE_AWE32)
206         {
207                 AWE_SET_CHANNEL_MODE(synth_dev,1);
208                 AWE_DRUM_CHANNELS(synth_dev,drumflag);
209         }
210         else
211 #endif
212         {
213                 voices = malloc(sizeof(Voice_info)*card_info.nr_voices);
214                 for (i=0;i<card_info.nr_voices;i++)
215                 {
216                         voices[i].note = -1;
217                         voices[i].channel = -1;
218                 }
219         }
220         
221         return(0);
222 }
223
224 void seq_close()
225 {
226         SEQ_DUMPBUF();
227         ioctl(seqfd,SNDCTL_SEQ_SYNC);
228         close(seqfd);
229         free(voices);
230 }
231
232 void set_program(int channel, int pgm)
233 {
234 #ifdef WANT_AWE32
235         if (card_info.synth_type == SYNTH_TYPE_SAMPLE
236             && card_info.synth_subtype == SAMPLE_TYPE_AWE32)
237         {
238                 SEQ_SET_PATCH(synth_dev,channel,pgm);
239         }
240         else
241 #endif
242           program[channel]=pgm;
243 }
244
245 void start_note(int channel, int note, int vel)
246 {
247         int i;
248         
249 #ifdef WANT_AWE32
250         if (card_info.synth_type == SYNTH_TYPE_SAMPLE
251             && card_info.synth_subtype == SAMPLE_TYPE_AWE32)
252         {
253                 SEQ_START_NOTE(synth_dev,channel,note,vel);
254         }
255         else
256 #endif
257         {
258                 for (i=0; i<card_info.nr_voices;i++)
259                   if ((voices[i].note == -1) && (voices[i].channel == -1))
260                     break;
261                 if (i != card_info.nr_voices)
262                 {
263                         voices[i].note = note;
264                         voices[i].channel = channel;
265                         if (((1<<channel) & drumflag))         /* drum note */
266                         {       
267                                 SEQ_SET_PATCH(synth_dev, i, note + 128);
268                         }
269                         else
270                         {
271                                 SEQ_SET_PATCH(synth_dev, i, program[channel]);
272                         }
273                         SEQ_START_NOTE(synth_dev, i, note, vel);
274                 }
275         }
276 }
277
278 void stop_note(int channel, int note, int vel)
279 {
280         int i;
281         
282 #ifdef WANT_AWE32
283         if (card_info.synth_type == SYNTH_TYPE_SAMPLE
284             && card_info.synth_subtype == SAMPLE_TYPE_AWE32)
285         {
286                 SEQ_STOP_NOTE(synth_dev,channel,note,vel);
287         }
288         else
289 #endif
290         {      
291                 for (i=0; i<card_info.nr_voices;i++)
292                   if ((voices[i].note == note) && (voices[i].channel == channel))
293                     break;
294                 if (i != card_info.nr_voices)
295                 {
296                         voices[i].note = -1;
297                         voices[i].channel = -1;
298                         SEQ_STOP_NOTE(synth_dev,i,note,vel);
299                 }
300         }
301 }
302
303 void set_control(int channel,int ctrl,int value)
304 {
305         int i;
306         
307 #ifdef WANT_AWE32
308         if (card_info.synth_type == SYNTH_TYPE_SAMPLE
309             && card_info.synth_subtype == SAMPLE_TYPE_AWE32)
310         {
311                 SEQ_CONTROL(synth_dev,channel,ctrl,value);
312         }
313         else
314 #endif
315         {
316                 for (i=0; i<card_info.nr_voices;i++)
317                   if (voices[i].channel == channel)
318                     if (ctrl == CTL_MAIN_VOLUME)
319                       SEQ_MAIN_VOLUME(synth_dev,i,value);
320         }
321 }
322
323 void set_pitchbend(int channel, int bend)
324 {
325         int i;
326         
327 #ifdef WANT_AWE32
328         if (card_info.synth_type == SYNTH_TYPE_SAMPLE
329             && card_info.synth_subtype == SAMPLE_TYPE_AWE32)
330         {
331                 SEQ_BENDER(synth_dev,channel,bend);
332         }
333         else
334 #endif
335         {
336                 for (i=0; i<card_info.nr_voices;i++)
337                   if (voices[i].channel == channel)
338                 {
339                         /*SEQ_BENDER_RANGE(synth_dev, i, 200);*/
340                         SEQ_BENDER(synth_dev, i, bend);
341                 }    
342         }
343 }
344
345 void set_key_pressure(int channel, int note, int vel)
346 {
347         int i;
348         
349 #ifdef WANT_AWE32
350         if (card_info.synth_type == SYNTH_TYPE_SAMPLE
351             && card_info.synth_subtype == SAMPLE_TYPE_AWE32)
352         {
353                 AWE_KEY_PRESSURE(synth_dev,channel,note,vel);
354         }
355         else
356 #endif
357         {
358                 for (i=0; i<card_info.nr_voices;i++)
359                   if ((voices[i].note == note) && (voices[i].channel == channel))
360                     SEQ_KEY_PRESSURE(synth_dev,i,note,vel);
361         }
362 }
363
364 void set_chn_pressure(int channel, int vel)
365 {    
366         int i;
367         
368 #ifdef WANT_AWE32
369         if (card_info.synth_type == SYNTH_TYPE_SAMPLE
370             && card_info.synth_subtype == SAMPLE_TYPE_AWE32)    
371         {
372                 AWE_CHN_PRESSURE(synth_dev,channel,vel);
373         }
374         else
375 #endif
376         {
377                 for (i=0; i<card_info.nr_voices;i++)
378                   if (voices[i].channel == channel)
379                     SEQ_CHN_PRESSURE(synth_dev,i,vel);
380         }    
381 }
382
383 void stop_all()
384 {
385         int i;
386         
387 #ifdef WANT_AWE32
388         int j;
389         if (card_info.synth_type == SYNTH_TYPE_SAMPLE
390             && card_info.synth_subtype == SAMPLE_TYPE_AWE32)    
391         {
392                 for (i=0; i<16;i++)
393                   for (j=0;j<128;j++)
394                     SEQ_STOP_NOTE(synth_dev,i,j,0);
395         }
396         else
397 #endif
398 #ifdef WANT_MPU401
399           if (card_info.synth_type==SYNTH_TYPE_MIDI) {
400                 MIDI_RESET;
401                 SEQ_DUMPBUF();
402           } else
403 #endif
404         {
405                 for (i=0; i<card_info.nr_voices;i++)
406                   SEQ_STOP_NOTE(synth_dev,i,voices[i].note,0);
407         }    
408 }
409
410 int get_dtime(unsigned char *data, int *pos)
411 {
412         char buf;
413         int result;
414         result =0;
415         
416         buf = data[*pos];
417         *pos +=1;
418         result = (0x7f & buf);
419         
420         if (!(buf & 0x80))
421         {
422                 buf = data[*pos];
423                 *pos +=1;
424                 result |=(int) (((int) 0x7f & (int) buf)<<7);
425                 if (!(buf & 0x80))
426                 {
427                         buf = data[*pos];
428                         *pos +=1;
429                         result |=(int) (((int) 0x7f & (int) buf)<<14);
430                         if (!(buf & 0x80))
431                         {
432                                 buf = data[*pos];
433                                 *pos +=1;
434                                 result |=(int) (((int) 0x7f & (int) buf)<<21);
435                         }
436                 }
437         }
438         
439         return result;
440 }
441
442 int do_track_event(unsigned char *data, int *pos)
443 {
444         char channel;
445         unsigned char buf[5];
446         
447         buf[0]=data[*pos];
448         *pos +=1;
449         channel = buf[0] & 0xf;
450 #ifdef WANT_MPU401
451         if (card_info.synth_type==SYNTH_TYPE_MIDI) {
452                 switch((buf[0]&0xf0)) {
453                  case 0x80:
454                  case 0x90:
455                  case 0xa0:
456                  case 0xb0:
457                  case 0xe0:
458                         buf[1]=data[*pos]; *pos+=1;
459                         buf[2]=data[*pos]; *pos+=1;
460                         MIDI_MESSAGE3(buf[0],buf[1],buf[2]);
461                         break;
462                  case 0xc0:
463                  case 0xd0:
464                         buf[1]=data[*pos]; *pos+=1;
465                         MIDI_MESSAGE3(buf[0],0,buf[1]);
466                         break;
467                  case 0xf0:
468                         return 1;
469                  default:
470                         return 3;
471                 }
472                 seqbuf_dump();
473                 return 0;
474         }
475 #endif
476         
477         switch((buf[0] & 0xf0))
478         {
479          case 0x80:
480                 buf[1]=data[*pos];
481                 *pos +=1;
482                 buf[2]=data[*pos];
483                 *pos +=1;
484                 stop_note((int) channel, (int) buf[1], (int) buf[2]);
485                 break;
486          case 0x90:
487                 buf[1]=data[*pos];
488                 *pos +=1;
489                 buf[2]=data[*pos];
490                 *pos +=1;
491                 if(buf[2] == 0)
492                 {
493                         stop_note((int) channel, (int) buf[1], (int) buf[2]);
494                 }
495                 else
496                 {
497                         start_note((int) channel, (int) buf[1], (int) buf[2]);
498                 }
499                 break;
500          case 0xa0:
501                 buf[1]=data[*pos];
502                 *pos +=1;
503                 buf[2]=data[*pos];
504                 *pos +=1;
505                 set_key_pressure((int) channel, (int) buf[1], (int) buf[2]);
506                 break;
507          case 0xb0:
508                 buf[1]=data[*pos];
509                 *pos +=1;
510                 buf[2]=data[*pos];
511                 *pos +=1;
512                 set_control((int) channel, (int) buf[1], (int) buf[2]);
513                 break;
514          case 0xe0:
515                 buf[1]=data[*pos];
516                 *pos +=1;
517                 buf[2]=data[*pos];
518                 *pos +=1;
519                 set_pitchbend((int) channel, (int) ((buf[2] << 7) + buf[1]));
520                 break;
521          case 0xc0:
522                 buf[1]=data[*pos];
523                 *pos +=1;
524                 set_program((int) channel, (int) buf[1] );
525                 break;
526          case 0xd0:
527                 buf[1]=data[*pos];
528                 *pos +=1;
529                 set_chn_pressure((int) channel, (int) buf[1]);
530                 break;
531          case 0xf0:
532                 return 1;
533          default:
534                 return 3;
535         }
536         seqbuf_dump();
537         return 0;
538 }
539
540 void send_ipc(char *message)
541 {
542         printf ("sendipc %s\n", message);//##########3
543         if (ipc_queue_id<0)
544         {
545                 ipc_queue_id=msgget ((key_t) ('l'<<24) | ('d'<<16) | ('e'<<8) | 's', 
546                                      IPC_CREAT | 0660);
547                 snd=malloc(sizeof(long) + 32);
548                 snd->mtype=1;
549                 player_thread=SDL_CreateThread((int (*)(void *))play_hmi, NULL);
550 //              player_pid = play_hmi();
551         }    
552         if (strlen(message) < 16)
553         {
554                 sprintf(snd->mtext,"%s",message);
555                 msgsnd(ipc_queue_id,snd,16,0);
556         }
557 }
558
559 void kill_ipc()
560 {
561 //      send_ipc("q");
562 //      kill(player_pid,SIGTERM);
563         msgctl( ipc_queue_id, IPC_RMID, 0);
564         free(snd);
565         ipc_queue_id = -1;
566 //      player_pid = 0;
567 }
568
569 int do_ipc(int qid, struct msgbuf *buf, int flags)
570 {
571         int ipc_read;
572         CFILE *fptr = NULL;
573         float last_volume = volume;
574         int l=0;
575         
576         ipc_read = msgrcv(qid,buf,16,0,flags | MSG_NOERROR);
577         
578         switch (ipc_read)
579         {
580          case -1:
581                 if (errno == ENOMSG)
582                   break;
583                 perror("IPC trouble");
584                 break;
585          case 0:
586                 break;
587          default:
588                 printf ("do_ipc %s\n", buf->mtext);//##########3
589                 switch (buf->mtext[0])
590                 {
591                 case 'v':
592                         volume = (double)(atof(buf->mtext + 1) / 128.0);
593                         printf("vol %f->%f\n", last_volume, volume);
594                         if (last_volume <= 0 && volume > 0)
595                         {
596                                 buf->mtext[0] = 'p'; // start playing again if volume raised above 0
597                                 strcpy(buf->mtext + 1, digi_last_midi_song);
598                                 // fall through to case 'p'
599                         }
600                         else if (last_volume > 0 && volume <= 0)
601                         {
602                                 strcpy(buf->mtext, "s"); // stop playing if volume reduced to 0
603                                 stop = 2;
604                                 break;
605                         }
606                         else
607                                 break;
608                 case 'p':
609                         if (buf->mtext[1])
610                         {
611                                 strcpy(digi_last_midi_song, buf->mtext + 1);
612                                 if (volume > 0)
613                                         fptr = cfopen((buf->mtext + 1), "rb");
614                         }
615                         if(fptr != NULL)
616                         {
617                                 l = cfilelength(fptr);
618                                 data=realloc(data,(size_t) l);
619                                 cfread(data, l, 1, fptr);
620                                 cfclose(fptr);
621                                 printf ("good. fpr=%p l=%i data=%p\n", fptr, l, data);//##########3
622                                 stop = 0;
623                         }
624                         else
625                         {
626                                 strcpy(buf->mtext, "s"); // not playing, thus "stop".
627                                 stop = 2;
628                         }
629                         break;
630                  case 's':
631                         stop = 2;
632                         break;
633                  case 'q':
634 //                      SDL_KillThread(player_thread);
635                         break;  
636                 }
637                 //printf("do_ipc %s ret %i\n", buf->mtext, ipc_read); // ##########3
638         }
639         
640         return ipc_read;
641 }
642
643 void play_hmi (void * arg)
644 {
645         int i;
646         int pos = 0x308;
647         int n_chunks = 0;
648         int low_dtime;
649         int low_chunk;
650         int csec, lcsec;
651 //      pid_t loc_pid;
652         int qid;
653         int ipc_read = 0;
654         int k=0;
655         
656         struct msgbuf *rcv;
657         
658         Track_info *t_info;
659
660         printf ("play_hmi\n");//#########
661         
662         stop = 0;
663         ipc_read=0;
664 //      loc_pid=fork();
665     
666 /*      switch (loc_pid)
667         {
668          case 0:
669                 break;
670          case -1:
671                 return -1;
672          default:
673                 atexit(kill_ipc);
674                 return loc_pid;
675         }*/
676         
677 //      signal(SIGTERM, my_quit);
678         rcv=malloc(sizeof(long) + 16);
679         
680         rcv->mtype=1;
681         rcv->mtext[0]='0';
682
683         qid=msgget ((key_t) ('l'<<24) | ('d'<<16) | ('e'<<8) | 's', 0660);
684         if(qid == -1)
685         {       
686                 return;
687         }
688         
689         do
690         {
691                 ipc_read=do_ipc(qid,rcv,0);
692         }
693         while(rcv->mtext[0] != 'p');
694         
695         stop=0;
696         rcv->mtext[0] = '0';
697         
698         seq_init();
699         
700         n_chunks=data[0x30];
701         
702         t_info = malloc(sizeof(Track_info)*n_chunks);
703         
704         while(1)
705         {
706                 
707                 for(i=0;i<n_chunks;i++)
708                 {
709                         t_info[i].position = pos + 12;
710                         t_info[i].status = PLAYING;
711                         t_info[i].time = get_dtime(data,&t_info[i].position);
712                         pos += (( (0xff & data[pos + 5]) << 8 ) + (0xff & data[pos + 4]));
713                 }
714
715                 lcsec = 0;
716
717                 SEQ_START_TIMER();
718                 do
719                 {
720                         low_chunk = -1;
721                         k++;
722                         i=0;
723                         do
724                         {
725                                 if (t_info[i].status == PLAYING)
726                                   low_chunk = i;
727                                 i++;
728                         }
729                         while((low_chunk <=0) && (i<n_chunks));
730                         
731                         if (low_chunk == -1)
732                           break;
733                         
734                         low_dtime = t_info[low_chunk].time;
735                         
736                         for(i=1;i<n_chunks;i++)
737                         {
738                                 if ((t_info[i].time < low_dtime) && 
739                                     (t_info[i].status == PLAYING))
740                                 {
741                                         low_dtime = t_info[i].time;
742                                         low_chunk = i;
743                                 }
744                         }
745                         
746                         if (low_dtime < 0)
747                           printf("Serious warning: d_time negative!!!!!!\n");
748                         
749                         csec = 0.86 * low_dtime;
750                         
751                         //flush sequencer buffer after 20 events
752                         if (k == 20)
753                         {
754                                 ioctl(seqfd, SNDCTL_SEQ_SYNC);
755                                 k = 0;
756                         }
757                         
758                         if (csec != lcsec) {
759                                 SEQ_WAIT_TIME(csec);
760                         }
761                         
762                         lcsec = csec;
763                         
764                         t_info[low_chunk].status = do_track_event(data,&t_info[low_chunk].position);
765                         
766                         if (t_info[low_chunk].status == 3)
767                         {
768                                 printf("Error playing data in chunk %d\n",low_chunk);
769                                 t_info[low_chunk].status = STOPPED;
770                         }
771                         
772                         if (t_info[low_chunk].status == PLAYING)
773                           t_info[low_chunk].time += get_dtime(data,&t_info[low_chunk].position);
774                         
775                         //Check if the song has reached the end
776                         stop = t_info[0].status;
777                         for(i=1;i<n_chunks;i++)
778                           stop &= t_info[i].status;
779                         
780                         if((do_ipc(qid,rcv,IPC_NOWAIT) > 0) && (rcv->mtext[0]=='p'))
781                         {
782                                 n_chunks=data[0x30];
783                                 t_info = realloc(t_info,sizeof(Track_info)*n_chunks);
784                                 stop = 1;
785                                 rcv->mtext[0] = '0';  
786                                 stop_all();
787                         }
788                 }
789                 while(!stop);
790                 SEQ_STOP_TIMER();
791                 if( stop == 2)
792                 {
793                         stop_all();         
794                         do
795                         {
796                                 ipc_read=do_ipc(qid,rcv,0);
797                         }
798                         while(rcv->mtext[0] != 'p');
799                         rcv->mtext[0] = '0';
800                         n_chunks=data[0x30];
801                         t_info = realloc(t_info,sizeof(Track_info)*n_chunks);
802                         stop = 0;
803                 }
804                 pos=0x308;
805         }
806         free(data);
807         free(t_info);
808         free(rcv);
809         
810 }
811
812 void digi_play_midi_song(char *filename, char *melodic_bank, char *drum_bank, int loop)
813 {
814         if (FindArg("-nomusic"))
815                 return;
816
817         if (!filename)
818                 send_ipc("p");
819         else
820         {
821                 char buf[128];
822                 sprintf(buf, "p%s", filename);
823                 send_ipc(buf);
824         }
825 }
826
827 void digi_set_midi_volume( int mvolume ) { 
828         char buf[128];
829         if(FindArg("-nomusic"))
830                 return;
831
832         sprintf(buf,"v%i",mvolume);
833         send_ipc(buf);
834 }