📄 playmidi.c
字号:
{ /* Unlink chorus link */ voice[v1].chorus_link = v1; voice[v2].chorus_link = v2; } voice[v1].status = VOICE_FREE; voice[v1].temper_instant = 0;}static int find_free_voice(void){ int i, nv = voices, lowest; int32 lv, v; for(i = 0; i < nv; i++) if(voice[i].status == VOICE_FREE) { if(upper_voices <= i) upper_voices = i + 1; return i; } upper_voices = voices; /* Look for the decaying note with the lowest volume */ lv = 0x7FFFFFFF; lowest = -1; for(i = 0; i < nv; i++) { if(voice[i].status & ~(VOICE_ON | VOICE_DIE) && !(voice[i].sample && voice[i].sample->note_to_use && ISDRUMCHANNEL(voice[i].channel))) { 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 && !prescanning_flag) { free_voice(lowest); ctl_note_event(lowest); } return lowest;}static int find_samples(MidiEvent *e, int *vlist){ int i, j, ch, bank, prog, note, nv; SpecialPatch *s; Instrument *ip; ch = e->channel; if (channel[ch].special_sample > 0) { if ((s = special_patch[channel[ch].special_sample]) == NULL) { ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, "Strange: Special patch %d is not installed", channel[ch].special_sample); return 0; } note = e->a + channel[ch].key_shift + note_key_offset; note = (note < 0) ? 0 : ((note > 127) ? 127 : note); return select_play_sample(s->sample, s->samples, ¬e, vlist, e); } bank = channel[ch].bank; if (ISDRUMCHANNEL(ch)) { note = e->a & 0x7f; instrument_map(channel[ch].mapID, &bank, ¬e); if (! (ip = play_midi_load_instrument(1, bank, note))) return 0; /* No instrument? Then we can't play. */ /* if (ip->type == INST_GUS && ip->samples != 1) ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, "Strange: percussion instrument with %d samples!", ip->samples); */ /* "keynum" of SF2, and patch option "note=" */ if (ip->sample->note_to_use) note = ip->sample->note_to_use; } else { if ((prog = channel[ch].program) == SPECIAL_PROGRAM) ip = default_instrument; else { instrument_map(channel[ch].mapID, &bank, &prog); if (! (ip = play_midi_load_instrument(0, bank, prog))) return 0; /* No instrument? Then we can't play. */ } note = ((ip->sample->note_to_use) ? ip->sample->note_to_use : e->a) + channel[ch].key_shift + note_key_offset; note = (note < 0) ? 0 : ((note > 127) ? 127 : note); } nv = select_play_sample(ip->sample, ip->samples, ¬e, vlist, e); /* Replace the sample if the sample is cached. */ if (! prescanning_flag) { if (ip->sample->note_to_use) note = MIDI_EVENT_NOTE(e); for (i = 0; i < nv; i++) { j = vlist[i]; if (! opt_realtime_playing && allocate_cache_size > 0 && ! channel[ch].portamento) { voice[j].cache = resamp_cache_fetch(voice[j].sample, note); if (voice[j].cache) /* cache hit */ voice[j].sample = voice[j].cache->resampled; } else voice[j].cache = NULL; } } return nv;}static int select_play_sample(Sample *splist, int nsp, int *note, int *vlist, MidiEvent *e){ int ch = e->channel, kn = e->a & 0x7f, vel = e->b; int32 f, fs, ft, fst, fc, fr, cdiff, diff, sample_link; int8 tt = channel[ch].temper_type; uint8 tp = channel[ch].rpnmap[RPN_ADDR_0003]; Sample *sp, *spc, *spr; int16 sf, sn; double ratio; int i, j, k, nv, nvc; if (ISDRUMCHANNEL(ch)) f = fs = freq_table[*note]; else { if (opt_pure_intonation) { if (current_keysig < 8) f = freq_table_pureint[current_freq_table][*note]; else f = freq_table_pureint[current_freq_table + 12][*note]; } else if (opt_temper_control) switch (tt) { case 0: f = freq_table_tuning[tp][*note]; break; case 1: if (current_temper_keysig < 8) f = freq_table_pytha[ current_temper_freq_table][*note]; else f = freq_table_pytha[ current_temper_freq_table + 12][*note]; break; case 2: if (current_temper_keysig < 8) f = freq_table_meantone[current_temper_freq_table + ((temper_adj) ? 36 : 0)][*note]; else f = freq_table_meantone[current_temper_freq_table + ((temper_adj) ? 24 : 12)][*note]; break; case 3: if (current_temper_keysig < 8) f = freq_table_pureint[current_temper_freq_table + ((temper_adj) ? 36 : 0)][*note]; else f = freq_table_pureint[current_temper_freq_table + ((temper_adj) ? 24 : 12)][*note]; break; default: /* user-defined temperament */ if ((tt -= 0x40) >= 0 && tt < 4) { if (current_temper_keysig < 8) f = freq_table_user[tt][current_temper_freq_table + ((temper_adj) ? 36 : 0)][*note]; else f = freq_table_user[tt][current_temper_freq_table + ((temper_adj) ? 24 : 12)][*note]; } else f = freq_table[*note]; break; } else f = freq_table[*note]; if (! opt_pure_intonation && opt_temper_control && tt == 0 && f != freq_table[*note]) { *note = log(f / 440000.0) / log(2) * 12 + 69.5; *note = (*note < 0) ? 0 : ((*note > 127) ? 127 : *note); fs = freq_table[*note]; } else fs = freq_table[*note]; } nv = 0; for (i = 0, sp = splist; i < nsp; i++, sp++) { /* GUS/SF2 - Scale Tuning */ if ((sf = sp->scale_factor) != 1024) { sn = sp->scale_freq; ratio = pow(2.0, (*note - sn) * (sf - 1024) / 12288.0); ft = f * ratio + 0.5, fst = fs * ratio + 0.5; } else ft = f, fst = fs; if (ISDRUMCHANNEL(ch) && channel[ch].drums[kn] != NULL) if ((ratio = get_play_note_ratio(ch, kn)) != 1.0) ft = ft * ratio + 0.5, fst = fst * ratio + 0.5; if (sp->low_freq <= fst && sp->high_freq >= fst && sp->low_vel <= vel && sp->high_vel >= vel && ! (sp->inst_type == INST_SF2 && sp->sample_type == SF_SAMPLETYPE_RIGHT)) { j = vlist[nv] = find_voice(e); voice[j].orig_frequency = ft; MYCHECK(voice[j].orig_frequency); voice[j].sample = sp; voice[j].status = VOICE_ON; nv++; } } if (nv == 0) { /* we must select at least one sample. */ fr = fc = 0; spc = spr = NULL; cdiff = 0x7fffffff; for (i = 0, sp = splist; i < nsp; i++, sp++) { /* GUS/SF2 - Scale Tuning */ if ((sf = sp->scale_factor) != 1024) { sn = sp->scale_freq; ratio = pow(2.0, (*note - sn) * (sf - 1024) / 12288.0); ft = f * ratio + 0.5, fst = fs * ratio + 0.5; } else ft = f, fst = fs; if (ISDRUMCHANNEL(ch) && channel[ch].drums[kn] != NULL) if ((ratio = get_play_note_ratio(ch, kn)) != 1.0) ft = ft * ratio + 0.5, fst = fst * ratio + 0.5; diff = abs(sp->root_freq - fst); if (diff < cdiff) { if (sp->inst_type == INST_SF2 && sp->sample_type == SF_SAMPLETYPE_RIGHT) { fr = ft; /* reserve */ spr = sp; /* reserve */ } else { fc = ft; spc = sp; cdiff = diff; } } } /* If spc is not NULL, a makeshift sample is found. */ /* Otherwise, it's a lonely right sample, but better than nothing. */ j = vlist[nv] = find_voice(e); voice[j].orig_frequency = (spc) ? fc : fr; MYCHECK(voice[j].orig_frequency); voice[j].sample = (spc) ? spc : spr; voice[j].status = VOICE_ON; nv++; } nvc = nv; for (i = 0; i < nvc; i++) { spc = voice[vlist[i]].sample; /* If it's left sample, there must be right sample. */ if (spc->inst_type == INST_SF2 && spc->sample_type == SF_SAMPLETYPE_LEFT) { sample_link = spc->sf_sample_link; for (j = 0, sp = splist; j < nsp; j++, sp++) if (sp->inst_type == INST_SF2 && sp->sample_type == SF_SAMPLETYPE_RIGHT && sp->sf_sample_index == sample_link) { /* right sample is found. */ /* GUS/SF2 - Scale Tuning */ if ((sf = sp->scale_factor) != 1024) { sn = sp->scale_freq; ratio = pow(2.0, (*note - sn) * (sf - 1024) / 12288.0); ft = f * ratio + 0.5; } else ft = f; if (ISDRUMCHANNEL(ch) && channel[ch].drums[kn] != NULL) if ((ratio = get_play_note_ratio(ch, kn)) != 1.0) ft = ft * ratio + 0.5; k = vlist[nv] = find_voice(e); voice[k].orig_frequency = ft; MYCHECK(voice[k].orig_frequency); voice[k].sample = sp; voice[k].status = VOICE_ON; nv++; break; } } } return nv;}static double get_play_note_ratio(int ch, int note){ int play_note = channel[ch].drums[note]->play_note; int bank = channel[ch].bank; ToneBank *dbank; int def_play_note; if (play_note == -1) return 1.0; instrument_map(channel[ch].mapID, &bank, ¬e); dbank = (drumset[bank]) ? drumset[bank] : drumset[0]; if ((def_play_note = dbank->tone[note].play_note) == -1) return 1.0; if (play_note >= def_play_note) return bend_coarse[(play_note - def_play_note) & 0x7f]; else return 1 / bend_coarse[(def_play_note - play_note) & 0x7f];}/* Only one instance of a note can be playing on a single channel. */static int find_voice(MidiEvent *e){ int ch = e->channel; int note = MIDI_EVENT_NOTE(e); int status_check, mono_check; AlternateAssign *altassign; int i, lowest = -1; status_check = (opt_overlap_voice_allow) ? (VOICE_OFF | VOICE_SUSTAINED) : 0xff; mono_check = channel[ch].mono; altassign = find_altassign(channel[ch].altassign, note); for (i = 0; i < upper_voices; i++) if (voice[i].status == VOICE_FREE) { lowest = i; /* lower volume */ break; } for (i = 0; i < upper_voices; i++) if (voice[i].status != VOICE_FREE && voice[i].channel == ch) { if ((voice[i].note == note && (voice[i].status & status_check)) || mono_check || (altassign && find_altassign(altassign, voice[i].note))) kill_note(i); else if (voice[i].note == note && (channel[ch].assign_mode == 0 || (channel[ch].assign_mode == 1 && voice[i].proximate_flag == 0))) kill_note(i); } for (i = 0; i < upper_voices; i++) if (voice[i].channel == ch && voice[i].note == note) voice[i].proximate_flag = 0; if (lowest != -1) /* Found a free voice. */ return lowest; if (upper_voices < voices) return upper_voices++; return reduce_voice();}int32 get_note_freq(Sample *sp, int note){ int32 f; int16 sf, sn; double ratio; f = freq_table[note]; /* GUS/SF2 - Scale Tuning */ if ((sf = sp->scale_factor) != 1024) { sn = sp->scale_freq; ratio = pow(2.0, (note - sn) * (sf - 1024) / 12288.0); f = f * ratio + 0.5; } return f;}static int get_panning(int ch, int note,int v){ int pan; if(channel[ch].panning != NO_PANNING) {pan = (int)channel[ch].panning - 64;} else {pan = 0;} if(ISDRUMCHANNEL(ch) && channel[ch].drums[note] != NULL && channel[ch].drums[note]->drum_panning != NO_PANNING) { pan += channel[ch].drums[note]->drum_panning; } else { pan += voice[v].sample->panning; } if (pan > 127) pan = 127; else if (pan < 0) pan = 0; return pan;}/*! initialize vibrato parameters for a voice. */static void init_voice_vibrato(int v){ Voice *vp = &(voice[v]); int ch = vp->channel, j, nrpn_vib_flag; double ratio; /* if NRPN vibrato is set, it's believed that there must be vibrato. */ nrpn_vib_flag = opt_nrpn_vibrato && (channel[ch].vibrato_ratio != 1.0 || channel[ch].vibrato_depth != 0); /* vibrato sweep */ vp->vibrato_sweep = vp->sample->vibrato_sweep_increment; vp->vibrato_sweep_position = 0; /* vibrato rate */ if (nrpn_vib_flag) { if(vp->sample->vibrato_control_ratio == 0) { ratio = cnv_Hz_to_vib_ratio(5.0) * channel[ch].vibrato_ratio; } else { ratio = (double)vp->sample->vibrato_control_ratio * channel[ch].vibrato_ratio; } if (ratio < 0) {ratio = 0;} vp->vibrato_control_ratio = (int)ratio; } else { vp->vibrato_control_ratio = vp->sample->vibrato_control_ratio; } /* vibrato depth */ if (nrpn_vib_flag) { vp->vibrato_depth = vp->sample->vibrato_depth + channel[ch].vibrato_depth; if (vp->vibrato_depth > VIBRATO_DEPTH_MAX) {vp->vibrato_depth = VIBRATO_DEPTH_MAX;} else if (vp->vibrato_depth < 1) {vp->vibrato_depth = 1;} if (vp->sample->vibrato_depth < 0) { /* in opposite phase */ vp->vibrato_depth = -vp->vibrato_depth; } } else { vp->vibrato_depth = vp->sample->vibrato_depth; } /* vibrato delay */ vp->vibrato_delay = vp->sample->vibrato_delay + channel[ch].vibrato_delay; /* internal parameters */ vp->orig_vibrato_control_ratio = vp->vibrato_control_ratio; vp->vibrato_control_counter = vp->vibrato_phase = 0; for (j = 0; j < VIBRATO_SAMPLE_INCREMENTS; j++) { vp->vibrato_sample_increment[j] = 0; }}/*! initialize panning-delay for a voice. */static void init_voice_pan_delay(int v){#ifdef ENABLE_PAN_DELAY Voice *vp = &(voice[v]); int ch = vp->channel; double pan_delay_diff; if (vp->pan_delay_buf != NULL) { free(vp->pan_delay_buf); vp->pan_delay_buf = NULL; } vp->pan_delay_rpt = 0; if (opt_pan_delay && channel[ch].insertion_effect == 0 && !opt_surround_chorus) { if (vp->panning == 64) {vp->delay += pan_delay_table[64] * play_mode->rate / 1000;} else { if(pan_delay_table[vp->panning] > pan_delay_table[127 - vp->panning]) { pan_delay_diff = pan_delay_table[vp->panning] - pan_delay_table[127 - vp->panning]; vp->delay += (pan_delay_table[vp->panning] - pan_delay_diff) * play_mode->rate / 1000; } else { pan_delay_diff = pan_delay_table[127 - vp->panning] - pan_delay_table[vp->panning]; vp->delay += (pan_delay_t
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -