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

📄 readmidi.c

📁 SDL_mixer 是一个基于 SDL 的混音器
💻 C
📖 第 1 页 / 共 2 页
字号:
/*    TiMidity -- Experimental MIDI to WAVE converter    Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>    This program is free software; you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation; either version 2 of the License, or    (at your option) any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program; if not, write to the Free Software    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <SDL_rwops.h>#include "config.h"#include "common.h"#include "instrum.h"#include "playmidi.h"#include "readmidi.h"#include "output.h"#include "ctrlmode.h"int32 quietchannels=0;static int midi_port_number;char midi_name[FILENAME_MAX+1];static int track_info, curr_track, curr_title_track;static char title[128];#if MAXCHAN <= 16#define MERGE_CHANNEL_PORT(ch) ((int)(ch))#else#define MERGE_CHANNEL_PORT(ch) ((int)(ch) | (midi_port_number << 4))#endif/* to avoid some unnecessary parameter passing */static MidiEventList *evlist;static int32 event_count;static SDL_RWops *rw;static int32 at;/* These would both fit into 32 bits, but they are often added in   large multiples, so it's simpler to have two roomy ints */static int32 sample_increment, sample_correction; /*samples per MIDI delta-t*//* Computes how many (fractional) samples one MIDI delta-time unit contains */static void compute_sample_increment(int32 tempo, int32 divisions){  double a;  a = (double) (tempo) * (double) (play_mode->rate) * (65536.0/1000000.0) /    (double)(divisions);  sample_correction = (int32)(a) & 0xFFFF;  sample_increment = (int32)(a) >> 16;  ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Samples per delta-t: %d (correction %d)",       sample_increment, sample_correction);}/* Read variable-length number (7 bits per byte, MSB first) */static int32 getvl(void){  int32 l=0;  uint8 c;  for (;;)    {      SDL_RWread(rw,&c,1,1);      l += (c & 0x7f);      if (!(c & 0x80)) return l;      l<<=7;    }}static int sysex(uint32 len, uint8 *syschan, uint8 *sysa, uint8 *sysb, SDL_RWops *rw){  unsigned char *s=(unsigned char *)safe_malloc(len);  int id, model, ch, port, adhi, adlo, cd, dta, dtb, dtc;  if (len != (uint32)SDL_RWread(rw, s, 1, len))    {      free(s);      return 0;    }  if (len<5) { free(s); return 0; }  if (curr_track == curr_title_track && track_info > 1) title[0] = '\0';  id=s[0]; port=s[1]; model=s[2]; adhi=s[3]; adlo=s[4];  if (id==0x7e && port==0x7f && model==0x09 && adhi==0x01)    {      ctl->cmsg(CMSG_TEXT, VERB_VERBOSE, "GM System On", len);      GM_System_On=1;      free(s);      return 0;    }  ch = adlo & 0x0f;  *syschan=(uint8)ch;  if (id==0x7f && len==7 && port==0x7f && model==0x04 && adhi==0x01)    {      ctl->cmsg(CMSG_TEXT, VERB_DEBUG, "Master Volume %d", s[4]+(s[5]<<7));      free(s);      *sysa = s[4];      *sysb = s[5];      return ME_MASTERVOLUME;      /** return s[4]+(s[5]<<7); **/    }  if (len<8) { free(s); return 0; }  port &=0x0f;  ch = (adlo & 0x0f) | ((port & 0x03) << 4);  *syschan=(uint8)ch;  cd=s[5]; dta=s[6];  if (len >= 8) dtb=s[7];  else dtb=-1;  if (len >= 9) dtc=s[8];  else dtc=-1;  free(s);  if (id==0x43 && model==0x4c)    {	if (!adhi && !adlo && cd==0x7e && !dta)	  {      	    ctl->cmsg(CMSG_TEXT, VERB_VERBOSE, "XG System On", len);	    XG_System_On=1;	    #ifdef tplus	    vol_table = xg_vol_table;	    #endif	  }	else if (adhi == 2 && adlo == 1)	 {	    if (dtb==8) dtb=3;	    switch (cd)	      {		case 0x00:		  XG_System_reverb_type=(dta<<3)+dtb;		  break;		case 0x20:		  XG_System_chorus_type=((dta-64)<<3)+dtb;		  break;		case 0x40:		  XG_System_variation_type=dta;		  break;		case 0x5a:		  /* dta==0 Insertion; dta==1 System */		  break;		default: break;	      }	 }	else if (adhi == 8 && cd <= 40)	 {	    *sysa = dta & 0x7f;	    switch (cd)	      {		case 0x01: /* bank select MSB */		  return ME_TONE_KIT;		  break;		case 0x02: /* bank select LSB */		  return ME_TONE_BANK;		  break;		case 0x03: /* program number */	      		/** MIDIEVENT(d->at, ME_PROGRAM, lastchan, a, 0); **/		  return ME_PROGRAM;		  break;		case 0x08: /*  */		  /* d->channel[adlo&0x0f].transpose = (char)(dta-64); */		  channel[ch].transpose = (char)(dta-64);      	    	  ctl->cmsg(CMSG_TEXT, VERB_DEBUG, "transpose channel %d by %d",			(adlo&0x0f)+1, dta-64);		  break;		case 0x0b: /* volume */		  return ME_MAINVOLUME;		  break;		case 0x0e: /* pan */		  return ME_PAN;		  break;		case 0x12: /* chorus send */		  return ME_CHORUSDEPTH;		  break;		case 0x13: /* reverb send */		  return ME_REVERBERATION;		  break;		case 0x14: /* variation send */		  break;		case 0x18: /* filter cutoff */		  return ME_BRIGHTNESS;		  break;		case 0x19: /* filter resonance */		  return ME_HARMONICCONTENT;		  break;		default: break;	      }	  }      return 0;    }  else if (id==0x41 && model==0x42 && adhi==0x12 && adlo==0x40)    {	if (dtc<0) return 0;	if (!cd && dta==0x7f && !dtb && dtc==0x41)	  {      	    ctl->cmsg(CMSG_TEXT, VERB_VERBOSE, "GS System On", len);	    GS_System_On=1;	    #ifdef tplus	    vol_table = gs_vol_table;	    #endif	  }	else if (dta==0x15 && (cd&0xf0)==0x10)	  {	    int chan=cd&0x0f;	    if (!chan) chan=9;	    else if (chan<10) chan--;	    chan = MERGE_CHANNEL_PORT(chan);	    channel[chan].kit=dtb;	  }	else if (cd==0x01) switch(dta)	  {	    case 0x30:		switch(dtb)		  {		    case 0: XG_System_reverb_type=16+0; break;		    case 1: XG_System_reverb_type=16+1; break;		    case 2: XG_System_reverb_type=16+2; break;		    case 3: XG_System_reverb_type= 8+0; break;		    case 4: XG_System_reverb_type= 8+1; break;		    case 5: XG_System_reverb_type=32+0; break;		    case 6: XG_System_reverb_type=8*17; break;		    case 7: XG_System_reverb_type=8*18; break;		  }		break;	    case 0x38:		switch(dtb)		  {		    case 0: XG_System_chorus_type= 8+0; break;		    case 1: XG_System_chorus_type= 8+1; break;		    case 2: XG_System_chorus_type= 8+2; break;		    case 3: XG_System_chorus_type= 8+4; break;		    case 4: XG_System_chorus_type=  -1; break;		    case 5: XG_System_chorus_type= 8*3; break;		    case 6: XG_System_chorus_type=  -1; break;		    case 7: XG_System_chorus_type=  -1; break;		  }		break;	  }      return 0;    }  return 0;}/* Print a string from the file, followed by a newline. Any non-ASCII   or unprintable characters will be converted to periods. */static int dumpstring(int32 len, char *label){  signed char *s=safe_malloc(len+1);  if (len != (int32)SDL_RWread(rw, s, 1, len))    {      free(s);      return -1;    }  s[len]='\0';  while (len--)    {      if (s[len]<32)	s[len]='.';    }  ctl->cmsg(CMSG_TEXT, VERB_VERBOSE, "%s%s", label, s);  free(s);  return 0;}#define MIDIEVENT(at,t,ch,pa,pb) \  new=safe_malloc(sizeof(MidiEventList)); \  new->event.time=at; new->event.type=t; new->event.channel=ch; \  new->event.a=pa; new->event.b=pb; new->next=0;\  return new;#define MAGIC_EOT ((MidiEventList *)(-1))/* Read a MIDI event, returning a freshly allocated element that can   be linked to the event list */static MidiEventList *read_midi_event(void){  static uint8 laststatus, lastchan;  static uint8 nrpn=0, rpn_msb[16], rpn_lsb[16]; /* one per channel */  uint8 me, type, a,b,c;  int32 len;  MidiEventList *new;  for (;;)    {      at+=getvl();      if (SDL_RWread(rw,&me,1,1)!=1)	{	  ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: read_midi_event: %s", 	       current_filename, strerror(errno));	  return 0;	}            if(me==0xF0 || me == 0xF7) /* SysEx event */	{	  int32 sret;	  uint8 sysa=0, sysb=0, syschan=0;	  len=getvl();	  sret=sysex(len, &syschan, &sysa, &sysb, rw);	  if (sret)	   {	     MIDIEVENT(at, sret, syschan, sysa, sysb);	   }	}      else if(me==0xFF) /* Meta event */	{	  SDL_RWread(rw,&type,1,1);	  len=getvl();	  if (type>0 && type<16)	    {	      static char *label[]={		"Text event: ", "Text: ", "Copyright: ", "Track name: ",		"Instrument: ", "Lyric: ", "Marker: ", "Cue point: "};	      dumpstring(len, label[(type>7) ? 0 : type]);	    }	  else	    switch(type)	      {	      case 0x21: /* MIDI port number */		if(len == 1)		{	  	    SDL_RWread(rw,&midi_port_number,1,1);		    if(midi_port_number == EOF)		    {			    ctl->cmsg(CMSG_ERROR, VERB_NORMAL,				      "Warning: \"%s\": Short midi file.",				      midi_name);			    return 0;		    }		    midi_port_number &= 0x0f;		    if (midi_port_number)			ctl->cmsg(CMSG_INFO, VERB_VERBOSE,			  "(MIDI port number %d)", midi_port_number);		    midi_port_number &= 0x03;		}		else SDL_RWseek(rw, len, SEEK_CUR);		break;	      case 0x2F: /* End of Track */		return MAGIC_EOT;	      case 0x51: /* Tempo */		SDL_RWread(rw,&a,1,1); SDL_RWread(rw,&b,1,1); SDL_RWread(rw,&c,1,1);		MIDIEVENT(at, ME_TEMPO, c, a, b);			      default:		ctl->cmsg(CMSG_INFO, VERB_DEBUG, 		     "(Meta event type 0x%02x, length %ld)", type, len);		SDL_RWseek(rw, len, SEEK_CUR);		break;	      }	}      else	{	  a=me;	  if (a & 0x80) /* status byte */	    {	      lastchan=a & 0x0F;	      laststatus=(a>>4) & 0x07;	      SDL_RWread(rw,&a, 1,1);	      a &= 0x7F;	    }	  switch(laststatus)	    {	    case 0: /* Note off */	      SDL_RWread(rw,&b, 1,1);	      b &= 0x7F;	      MIDIEVENT(at, ME_NOTEOFF, lastchan, a,b);	    case 1: /* Note on */	      SDL_RWread(rw,&b, 1,1);	      b &= 0x7F;	      if (curr_track == curr_title_track && track_info > 1) title[0] = '\0';	      MIDIEVENT(at, ME_NOTEON, lastchan, a,b);	    case 2: /* Key Pressure */	      SDL_RWread(rw,&b, 1,1);	      b &= 0x7F;	      MIDIEVENT(at, ME_KEYPRESSURE, lastchan, a, b);	    case 3: /* Control change */	      SDL_RWread(rw,&b, 1,1);	      b &= 0x7F;	      {		int control=255;		switch(a)		  {		  case 7: control=ME_MAINVOLUME; break;		  case 10: control=ME_PAN; break;		  case 11: control=ME_EXPRESSION; break;		  case 64: control=ME_SUSTAIN; break;		  case 71: control=ME_HARMONICCONTENT; break;		  case 72: control=ME_RELEASETIME; break;		  case 73: control=ME_ATTACKTIME; break;		  case 74: control=ME_BRIGHTNESS; break;		  case 91: control=ME_REVERBERATION; break;		  case 93: control=ME_CHORUSDEPTH; break;		  case 120: control=ME_ALL_SOUNDS_OFF; break;		  case 121: control=ME_RESET_CONTROLLERS; break;		  case 123: control=ME_ALL_NOTES_OFF; break;		    /* These should be the SCC-1 tone bank switch		       commands. I don't know why there are two, or		       why the latter only allows switching to bank 0.		       Also, some MIDI files use 0 as some sort of		       continuous controller. This will cause lots of		       warnings about undefined tone banks. */		  case 0: if (XG_System_On) control = ME_TONE_KIT; else control=ME_TONE_BANK; break;		  case 32: if (XG_System_On) control = ME_TONE_BANK; break;		  case 100: nrpn=0; rpn_msb[lastchan]=b; break;		  case 101: nrpn=0; rpn_lsb[lastchan]=b; break;		  case 99: nrpn=1; rpn_msb[lastchan]=b; break;		  case 98: nrpn=1; rpn_lsb[lastchan]=b; break;		    		  case 6:		    if (nrpn)		      {			if (rpn_msb[lastchan]==1) switch (rpn_lsb[lastchan])			 {#ifdef tplus			   case 0x08: control=ME_VIBRATO_RATE; break;			   case 0x09: control=ME_VIBRATO_DEPTH; break;			   case 0x0a: control=ME_VIBRATO_DELAY; break;#endif			   case 0x20: control=ME_BRIGHTNESS; break;			   case 0x21: control=ME_HARMONICCONTENT; break;			/*			   case 0x63: envelope attack rate			   case 0x64: envelope decay rate			   case 0x66: envelope release rate			*/			 }			else switch (rpn_msb[lastchan])			 {			/*			   case 0x14: filter cutoff frequency			   case 0x15: filter resonance			   case 0x16: envelope attack rate			   case 0x17: envelope decay rate			   case 0x18: pitch coarse			   case 0x19: pitch fine			*/			   case 0x1a: drumvolume[lastchan][0x7f & rpn_lsb[lastchan]] = b; break;			   case 0x1c:			     if (!b) b=(int) (127.0*rand()/(RAND_MAX));			     drumpanpot[lastchan][0x7f & rpn_lsb[lastchan]] = b;			     break;			   case 0x1d: drumreverberation[lastchan][0x7f & rpn_lsb[lastchan]] = b; break;			   case 0x1e: drumchorusdepth[lastchan][0x7f & rpn_lsb[lastchan]] = b; break;			/*			   case 0x1f: variation send level			*/			 }			ctl->cmsg(CMSG_INFO, VERB_DEBUG, 				  "(Data entry (MSB) for NRPN %02x,%02x: %ld)",				  rpn_msb[lastchan], rpn_lsb[lastchan],				  b);			break;		      }		    		    switch((rpn_msb[lastchan]<<8) | rpn_lsb[lastchan])		      {		      case 0x0000: /* Pitch bend sensitivity */			control=ME_PITCH_SENS;			break;		      case 0x7F7F: /* RPN reset */			/* reset pitch bend sensitivity to 2 */			MIDIEVENT(at, ME_PITCH_SENS, lastchan, 2, 0);		      default:			ctl->cmsg(CMSG_INFO, VERB_DEBUG, 				  "(Data entry (MSB) for RPN %02x,%02x: %ld)",				  rpn_msb[lastchan], rpn_lsb[lastchan],				  b);			break;		      }		    break;		    		  default:		    ctl->cmsg(CMSG_INFO, VERB_DEBUG, 			      "(Control %d: %d)", a, b);		    break;		  }		if (control != 255)		  { 		    MIDIEVENT(at, control, lastchan, b, 0); 		  }	      }	      break;	    case 4: /* Program change */	      a &= 0x7f;	      MIDIEVENT(at, ME_PROGRAM, lastchan, a, 0);	    case 5: /* Channel pressure - NOT IMPLEMENTED */	      break;	    case 6: /* Pitch wheel */	      SDL_RWread(rw,&b, 1,1);	      b &= 0x7F;	      MIDIEVENT(at, ME_PITCHWHEEL, lastchan, a, b);	    default: 	      ctl->cmsg(CMSG_ERROR, VERB_NORMAL, 		   "*** Can't happen: status 0x%02X, channel 0x%02X",		   laststatus, lastchan);	      break;	    }	}    }    return new;}#undef MIDIEVENT/* Read a midi track into the linked list, either merging with any previous   tracks or appending to them. */

⌨️ 快捷键说明

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