⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 readmidi.c

📁 SDL_mixer 是一个基于 SDL 的混音器
💻 C
📖 第 1 页 / 共 2 页
字号:
static int read_track(int append){  MidiEventList *meep;  MidiEventList *next, *new;  int32 len;  char tmp[4];  meep=evlist;  if (append && meep)    {      /* find the last event in the list */      for (; meep->next; meep=meep->next)	;      at=meep->event.time;    }  else    at=0;  /* Check the formalities */  if ((SDL_RWread(rw,tmp,1,4) != 4) || (SDL_RWread(rw,&len,4,1) != 1))    {      ctl->cmsg(CMSG_ERROR, VERB_NORMAL,	   "%s: Can't read track header.", current_filename);      return -1;    }  len=BE_LONG(len);  if (memcmp(tmp, "MTrk", 4))    {      ctl->cmsg(CMSG_ERROR, VERB_NORMAL,	   "%s: Corrupt MIDI file.", current_filename);      return -2;    }  for (;;)    {      if (!(new=read_midi_event())) /* Some kind of error  */	return -2;      if (new==MAGIC_EOT) /* End-of-track Hack. */	{	  return 0;	}      next=meep->next;      while (next && (next->event.time < new->event.time))	{	  meep=next;	  next=meep->next;	}	        new->next=next;      meep->next=new;      event_count++; /* Count the event. (About one?) */      meep=new;    }}/* Free the linked event list from memory. */static void free_midi_list(void){  MidiEventList *meep, *next;  if (!(meep=evlist)) return;  while (meep)    {      next=meep->next;      free(meep);      meep=next;    }  evlist=0;}static void xremap_percussion(int *banknumpt, int *this_notept, int this_kit) {        int i, newmap;        int banknum = *banknumpt;        int this_note = *this_notept;        int newbank, newnote;        if (this_kit != 127 && this_kit != 126) return;        for (i = 0; i < XMAPMAX; i++) {                newmap = xmap[i][0];                if (!newmap) return;                if (this_kit == 127 && newmap != XGDRUM) continue;                if (this_kit == 126 && newmap != SFXDRUM1) continue;                if (xmap[i][1] != banknum) continue;                if (xmap[i][3] != this_note) continue;                newbank = xmap[i][2];                newnote = xmap[i][4];                if (newbank == banknum && newnote == this_note) return;                if (!drumset[newbank]) return;                *banknumpt = newbank;                *this_notept = newnote;                return;        }}/* Allocate an array of MidiEvents and fill it from the linked list of   events, marking used instruments for loading. Convert event times to   samples: handle tempo changes. Strip unnecessary events from the list.   Free the linked list. */static MidiEvent *groom_list(int32 divisions,int32 *eventsp,int32 *samplesp){  MidiEvent *groomed_list, *lp;  MidiEventList *meep;  int32 i, our_event_count, tempo, skip_this_event, new_value;  int32 sample_cum, samples_to_do, at, st, dt, counting_time;  int current_bank[MAXCHAN], current_banktype[MAXCHAN], current_set[MAXCHAN],    current_kit[MAXCHAN], current_program[MAXCHAN];  /* Or should each bank have its own current program? */  int dset, dnote, drumsflag, mprog;  for (i=0; i<MAXCHAN; i++)    {      current_bank[i]=0;      current_banktype[i]=0;      current_set[i]=0;      current_kit[i]=channel[i].kit;      current_program[i]=default_program;    }  tempo=500000;  compute_sample_increment(tempo, divisions);  /* This may allocate a bit more than we need */  groomed_list=lp=safe_malloc(sizeof(MidiEvent) * (event_count+1));  meep=evlist;  our_event_count=0;  st=at=sample_cum=0;  counting_time=2; /* We strip any silence before the first NOTE ON. */  for (i=0; i<event_count; i++)    {      skip_this_event=0;      ctl->cmsg(CMSG_INFO, VERB_DEBUG_SILLY,		"%6d: ch %2d: event %d (%d,%d)",		meep->event.time, meep->event.channel + 1,		meep->event.type, meep->event.a, meep->event.b);      if (meep->event.type==ME_TEMPO)	{	  tempo=	    meep->event.channel + meep->event.b * 256 + meep->event.a * 65536;	  compute_sample_increment(tempo, divisions);	  skip_this_event=1;	}      else if ((quietchannels & (1<<meep->event.channel)))	skip_this_event=1;      else switch (meep->event.type)	{	case ME_PROGRAM:	  if (current_kit[meep->event.channel])	    {	      if (current_kit[meep->event.channel]==126)		{		  /* note request for 2nd sfx rhythm kit */		  if (meep->event.a && drumset[SFXDRUM2])		  {			 current_kit[meep->event.channel]=125;			 current_set[meep->event.channel]=SFXDRUM2;		         new_value=SFXDRUM2;		  }		  else if (!meep->event.a && drumset[SFXDRUM1])		  {			 current_set[meep->event.channel]=SFXDRUM1;		         new_value=SFXDRUM1;		  }		  else		  {		  	ctl->cmsg(CMSG_WARNING, VERB_VERBOSE,		       		"XG SFX drum set is undefined");			skip_this_event=1;		  	break;		  }		}	      if (drumset[meep->event.a]) /* Is this a defined drumset? */		new_value=meep->event.a;	      else		{		  ctl->cmsg(CMSG_WARNING, VERB_VERBOSE,		       "Drum set %d is undefined", meep->event.a);		  if (drumset[0])		      new_value=meep->event.a=0;		  else		    {			skip_this_event=1;			break;		    }		}	      if (current_set[meep->event.channel] != new_value)		current_set[meep->event.channel]=new_value;	      else 		skip_this_event=1;	    }	  else	    {	      new_value=meep->event.a;	      if ((current_program[meep->event.channel] != SPECIAL_PROGRAM)		  && (current_program[meep->event.channel] != new_value))		current_program[meep->event.channel] = new_value;	      else		skip_this_event=1;	    }	  break;	case ME_NOTEON:	  if (counting_time)	    counting_time=1;	  drumsflag = current_kit[meep->event.channel];	  if (drumsflag) /* percussion channel? */	    {	      dset = current_set[meep->event.channel];	      dnote=meep->event.a;	      if (XG_System_On) xremap_percussion(&dset, &dnote, drumsflag);	      /*if (current_config_pc42b) pcmap(&dset, &dnote, &mprog, &drumsflag);*/	     if (drumsflag)	     {	      /* Mark this instrument to be loaded */	      if (!(drumset[dset]->tone[dnote].layer))	       {		drumset[dset]->tone[dnote].layer=		    MAGIC_LOAD_INSTRUMENT;	       }	      else drumset[dset]->tone[dnote].last_used		 = current_tune_number;	      if (!channel[meep->event.channel].name) channel[meep->event.channel].name=		    drumset[dset]->name;	     }	    }	  if (!drumsflag) /* not percussion */	    {	      int chan=meep->event.channel;	      int banknum;	      if (current_banktype[chan]) banknum=SFXBANK;	      else banknum=current_bank[chan];	      mprog = current_program[chan];	      if (mprog==SPECIAL_PROGRAM)		break;	      if (XG_System_On && banknum==SFXBANK && !tonebank[SFXBANK] && tonebank[120]) 		      banknum = 120;	      /*if (current_config_pc42b) pcmap(&banknum, &dnote, &mprog, &drumsflag);*/	     if (drumsflag)	     {	      /* Mark this instrument to be loaded */	      if (!(drumset[dset]->tone[dnote].layer))	       {		drumset[dset]->tone[dnote].layer=MAGIC_LOAD_INSTRUMENT;	       }	      else drumset[dset]->tone[dnote].last_used = current_tune_number;	      if (!channel[meep->event.channel].name) channel[meep->event.channel].name=		    drumset[dset]->name;	     }	     if (!drumsflag)	     {	      /* Mark this instrument to be loaded */	      if (!(tonebank[banknum]->tone[mprog].layer))		{		  tonebank[banknum]->tone[mprog].layer=MAGIC_LOAD_INSTRUMENT;		}	      else tonebank[banknum]->tone[mprog].last_used = current_tune_number;	      if (!channel[meep->event.channel].name) channel[meep->event.channel].name=		    tonebank[banknum]->tone[mprog].name;	     }	    }	  break;	case ME_TONE_KIT:	  if (!meep->event.a || meep->event.a == 127)	    {	      new_value=meep->event.a;	      if (current_kit[meep->event.channel] != new_value)		current_kit[meep->event.channel]=new_value;	      else 		skip_this_event=1;	      break;	    }	  else if (meep->event.a == 126)	    {	      if (drumset[SFXDRUM1]) /* Is this a defined tone bank? */	        new_value=meep->event.a;	      else		{	          ctl->cmsg(CMSG_WARNING, VERB_VERBOSE,		   "XG rhythm kit %d is undefined", meep->event.a);	          skip_this_event=1;	          break;		}	      current_set[meep->event.channel]=SFXDRUM1;	      current_kit[meep->event.channel]=new_value;	      break;	    }	  else if (meep->event.a != SFX_BANKTYPE)	    {	      ctl->cmsg(CMSG_WARNING, VERB_VERBOSE,		   "XG kit %d is impossible", meep->event.a);	      skip_this_event=1;	      break;	    }	  if (current_kit[meep->event.channel])	    {	      skip_this_event=1;	      break;	    }	  if (tonebank[SFXBANK] || tonebank[120]) /* Is this a defined tone bank? */	    new_value=SFX_BANKTYPE;	  else 	    {	      ctl->cmsg(CMSG_WARNING, VERB_VERBOSE,		   "XG Sfx bank is undefined");	      skip_this_event=1;	      break;	    }	  if (current_banktype[meep->event.channel]!=new_value)	    current_banktype[meep->event.channel]=new_value;	  else	    skip_this_event=1;	  break;	case ME_TONE_BANK:	  if (current_kit[meep->event.channel])	    {	      skip_this_event=1;	      break;	    }	  if (XG_System_On && meep->event.a > 0 && meep->event.a < 48) {	      channel[meep->event.channel].variationbank=meep->event.a;	      ctl->cmsg(CMSG_WARNING, VERB_VERBOSE,		   "XG variation bank %d", meep->event.a);	      new_value=meep->event.a=0;	  }	  else if (tonebank[meep->event.a]) /* Is this a defined tone bank? */	    new_value=meep->event.a;	  else 	    {	      ctl->cmsg(CMSG_WARNING, VERB_VERBOSE,		   "Tone bank %d is undefined", meep->event.a);	      new_value=meep->event.a=0;	    }	  if (current_bank[meep->event.channel]!=new_value)	    current_bank[meep->event.channel]=new_value;	  else	    skip_this_event=1;	  break;	case ME_HARMONICCONTENT:	  channel[meep->event.channel].harmoniccontent=meep->event.a;	  break;	case ME_BRIGHTNESS:	  channel[meep->event.channel].brightness=meep->event.a;	  break;	}      /* Recompute time in samples*/      if ((dt=meep->event.time - at) && !counting_time)	{	  samples_to_do=sample_increment * dt;	  sample_cum += sample_correction * dt;	  if (sample_cum & 0xFFFF0000)	    {	      samples_to_do += ((sample_cum >> 16) & 0xFFFF);	      sample_cum &= 0x0000FFFF;	    }	  st += samples_to_do;	}      else if (counting_time==1) counting_time=0;      if (!skip_this_event)	{	  /* Add the event to the list */	  *lp=meep->event;	  lp->time=st;	  lp++;	  our_event_count++;	}      at=meep->event.time;      meep=meep->next;    }  /* Add an End-of-Track event */  lp->time=st;  lp->type=ME_EOT;  our_event_count++;  free_midi_list();    *eventsp=our_event_count;  *samplesp=st;  return groomed_list;}MidiEvent *read_midi_file(SDL_RWops *mrw, int32 *count, int32 *sp){  int32 len, divisions;  int16 format, tracks, divisions_tmp;  int i;  char tmp[4];  rw = mrw;  event_count=0;  at=0;  evlist=0;  GM_System_On=GS_System_On=XG_System_On=0;  /* vol_table = def_vol_table; */  XG_System_reverb_type=XG_System_chorus_type=XG_System_variation_type=0;  memset(&drumvolume,-1,sizeof(drumvolume));  memset(&drumchorusdepth,-1,sizeof(drumchorusdepth));  memset(&drumreverberation,-1,sizeof(drumreverberation));  memset(&drumpanpot,NO_PANNING,sizeof(drumpanpot));  for (i=0; i<MAXCHAN; i++)     {	if (ISDRUMCHANNEL(i)) channel[i].kit = 127;	else channel[i].kit = 0;	channel[i].brightness = 64;	channel[i].harmoniccontent = 64;	channel[i].variationbank = 0;	channel[i].chorusdepth = 0;	channel[i].reverberation = 0;	channel[i].transpose = 0;     }past_riff:  if ((SDL_RWread(rw,tmp,1,4) != 4) || (SDL_RWread(rw,&len,4,1) != 1))    {     /* if (ferror(fp))	{	  ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s", current_filename, 	       strerror(errno));	}      else*/	ctl->cmsg(CMSG_ERROR, VERB_NORMAL, 	     "%s: Not a MIDI file!", current_filename);      return 0;    }  len=BE_LONG(len);  if (!memcmp(tmp, "RIFF", 4))    {      SDL_RWread(rw,tmp,1,12);      goto past_riff;    }  if (memcmp(tmp, "MThd", 4) || len < 6)    {      ctl->cmsg(CMSG_ERROR, VERB_NORMAL,	   "%s: Not a MIDI file!", current_filename);      return 0;    }  SDL_RWread(rw,&format, 2, 1);  SDL_RWread(rw,&tracks, 2, 1);  SDL_RWread(rw,&divisions_tmp, 2, 1);  format=BE_SHORT(format);  tracks=BE_SHORT(tracks);  track_info = tracks;  curr_track = 0;  curr_title_track = -1;  divisions_tmp=BE_SHORT(divisions_tmp);  if (divisions_tmp<0)    {      /* SMPTE time -- totally untested. Got a MIDI file that uses this? */      divisions=	(int32)(-(divisions_tmp/256)) * (int32)(divisions_tmp & 0xFF);    }  else divisions=(int32)(divisions_tmp);  if (len > 6)    {      ctl->cmsg(CMSG_WARNING, VERB_NORMAL, 	   "%s: MIDI file header size %ld bytes", 	   current_filename, len);      SDL_RWseek(rw, len-6, SEEK_CUR); /* skip the excess */    }  if (format<0 || format >2)    {      ctl->cmsg(CMSG_ERROR, VERB_NORMAL, 	   "%s: Unknown MIDI file format %d", current_filename, format);      return 0;    }  ctl->cmsg(CMSG_INFO, VERB_VERBOSE,        "Format: %d  Tracks: %d  Divisions: %d", format, tracks, divisions);  /* Put a do-nothing event first in the list for easier processing */  evlist=safe_malloc(sizeof(MidiEventList));  evlist->event.time=0;  evlist->event.type=ME_NONE;  evlist->next=0;  event_count++;  switch(format)    {    case 0:      if (read_track(0))	{	  free_midi_list();	  return 0;	}      else curr_track++;      break;    case 1:      for (i=0; i<tracks; i++)	if (read_track(0))	  {	    free_midi_list();	    return 0;	  }      break;    case 2: /* We simply play the tracks sequentially */      for (i=0; i<tracks; i++)	if (read_track(1))	  {	    free_midi_list();	    return 0;	  }         else curr_track++;      break;    }  return groom_list(divisions, count, sp);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -