📄 playmidi.c
字号:
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 + -