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