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