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