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