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