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

📄 playmidi.c

📁 MIDI解码程序(用VC编写)
💻 C
📖 第 1 页 / 共 5 页
字号:
		return NULL;	return ip;}#if 0/* reduce_voice_CPU() may not have any speed advantage over reduce_voice(). * So this function is not used, now. *//* The goal of this routine is to free as much CPU as possible without   loosing too much sound quality.  We would like to know how long a note   has been playing, but since we usually can't calculate this, we guess at   the value instead.  A bad guess is better than nothing.  Notes which   have been playing a short amount of time are killed first.  This causes   decays and notes to be cut earlier, saving more CPU time.  It also causes   notes which are closer to ending not to be cut as often, so it cuts   a different note instead and saves more CPU in the long run.  ON voices   are treated a little differently, since sound quality is more important   than saving CPU at this point.  Duration guesses for loop regions are very   crude, but are still better than nothing, they DO help.  Non-looping ON   notes are cut before looping ON notes.  Since a looping ON note is more   likely to have been playing for a long time, we want to keep it because it   sounds better to keep long notes.*/static int reduce_voice_CPU(void){    int32 lv, v, vr;    int i, j, lowest=-0x7FFFFFFF;    int32 duration;    i = upper_voices;    lv = 0x7FFFFFFF;        /* Look for the decaying note with the longest remaining decay time */    /* Protect drum decays.  They do not take as much CPU (?) and truncating       them early sounds bad, especially on snares and cymbals */    for(j = 0; j < i; j++)    {	if(voice[j].status & VOICE_FREE || voice[j].cache != NULL)	    continue;	/* skip notes that don't need resampling (most drums) */	if (voice[j].sample->note_to_use)	    continue;	if(voice[j].status & ~(VOICE_ON | VOICE_DIE | VOICE_SUSTAINED))	{	    /* Choose note with longest decay time remaining */	    /* This frees more CPU than choosing lowest volume */	    if (!voice[j].envelope_increment) duration = 0;	    else duration =	    	(voice[j].envelope_target - voice[j].envelope_volume) /	    	voice[j].envelope_increment;	    v = -duration;	    if(v < lv)	    {		lv = v;		lowest = j;	    }	}    }    if(lowest != -0x7FFFFFFF)    {	/* 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. */	cut_notes++;	return lowest;    }    /* try to remove VOICE_DIE before VOICE_ON */    lv = 0x7FFFFFFF;    lowest = -1;    for(j = 0; j < i; j++)    {      if(voice[j].status & VOICE_FREE || voice[j].cache != NULL)	    continue;      if(voice[j].status & ~(VOICE_ON | VOICE_SUSTAINED))      {	/* continue protecting non-resample decays */	if (voice[j].status & ~(VOICE_DIE) && voice[j].sample->note_to_use)		continue;	/* choose note which has been on the shortest amount of time */	/* this is a VERY crude estimate... */	if (voice[j].sample->modes & MODES_LOOPING)	    duration = voice[j].sample_offset - voice[j].sample->loop_start;	else	    duration = voice[j].sample_offset;	if (voice[j].sample_increment > 0)	    duration /= voice[j].sample_increment;	v = duration;	if(v < lv)	{	    lv = v;	    lowest = j;	}      }    }    if(lowest != -1)    {	cut_notes++;	return lowest;    }    /* try to remove VOICE_SUSTAINED before VOICE_ON */    lv = 0x7FFFFFFF;    lowest = -0x7FFFFFFF;    for(j = 0; j < i; j++)    {      if(voice[j].status & VOICE_FREE || voice[j].cache != NULL)	    continue;      if(voice[j].status & VOICE_SUSTAINED)      {	/* choose note which has been on the shortest amount of time */	/* this is a VERY crude estimate... */	if (voice[j].sample->modes & MODES_LOOPING)	    duration = voice[j].sample_offset - voice[j].sample->loop_start;	else	    duration = voice[j].sample_offset;	if (voice[j].sample_increment > 0)	    duration /= voice[j].sample_increment;	v = duration;	if(v < lv)	{	    lv = v;	    lowest = j;	}      }    }    if(lowest != -0x7FFFFFFF)    {	cut_notes++;	return lowest;    }    /* try to remove chorus before VOICE_ON */    lv = 0x7FFFFFFF;    lowest = -0x7FFFFFFF;    for(j = 0; j < i; j++)    {      if(voice[j].status & VOICE_FREE || voice[j].cache != NULL)	    continue;      if(voice[j].chorus_link < j)      {	/* score notes based on both volume AND duration */	/* this scoring function needs some more tweaking... */	if (voice[j].sample->modes & MODES_LOOPING)	    duration = voice[j].sample_offset - voice[j].sample->loop_start;	else	    duration = voice[j].sample_offset;	if (voice[j].sample_increment > 0)	    duration /= voice[j].sample_increment;	v = voice[j].left_mix * duration;	vr = voice[j].right_mix * duration;	if(voice[j].panned == PANNED_MYSTERY && vr > v)	    v = vr;	if(v < lv)	{	    lv = v;	    lowest = j;	}      }    }    if(lowest != -0x7FFFFFFF)    {	cut_notes++;	/* hack - double volume of chorus partner, fix pan */	j = voice[lowest].chorus_link;	voice[j].velocity <<= 1;    	voice[j].panning = channel[voice[lowest].channel].panning;    	recompute_amp(j);    	apply_envelope_to_amp(j);	return lowest;    }    lost_notes++;    /* try to remove non-looping voices first */    lv = 0x7FFFFFFF;    lowest = -0x7FFFFFFF;    for(j = 0; j < i; j++)    {      if(voice[j].status & VOICE_FREE || voice[j].cache != NULL)	    continue;      if(!(voice[j].sample->modes & MODES_LOOPING))      {	/* score notes based on both volume AND duration */	/* this scoring function needs some more tweaking... */	duration = voice[j].sample_offset;	if (voice[j].sample_increment > 0)	    duration /= voice[j].sample_increment;	v = voice[j].left_mix * duration;	vr = voice[j].right_mix * duration;	if(voice[j].panned == PANNED_MYSTERY && vr > v)	    v = vr;	if(v < lv)	{	    lv = v;	    lowest = j;	}      }    }    if(lowest != -0x7FFFFFFF)    {	return lowest;    }    lv = 0x7FFFFFFF;    lowest = 0;    for(j = 0; j < i; j++)    {	if(voice[j].status & VOICE_FREE || voice[j].cache != NULL)	    continue;	if (!(voice[j].sample->modes & MODES_LOOPING)) continue;	/* score notes based on both volume AND duration */	/* this scoring function needs some more tweaking... */	duration = voice[j].sample_offset - voice[j].sample->loop_start;	if (voice[j].sample_increment > 0)	    duration /= voice[j].sample_increment;	v = voice[j].left_mix * duration;	vr = voice[j].right_mix * duration;	if(voice[j].panned == PANNED_MYSTERY && vr > v)	    v = vr;	if(v < lv)	{	    lv = v;	    lowest = j;	}    }    return lowest;}#endif/* this reduces voices while maintaining sound quality */static int reduce_voice(void){    int32 lv, v;    int i, j, lowest=-0x7FFFFFFF;    i = upper_voices;    lv = 0x7FFFFFFF;        /* Look for the decaying note with the smallest volume */    /* Protect drum decays.  Truncating them early sounds bad, especially on       snares and cymbals */    for(j = 0; j < i; j++)    {	if(voice[j].status & VOICE_FREE ||	   (voice[j].sample->note_to_use && ISDRUMCHANNEL(voice[j].channel)))	    continue;		if(voice[j].status & ~(VOICE_ON | VOICE_DIE | VOICE_SUSTAINED))	{	    /* find lowest volume */	    v = voice[j].left_mix;	    if(voice[j].panned == PANNED_MYSTERY && voice[j].right_mix > v)	    	v = voice[j].right_mix;	    if(v < lv)	    {		lv = v;		lowest = j;	    }	}    }    if(lowest != -0x7FFFFFFF)    {	/* 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. */	cut_notes++;	free_voice(lowest);	if(!prescanning_flag)	    ctl_note_event(lowest);	return lowest;    }    /* try to remove VOICE_DIE before VOICE_ON */    lv = 0x7FFFFFFF;    lowest = -1;    for(j = 0; j < i; j++)    {      if(voice[j].status & VOICE_FREE)	    continue;      if(voice[j].status & ~(VOICE_ON | VOICE_SUSTAINED))      {	/* continue protecting drum decays */	if (voice[j].status & ~(VOICE_DIE) &&	    (voice[j].sample->note_to_use && ISDRUMCHANNEL(voice[j].channel)))		continue;	/* find lowest volume */	v = voice[j].left_mix;	if(voice[j].panned == PANNED_MYSTERY && voice[j].right_mix > v)	    v = voice[j].right_mix;	if(v < lv)	{	    lv = v;	    lowest = j;	}      }    }    if(lowest != -1)    {	cut_notes++;	free_voice(lowest);	if(!prescanning_flag)	    ctl_note_event(lowest);	return lowest;    }    /* try to remove VOICE_SUSTAINED before VOICE_ON */    lv = 0x7FFFFFFF;    lowest = -0x7FFFFFFF;    for(j = 0; j < i; j++)    {      if(voice[j].status & VOICE_FREE)	    continue;      if(voice[j].status & VOICE_SUSTAINED)      {	/* find lowest volume */	v = voice[j].left_mix;	if(voice[j].panned == PANNED_MYSTERY && voice[j].right_mix > v)	    v = voice[j].right_mix;	if(v < lv)	{	    lv = v;	    lowest = j;	}      }    }    if(lowest != -0x7FFFFFFF)    {	cut_notes++;	free_voice(lowest);	if(!prescanning_flag)	    ctl_note_event(lowest);	return lowest;    }    /* try to remove chorus before VOICE_ON */    lv = 0x7FFFFFFF;    lowest = -0x7FFFFFFF;    for(j = 0; j < i; j++)    {      if(voice[j].status & VOICE_FREE)	    continue;      if(voice[j].chorus_link < j)      {	/* find lowest volume */	v = voice[j].left_mix;	if(voice[j].panned == PANNED_MYSTERY && voice[j].right_mix > v)	    v = voice[j].right_mix;	if(v < lv)	{	    lv = v;	    lowest = j;	}      }    }    if(lowest != -0x7FFFFFFF)    {	cut_notes++;	/* hack - double volume of chorus partner, fix pan */	j = voice[lowest].chorus_link;	voice[j].velocity <<= 1;    	voice[j].panning = channel[voice[lowest].channel].panning;    	recompute_amp(j);    	apply_envelope_to_amp(j);	free_voice(lowest);	if(!prescanning_flag)	    ctl_note_event(lowest);	return lowest;    }    lost_notes++;    /* remove non-drum VOICE_ON */    lv = 0x7FFFFFFF;    lowest = -0x7FFFFFFF;    for(j = 0; j < i; j++)    {        if(voice[j].status & VOICE_FREE ||	   (voice[j].sample->note_to_use && ISDRUMCHANNEL(voice[j].channel)))	   	continue;	/* find lowest volume */	v = voice[j].left_mix;	if(voice[j].panned == PANNED_MYSTERY && voice[j].right_mix > v)	    v = voice[j].right_mix;	if(v < lv)	{	    lv = v;	    lowest = j;	}    }    if(lowest != -0x7FFFFFFF)    {	free_voice(lowest);	if(!prescanning_flag)	    ctl_note_event(lowest);	return lowest;    }    /* remove all other types of notes */    lv = 0x7FFFFFFF;    lowest = 0;    for(j = 0; j < i; j++)    {	if(voice[j].status & VOICE_FREE)	    continue;	/* find lowest volume */	v = voice[j].left_mix;	if(voice[j].panned == PANNED_MYSTERY && voice[j].right_mix > v)	    v = voice[j].right_mix;	if(v < lv)	{	    lv = v;	    lowest = j;	}    }    free_voice(lowest);    if(!prescanning_flag)	ctl_note_event(lowest);    return lowest;}void free_voice(int v1){    int v2;#ifdef ENABLE_PAN_DELAY	if (voice[v1].pan_delay_buf != NULL) {		free(voice[v1].pan_delay_buf);		voice[v1].pan_delay_buf = NULL;	}#endif /* ENABLE_PAN_DELAY */    v2 = voice[v1].chorus_link;    if(v1 != v2)

⌨️ 快捷键说明

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