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

📄 playmidi.c

📁 SDL_mixer 是一个基于 SDL 的混音器
💻 C
📖 第 1 页 / 共 3 页
字号:
		  break;		case 3: /* stage */		  voice[w].velocity = voice[v].velocity;		  break;		case 4: /* plate */		  voice[w].panning = voice[v].panning;		  break;		case 16: /* white room */		  voice[w].echo_delay = 0;		  break;		case 17: /* tunnel */		  voice[w].echo_delay *= 2;		  voice[w].velocity /= 2;		  break;		case 18: /* canyon */		  voice[w].echo_delay *= 2;		  break;		case 19: /* basement */		  voice[w].velocity /= 2;		  break;	        default: break;	    }	}  }  played_note = voice[w].sample->note_to_use;  if (!played_note) {	played_note = e->a & 0x7f;	if (variationbank == 35) played_note += 12;	else if (variationbank == 36) played_note -= 12;	else if (variationbank == 37) played_note += 7;	else if (variationbank == 36) played_note -= 7;  }#if 0  played_note = ( (played_note - voice[w].sample->freq_center) * voice[w].sample->freq_scale ) / 1024 +		voice[w].sample->freq_center;#endif  voice[w].note = played_note;  voice[w].orig_frequency = freq_table[played_note];  if (chorus) {	if (opt_stereo_surround) {	  if (voice[v].panning < 64) voice[w].panning = voice[v].panning + 32;	  else voice[w].panning = voice[v].panning - 32;	}	if (!voice[w].vibrato_control_ratio) {		voice[w].vibrato_control_ratio = 100;		voice[w].vibrato_depth = 6;		voice[w].vibrato_sweep = 74;	}	voice[w].volume *= 0.40;	voice[v].volume = voice[w].volume;	recompute_amp(v);        apply_envelope_to_amp(v);	voice[w].vibrato_sweep = chorus/2;	voice[w].vibrato_depth /= 2;	if (!voice[w].vibrato_depth) voice[w].vibrato_depth = 2;	voice[w].vibrato_control_ratio /= 2;	voice[w].echo_delay += 30 * milli;	if (XG_System_chorus_type >= 0) {	    int subtype = XG_System_chorus_type & 0x07;	    int chtype = 0x0f & (XG_System_chorus_type >> 3);	    switch (chtype) {		case 0: /* no effect */		  break;		case 1: /* chorus */		  chorus /= 3;		  if(channel[ voice[w].channel ].pitchbend + chorus < 0x2000)            		voice[w].orig_frequency =				(uint32)( (FLOAT_T)voice[w].orig_frequency * bend_fine[chorus] );        	  else voice[w].orig_frequency =			(uint32)( (FLOAT_T)voice[w].orig_frequency / bend_fine[chorus] );		  if (subtype) voice[w].vibrato_depth *= 2;		  break;		case 2: /* celeste */		  voice[w].orig_frequency += (voice[w].orig_frequency/128) * chorus;		  break;		case 3: /* flanger */		  voice[w].vibrato_control_ratio = 10;		  voice[w].vibrato_depth = 100;		  voice[w].vibrato_sweep = 8;		  voice[w].echo_delay += 200 * milli;		  break;		case 4: /* symphonic : cf Children of the Night /128 bad, /1024 ok */		  voice[w].orig_frequency += (voice[w].orig_frequency/512) * chorus;		  voice[v].orig_frequency -= (voice[v].orig_frequency/512) * chorus;		  recompute_freq(v);		  break;		case 8: /* phaser */		  break;	      default:		  break;	    }	}	else {	    chorus /= 3;	    if(channel[ voice[w].channel ].pitchbend + chorus < 0x2000)          	voice[w].orig_frequency =			(uint32)( (FLOAT_T)voice[w].orig_frequency * bend_fine[chorus] );            else voice[w].orig_frequency =		(uint32)( (FLOAT_T)voice[w].orig_frequency / bend_fine[chorus] );	}  }#if 0  voice[w].loop_start = voice[w].sample->loop_start;  voice[w].loop_end = voice[w].sample->loop_end;#endif  voice[w].echo_delay_count = voice[w].echo_delay;  if (reverb) voice[w].echo_delay *= 2;  recompute_freq(w);  recompute_amp(w);  if (voice[w].sample->modes & MODES_ENVELOPE)    {      /* Ramp up from 0 */      voice[w].envelope_stage=ATTACK;      voice[w].modulation_stage=ATTACK;      voice[w].envelope_volume=0;      voice[w].modulation_volume=0;      voice[w].control_counter=0;      voice[w].modulation_counter=0;      recompute_envelope(w);      /*recompute_modulation(w);*/    }  else    {      voice[w].envelope_increment=0;      voice[w].modulation_increment=0;    }  apply_envelope_to_amp(w);}static void xremap(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) {		if (banknum == SFXBANK && tonebank[SFXBANK]) return;		if (banknum == SFXBANK && tonebank[120]) *banknumpt = 120;		return;	}	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;		if (!drumset[newbank]->tone[newnote].layer) return;		if (drumset[newbank]->tone[newnote].layer == MAGIC_LOAD_INSTRUMENT) return;		*banknumpt = newbank;		*this_notept = newnote;		return;	}}static void start_note(MidiEvent *e, int i){  InstrumentLayer *lp;  Instrument *ip;  int j, banknum, ch=e->channel;  int played_note, drumpan=NO_PANNING;  int32 rt;  int attacktime, releasetime, decaytime, variationbank;  int brightness = channel[ch].brightness;  int harmoniccontent = channel[ch].harmoniccontent;  int this_note = e->a;  int this_velocity = e->b;  int drumsflag = channel[ch].kit;  int this_prog = channel[ch].program;  if (channel[ch].sfx) banknum=channel[ch].sfx;  else banknum=channel[ch].bank;  voice[i].velocity=this_velocity;  if (XG_System_On) xremap(&banknum, &this_note, drumsflag);  /*   if (current_config_pc42b) pcmap(&banknum, &this_note, &this_prog, &drumsflag); */  if (drumsflag)    {      if (!(lp=drumset[banknum]->tone[this_note].layer))	{	  if (!(lp=drumset[0]->tone[this_note].layer))	    return; /* No instrument? Then we can't play. */	}      ip = lp->instrument;      if (ip->type == INST_GUS && ip->samples != 1)	{	  ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, 	       "Strange: percussion instrument with %d samples!", ip->samples);	}      if (ip->sample->note_to_use) /* Do we have a fixed pitch? */	{	  voice[i].orig_frequency=freq_table[(int)(ip->sample->note_to_use)];	  drumpan=drumpanpot[ch][(int)ip->sample->note_to_use];	}      else	voice[i].orig_frequency=freq_table[this_note & 0x7F];    }  else    {      if (channel[ch].program==SPECIAL_PROGRAM)	lp=default_instrument;      else if (!(lp=tonebank[channel[ch].bank]->		 tone[channel[ch].program].layer))	{	  if (!(lp=tonebank[0]->tone[this_prog].layer))	    return; /* No instrument? Then we can't play. */	}      ip = lp->instrument;      if (ip->sample->note_to_use) /* Fixed-pitch instrument? */	voice[i].orig_frequency=freq_table[(int)(ip->sample->note_to_use)];      else	voice[i].orig_frequency=freq_table[this_note & 0x7F];    }    select_stereo_samples(i, lp);  voice[i].starttime = e->time;  played_note = voice[i].sample->note_to_use;  if (!played_note || !drumsflag) played_note = this_note & 0x7f;#if 0  played_note = ( (played_note - voice[i].sample->freq_center) * voice[i].sample->freq_scale ) / 1024 +		voice[i].sample->freq_center;#endif  voice[i].status=VOICE_ON;  voice[i].channel=ch;  voice[i].note=played_note;  voice[i].velocity=this_velocity;  voice[i].sample_offset=0;  voice[i].sample_increment=0; /* make sure it isn't negative */  voice[i].tremolo_phase=0;  voice[i].tremolo_phase_increment=voice[i].sample->tremolo_phase_increment;  voice[i].tremolo_sweep=voice[i].sample->tremolo_sweep_increment;  voice[i].tremolo_sweep_position=0;  voice[i].vibrato_sweep=voice[i].sample->vibrato_sweep_increment;  voice[i].vibrato_sweep_position=0;  voice[i].vibrato_depth=voice[i].sample->vibrato_depth;  voice[i].vibrato_control_ratio=voice[i].sample->vibrato_control_ratio;  voice[i].vibrato_control_counter=voice[i].vibrato_phase=0;  voice[i].vibrato_delay = voice[i].sample->vibrato_delay;  kill_others(i);  for (j=0; j<VIBRATO_SAMPLE_INCREMENTS; j++)    voice[i].vibrato_sample_increment[j]=0;  attacktime = channel[ch].attacktime;  releasetime = channel[ch].releasetime;  decaytime = 64;  variationbank = channel[ch].variationbank;  switch (variationbank) {	case  8:		attacktime = 64+32;		break;	case 12:		decaytime = 64-32;		break;	case 16:		brightness = 64+16;		break;	case 17:		brightness = 64+32;		break;	case 18:		brightness = 64-16;		break;	case 19:		brightness = 64-32;		break;	case 20:		harmoniccontent = 64+16;		break;#if 0	case 24:		voice[i].modEnvToFilterFc=2.0;      		voice[i].sample->cutoff_freq = 800;		break;	case 25:		voice[i].modEnvToFilterFc=-2.0;      		voice[i].sample->cutoff_freq = 800;		break;	case 27:		voice[i].modLfoToFilterFc=2.0;		voice[i].lfo_phase_increment=109;		voice[i].lfo_sweep=122;      		voice[i].sample->cutoff_freq = 800;		break;	case 28:		voice[i].modLfoToFilterFc=-2.0;		voice[i].lfo_phase_increment=109;		voice[i].lfo_sweep=122;      		voice[i].sample->cutoff_freq = 800;		break;#endif	default:		break;  }  for (j=ATTACK; j<MAXPOINT; j++)    {	voice[i].envelope_rate[j]=voice[i].sample->envelope_rate[j];	voice[i].envelope_offset[j]=voice[i].sample->envelope_offset[j];    }  voice[i].echo_delay=voice[i].envelope_rate[DELAY];  voice[i].echo_delay_count = voice[i].echo_delay;  if (attacktime!=64)    {	rt = voice[i].envelope_rate[ATTACK];	rt = rt + ( (64-attacktime)*rt ) / 100;	if (rt > 1000) voice[i].envelope_rate[ATTACK] = rt;    }  if (releasetime!=64)    {	rt = voice[i].envelope_rate[RELEASE];	rt = rt + ( (64-releasetime)*rt ) / 100;	if (rt > 1000) voice[i].envelope_rate[RELEASE] = rt;    }  if (decaytime!=64)    {	rt = voice[i].envelope_rate[DECAY];	rt = rt + ( (64-decaytime)*rt ) / 100;	if (rt > 1000) voice[i].envelope_rate[DECAY] = rt;    }  if (channel[ch].panning != NO_PANNING)    voice[i].panning=channel[ch].panning;  else    voice[i].panning=voice[i].sample->panning;  if (drumpan != NO_PANNING)    voice[i].panning=drumpan;  if (variationbank == 1) {    int pan = voice[i].panning;    int disturb = 0;    /* If they're close up (no reverb) and you are behind the pianist,     * high notes come from the right, so we'll spread piano etc. notes     * out horizontally according to their pitches.     */    if (this_prog < 21) {	    int n = voice[i].velocity - 32;	    if (n < 0) n = 0;	    if (n > 64) n = 64;	    pan = pan/2 + n;	}    /* For other types of instruments, the music sounds more alive if     * notes come from slightly different directions.  However, instruments     * do drift around in a sometimes disconcerting way, so the following     * might not be such a good idea.     */    else disturb = (voice[i].velocity/32 % 8) +	(voice[i].note % 8); /* /16? */    if (pan < 64) pan += disturb;    else pan -= disturb;    if (pan < 0) pan = 0;    else if (pan > 127) pan = 127;    voice[i].panning = pan;  }  recompute_freq(i);  recompute_amp(i);  if (voice[i].sample->modes & MODES_ENVELOPE)    {      /* Ramp up from 0 */      voice[i].envelope_stage=ATTACK;      voice[i].envelope_volume=0;      voice[i].control_counter=0;      recompute_envelope(i);    }  else    {      voice[i].envelope_increment=0;    }  apply_envelope_to_amp(i);  voice[i].clone_voice = -1;  voice[i].clone_type = NOT_CLONE;  clone_voice(ip, i, e, STEREO_CLONE, variationbank);  clone_voice(ip, i, e, CHORUS_CLONE, variationbank);  clone_voice(ip, i, e, REVERB_CLONE, variationbank);  ctl->note(i);}static void kill_note(int i){  voice[i].status=VOICE_DIE;  if (voice[i].clone_voice >= 0)	voice[ voice[i].clone_voice ].status=VOICE_DIE;  ctl->note(i);}/* Only one instance of a note can be playing on a single channel. */static void note_on(MidiEvent *e){  int i=voices, lowest=-1;   int32 lv=0x7FFFFFFF, v;  while (i--)    {      if (voice[i].status == VOICE_FREE)	lowest=i; /* Can't get a lower volume than silence */      else if (voice[i].channel==e->channel && 	       (voice[i].note==e->a || channel[voice[i].channel].mono))	kill_note(i);    }  if (lowest != -1)    {      /* Found a free voice. */      start_note(e,lowest);      return;    }  #if 0  /* Look for the decaying note with the lowest volume */  i=voices;  while (i--)    {      if (voice[i].status & ~(VOICE_ON | VOICE_DIE | VOICE_FREE))	{	  v=voice[i].left_mix;	  if ((voice[i].panned==PANNED_MYSTERY) && (voice[i].right_mix>v))	    v=voice[i].right_mix;	  if (v<lv)	    {	      lv=v;	      lowest=i;	    }	}    }#endif  /* Look for the decaying note with the lowest volume */  if (lowest==-1)   {   i=voices;   while (i--)    {      if ( (voice[i].status & ~(VOICE_ON | VOICE_DIE | VOICE_FREE)) &&	  (!voice[i].clone_type))	{	  v=voice[i].left_mix;	  if ((voice[i].panned==PANNED_MYSTERY) && (voice[i].right_mix>v))	    v=voice[i].right_mix;	  if (v<lv)	    {	      lv=v;	      lowest=i;	    }	}    }   }  if (lowest != -1)    {      int cl = voice[lowest].clone_voice;      /* This can still cause a click, but if we had a free voice to	 spare for ramping down this note, we wouldn't need to kill it	 in the first place... Still, this needs to be fixed. Perhaps	 we could use a reserve of voices to play dying notes only. */      if (cl >= 0) {	if (voice[cl].clone_type==STEREO_CLONE ||		       	(!voice[cl].clone_type && voice[lowest].clone_type==STEREO_CLONE))	   voice[cl].status=VOICE_FREE;	else if (voice[cl].clone_voice==lowest) voice[cl].clone_voice=-1;      }      cut_notes++;      voice[lowest].status=VOICE_FREE;      ctl->note(lowest);      start_note(e,lowest);    }  else    lost_notes++;}static void finish_note(int i){  if (voice[i].sample->modes & MODES_ENVELOPE)    {      /* We need to get the envelope out of Sustain stage */      voice[i].envelope_stage=3;      voice[i].status=VOICE_OFF;      recompute_envelope(i);      apply_envelope_to_amp(i);      ctl->note(i);    }  else    {      /* Set status to OFF so resample_voice() will let this voice out         of its loop, if any. In any case, this voice dies when it         hits the end of its data (ofs>=data_length). */      voice[i].status=VOICE_OFF;    }  { int v;    if ( (v=voice[i].clone_voice) >= 0)      {	voice[i].clone_voice = -1;        finish_note(v);      }  }}static void note_off(MidiEvent *e){  int i=voices, v;  while (i--)    if (voice[i].status==VOICE_ON &&	voice[i].channel==e->channel &&	voice[i].note==e->a)      {	if (channel[e->channel].sustain)	  {	    voice[i].status=VOICE_SUSTAINED;    	    if ( (v=voice[i].clone_voice) >= 0)	      {		if (voice[v].status == VOICE_ON)		  voice[v].status=VOICE_SUSTAINED;	      }	    ctl->note(i);	  }	else	  finish_note(i);	return;      }}/* Process the All Notes Off event */static void all_notes_off(int c){  int i=voices;  ctl->cmsg(CMSG_INFO, VERB_DEBUG, "All notes off on channel %d", c);  while (i--)    if (voice[i].status==VOICE_ON &&	voice[i].channel==c)      {	if (channel[c].sustain) 	  {	    voice[i].status=VOICE_SUSTAINED;	    ctl->note(i);	  }	else	  finish_note(i);      }}/* Process the All Sounds Off event */static void all_sounds_off(int c){  int i=voices;  while (i--)    if (voice[i].channel==c && 	voice[i].status != VOICE_FREE &&	voice[i].status != VOICE_DIE)      {	kill_note(i);      }}static void adjust_pressure(MidiEvent *e){  int i=voices;  while (i--)    if (voice[i].status==VOICE_ON &&	voice[i].channel==e->channel &&	voice[i].note==e->a)      {

⌨️ 快捷键说明

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