Esempio n. 1
0
void AmplitudePanner::pan(float* input, float** outputs) {
	//TODO: move all this logic into something that's only called when needed.
	//the two degenerates: 0 and 1 channels.
	if(input == nullptr || outputs == nullptr || channels.size() == 0) return;
	if(channels.size() == 1) {
		std::copy(input, input+block_size, outputs[channels[0].channel]);
		return;
	}
	//We need a local copy.
	float angle = azimuth;
	angle = ringmodf(angle, 360.0f);
	int left = 0, right = 0;
	bool found_right= false;
	for(int i = 0; i < channels.size(); i++) {
		if(channels[i].angle >= angle) {
			right = i;
			found_right = true;
			break;
		}
	}
	if(found_right == false) {
		right = 0;
		left = channels.size()-1;
	}
	else {
		left = right == 0 ? channels.size()-1 : right-1;
	}
	int channel1 = channels[left].channel;
	int channel2 = channels[right].channel;
	//two cases: we wrapped or didn't.
	float angle1, angle2, angleSum;
	if(right == 0) { //left is all the way around, special handling is needed.
		if(angle >= channels[left].angle) {
			angle1 = angle-channels[left].angle; //angle between left and source.
			angle2 = (360.0f-angle)+channels[right].angle;
		}
		else {
			angle1 = (360-channels[left].angle)+angle;
			angle2 = fabs(channels[right].angle-angle);
		}
	}
	else {
		angle1 = fabs(channels[left].angle-angle);
		angle2 = fabs(channels[right].angle-angle);
	}
	angleSum = angle1+angle2;
	float weight2 = angle1/angleSum;
	float weight1 = angle2/angleSum;
	scalarMultiplicationKernel(block_size, weight1, input, outputs[channel1]);
	scalarMultiplicationKernel(block_size, weight2, input, outputs[channel2]);
}
Esempio n. 2
0
void Buffer::normalize() {
	float min = *std::min_element(data, data+channels*frames);
	float max = *std::max_element(data, data+channels*frames);
	float normfactor = std::max(fabs(min), fabs(max));
	normfactor = 1.0f/normfactor;
	scalarMultiplicationKernel(channels*frames, normfactor, data, data);
}
void DoppleringDelayLine::process(int count, float* in, float* out) {
	int i = 0;
	// Take the slow path as long as we're crossfading.
	for(; i < count && counter; i++) out[i] = tick(in[i]);
	// then we can do this.
	float w1 = delay-floorf(delay);
	float w2 = 1-w1;
	int i1 = (int)(delay);
	int i2=i1+1;
	//make sure neither of these is over max delay.
	i1 =std::min(i1, max_delay);
	i2=std::min(i2, max_delay);
	float last = line.read(i2);
	unsigned int iterationSize = (unsigned int)doppleringProcessingWorkspaceSize;
	// Put a lower bound on this.
	while(iterationSize > 8) {
		while(count-i > iterationSize) {
			line.process(i1, iterationSize, in+i, doppleringProcessingWorkspace);
			// We can use scalarMultiplicationKernel with a bit of creativity.
			scalarMultiplicationKernel(iterationSize, w1, doppleringProcessingWorkspace, out+i);
			out[i] += w2*last;
			multiplicationAdditionKernel(iterationSize-1, w2, doppleringProcessingWorkspace, out+i+1, out+i+1);
			last = doppleringProcessingWorkspace[iterationSize-1];
			i += iterationSize;
		}
		iterationSize /= 2;
	}
	for(; i < count; i++) {
		float sample = in[i];
		float newLast = line.read(i1);
		out[i] = w1*newLast+w2*last;
		line.advance(sample);
		last = newLast;
	}
}
Esempio n. 4
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]);
}
Esempio n. 5
0
void HrtfData::linearPhase(float* buffer) {
    //Note that this is in effect circular convolution with a truncation.
    std::copy(buffer, buffer+hrir_length, fft_time_data);
    std::fill(fft_time_data+hrir_length, fft_time_data+hrir_length*2, 0.0f);
    kiss_fftr(fft, fft_time_data, fft_data);
    for(int i = 0; i < hrir_length+1; i++) {
        fft_data[i].r = cabs(fft_data[i].r, fft_data[i].i);
        fft_data[i].i = 0.0f;
    }
    kiss_fftri(ifft, fft_data, fft_time_data);
    //Apply the downscaling that kissfft requires, otherwise this is too loud.
    //Also accomplish copying back to the starting piont.
    scalarMultiplicationKernel(hrir_length, 1.0f/(2*hrir_length), fft_time_data, buffer);
}
Esempio n. 6
0
void Node::applyMul() {
	auto &mulProp = getProperty(Lav_NODE_MUL);
	float** outputs =getOutputBufferArray();
	if(mulProp.needsARate()) {
		for(int i = 0; i < block_size; i++) {
			float mul = mulProp.getFloatValue(i);
			for(int j = 0; j < getOutputBufferCount(); j++) outputs[j][i]*=mul;
		}
	}
	else if(mulProp.getFloatValue() !=1.0) {
		for(int i = 0; i < getOutputBufferCount(); i++) {
			scalarMultiplicationKernel(block_size, mulProp.getFloatValue(), outputs[i], outputs[i]);
		}
	}
}
void FftConvolver::convolveFft(kiss_fft_cpx *fft, float* output) {
	//Do a complex multiply.
	//Note that the first line is subtraction because of the i^2.
	for(int i=0; i < fft_size; i++) {
		kiss_fft_cpx tmp;
		tmp.r = fft[i].r*response_fft[i].r-fft[i].i*response_fft[i].i;
		tmp.i = fft[i].r*response_fft[i].i+fft[i].i*response_fft[i].r;
		block_fft[i] = tmp;
	}
	kiss_fftri(ifft, block_fft, workspace);
	//Add the tail over the block.
	additionKernel(tail_size, tail, workspace, workspace);
	//Downscale the first part, our output.
	//Also copy to the output at the same time.
	scalarMultiplicationKernel(block_size, 1.0/workspace_size, workspace, output);
	//Copy out the tail.
	std::copy(workspace+block_size, workspace+workspace_size, tail);
}
Esempio n. 8
0
void hadamard(int n, float* buffer, bool shouldNormalize) {
    buffer[0] = 1.0f;
    if(n == 1) return; //because it's a matrix of order 1.
    for(int powerOfTwo = 2; powerOfTwo <= n; powerOfTwo *= 2) { //step through powers of 2.
        //Step through the smaller matrix we've already generated.
        int prevPowerOfTwo = powerOfTwo/2;
        for(int row = 0; row < prevPowerOfTwo; row++) {
            for(int column = 0; column < prevPowerOfTwo; column++) {
                //the two copies:
                buffer[row*n+column+prevPowerOfTwo] = buffer[row*n+column];
                buffer[(row+prevPowerOfTwo)*n+column] = buffer[row*n+column];
                //And the negation.
                buffer[(row+prevPowerOfTwo)*n+column+prevPowerOfTwo] = -buffer[row*n+column];
            }
        }
    }
    if(shouldNormalize) {
        float normFactor=1.0/sqrtf(n);
        scalarMultiplicationKernel(n*n, normFactor, buffer, buffer);
    }
}
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]);
		}
	}
}