示例#1
0
void HrtfData::computeCoefficientsStereo(float elevation, float azimuth, float *left, float* right, bool linphase) {
    //wrap azimuth to be > 0 and < 360.
    azimuth = ringmodf(azimuth, 360.0f);
    //the hrtf datasets are right ear coefficients.  Consequently, the right ear requires no changes.
    computeCoefficientsMono(elevation, azimuth, right, linphase);
    //the left ear is found at an azimuth which is reflectred about 0 degrees.
    azimuth = ringmodf(360-azimuth, 360.0f);
    computeCoefficientsMono(elevation, azimuth, left, linphase);
}
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]);
}
void AmplitudePanner::addEntry(float angle, int channel) {
	channels.emplace_back(ringmodf(angle, 360.0f), channel);
	std::sort(channels.begin(), channels.end(),
	[](AmplitudePannerEntry &a, AmplitudePannerEntry& b) {return a.angle < b.angle;});
}
示例#4
0
//a complete HRTF for stereo is two calls to this function.
//some final preparation is done afterwords.
//This is very complicated, thus the heavy commenting.
//todo: can this be made simpler?
void HrtfData::computeCoefficientsMono(float elevation, float azimuth, float* out, bool linphase) {
    //clamp the elevation.
    if(elevation < min_elevation) {
        elevation = (float)min_elevation;
    }
    else if(elevation > max_elevation) {
        elevation = (float)max_elevation;
    }

    //we need to convert the elevation into an index.  First, truncate it to an integer (which rounds towards 0).
    int truncatedElevation = (int)truncf(elevation);
    //we now need to know how many degrees there are per elevation increase/decrease.  This is a bit tricky and, if done wrong, will result in an off-by-one.
    int degreesPerElevation = 0;
    if(min_elevation != max_elevation) { //it's not 0, it has to be something else, and the count has to be at least 2.
        //it's the difference between min and max, dividedd by the count.
        //The count includes both endpoints of an interval, as well as  all the marks between.
        //We subtract 1 because we're not counting points, we're counting spaces between points.
        degreesPerElevation = (max_elevation-min_elevation)/(elev_count-1);
    }

    //we have a truncated elevation.  We now simply take an integer division, or assume it's 0.
    //This is an array because We need to do the vertical crossfade in this function.
    int elevationIndex[2];
    elevationIndex[0] = degreesPerElevation ? truncatedElevation/degreesPerElevation : 0;
    //this is relative to whatever index happens to be "0", that is it is an offset from the 0 index.  We have to offset it upwards so it's not negative.
    int elevationIndexOffset = degreesPerElevation ? abs(min_elevation)/degreesPerElevation : 0;
    elevationIndex[0] += elevationIndexOffset;
    elevationIndex[1] = std::min(elevationIndex[0]+1, elev_count-1);
    double elevationWeights[2];
    float ringmoddedElevation = ringmodf(elevation, degreesPerElevation);
    if(ringmoddedElevation < 0) ringmoddedElevation =degreesPerElevation-ringmoddedElevation;
    if(ringmoddedElevation > degreesPerElevation) ringmoddedElevation = degreesPerElevation;
    elevationWeights[0] = (degreesPerElevation-ringmoddedElevation)/degreesPerElevation;
    elevationWeights[1] = ringmoddedElevation/degreesPerElevation;

    memset(out, 0, sizeof(float)*hrir_length);
    for(int i = 0; i < 2; i++) {
        //ElevationIndex lets us get an array of azimuth coefficients.  Go ahead and pull it out now, so we can conceptually forget about all the above variables.
        float** azimuths = hrirs[elevationIndex[i]];
        int azimuthCount = azimuth_counts[elevationIndex[i]];
        float degreesPerAzimuth = 360.0f/azimuthCount;
        int azimuthIndex1, azimuthIndex2;
        azimuthIndex1 = (int)floorf(azimuth/degreesPerAzimuth);
        azimuthIndex2 = azimuthIndex1+1;
        float azimuthWeight1, azimuthWeight2;
        //this is the same logic as a bunch of other places, with a minor variation.
        azimuthWeight1 = ceilf(azimuthIndex2*degreesPerAzimuth-azimuth)/degreesPerAzimuth;
        azimuthWeight2 = floorf(azimuth-azimuthIndex1*degreesPerAzimuth)/degreesPerAzimuth;
        //now that we have some weights, we need to ringmod the azimuth indices. 360==0 in trig, but causes one of them to go past the end.
        azimuthIndex1 = ringmodi(azimuthIndex1, azimuthCount);
        azimuthIndex2 = ringmodi(azimuthIndex2, azimuthCount);

        //this is probably the only part of this that can't go wrong, assuming the above calculations are all correct.  Interpolate between the two azimuths.
        if(linphase == false) {
            for(int j = 0; j < hrir_length; j++) {
                out[j] += elevationWeights[i]*(azimuthWeight1*azimuths[azimuthIndex1][j]+azimuthWeight2*azimuths[azimuthIndex2][j]);
            }
        }
        //otherwise, the slower version; this involves copies and the fft.
        else {
            std::copy(azimuths[azimuthIndex1], azimuths[azimuthIndex1]+hrir_length, temporary_buffer1);
            std::copy(azimuths[azimuthIndex2], azimuths[azimuthIndex2]+hrir_length, temporary_buffer2);
            linearPhase(temporary_buffer1);
            linearPhase(temporary_buffer2);
            for(int j = 0; j < hrir_length; j++) {
                out[j] += elevationWeights[i]*(temporary_buffer1[j]*azimuthWeight1+temporary_buffer2[j]*azimuthWeight2);
            }
        }
    }
}