📄 playmidi.c
字号:
if (frac < 0.5 && frac > 0.40)
{
delay = (floor(delay) + 0.40) / freq;
if (play_mode->encoding & ~PE_MONO)
delay += (0.5 - frac) * (1.0 - labs(64 - pan) / 63.0) / freq;
}
else if (frac >= 0.5 && frac < 0.60)
{
delay = (floor(delay) + 0.60) / freq;
if (play_mode->encoding & ~PE_MONO)
delay += (0.5 - frac) * (1.0 - labs(64 - pan) / 63.0) / freq;
}
else
delay = DEFAULT_CHORUS_DELAY2;
}
/* set panning & delay for pseudo-surround effect */
if(play_mode->encoding & PE_MONO) /* delay sounds good */
voice[v2].delay += (int)(play_mode->rate * delay);
else
{
panlevel = 63;
if (pan - panlevel < 1) panlevel = pan - 1;
if (pan + panlevel > 127) panlevel = 127 - pan;
voice[v1].panning -= panlevel;
voice[v2].panning += panlevel;
/* choose which voice is delayed based on panning */
if (voice[v1].panned == PANNED_CENTER) {
/* randomly choose which voice is delayed */
if (int_rand(2))
voice[v1].delay += (int)(play_mode->rate * delay);
else
voice[v2].delay += (int)(play_mode->rate * delay);
}
else if (pan - 64 < 0) {
voice[v2].delay += (int)(play_mode->rate * delay);
}
else {
voice[v1].delay += (int)(play_mode->rate * delay);
}
}
recompute_amp(v1);
apply_envelope_to_amp(v1);
recompute_amp(v2);
apply_envelope_to_amp(v2);
if (level) recompute_freq(v2);
}
static void note_on(MidiEvent *e)
{
int i, nv, v, ch, note;
int vlist[32];
int vid;
if((nv = find_samples(e, vlist)) == 0)
return;
note = MIDI_EVENT_NOTE(e);
vid = new_vidq(e->channel, note);
ch = e->channel;
for(i = 0; i < nv; i++)
{
v = vlist[i];
if(ISDRUMCHANNEL(ch) &&
channel[ch].drums[note] != NULL &&
channel[ch].drums[note]->pan_random)
channel[ch].drums[note]->drum_panning = int_rand(128);
else if(channel[ch].pan_random)
{
channel[ch].panning = int_rand(128);
ctl_mode_event(CTLE_PANNING, 1, ch, channel[ch].panning);
}
start_note(e, v, vid, nv - i - 1);
# if (0)
/* sms debug 045.31 */
{ int VEL,TV,VOC,NOTE; double volume;
VEL = voice[v].velocity;
TV = velocity_table[VEL];
volume = vol_table[TV];
printf("start_note vel %4d temp vel %4d volume %g\n",VEL,TV,volume);
}
/* sms debug 045.31*/
# endif
#ifdef SMOOTH_MIXING
voice[v].old_left_mix = voice[v].old_right_mix =
voice[v].left_mix_inc = voice[v].left_mix_offset =
voice[v].right_mix_inc = voice[v].right_mix_offset = 0;
#endif
if((channel[ch].chorus_level || opt_surround_chorus))
{
if(opt_surround_chorus)
new_chorus_voice_alternate(v, channel[ch].chorus_level);
else
new_chorus_voice(v, channel[ch].chorus_level);
}
if(channel[ch].delay_level)
{
new_delay_voice(v, channel[ch].delay_level);
}
if(channel[ch].resonance_level)
{
new_flanger_voice(v, channel[ch].cutoff_freq,channel[ch].resonance_level);
}
}
}
static void set_voice_timeout(Voice *vp, int ch, int note)
{
int prog;
ToneBank *bank;
if(channel[ch].special_sample > 0)
return;
if(ISDRUMCHANNEL(ch))
{
prog = note;
bank = drumset[(int)channel[ch].bank];
if(bank == NULL)
bank = drumset[0];
}
else
{
if((prog = channel[ch].program) == SPECIAL_PROGRAM)
return;
bank = tonebank[(int)channel[ch].bank];
if(bank == NULL)
bank = tonebank[0];
}
if(bank->tone[prog].loop_timeout > 0)
vp->timeout = (int32)(bank->tone[prog].loop_timeout
* play_mode->rate * midi_time_ratio
+ current_sample);
}
static void note_off(MidiEvent *e)
{
int uv = upper_voices, i;
int ch, note, vid, sustain;
ch = e->channel;
note = MIDI_EVENT_NOTE(e);
if((vid = last_vidq(ch, note)) == -1)
return;
sustain = channel[ch].sustain;
for(i = 0; i < uv; i++)
if(voice[i].status==VOICE_ON &&
voice[i].channel==ch &&
voice[i].note==note &&
voice[i].vid==vid)
{
if(sustain)
{
voice[i].status=VOICE_SUSTAINED;
set_voice_timeout(voice + i, ch, note);
ctl_note_event(i);
}
else
finish_note(i);
}
}
/* Process the All Notes Off event */
static void all_notes_off(int c)
{
int i, uv = upper_voices;
ctl->cmsg(CMSG_INFO, VERB_DEBUG, "All notes off on channel %d", c);
for(i = 0; i < uv; i++)
if (voice[i].status==VOICE_ON &&
voice[i].channel==c)
{
if (channel[c].sustain)
{
voice[i].status=VOICE_SUSTAINED;
set_voice_timeout(voice + i, c, voice[i].note);
ctl_note_event(i);
}
else
finish_note(i);
}
for(i = 0; i < 128; i++)
vidq_head[c * 128 + i] = vidq_tail[c * 128 + i] = 0;
}
/* Process the All Sounds Off event */
static void all_sounds_off(int c)
{
int i, uv = upper_voices;
for(i = 0; i < uv; i++)
if (voice[i].channel==c &&
(voice[i].status & ~(VOICE_FREE | VOICE_DIE)))
{
kill_note(i);
}
for(i = 0; i < 128; i++)
vidq_head[c * 128 + i] = vidq_tail[c * 128 + i] = 0;
}
static void adjust_pressure(MidiEvent *e)
{
int i, uv = upper_voices;
int note, ch, vel;
note = MIDI_EVENT_NOTE(e);
ch = e->channel;
vel = e->b;
for(i = 0; i < uv; i++)
if(voice[i].status == VOICE_ON &&
voice[i].channel == ch &&
voice[i].note == note)
{
voice[i].velocity = vel;
recompute_amp(i);
apply_envelope_to_amp(i);
}
}
static void adjust_channel_pressure(MidiEvent *e)
{
if(opt_channel_pressure)
{
int i, uv = upper_voices;
int ch, pressure;
ch = e->channel;
pressure = e->a;
for(i = 0; i < uv; i++)
{
if(voice[i].status == VOICE_ON && voice[i].channel == ch)
{
voice[i].velocity = pressure;
recompute_amp(i);
apply_envelope_to_amp(i);
}
}
}
}
static void adjust_panning(int c)
{
int i, uv = upper_voices, pan = channel[c].panning;
for(i = 0; i < uv; i++)
{
if ((voice[i].channel==c) &&
(voice[i].status & (VOICE_ON | VOICE_SUSTAINED)))
{
/* adjust pan to include drum/sample pan offsets */
if(ISDRUMCHANNEL(c) &&
channel[c].drums[i] != NULL &&
channel[c].drums[i]->drum_panning != NO_PANNING)
pan += channel[c].drums[i]->drum_panning - 64;
else
pan += voice[i].sample->panning - 64;
if (pan > 127) pan = 127;
if (pan < 0) pan = 0;
/* Hack to handle -EFchorus=2 in a "reasonable" way */
if((channel[c].chorus_level || opt_surround_chorus) &&
voice[i].chorus_link != i)
{
int v1, v2;
if(i >= voice[i].chorus_link)
/* `i' is not base chorus voice.
* This sub voice is already updated.
*/
continue;
v1 = i; /* base voice */
v2 = voice[i].chorus_link; /* sub voice (detuned) */
if(opt_surround_chorus) /* Surround chorus mode by Eric. */
{
int panlevel;
if (!pan) pan = 1; /* make hard left be 1 instead of 0 */
panlevel = 63;
if (pan - panlevel < 1) panlevel = pan - 1;
if (pan + panlevel > 127) panlevel = 127 - pan;
voice[v1].panning = pan - panlevel;
voice[v2].panning = pan + panlevel;
}
else
{
voice[v1].panning = pan;
if(pan > 60 && pan < 68) /* PANNED_CENTER */
voice[v2].panning =
64 + int_rand(40) - 20; /* 64 +- rand(20) */
else if(pan < CHORUS_OPPOSITE_THRESHOLD)
voice[v2].panning = 127;
else if(pan > 127 - CHORUS_OPPOSITE_THRESHOLD)
voice[v2].panning = 0;
else
voice[v2].panning = (pan < 64 ? 0 : 127);
}
recompute_amp(v2);
apply_envelope_to_amp(v2);
/* v1 == i, so v1 will be updated next */
}
else
voice[i].panning = pan;
recompute_amp(i);
apply_envelope_to_amp(i);
}
}
}
static void play_midi_setup_drums(int ch, int note)
{
channel[ch].drums[note] = (struct DrumParts *)
new_segment(&playmidi_pool, sizeof(struct DrumParts));
reset_drum_controllers(channel[ch].drums, note);
}
static void adjust_drum_panning(int ch, int note)
{
int i, uv = upper_voices, pan;
if(!ISDRUMCHANNEL(ch) || channel[ch].drums[note] == NULL)
return;
pan = channel[ch].drums[note]->drum_panning;
if(pan == 0xFF)
return;
/* slide the pan by the channel pan offset */
if(channel[ch].panning != NO_PANNING)
pan += channel[ch].panning - 64;
if (pan > 127) pan = 127;
if (pan < 0) pan = 0;
for(i = 0; i < uv; i++)
if(voice[i].channel == ch &&
voice[i].note == note &&
(voice[i].status & (VOICE_ON | VOICE_SUSTAINED)))
{
voice[i].panning = pan;
recompute_amp(i);
apply_envelope_to_amp(i);
}
}
static void drop_sustain(int c)
{
int i, uv = upper_voices;
for(i = 0; i < uv; i++)
if (voice[i].status==VOICE_SUSTAINED && voice[i].channel==c)
finish_note(i);
}
static void adjust_pitchbend(int c)
{
int i, uv = upper_voices;
for(i = 0; i < uv; i++)
if (voice[i].status!=VOICE_FREE && voice[i].channel==c)
recompute_freq(i);
}
static void adjust_volume(int c)
{
int i, uv = upper_voices;
for(i = 0; i < uv; i++)
if (voice[i].channel==c &&
(voice[i].status & (VOICE_ON | VOICE_SUSTAINED)))
{
recompute_amp(i);
apply_envelope_to_amp(i);
}
}
static void set_reverb_level(int ch, int level)
{
if(opt_reverb_control <= 0)
{
channel[ch].reverb_level = channel[ch].reverb_id =
-opt_reverb_control;
make_rvid_flag = 1;
return;
}
channel[ch].reverb_level = level;
make_rvid_flag = 0; /* to update reverb_id */
}
int get_reverb_level(int ch)
{
if(opt_reverb_control <= 0)
return -opt_reverb_control;
if(channel[ch].reverb_level == -1)
return DEFAULT_REVERB_SEND_LEVEL;
return channel[ch].reverb_level;
}
int get_chorus_level(int ch)
{
#ifdef DISALLOW_DRUM_BENDS
if(ISDRUMCHANNEL(ch))
return 0; /* Not supported drum channel chorus */
#endif
if(opt_chorus_control == 1)
return channel[ch].chorus_level;
return -opt_chorus_control;
}
static void make_rvid(void)
{
int i, j, lv, maxrv;
for(maxrv = MAX_CHANNELS - 1; maxrv >= 0; maxrv--)
{
if(channel[maxrv].reverb_level == -1)
channel[maxrv].reverb_id = -1;
else if(channel[maxrv].reverb_level >= 0)
break;
}
/* collect same reverb level. */
for(i = 0; i <= maxrv; i++)
{
if((lv = channel[i].reverb_level) == -1)
{
channel[i].reverb_id = -1;
continue;
}
channel[i].reverb_id = i;
for(j = 0; j < i; j++)
{
if(channel[j].reverb_level == lv)
{
channel[i].reverb_id = j;
break;
}
}
}
}
static void adjust_master_volume(void)
{
int i, uv = upper_voices;
adjust_amplification();
for(i = 0; i < uv; i++)
if(voice[i].status & (VOICE_ON | VOICE_SUSTAINED))
{
recompute_amp(i);
apply_envelope_to_amp(i);
}
}
int midi_drumpart_change(int ch, int isdrum)
{
if(IS_SET_CHANNELMASK(drumchannel_mask, ch))
return 0;
if(isdrum)
SET_CHANNELMASK(drumchannels, ch);
else
UNSET_CHANNELMASK(drumchannels, ch);
return 1;
}
void midi_program_change(int ch, int prog)
{
int newbank, dr;
dr = (int)ISDRUMCHANNEL(ch);
if(dr)
newbank = channel[ch].program;
else
newbank = channel[ch].bank;
switch(play_system_mode)
{
case GS_SYSTEM_MODE: /* GS */
switch(channel[ch].bank_lsb)
{
case 0: /* No change */
break;
case 1:
channel[ch].mapID = (ISDRUMCHANNEL(ch) ? SC_55_TONE_MAP
: SC_55_DRUM_MAP);
break;
case 2:
channel[ch].mapID = (IS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -