void FeedbackDelayNetworkNode::process() {
	//First, check an d set properties.
	//We just do this inline because it's trivial.
	if(werePropertiesModified(this, Lav_FDN_DELAYS)) {
		setDelays(getProperty(Lav_FDN_DELAYS).getFloatArrayPtr());
	}
	if(werePropertiesModified(this, Lav_FDN_MATRIX)) {
		setMatrix(getProperty(Lav_FDN_MATRIX).getFloatArrayPtr());
	}
	if(werePropertiesModified(this, Lav_FDN_OUTPUT_GAINS)) {
		setOutputGains(getProperty(Lav_FDN_OUTPUT_GAINS).getFloatArrayPtr());
	}
	if(werePropertiesModified(this, Lav_FDN_FILTER_TYPES, Lav_FDN_FILTER_FREQUENCIES)) {
		configureFilters(
		getProperty(Lav_FDN_FILTER_TYPES).getIntArrayPtr(),
		getProperty(Lav_FDN_FILTER_FREQUENCIES).getFloatArrayPtr());
	}
	for(int i = 0	; i < block_size; i++) {
		network->computeFrame(last_output);
		for(int j = 0; j < num_output_buffers; j++) { 	
			output_buffers[j][i] = last_output[j]*gains[j];
			next_input[j] = input_buffers[j][i];
			//Apply the filter.
			last_output[j] = filters[j]->tick(last_output[j]);
		}
		network->advance(next_input, last_output);
	}
}
示例#2
0
void FilteredDelayNode::process() {
	if(werePropertiesModified(this, Lav_FILTERED_DELAY_DELAY)) delayChanged();
	if(werePropertiesModified(this, Lav_FILTERED_DELAY_INTERPOLATION_TIME)) recomputeDelta();
	reconfigureBiquads();
	float feedback = getProperty(Lav_FILTERED_DELAY_FEEDBACK).getFloatValue();
	//optimize the common case of not having feedback.
	//the only difference between these blocks is in the advance line.
	if(feedback == 0.0f) {
		for(unsigned int output = 0; output < num_output_buffers; output++) {
			auto &line = *lines[output];
			auto &filter=*biquads[output];
			line.processBuffer(block_size, input_buffers[output], output_buffers[output]);
			for(int i=0; i < block_size; i++) output_buffers[output][i] = filter.tick(output_buffers[output][i]);
		}
	}
	else {
		for(unsigned int output = 0; output < num_output_buffers; output++) {
			auto &line = *lines[output];
			auto &filter = *biquads[output];
			for(unsigned int i = 0; i < block_size; i++) {
				output_buffers[output][i] = line.computeSample();
				output_buffers[output][i] = filter.tick(output_buffers[output][i]);
				line.advance(input_buffers[output][i]+output_buffers[output][i]*feedback);
			}
		}
	}
}
void DoppleringDelayNode::process() {
	if(werePropertiesModified(this, Lav_DELAY_DELAY)) delayChanged();
	if(werePropertiesModified(this, Lav_DELAY_INTERPOLATION_TIME)) recomputeDelta();
	for(int output = 0; output < num_output_buffers; output++) {
		auto &line = *lines[output];
		for(int i = 0; i < block_size; i++) output_buffers[output][i] = line.tick(input_buffers[output][i]);
	}
}
示例#4
0
void BufferNode::process() {
	auto buff = getProperty(Lav_BUFFER_BUFFER).getBufferValue();
	if(buff == nullptr) return;
	if(werePropertiesModified(this, Lav_BUFFER_POSITION)) player.setPosition(getProperty(Lav_BUFFER_POSITION).getDoubleValue());
	if(werePropertiesModified(this, Lav_BUFFER_RATE)) player.setRate(getProperty(Lav_BUFFER_RATE).getDoubleValue());
	if(werePropertiesModified(this, Lav_BUFFER_LOOPING)) player.setIsLooping(getProperty(Lav_BUFFER_LOOPING).getIntValue() != 0);
	int prevEndedCount = player.getEndedCount();
	player.process(buff->getChannels(), &output_buffers[0]);
	getProperty(Lav_BUFFER_POSITION).setDoubleValue(player.getPosition());
	for(int i = player.getEndedCount(); i > prevEndedCount; i--) {
		simulation->enqueueTask([=] () {(*end_callback)();});
	}
	getProperty(Lav_BUFFER_ENDED_COUNT).setIntValue(player.getEndedCount());
}
void EnvironmentNode::willTick() {
	if(werePropertiesModified(this, Lav_ENVIRONMENT_OUTPUT_CHANNELS)) {
		int channels = getProperty(Lav_ENVIRONMENT_OUTPUT_CHANNELS).getIntValue();
		output->resize(channels, channels);
		getOutputConnection(0)->reconfigure(0, channels);
		output->getOutputConnection(0)->reconfigure(0, channels);
		output->getInputConnection(0)->reconfigure(0, channels);
	}
}
示例#6
0
void AdditiveTriangleNode::process() {
	if(werePropertiesModified(this, Lav_TRIANGLE_HARMONICS)) oscillator.setHarmonics(getProperty(Lav_TRIANGLE_HARMONICS).getIntValue());
	if(werePropertiesModified(this, Lav_OSCILLATOR_PHASE)) oscillator.setPhase(getProperty(Lav_OSCILLATOR_PHASE).getFloatValue()+oscillator.getPhase());
	auto &freq = getProperty(Lav_OSCILLATOR_FREQUENCY);
	auto &freqMul = getProperty(Lav_OSCILLATOR_FREQUENCY_MULTIPLIER);
	if(freq.needsARate() || freqMul.needsARate()) {
		for(int i = 0; i < block_size; i++) {
			oscillator.setFrequency(freq.getFloatValue(i)*freqMul.getFloatValue(i));
			output_buffers[0][i] = oscillator.tick();
		}
	}
	else {
		oscillator.setFrequency(freq.getFloatValue()*freqMul.getFloatValue());
		for(int i = 0; i < block_size; i++) {
			output_buffers[0][i] = oscillator.tick();
		}
	}
}
示例#7
0
void BlitNode::process() {
	if(werePropertiesModified(this, Lav_OSCILLATOR_PHASE)) {
		oscillator.setPhase(oscillator.getPhase()+getProperty(Lav_OSCILLATOR_PHASE).getFloatValue());
	}
	if(werePropertiesModified(this, Lav_BLIT_HARMONICS)) oscillator.setHarmonics(getProperty(Lav_BLIT_HARMONICS).getIntValue());
	if(werePropertiesModified(this, Lav_OSCILLATOR_FREQUENCY)) oscillator.setFrequency(getProperty(Lav_OSCILLATOR_FREQUENCY).getFloatValue());
	if(werePropertiesModified(this, Lav_BLIT_SHOULD_NORMALIZE)) oscillator.setShouldNormalize(getProperty(Lav_BLIT_SHOULD_NORMALIZE).getIntValue() == 1);
	auto &freq = getProperty(Lav_OSCILLATOR_FREQUENCY);
	auto &freqMul = getProperty(Lav_OSCILLATOR_FREQUENCY_MULTIPLIER);
	if(freq.needsARate()| freqMul.needsARate()) {
		for(int i = 0; i < block_size; i++) {
			oscillator.setFrequency(freq.getFloatValue(i)*freqMul.getFloatValue(i));
			output_buffers[0][i] = (float)oscillator.tick();
		}
	}
	else {
		oscillator.setFrequency(freq.getFloatValue()*freqMul.getFloatValue());
		for(int i = 0; i < block_size; i++) output_buffers[0][i] = (float)oscillator.tick();
	}
}
示例#8
0
void ThreeBandEqNode::process() {
	if(werePropertiesModified(this,
	Lav_THREE_BAND_EQ_LOWBAND_DBGAIN,
	Lav_THREE_BAND_EQ_LOWBAND_FREQUENCY,
	Lav_THREE_BAND_EQ_MIDBAND_DBGAIN,
	Lav_THREE_BAND_EQ_HIGHBAND_DBGAIN,
	Lav_THREE_BAND_EQ_HIGHBAND_FREQUENCY
	)) recompute();
	for(int channel=0; channel < midband_peaks.getChannelCount(); channel++) scalarMultiplicationKernel(block_size, lowband_gain, input_buffers[channel], output_buffers[channel]);
	midband_peaks.process(block_size, &output_buffers[0], &output_buffers[0]);
	highband_shelves.process(block_size, &output_buffers[0], &output_buffers[0]);
}
void ThreeBandEqNode::process() {
	if(werePropertiesModified(this,
	Lav_THREE_BAND_EQ_LOWBAND_DBGAIN,
	Lav_THREE_BAND_EQ_LOWBAND_FREQUENCY,
	Lav_THREE_BAND_EQ_MIDBAND_DBGAIN,
	Lav_THREE_BAND_EQ_HIGHBAND_DBGAIN,
	Lav_THREE_BAND_EQ_HIGHBAND_FREQUENCY
	)) recompute();
	for(int channel=0; channel < channels; channel++) {
		auto &peak= *midband_peaks[channel];
		auto &shelf = *highband_shelves[channel];
		for(int i= 0; i < block_size; i++) {
			output_buffers[channel][i] = lowband_gain*peak.tick(shelf.tick(input_buffers[channel][i]));
		}
	}
}
示例#10
0
void SineNode::process() {
	if(werePropertiesModified(this, Lav_OSCILLATOR_PHASE)) oscillator.setPhase(oscillator.getPhase()+getProperty(Lav_OSCILLATOR_PHASE).getFloatValue());
	auto &freq = getProperty(Lav_OSCILLATOR_FREQUENCY);
	auto &freqMul = getProperty(Lav_OSCILLATOR_FREQUENCY_MULTIPLIER);
	if(freq.needsARate() | freqMul.needsARate()) {
		for(int i=0; i < block_size; i++) {
			oscillator.setFrequency(freq.getFloatValue(i)*freqMul.getFloatValue(i));
			output_buffers[0][i] = oscillator.tick();
		}
	}
	else {
		oscillator.setFrequency(freq.getFloatValue()*freqMul.getFloatValue());
		for(int i = 0; i < block_size; i++) {
			output_buffers[0][i] = (float)oscillator.tick();
		}
	}
}
示例#11
0
void EnvironmentNode::willProcessParents() {
	if(werePropertiesModified(this, Lav_3D_POSITION, Lav_3D_ORIENTATION)) {
		//update the matrix.
		//Important: look at the glsl constructors. Glm copies them, and there is nonintuitive stuff here.
		const float* pos = getProperty(Lav_3D_POSITION).getFloat3Value();
		const float* atup = getProperty(Lav_3D_ORIENTATION).getFloat6Value();
		auto at = glm::vec3(atup[0], atup[1], atup[2]);
		auto up = glm::vec3(atup[3], atup[4], atup[5]);
		auto right = glm::cross(at, up);
		auto m = glm::mat4(
		right.x, up.x, -at.x, 0,
		right.y, up.y, -at.y, 0,
		right.z, up.z, -at.z, 0,
		0, 0, 0, 1);
		//Above is a rotation matrix, which works presuming the player is at (0, 0).
		//Pass the translation through it, so that we can bake the translation in.
		auto posvec = m*glm::vec4(pos[0], pos[1], pos[2], 1.0f);
		//[column][row] because GLSL.
		m[3][0] = -posvec.x;
		m[3][1] = -posvec.y;
		m[3][2] = -posvec.z;
		environment_info.world_to_listener_transform = m;
		//this debug code left in case this is still all broken.
		/*printf("\n%f %f %f %f\n", m[0][0], m[1][0], m[2][0], m[3][0]);
		printf("%f %f %f %f\n", m[0][1], m[1][1], m[2][1], m[3][1]);
		printf("%f %f %f %f\n", m[0][2], m[1][2], m[2][2], m[3][2]);
		printf("%f %f %f %f\n\n", m[0][3], m[1][3], m[2][3], m[3][3]);*/
	}
	//give the new environment to the sources.
	//this is a set of weak pointers.
	decltype(sources) needsRemoval; //for source cleanup below.
	for(auto i: sources) {
		auto tmp = i.lock();
		if(tmp == nullptr) {
			needsRemoval.insert(i);
			continue;
		}
		tmp->update(environment_info);
	}
	//do cleanup of dead sources.
	for(auto i: needsRemoval) sources.erase(i);
}
示例#12
0
void PannerBankNode::willTick() {
	if(werePropertiesModified(this, Lav_PANNER_STRATEGY)) strategyChanged();
	if(werePropertiesModified(this, Lav_PANNER_AZIMUTH, Lav_PANNER_BANK_SPREAD, Lav_PANNER_BANK_IS_CENTERED)) needsRepositioning();
}
示例#13
0
void AllpassNode::process() {
	if(werePropertiesModified(this, Lav_ALLPASS_INTERPOLATION_TIME)) reconfigureInterpolationTime();
	if(werePropertiesModified(this, Lav_ALLPASS_COEFFICIENT)) reconfigureCoefficient();
	if(werePropertiesModified(this, Lav_ALLPASS_DELAY_SAMPLES)) reconfigureDelay();
	bank.process(block_size, &input_buffers[0], &output_buffers[0]);
}
示例#14
0
bool werePropertiesModified(Node* node, int first, args... rest) {
	if(werePropertiesModified(node, first)) return true;
	else return werePropertiesModified(node, rest...);
}
void LateReflectionsNode::process() {
	if(werePropertiesModified(this,
	Lav_LATE_REFLECTIONS_T60, Lav_LATE_REFLECTIONS_DENSITY, Lav_LATE_REFLECTIONS_HF_T60,
	Lav_LATE_REFLECTIONS_LF_T60, Lav_LATE_REFLECTIONS_HF_REFERENCE, Lav_LATE_REFLECTIONS_LF_REFERENCE
	)) recompute();
	if(werePropertiesModified(this, Lav_LATE_REFLECTIONS_AMPLITUDE_MODULATION_FREQUENCY)) amplitudeModulationFrequencyChanged();
	if(werePropertiesModified(this, Lav_LATE_REFLECTIONS_DELAY_MODULATION_FREQUENCY)) delayModulationFrequencyChanged();
	if(werePropertiesModified(this, Lav_LATE_REFLECTIONS_ALLPASS_ENABLED)) allpassEnabledChanged();
	if(werePropertiesModified(this, Lav_LATE_REFLECTIONS_ALLPASS_MODULATION_FREQUENCY)) allpassModulationFrequencyChanged();
	normalizeOscillators();
	float amplitudeModulationDepth = getProperty(Lav_LATE_REFLECTIONS_AMPLITUDE_MODULATION_DEPTH).getFloatValue();
	float delayModulationDepth = getProperty(Lav_LATE_REFLECTIONS_DELAY_MODULATION_DEPTH).getFloatValue();
	float allpassMinFreq=getProperty(Lav_LATE_REFLECTIONS_ALLPASS_MINFREQ).getFloatValue();
	float allpassMaxFreq = getProperty(Lav_LATE_REFLECTIONS_ALLPASS_MAXFREQ).getFloatValue();
	float allpassQ=getProperty(Lav_LATE_REFLECTIONS_ALLPASS_Q).getFloatValue();
	bool allpassEnabled = getProperty(Lav_LATE_REFLECTIONS_ALLPASS_ENABLED).getIntValue() == 1;
	float allpassDelta= (allpassMaxFreq-allpassMinFreq)/2.0f;
	//we move delta upward and delta downward of this point.
	//consequently, we therefore range from the min to the max.
	float allpassModulationStart =allpassMinFreq+allpassDelta;
	for(int i= 0; i < block_size; i++) {
		//We modulate the delay lines first.
		for(int modulating = 0; modulating < 16; modulating++) {
			float delay = delays[modulating];
			delay =delay+delay*delayModulationDepth*delay_modulators[modulating]->tick();
			delay = std::min(delay, 1.0f);
			fdn.setDelay(modulating, delay);
		}
		//Prepare the allpasses, if enabled.
		if(allpassEnabled) {
			for(int modulating =0; modulating < order; modulating++) {
				allpasses[modulating]->configure(Lav_BIQUAD_TYPE_ALLPASS, allpassModulationStart+allpassDelta*allpass_modulators[modulating]->tick(), 0.0, allpassQ);
			}
		}
		//If disabled, the modulators are advanced later.
		//Get the fdn's output.
		fdn.computeFrame(output_frame);
		for(int j= 0; j < order; j++) output_buffers[j][i] = output_frame[j];
		for(int j=0; j < order; j++)  {
			//Through the highshelf, then the lowshelf.
			output_frame[j] = midshelves[j]->tick(highshelves[j]->tick(gains[j]*output_frame[j]));
			//and maybe through the allpass
			if(allpassEnabled) output_frame[j] = allpasses[j]->tick(output_frame[j]);
		}
		//Gains are baked into the fdn matrix.
		//bring in the inputs.
		for(int j = 0; j < order; j++) next_input_frame[j] = input_buffers[j][i];
		fdn.advance(next_input_frame, output_frame);
	}
	//appluy the amplitude modulation, if it's needed.
	if(amplitudeModulationDepth!=0.0f) {
		for(int output = 0; output < num_output_buffers; output++) {
			float* output_buffer=output_buffers[output];
			SinOsc& osc= *amplitude_modulators[output];
			//get  A sine wave.
			osc.fillBuffer(block_size, amplitude_modulation_buffer);
			//Implement 1.0-amplitudeModulationDepth/2+amplitudeModulationDepth*oscillatorValue.
			scalarMultiplicationKernel(block_size, amplitudeModulationDepth, amplitude_modulation_buffer, amplitude_modulation_buffer);
			scalarAdditionKernel(block_size, 1.0f-amplitudeModulationDepth/2.0f, amplitude_modulation_buffer, amplitude_modulation_buffer);
			//Apply the modulation.
			multiplicationKernel(block_size, amplitude_modulation_buffer, output_buffer, output_buffer);
		}
	}
	//Advance modulators for anything we aren't modulating:
	//We do this so that the same parameters always produce the same reverb, even after transitioning through multiple presets.
	//Without the following, the modulators for different stages can get out of phase with each other.
	if(allpassEnabled == false) {
		for(int i=0; i < order; i++)allpass_modulators[i]->skipSamples(block_size);
	}
	if(amplitudeModulationDepth == 0.0f) {
		for(int i = 0; i < 16; i++) {
			amplitude_modulators[i]->skipSamples(block_size);
		}
	}
	//Apply the pan reduction:
	for(int i = 0; i < order; i++) {
		auto &line = *pan_reducers[i];
		for(int j = 0; j < block_size; j++) {
			output_buffers[i][j] = line.tick(output_buffers[i][j]);
		}
	}
}
示例#16
0
void MultipannerNode::willTick() {
	if(werePropertiesModified(this, Lav_PANNER_STRATEGY)) strategyChanged();
}
示例#17
0
void BiquadNode::process() {
	if(werePropertiesModified(this, Lav_BIQUAD_FILTER_TYPE, Lav_BIQUAD_DBGAIN, Lav_BIQUAD_FREQUENCY, Lav_BIQUAD_Q)) reconfigure();
	bank.process(block_size, &input_buffers[0], &output_buffers[0]);
}
示例#18
0
void HrtfNode::process() {
	if(werePropertiesModified(this, Lav_PANNER_APPLY_ITD)) applyIdtChanged();
	bool applyingItd = getProperty(Lav_PANNER_APPLY_ITD).getIntValue() == 1;
	bool linearPhase = getProperty(Lav_PANNER_USE_LINEAR_PHASE).getIntValue() == 1;
	//Get the fft of the input.
	std::copy(input_buffers[0], input_buffers[0]+block_size, fft_workspace);
	kiss_fftr(fft, fft_workspace, input_fft);
	//calculating the hrir is expensive, do it only if needed.
	bool didRecompute = false;
	bool allowCrossfade = getProperty(Lav_PANNER_SHOULD_CROSSFADE).getIntValue();
	float currentAzimuth = getProperty(Lav_PANNER_AZIMUTH).getFloatValue();
	float currentElevation = getProperty(Lav_PANNER_ELEVATION).getFloatValue();
	if(fabs(currentElevation-prev_elevation) > 0.5f || fabs(currentAzimuth-prev_azimuth) > 0.5f) {
		hrtf->computeCoefficientsStereo(currentElevation, currentAzimuth, left_response, right_response, linearPhase);
		if(allowCrossfade) {
			new_left_convolver->setResponse(response_length, left_response);
			new_right_convolver->setResponse(response_length, right_response);
		}
		else {
			left_convolver->setResponse(response_length, left_response);
			right_convolver->setResponse(response_length, right_response);
		}
		didRecompute=true;
		//note: putting these anywhere in the didnt-recompute path causes things to never move.
		prev_elevation = currentElevation;
		prev_azimuth = currentAzimuth;
	}
	//These happen regardless of if we are crossfading or recomputed.
	left_convolver->convolveFft(input_fft, output_buffers[0]);
	right_convolver->convolveFft(input_fft, output_buffers[1]);
	//If we crossfaded, we need to apply the following change.
	if(didRecompute && allowCrossfade) {
		//Shape the buffers as follows, enabling a simple add.
		for(int i=0; i < block_size; i++) {
			float w = 1.0f-i*crossfade_delta;
			output_buffers[0][i]*=w;
			output_buffers[1][i] *= w;
		}
		//Run the new convolver for the left channel and crossfade.
		//Then, repeat for the right.
		new_left_convolver->convolveFft(input_fft, crossfade_workspace);
		for(int i =0; i < block_size; i++) output_buffers[0][i] += crossfade_workspace[i]*i*crossfade_delta;
		new_right_convolver->convolveFft(input_fft, crossfade_workspace);
		for(int i=0; i < block_size; i++) output_buffers[1][i] += crossfade_workspace[i]*i*crossfade_delta;
		//Finally, swap them.
		std::swap(left_convolver, new_left_convolver);
		std::swap(right_convolver, new_right_convolver);
	}
	//break out early if we aren't doing interaural delay.
	if(applyingItd == false) return;
	//we compute the interaural delay and apply it to the lines.
	float interauralDelay = computeInterauralDelay();
	if(interauralDelay > 0) {
		left_delay_line.setDelay(0.0);
		right_delay_line.setDelay(std::min(interauralDelay, max_interaural_delay));
	}
	else {
		left_delay_line.setDelay(std::min(-interauralDelay, max_interaural_delay));
		right_delay_line.setDelay(0.0);
	}
	//apply the delay lines.
	left_delay_line.processBuffer(block_size, output_buffers[0], output_buffers[0]);
	right_delay_line.processBuffer(block_size, output_buffers[1], output_buffers[1]);
}