void LateReflectionsNode::recompute() {
	float density = getProperty(Lav_LATE_REFLECTIONS_DENSITY).getFloatValue();
	float t60=getProperty(Lav_LATE_REFLECTIONS_T60).getFloatValue();
	float t60_high =getProperty(Lav_LATE_REFLECTIONS_HF_T60).getFloatValue();
	float t60_low =getProperty(Lav_LATE_REFLECTIONS_LF_T60).getFloatValue();
	float hf_reference=getProperty(Lav_LATE_REFLECTIONS_HF_REFERENCE).getFloatValue();
	float lf_reference = getProperty(Lav_LATE_REFLECTIONS_LF_REFERENCE).getFloatValue();
	//The base delay is the amount we are delaying all delay lines by.
	float baseDelay = 0.003+(1.0f-density)*0.025;
	//Approximate delay line lengths using powers of primes.
	for(int i = 0; i < 16; i+=1) {
		//0, 4, 8, 12, 1, 5, 9, 13...
		int prime= coprimes[(i%4)*4+i/4];
		//use change of base.
		double powerApprox = log(baseDelay*simulation->getSr())/log(prime);
		int neededPower=round(powerApprox);
		double delayInSamples = pow(prime, neededPower);
		double delay=delayInSamples/simulation->getSr();
		delay = std::min(delay, 1.0);
		delays[i] = delay;
	}
	//The following two lines were determined experimentaly, and greatly reduce metallicness.
	//This is probably because, by default, the shortest and longest delay line are adjacent and this node  is typically used with panners at the input and output.
	std::swap(delays[0], delays[15]);
	std::swap(delays[1], delays[14]);
	fdn.setDelays(delays);
	//configure the gains.
	for(int i= 0; i < order; i++) {
		gains[i] = t60ToGain(t60_low, delays[i]);
	}
	//Configure the filters.
	for(int i = 0; i < order; i++) {
		//We get the mid and high t60 gains, and turn them into db.
		double highGain=t60ToGain(t60_high, delays[i]);
		double midGain=t60ToGain(t60, delays[i]);
		double midDb=scalarToDb(midGain, gains[i]);
		double highDb = scalarToDb(highGain, midGain);
		//Careful reading of the audio eq cookbook reveals that when s=1, q is always sqrt(2).
		//We add a very tiny bit to help against numerical error.
		highshelves[i]->configure(Lav_BIQUAD_TYPE_HIGHSHELF, hf_reference, highDb, 1/sqrt(2.0)+1e-4);
		midshelves[i]->configure(Lav_BIQUAD_TYPE_HIGHSHELF, lf_reference, midDb, 1.0/sqrt(2.0)+1e-4);
	}
	//Finally, bake the gains into the fdn matrix:
	hadamard(order, fdn_matrix);
	for(int i=0; i < order; i++) {
		for(int j = 0; j < order; j++) {
			fdn_matrix[i*order+j]*=gains[i];
		}
	}
	fdn.setMatrix(fdn_matrix);
	//Reduce the panning effect.
	//Explanation: the first sample of output should reach all of the 16 outputs at the same time, before degrading normally.
	//This offset basically helps the reflections feel more "centered" when all channels are fed by the source.
	//We add one sample here so that we never have a delay of 0, which reduces some possible compatability issues with delay lines.
	double panReductionDelay = *std::max_element(delays, delays+order)+1.0/simulation->getSr();
	for(int i=0; i < order; i++) {
		double neededDelay = panReductionDelay-delays[i];
		pan_reducers[i]->setDelay(neededDelay);
	}
}
示例#2
0
double gainToDb(double gain) {
	return scalarToDb(gain, 1.0);
}