native_midi_gpl/native_midi_gpl.c
changeset 160 c62666b42573
child 243 9df1205de531
equal deleted inserted replaced
159:01490534f9fe 160:c62666b42573
       
     1 /***************************************************************************
       
     2                            native_midi_lnx.c
       
     3 			   -----------------
       
     4 			   
       
     5     copyright            : (C) 2002 by Peter Kuȇk
       
     6     email                : kutak@stonline.sk
       
     7  ***************************************************************************/
       
     8 
       
     9 /* in this file is used code from PlayMidi    Copyright (C) 1994-1996 Nathan I. Laredo */
       
    10 
       
    11 /***************************************************************************
       
    12  *                                                                         *
       
    13  *   This program is free software; you can redistribute it and/or modify  *
       
    14  *   it under the terms of the GNU General Public License as published by  *
       
    15  *   the Free Software Foundation; either version 2 of the License, or     *
       
    16  *   (at your option) any later version.                                   *
       
    17  *                                                                         *
       
    18  ***************************************************************************/
       
    19 
       
    20 #if defined(linux) || defined(__FreeBSD__)
       
    21 
       
    22 #ifndef __FreeBSD__
       
    23 #include <getopt.h>
       
    24 #endif
       
    25 #include <fcntl.h>
       
    26 #include <ctype.h>
       
    27 #include <unistd.h>
       
    28 #include <sys/stat.h>
       
    29 #include <string.h>
       
    30 #include "SDL_thread.h"
       
    31 #include "native_midi.h"
       
    32 #include "playmidi.h"
       
    33 
       
    34 SEQ_DEFINEBUF(SEQUENCERBLOCKSIZE);
       
    35 
       
    36 int play_fm = 0, play_gus = 0, play_ext = 0, play_awe = 0;
       
    37 int opl3_patch_aviable = 0, fm_patch_aviable = 0;
       
    38 
       
    39 struct miditrack seq[MAXTRKS];
       
    40 struct synth_info card_info[MAX_CARDS];
       
    41 
       
    42 int FORCE_EXT_DEV = -1;
       
    43 int chanmask = 0xffff, perc = PERCUSSION;
       
    44 int dochan = 1, force8bit = 0, wantopl3 = FM_DEFAULT_MODE;
       
    45 int patchloaded[256], fmloaded[256], useprog[16], usevol[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
       
    46 int reverb = 0, chorus = 0, nrsynths, nrmidis;
       
    47 int sb_dev = -1, gus_dev = -1, ext_dev = -1, awe_dev = -1, p_remap = 0;
       
    48 int seqfd,  MT32 = 0;
       
    49 FILE *mfd;
       
    50 unsigned long int default_tempo;
       
    51 float skew = 1.0;
       
    52 char ImPlaying = 0;
       
    53 SDL_Thread *playevents_thread=NULL;
       
    54 
       
    55 extern int ntrks;
       
    56 extern char *gmvoice[256];
       
    57 extern int mt32pgm[128];
       
    58 extern int note_vel[16][128];
       
    59 extern int playevents();
       
    60 extern int gus_load(int);
       
    61 extern int readmidi(unsigned char *, off_t);
       
    62 extern void loadfm();
       
    63 
       
    64 void seqbuf_dump();
       
    65 int synth_setup();
       
    66 
       
    67 struct _NativeMidiSong
       
    68 {
       
    69     char *filebuf;
       
    70     unsigned long int file_size;
       
    71 };
       
    72 
       
    73 int native_midi_detect()
       
    74 {
       
    75 
       
    76     int sbfd;
       
    77     int ret=0;    
       
    78 
       
    79     /* Open sequencer device */
       
    80     if ((seqfd = open(SEQUENCER_DEV, O_WRONLY, 0)) < 0) 
       
    81     {
       
    82 	perror("open " SEQUENCER_DEV);
       
    83 	return 0;
       
    84     }
       
    85 
       
    86     gus_dev = -1;
       
    87     sb_dev = -1;
       
    88     ext_dev = -1;
       
    89     awe_dev = -1;
       
    90     play_fm = 0;
       
    91     play_gus = 0;
       
    92     play_ext = 0;
       
    93     play_awe = 0;
       
    94     
       
    95     opl3_patch_aviable = 0;
       
    96     fm_patch_aviable = 0;
       
    97 
       
    98     sbfd = open(SBMELODIC, O_RDONLY, 0);
       
    99     if (sbfd != -1)
       
   100     {
       
   101 	close(sbfd);
       
   102 	sbfd = open(SBDRUMS, O_RDONLY, 0);
       
   103 	if (sbfd != -1)
       
   104 	{
       
   105             close(sbfd);
       
   106 	    fm_patch_aviable = 1;
       
   107 	}
       
   108     }
       
   109 
       
   110     sbfd = open(O3MELODIC, O_RDONLY, 0);
       
   111     if (sbfd != -1)
       
   112     {
       
   113         close(sbfd);
       
   114         sbfd = open(O3DRUMS, O_RDONLY, 0);
       
   115 	if (sbfd != -1)
       
   116 	{
       
   117             close(sbfd);
       
   118 	    opl3_patch_aviable = 1;
       
   119 	}
       
   120     }
       
   121 
       
   122     ret=synth_setup();
       
   123 
       
   124     /* Close sequencer device */
       
   125     close(seqfd);
       
   126 
       
   127     return ret;
       
   128 }
       
   129 
       
   130 NativeMidiSong *native_midi_loadsong(char *midifile)
       
   131 {
       
   132     NativeMidiSong	*song = NULL;
       
   133     char 		*extra;
       
   134     int 		piped = 0;
       
   135     struct stat 	info;
       
   136 
       
   137     song = malloc(sizeof(NativeMidiSong));
       
   138     if (!song)
       
   139     {
       
   140 	return NULL;
       
   141     };
       
   142     if (stat(midifile, &info) == -1) 
       
   143     {
       
   144         if ((extra = malloc(strlen(midifile) + 4)) == NULL)
       
   145         {
       
   146 	    goto end;
       
   147 	}
       
   148 	sprintf(extra, "%s.mid", midifile);
       
   149 	if (stat(extra, &info) == -1)
       
   150 	{
       
   151 	    free(extra);
       
   152 	    goto end;
       
   153 	}
       
   154 	if ((mfd = fopen(extra, "r")) == NULL)
       
   155 	{
       
   156 	    free(extra);
       
   157 	    goto end;
       
   158 	}
       
   159 	free(extra);
       
   160     } else
       
   161     {
       
   162         char *ext = strrchr(midifile, '.');
       
   163         if (ext && strcmp(ext, ".gz") == 0) 
       
   164 	{
       
   165 	    char temp[1024];
       
   166 	    piped = 1;
       
   167 	    sprintf(temp, "gzip -l %s", midifile);
       
   168 	    if ((mfd = popen(temp, "r")) == NULL)
       
   169 	    {
       
   170 	        goto end;
       
   171 	    }
       
   172 	    fgets(temp, sizeof(temp), mfd); /* skip 1st line */
       
   173 	    fgets(temp, sizeof(temp), mfd);
       
   174 	    strtok(temp, " "); /* compressed size */
       
   175 	    info.st_size = atoi(strtok(NULL, " ")); /* original size */
       
   176 	    pclose(mfd);
       
   177 	    sprintf(temp, "gzip -d -c %s",midifile);
       
   178 	    if ((mfd = popen(temp, "r")) == NULL)
       
   179 	    {
       
   180 	        goto end;
       
   181 	    }
       
   182 	}else if ((mfd = fopen(midifile, "r")) == NULL)
       
   183 	{
       
   184 	    goto end;
       
   185 	}
       
   186     }
       
   187     if ((song->filebuf = malloc(info.st_size)) == NULL)
       
   188     {
       
   189         if (piped)
       
   190         {
       
   191 	    pclose(mfd);
       
   192 	}else
       
   193 	{
       
   194 	    fclose(mfd);
       
   195 	}
       
   196 	goto end;
       
   197     }
       
   198     song->file_size=info.st_size;
       
   199     fread(song->filebuf, 1, info.st_size, mfd);
       
   200     if (piped)
       
   201     {
       
   202         pclose(mfd);
       
   203     } else
       
   204     {
       
   205         fclose(mfd);
       
   206     }
       
   207     
       
   208   return song;
       
   209 
       
   210 end:
       
   211     free(song);
       
   212     return NULL;
       
   213 }
       
   214 
       
   215 void native_midi_freesong(NativeMidiSong *song)
       
   216 {
       
   217     free(song->filebuf);
       
   218     free(song);
       
   219 }
       
   220 
       
   221 void native_midi_start(NativeMidiSong *song)
       
   222 {
       
   223 
       
   224     int i, error = 0, j;
       
   225 
       
   226 
       
   227     for (i = 0; i < 16; i++)
       
   228     {
       
   229 	useprog[i] = 0;	/* reset options */
       
   230     }
       
   231     
       
   232     /* Open sequencer device */
       
   233     if ((seqfd = open(SEQUENCER_DEV, O_WRONLY, 0)) < 0) 
       
   234     {
       
   235 	perror("open " SEQUENCER_DEV);
       
   236 	goto eend;
       
   237     }
       
   238     if(!synth_setup()) { goto end;};
       
   239 
       
   240 
       
   241 	    if (play_gus)
       
   242 	    {
       
   243 		gus_load(-1);
       
   244 	    }
       
   245 	    default_tempo = 500000;
       
   246 	    /* error holds number of tracks read */
       
   247 	    error = readmidi(song->filebuf, song->file_size);
       
   248 	    if (play_gus && error > 0) 
       
   249 	    {
       
   250 		int i;		/* need to keep other i safe */
       
   251 #define CMD (seq[i].data[j] & 0xf0)
       
   252 #define CHN (seq[i].data[j] & 0x0f)
       
   253 #define PGM (seq[i].data[j + 1])
       
   254 		/* REALLY STUPID way to preload GUS, but it works */
       
   255 		for (i = 0; i < ntrks; i++)
       
   256 		    for (j = 0; j < seq[i].length - 5; j++)
       
   257 			if (ISGUS(CHN) && !(PGM & 0x80) &&
       
   258 			    ((CMD == MIDI_PGM_CHANGE && !ISPERC(CHN))
       
   259 			     || (CMD == MIDI_NOTEON && ISPERC(CHN))))
       
   260 			    gus_load(ISPERC(CHN) ? PGM + 128 :
       
   261 				     useprog[CHN] ? useprog[CHN] - 1 :
       
   262 				     MT32 ? mt32pgm[PGM] : PGM);
       
   263 		/* make sure that some program was loaded to use */
       
   264 		for (j = 0; patchloaded[j] != 1 && j < 128; j++);
       
   265 		if (j > 127)
       
   266 		    gus_load(0);
       
   267 	    }
       
   268 				/* if there's an error skip to next file */
       
   269 	    if (error > 0)	/* error holds number of tracks read */
       
   270 	    {
       
   271 		ImPlaying=1;
       
   272 	    	playevents_thread=SDL_CreateThread(playevents,NULL);
       
   273 	    }
       
   274 
       
   275 end:
       
   276 eend:
       
   277 }
       
   278 
       
   279 void native_midi_stop()
       
   280 {
       
   281     /* Close sequencer device */
       
   282     close(seqfd);
       
   283 }
       
   284 
       
   285 int native_midi_active()
       
   286 {
       
   287     return ImPlaying;
       
   288 }
       
   289 
       
   290 void native_midi_setvolume(int volume)
       
   291 {
       
   292 }
       
   293 
       
   294 char *native_midi_error()
       
   295 {
       
   296   return "stala sa chyba";
       
   297 }
       
   298 
       
   299 void seqbuf_dump()
       
   300 {
       
   301     if (_seqbufptr)
       
   302 	if (write(seqfd, _seqbuf, _seqbufptr) == -1) {
       
   303 	    perror("write " SEQUENCER_DEV);
       
   304 	    return;
       
   305 	}
       
   306     _seqbufptr = 0;
       
   307 }
       
   308 
       
   309 int synth_setup()
       
   310 {
       
   311     int i;
       
   312     char *nativemusicenv = getenv("SDL_NATIVE_MUSIC");
       
   313     char *extmidi=getenv("SDL_NATIVE_MUSIC_EXT");
       
   314 
       
   315     if(extmidi)
       
   316     {
       
   317 	
       
   318     	FORCE_EXT_DEV = atoi(extmidi);
       
   319 	printf("EXT midi %s , %d \n",extmidi,FORCE_EXT_DEV);
       
   320     }
       
   321     
       
   322     if (ioctl(seqfd, SNDCTL_SEQ_NRSYNTHS, &nrsynths) == -1) 
       
   323     {
       
   324 	fprintf(stderr, "there is no soundcard\n");
       
   325 	return 0;
       
   326     }
       
   327     for (i = 0; i < nrsynths; i++) 
       
   328     {
       
   329 	card_info[i].device = i;
       
   330 	if (ioctl(seqfd, SNDCTL_SYNTH_INFO, &card_info[i]) == -1) 
       
   331 	{
       
   332 	    fprintf(stderr, "cannot get info on soundcard\n");
       
   333 	    perror(SEQUENCER_DEV);
       
   334 	    return 0;
       
   335 	}
       
   336 	card_info[i].device = i;
       
   337 	if (card_info[i].synth_type == SYNTH_TYPE_SAMPLE
       
   338 	    && card_info[i].synth_subtype == SAMPLE_TYPE_GUS)
       
   339 	{
       
   340 	    gus_dev = i;
       
   341 	}else if (card_info[i].synth_type == SYNTH_TYPE_SAMPLE
       
   342 	    && card_info[i].synth_subtype == SAMPLE_TYPE_AWE32)
       
   343 	{
       
   344 	    awe_dev = i;
       
   345 	}else if (card_info[i].synth_type == SYNTH_TYPE_FM) 
       
   346 	{
       
   347 	    sb_dev = i;
       
   348 	    if (play_fm)
       
   349 		loadfm();
       
   350 	    if (wantopl3) 
       
   351 	    {
       
   352 		card_info[i].nr_voices = 12;	/* we have 12 with 4-op */
       
   353 	    }
       
   354 	}
       
   355     }
       
   356 
       
   357     if (gus_dev >= 0) {
       
   358 	if (ioctl(seqfd, SNDCTL_SEQ_RESETSAMPLES, &gus_dev) == -1) 
       
   359 	{
       
   360 	    perror("Sample reset");
       
   361 	    return 0;
       
   362 	}
       
   363     }
       
   364     if (ioctl(seqfd, SNDCTL_SEQ_NRMIDIS, &nrmidis) == -1) 
       
   365     {
       
   366 	fprintf(stderr, "can't get info about midi ports\n");
       
   367 	return 0;
       
   368     }
       
   369     if (nrmidis > 0) {
       
   370 	if (FORCE_EXT_DEV >= 0)
       
   371 	    ext_dev = FORCE_EXT_DEV;
       
   372 	else
       
   373 	    ext_dev = nrmidis - 1;
       
   374     }
       
   375 
       
   376     if( nativemusicenv ) /* select device by SDL_NATIVE_MUSIC */
       
   377     {
       
   378 	if(strcasecmp(nativemusicenv,"GUS") == 0)
       
   379 	{
       
   380     	    if( gus_dev >= 0 )
       
   381 	    {
       
   382     		play_gus = 1;
       
   383 	        awe_dev = -1;
       
   384 		sb_dev  = -1;
       
   385 	        ext_dev = -1;
       
   386 	        return 1;
       
   387             }else
       
   388 	    {
       
   389     		play_gus = 0;
       
   390 		return 0;
       
   391 	    }
       
   392 	}else if(strcasecmp(nativemusicenv,"AWE") == 0)
       
   393 	{
       
   394     	    if( awe_dev >= 0 )
       
   395 	    {
       
   396     		play_awe = 1;
       
   397 	        gus_dev = -1;
       
   398 		sb_dev  = -1;
       
   399 	        ext_dev = -1;
       
   400 	        return 1;
       
   401             }else
       
   402 	    {
       
   403     		play_awe = 0;
       
   404 		return 0;
       
   405 	    }
       
   406 	}else if(strcasecmp(nativemusicenv,"FM") == 0)
       
   407 	{
       
   408     	    if( sb_dev >= 0 && fm_patch_aviable )
       
   409 	    {
       
   410     		play_fm = 1;
       
   411 		gus_dev = -1;
       
   412 	        awe_dev = -1;
       
   413 	        ext_dev = -1;
       
   414 	        wantopl3 = 0;
       
   415 	        return 1;
       
   416             }else
       
   417 	    {
       
   418     		play_fm = 0;
       
   419 		return 0;
       
   420 	    }
       
   421 	}else if(strcasecmp(nativemusicenv,"OPL3") == 0)
       
   422 	{
       
   423     	    if( sb_dev >= 0 && opl3_patch_aviable )
       
   424 	    {
       
   425     		play_fm = 1;
       
   426 		gus_dev = -1;
       
   427 	        awe_dev = -1;
       
   428 	        ext_dev = -1;
       
   429 	        wantopl3 = 1;
       
   430 	        return 1;
       
   431             }else
       
   432 	    {
       
   433     		play_fm = 0;
       
   434 		return 0;
       
   435 	    }
       
   436 	}else if(strcasecmp(nativemusicenv,"EXT") == 0)
       
   437 	{
       
   438     	    if( ext_dev >= 0 )
       
   439 	    {
       
   440     		play_ext = 1;
       
   441 	        gus_dev = -1;
       
   442 	        awe_dev = -1;
       
   443 		sb_dev  = -1;
       
   444 	        return 1;
       
   445             }else
       
   446 	    {
       
   447     		play_ext = 0;
       
   448 		return 0;
       
   449 	    }
       
   450 	}
       
   451     }
       
   452     /* autoselect best device */
       
   453     if( gus_dev >= 0 )
       
   454     {
       
   455         play_gus = 1;
       
   456         awe_dev = -1;
       
   457         sb_dev  = -1;
       
   458         ext_dev = -1;
       
   459         return 1;
       
   460         }
       
   461     if( awe_dev >= 0 )
       
   462     {
       
   463         play_awe = 1;
       
   464 	gus_dev = -1;
       
   465         sb_dev  = -1;
       
   466         ext_dev = -1;
       
   467         return 1;
       
   468     }
       
   469     if( sb_dev >= 0 && fm_patch_aviable )
       
   470     {
       
   471         play_fm = 1;
       
   472 	gus_dev = -1;
       
   473         awe_dev = -1;
       
   474         ext_dev = -1;
       
   475         return 2;	/* return 1 if use FM befor Timidity */
       
   476     }
       
   477     if( ext_dev >= 0 )
       
   478     {
       
   479         play_ext = 1;
       
   480 	gus_dev = -1;
       
   481         awe_dev = -1;
       
   482         sb_dev  = -1;
       
   483         return 3;
       
   484     }
       
   485     return 0;
       
   486 }
       
   487 
       
   488 #endif /* linux || FreeBSD */