📄 playmidi.c
字号:
voice[i].vid=vid;
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;
if(opt_nrpn_vibrato &&
channel[ch].vibrato_ratio && voice[i].vibrato_depth > 0)
{
voice[i].vibrato_control_ratio = channel[ch].vibrato_ratio;
voice[i].vibrato_depth = channel[ch].vibrato_depth;
voice[i].vibrato_delay = channel[ch].vibrato_delay;
}
else
{
voice[i].vibrato_control_ratio = voice[i].sample->vibrato_control_ratio;
voice[i].vibrato_depth = voice[i].sample->vibrato_depth;
voice[i].vibrato_delay = 0;
}
voice[i].orig_vibrato_control_ratio = voice[i].sample->vibrato_control_ratio;
voice[i].vibrato_control_counter=voice[i].vibrato_phase=0;
for (j=0; j<VIBRATO_SAMPLE_INCREMENTS; j++)
voice[i].vibrato_sample_increment[j]=0;
/* Pan */
if(channel[ch].panning != NO_PANNING) pan = channel[ch].panning;
else pan = 64;
if(ISDRUMCHANNEL(ch) &&
channel[ch].drums[note] != NULL &&
channel[ch].drums[note]->drum_panning != NO_PANNING)
pan += channel[ch].drums[note]->drum_panning - 64;
else
pan += voice[i].sample->panning - 64;
if (pan > 127) pan = 127;
if (pan < 0) pan = 0;
voice[i].panning = pan;
voice[i].porta_control_counter = 0;
if(channel[ch].portamento && !channel[ch].porta_control_ratio)
update_portamento_controls(ch);
if(channel[ch].porta_control_ratio)
{
if(channel[ch].last_note_fine == -1)
{
/* first on */
channel[ch].last_note_fine = voice[i].note * 256;
channel[ch].porta_control_ratio = 0;
}
else
{
voice[i].porta_control_ratio = channel[ch].porta_control_ratio;
voice[i].porta_dpb = channel[ch].porta_dpb;
voice[i].porta_pb = channel[ch].last_note_fine -
voice[i].note * 256;
if(voice[i].porta_pb == 0)
voice[i].porta_control_ratio = 0;
}
}
if(cnt == 0)
channel[ch].last_note_fine = voice[i].note * 256;
recompute_freq(i);
recompute_amp(i);
if (voice[i].sample->modes & MODES_ENVELOPE)
{
/* Ramp up from 0 */
voice[i].envelope_stage=0;
voice[i].envelope_volume=0;
voice[i].control_counter=0;
recompute_envelope(i);
apply_envelope_to_amp(i);
}
else
{
voice[i].envelope_increment=0;
apply_envelope_to_amp(i);
}
voice[i].timeout = -1;
if(!prescanning_flag)
ctl_note_event(i);
}
static void finish_note(int i)
{
if (voice[i].sample->modes & MODES_ENVELOPE)
{
/* We need to get the envelope out of Sustain stage. */
/* Note that voice[i].envelope_stage < 3 */
voice[i].status=VOICE_OFF;
voice[i].envelope_stage=3;
recompute_envelope(i);
apply_envelope_to_amp(i);
ctl_note_event(i);
}
else
{
if(current_file_info->pcm_mode != PCM_MODE_NON)
{
free_voice(i);
ctl_note_event(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). */
if(voice[i].status != VOICE_OFF)
{
voice[i].status = VOICE_OFF;
ctl_note_event(i);
}
}
}
}
static void set_envelope_time(int ch,int val,int stage)
{
val = val & 0x7F;
if(play_system_mode != GS_SYSTEM_MODE) {
val = val / 2 + 32;
}
val -= 64;
if(channel[ch].mapID == SC_55_TONE_MAP) {
val *= 1.23;
if(val > 63) {val = 63;}
else if(val < -64) {val = -64;}
}
switch(stage) {
case 0: // Attack
ctl->cmsg(CMSG_INFO,VERB_NOISY,"Attack Time (CH:%d VALUE:%d)",ch,val);
break;
case 1: // Decay
ctl->cmsg(CMSG_INFO,VERB_NOISY,"Decay Time (CH:%d VALUE:%d)",ch,val);
break;
case 3: // Release
ctl->cmsg(CMSG_INFO,VERB_NOISY,"Release Time (CH:%d VALUE:%d)",ch,val);
break;
default:
ctl->cmsg(CMSG_INFO,VERB_NOISY,"? Time (CH:%d VALUE:%d)",ch,val);
}
channel[ch].envelope_rate[stage] = val;
}
static void new_flanger_voice(int v1, int level1,int level2)
{
int v2,i,fb_loop,level,ch,pan;
double delay,width;
int32 orig_frequency;
ch = voice[v1].channel;
fb_loop = abs(level2) / 16;
level = (level2 + 64) >> 2;
level1 += rand() % 64 - 32;
width = 1.0 - level1 * 0.01;
delay = 0;
if((v2 = find_free_voice()) == -1) {return;}
delay += width;
voice[v2] = voice[v1]; /* copy all parameters */
voice[v2].delay += (int)(play_mode->rate * delay / 1000);
pan = rand() % 8 - 4;
voice[v2].panning += pan;
orig_frequency = voice[v1].orig_frequency;
orig_frequency *= bend_fine[level];
voice[v2].orig_frequency = orig_frequency;
voice[v2].cache = NULL;
recompute_amp(v2);
apply_envelope_to_amp(v2);
recompute_freq(v2);
for(i=0;i<fb_loop;i++) {
delay += width;
if((v2 = find_free_voice()) == -1) {return;}
voice[v2] = voice[v1];
voice[v2].delay += (int)(play_mode->rate * delay / 1000);
pan = rand() % 8 - 4;
voice[v2].panning += pan;
orig_frequency *= bend_fine[level];
voice[v2].orig_frequency = orig_frequency;
voice[v2].cache = NULL;
recompute_amp(v2);
apply_envelope_to_amp(v2);
recompute_freq(v2);
}
}
static void new_delay_voice(int v1, int level)
{
int v2,i,fb_loop,ch=voice[v1].channel;
int32 orig_frequency;
double delay,vol,fb_ratio;
uint8 pan;
struct delay_status_t *status = get_delay_status();
double threshold = 1.0;
/* NRPN Delay Send Level of Drum */
if(ISDRUMCHANNEL(ch) && channel[ch].drums[voice[v1].note] != NULL) {
level *= (FLOAT_T)channel[ch].drums[voice[v1].note]->delay_level / 127.0;
}
fb_loop = status->fb_loop;
fb_ratio = status->fb_ratio;
vol = voice[v1].velocity * level * status->level_ratio_center;
if (vol > threshold) { /* First Delay */
delay = 0;
if((v2 = find_free_voice()) == -1) {return;}
orig_frequency = voice[v1].orig_frequency;
orig_frequency *= bend_fine[level >> 2];
voice[v2].orig_frequency = orig_frequency;
voice[v2].cache = NULL;
delay += status->time_center;
voice[v2] = voice[v1]; /* copy all parameters */
voice[v2].velocity = (uint8)vol;
voice[v2].delay += (int)(play_mode->rate * delay / 1000);
recompute_amp(v2);
apply_envelope_to_amp(v2);
recompute_freq(v2);
for(i=0;i<fb_loop;i++) { /* Feedback */
vol *= fb_ratio;
delay += status->time_center;
if(vol < threshold) {break;}
if((v2 = find_free_voice()) == -1) {return;}
orig_frequency *= bend_fine[level >> 2];
voice[v2].orig_frequency = orig_frequency;
voice[v2].cache = NULL;
voice[v2] = voice[v1]; /* copy all parameters */
voice[v2].velocity = (uint8)vol;
voice[v2].delay += (int)(play_mode->rate * delay / 1000);
recompute_amp(v2);
apply_envelope_to_amp(v2);
recompute_freq(v2);
}
}
if(status->level_left) {
vol = voice[v1].velocity * level * status->level_ratio_left;
if (vol > threshold) { /* First Delay */
delay = 0;
pan = voice[v1].panning - 64;
if((v2 = find_free_voice()) == -1) {return;}
orig_frequency = voice[v1].orig_frequency;
orig_frequency *= bend_fine[level >> 2];
voice[v2].orig_frequency = orig_frequency;
voice[v2].cache = NULL;
delay += status->time_left;
voice[v2] = voice[v1]; /* copy all parameters */
voice[v2].velocity = (uint8)vol;
voice[v2].delay += (int)(play_mode->rate * delay / 1000);
voice[v2].panning = pan;
recompute_amp(v2);
apply_envelope_to_amp(v2);
recompute_freq(v2);
for(i=0;i<fb_loop;i++) { /* Feedback */
vol *= fb_ratio;
delay += status->time_left;
if(vol < threshold) {break;}
if((v2 = find_free_voice()) == -1) {return;}
orig_frequency *= bend_fine[level >> 2];
voice[v2].orig_frequency = orig_frequency;
voice[v2].cache = NULL;
voice[v2] = voice[v1]; /* copy all parameters */
voice[v2].velocity = (uint8)vol;
voice[v2].delay += (int)(play_mode->rate * delay / 1000);
voice[v2].panning = pan;
recompute_amp(v2);
apply_envelope_to_amp(v2);
recompute_freq(v2);
}
}
}
if(status->level_right) {
vol = voice[v1].velocity * level * status->level_ratio_right;
if (vol > threshold) { /* First Delay */
delay = 0;
pan = voice[v1].panning - 64;
if((v2 = find_free_voice()) == -1) {return;}
orig_frequency = voice[v1].orig_frequency;
orig_frequency *= bend_fine[level >> 2];
voice[v2].orig_frequency = orig_frequency;
voice[v2].cache = NULL;
delay += status->time_right;
voice[v2] = voice[v1]; /* copy all parameters */
voice[v2].velocity = (uint8)vol;
voice[v2].delay += (int)(play_mode->rate * delay / 1000);
voice[v2].panning = pan;
recompute_amp(v2);
apply_envelope_to_amp(v2);
recompute_freq(v2);
for(i=0;i<fb_loop;i++) { /* Feedback */
vol *= fb_ratio;
delay += status->time_right;
if(vol < threshold) {break;}
if((v2 = find_free_voice()) == -1) {return;}
orig_frequency *= bend_fine[level >> 2];
voice[v2].orig_frequency = orig_frequency;
voice[v2].cache = NULL;
voice[v2] = voice[v1]; /* copy all parameters */
voice[v2].velocity = (uint8)vol;
voice[v2].delay += (int)(play_mode->rate * delay / 1000);
voice[v2].panning = pan;
recompute_amp(v2);
apply_envelope_to_amp(v2);
recompute_freq(v2);
}
}
}
}
static void new_chorus_voice(int v1, int level)
{
int v2, ch;
uint8 vol;
int vel; /* sms 046.05 */
struct chorus_status_t *status = get_chorus_status();
if((v2 = find_free_voice()) == -1)
return;
ch = voice[v1].channel;
/* sms vol = voice[v1].velocity; */
vel = voice[v1].velocity;
voice[v2] = voice[v1]; /* copy all parameters */
/* NRPN Chorus Send Level of Drum */
if(ISDRUMCHANNEL(ch) && channel[ch].drums[voice[v1].note] != NULL) {
level *= (FLOAT_T)channel[ch].drums[voice[v1].note]->chorus_level / 127.0;
}
/* Choose lower voice index for base voice (v1) */
if(v1 > v2)
{
int tmp;
tmp = v1;
v1 = v2;
v2 = v1;
}
/* v1: Base churos voice
* v2: Sub chorus voice (detuned)
*/
/* sms 046.05
voice[v1].velocity = (uint8)(vol * CHORUS_VELOCITY_TUNING1);
voice[v2].velocity = (uint8)(vol * CHORUS_VELOCITY_TUNING2);
*/
vel -= CHORUS_VELOCITY_DELTA; if (vel<0) vel = 0;
voice[v1].velocity = voice[v2].velocity = (uint8) vel;
/* Make doubled link v1 and v2 */
voice[v1].chorus_link = v2;
voice[v2].chorus_link = v1;
level >>= 2; /* scale level to a "better" value */
if(channel[ch].pitchbend + level < 0x2000)
voice[v2].orig_frequency *= bend_fine[level];
else
voice[v2].orig_frequency /= bend_fine[level];
MYCHECK(voice[v2].orig_frequency);
voice[v2].cache = NULL;
/* set panning & delay */
if(!(play_mode->encoding & PE_MONO))
{
double delay;
if(voice[v2].panned == PANNED_CENTER)
{
voice[v2].panning = 64 + int_rand(40) - 20; /* 64 +- rand(20) */
delay = 0;
}
else
{
int panning = voice[v2].panning;
if(panning < CHORUS_OPPOSITE_THRESHOLD)
{
voice[v2].panning = 127;
delay = DEFAULT_CHORUS_DELAY1;
}
else if(panning > 127 - CHORUS_OPPOSITE_THRESHOLD)
{
voice[v2].panning = 0;
delay = DEFAULT_CHORUS_DELAY1;
}
else
{
voice[v2].panning = (panning < 64 ? 0 : 127);
delay = DEFAULT_CHORUS_DELAY2;
}
}
voice[v2].delay += (int)(play_mode->rate * delay);
}
recompute_amp(v1);
apply_envelope_to_amp(v1);
recompute_amp(v2);
apply_envelope_to_amp(v2);
/* voice[v2].orig_frequency is changed.
* Update the depened parameters.
*/
recompute_freq(v2);
}
/* Yet another chorus implementation
* by Eric A. Welsh <ewelsh@gpc.wustl.edu>.
*/
static void new_chorus_voice_alternate(int v1, int level)
{
int v2, ch, panlevel;
uint8 vol, pan;
int vel; /* sms 046.05 */
double delay;
struct chorus_status_t *status = get_chorus_status();
if((v2 = find_free_voice()) == -1)
return;
ch = voice[v1].channel;
voice[v2] = voice[v1];
/* NRPN Chorus Send Level of Drum */
if(ISDRUMCHANNEL(ch) && channel[ch].drums[voice[v1].note] != NULL) {
level *= (FLOAT_T)channel[ch].drums[voice[v1].note]->chorus_level / 127.0;
}
/* for our purposes, hard left will be equal to 1 instead of 0 */
pan = voice[v1].panning;
if (!pan) pan = 1;
/* Choose lower voice index for base voice (v1) */
if(v1 > v2)
{
int tmp;
tmp = v1;
v1 = v2;
v2 = v1;
}
/* lower the volumes so that the two notes add to roughly the orig. vol */
/* sms 046.05 velocity in logarithm space, volume in amplitude
vol = voice[v1].velocity;
voice[v1].velocity = (uint8)(vol * CHORUS_VELOCITY_TUNING2);
voice[v2].velocity = (uint8)(vol * CHORUS_VELOCITY_TUNING2);
*/
vel = voice[v1].velocity;
vel -= CHORUS_VELOCITY_DELTA; if (vel<0) vel = 0;
voice[v1].velocity = voice[v2].velocity = (uint8) vel;
/* Make doubled link v1 and v2 */
voice[v1].chorus_link = v2;
voice[v2].chorus_link = v1;
/* detune notes for chorus effect */
level >>= 2; /* scale to a "better" value */
if (level)
{
if(channel[ch].pitchbend + level < 0x2000)
voice[v2].orig_frequency *= bend_fine[level];
else
voice[v2].orig_frequency /= bend_fine[level];
voice[v2].cache = NULL;
}
MYCHECK(voice[v2].orig_frequency);
/* Try to keep the delayed voice from cancelling out the other voice */
/* Don't bother with trying to figure out drum pitches... */
/* Don't bother with mod files for the same reason... */
/* Drums and mods could be fixed, but pitch detection is too expensive */
delay = DEFAULT_CHORUS_DELAY2;
if (!ISDRUMCHANNEL(voice[v1].channel) &&
current_file_info->file_type != IS_MOD_FILE &&
current_file_info->file_type != IS_S3M_FILE)
{
double freq, frac;
freq = pitch_freq_table[voice[v1].note];
delay = DEFAULT_CHORUS_DELAY2 * freq;
frac = delay - floor(delay);
/* force the delay away from 0.5 period */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -