Example #1
0
double* FunctionAST::multiply_coefficients(double* coeff1, double* coeff2, int n)
{
    int         k;
    double      scale_factor;
    double*     coeff1_values;
    double*     coeff2_values;
    double*     temp_result_coeff;
    double*     result_coeff;
    
    // coeff_values stores values of the function at boxes
    // defined by coeff
    k               = this->func->k;
    coeff1_values   = Multiply_Vector_Matrix(coeff1, k, this->func->quad_phiT, k, k);
    coeff2_values   = Multiply_Vector_Matrix(coeff2, k, this->func->quad_phiT, k, k);
    
    // do the multiplication on the values for each of the boxes
    Vector_emul(coeff1_values, coeff2_values, k); 

    //  scale factor for this level = sqrt((2^d)^(n+1))
    scale_factor    = sqrt(pow(2.0, n));

    // convert values back to coefficients for each of the boxes
    temp_result_coeff = Multiply_Vector_Matrix(coeff1_values, k, this->func->quad_phiw, k, k);
    Vector_scale(temp_result_coeff, k, scale_factor);

    return temp_result_coeff;
}
Example #2
0
double* FunctionAST::diff_coefficients(double* left, double* center, double* right, int n)
{
    int         i, k;
    double*     resultVector;
    double*     tempRpLeft;
    double*     tempR0Center;
    double*     tempRmRight;

    k               = this->func->k;
    resultVector    = Vector_initialize(NULL, 0, k+ADD_K);
    tempRpLeft      = Multiply_Matrix_Vector(this->func->rp, k+ADD_K, k+ADD_K, left, k+ADD_K);
    tempR0Center    = Multiply_Matrix_Vector(this->func->r0, k+ADD_K, k+ADD_K, center, k+ADD_K);
    tempRmRight     = Multiply_Matrix_Vector(this->func->rm, k+ADD_K, k+ADD_K, right, k+ADD_K);

    for (i=0; i<k+ADD_K; i++) 
    {
        resultVector[i] = tempRpLeft[i] + tempR0Center[i] + tempRmRight[i];
    }

    free(tempRpLeft);
    free(tempR0Center);
    free(tempRmRight);
    Vector_scale(resultVector, this->func->k+ADD_K, pow(2.0, n));

    return resultVector;    
}
Example #3
0
Sound Sound_FormantGrid_filter (Sound me, FormantGrid formantGrid) {
	Sound thee = (structSound *)Data_copy (me);
	if (! thee) return NULL;
	Sound_FormantGrid_filter_inline (thee, formantGrid);
	Vector_scale (thee, 0.99);
	return thee;
}
Sound EEG_to_Sound_modulated (EEG me, double baseFrequency, double channelBandwidth, const wchar_t *channelRanges) {
	try {
		long numberOfChannels;
		autoNUMvector <long> channelNumbers (NUMstring_getElementsOfRanges (channelRanges, my d_numberOfChannels, & numberOfChannels, NULL, L"channel", true), 1);
		double maxFreq = baseFrequency + my d_numberOfChannels * channelBandwidth;
		double samplingFrequency = 2 * maxFreq;
		samplingFrequency = samplingFrequency < 44100 ? 44100 : samplingFrequency;
		autoSound thee = Sound_createSimple (1, my xmax - my xmin, samplingFrequency);
		for (long i = 1; i <= numberOfChannels; i++) {
			long ichannel = channelNumbers[i];
			double fbase = baseFrequency;// + (ichannel - 1) * channelBandwidth;
			autoSound si = Sound_extractChannel (my d_sound, ichannel);
			autoSpectrum spi = Sound_to_Spectrum (si.peek(), 1);
			Spectrum_passHannBand (spi.peek(), 0.5, channelBandwidth - 0.5, 0.5);
			autoSpectrum spi_shifted = Spectrum_shiftFrequencies (spi.peek(), fbase, samplingFrequency / 2, 30);
			autoSound resampled = Spectrum_to_Sound (spi_shifted.peek());
			long nx = resampled -> nx < thy nx ? resampled -> nx : thy nx;
			for (long j = 1; j <= nx; j++) {
				thy z[1][j] += resampled -> z[1][j];
			}
		}
		Vector_scale (thee.peek(), 0.99);
		return thee.transfer();
	} catch (MelderError) {
		Melder_throw (me, ": no playable sound created.");
	}
}
autoSound Sound_IntensityTier_multiply (Sound me, IntensityTier intensity, int scale) {
	try {
		autoSound thee = Data_copy (me);
		Sound_IntensityTier_multiply_inline (thee.peek(), intensity);
		if (scale) Vector_scale (thee.peek(), 0.9);
		return thee;
	} catch (MelderError) {
		Melder_throw (me, U": not multiplied with ", intensity, U".");
	}
}
Example #6
0
autoSound Sound_FormantTier_filter (Sound me, FormantTier formantTier) {
	try {
		autoSound thee = Data_copy (me);
		Sound_FormantTier_filter_inline (thee.peek(), formantTier);
		Vector_scale (thee.peek(), 0.99);
		return thee;
	} catch (MelderError) {
		Melder_throw (me, U": not filtered with ", formantTier, U".");
	}
}
Example #7
0
Sound Sound_FormantGrid_filter (Sound me, FormantGrid formantGrid) {
	try {
		autoSound thee = Data_copy (me);
		Sound_FormantGrid_filter_inline (thee.peek(), formantGrid);
		Vector_scale (thee.peek(), 0.99);
		return thee.transfer();
	} catch (MelderError) {
		Melder_throw (me, ": not filtered with ", formantGrid, ".");
	}
}
Example #8
0
// for values at the quadrature points at box n, l returns coefficients at
// the same box
double* FunctionAST::quad_values_to_coeff(double* values, int n, int l, double** transform_matrix)
{
    double* tempVector;   
 
    tempVector  = Multiply_Vector_Matrix(values, this->func->k, transform_matrix, this->func->k, this->func->k+ADD_K);

    Vector_scale(tempVector, this->func->k+ADD_K, sqrt(pow(2, -n)));

    return tempVector;
}
autoSound Sound_AmplitudeTier_multiply (Sound me, AmplitudeTier amplitude) {
	try {
		autoSound thee = Data_copy (me);
		Sound_AmplitudeTier_multiply_inline (thee.peek(), amplitude);
		Vector_scale (thee.peek(), 0.9);
		return thee;
	} catch (MelderError) {
		Melder_throw (me, U": not multiplied by ", amplitude, U".");
	}
}
Sound EEG_to_Sound_frequencyShifted (EEG me, long channel, double frequencyShift, double samplingFrequency, double maxAmp) {
	try {
		autoSound si = Sound_extractChannel (my d_sound, channel);
		autoSpectrum spi = Sound_to_Spectrum (si.peek(), 1);
		autoSpectrum spi_shifted = Spectrum_shiftFrequencies (spi.peek(), frequencyShift, samplingFrequency / 2, 30);
		autoSound thee = Spectrum_to_Sound (spi_shifted.peek());
		if (maxAmp > 0) {
			Vector_scale (thee.peek(), maxAmp);
		}
		return thee.transfer();
	} catch (MelderError) {
		Melder_throw (me, ": channel not converted to sound.");
	}
}
Example #11
0
int FormantGrid_playPart (FormantGrid me, double tmin, double tmax, double samplingFrequency,
	double tStart, double f0Start, double tMid, double f0Mid, double tEnd, double f0End,
	double adaptFactor, double maximumPeriod, double openPhase, double collisionPhase, double power1, double power2,
	int (*playCallback) (void *playClosure, int phase, double tmin, double tmax, double t), void *playClosure)
{
	Sound sound = FormantGrid_to_Sound (me, samplingFrequency,
		tStart, f0Start, tMid, f0Mid, tEnd, f0End,
		adaptFactor, maximumPeriod, openPhase, collisionPhase, power1, power2); cherror
	Vector_scale (sound, 0.99);
	Sound_playPart (sound, tmin, tmax, playCallback, playClosure);
end:
	forget (sound);
	iferror return 0;
	return 1;
}
Example #12
0
void FormantGrid_playPart (FormantGrid me, double tmin, double tmax, double samplingFrequency,
	double tStart, double f0Start, double tMid, double f0Mid, double tEnd, double f0End,
	double adaptFactor, double maximumPeriod, double openPhase, double collisionPhase, double power1, double power2,
	int (*playCallback) (void *playClosure, int phase, double tmin, double tmax, double t), void *playClosure)
{
	try {
		autoSound sound = FormantGrid_to_Sound (me, samplingFrequency,
			tStart, f0Start, tMid, f0Mid, tEnd, f0End,
			adaptFactor, maximumPeriod, openPhase, collisionPhase, power1, power2);
		Vector_scale (sound.peek(), 0.99);
		Sound_playPart (sound.peek(), tmin, tmax, playCallback, playClosure);
	} catch (MelderError) {
		Melder_throw (me, ": not played.");
	}
}
Example #13
0
void NBody_tick(NBody* self, uint32_t dt) {
    self->player->acceleration = Vector_init(0.0f, 0.0f, 0.0f);
    Vector accelerations[NUM_STARS] = {{0.0f, 0.0f, 0.0f}};

    // Update player
    for (size_t i = 0; i < NUM_STARS; ++i) {
        Star* star = &self->stars[i];

        Vector delta = Vector_subtract(star->position, self->player->position);
        float distance = Vector_mag(delta) + 0.00001f;  // Add small amount to avoid collision

        Vector force = Vector_scale(delta, 0.001f / (distance * distance * distance));
        self->player->acceleration = Vector_add(self->player->acceleration, Vector_scale(force, star->mass));
    }

    self->player->velocity = Vector_add(self->player->velocity, Vector_scale(self->player->acceleration, 0.001f * dt));
    self->player->position = Vector_add(self->player->position, Vector_scale(self->player->velocity, 0.001f * dt));

    // Update stars
    for (size_t i = 0; i < NUM_STARS; ++i) {
        Star* star_i = &self->stars[i];

        for (size_t j = i + 1; j < NUM_STARS; ++j) {
            Star* star_j = &self->stars[j];

            Vector delta = Vector_subtract(star_j->position, star_i->position);
            float distance = Vector_mag(delta) + 0.00001f;  // Add small amount to avoid collision

            Vector force = Vector_scale(delta, 0.001f / (distance * distance * distance));
            accelerations[i] = Vector_add(accelerations[i], Vector_scale(force, star_j->mass));
            accelerations[j] = Vector_add(accelerations[j], Vector_scale(force, -star_i->mass));
        }

        star_i->velocity = Vector_add(star_i->velocity, Vector_scale(accelerations[i], 0.001f * dt));
        star_i->position = Vector_add(star_i->position, Vector_scale(star_i->velocity, 0.001f * dt));
    }
}
Example #14
0
static autoSound synthesize_pulses_lpc (Manipulation me) {
	try {
		if (! my lpc) {
			if (! my sound) Melder_throw (U"Missing original sound.");
			autoSound sound10k = Sound_resample (my sound.get(), 10000.0, 50);
			my lpc = Sound_to_LPC_burg (sound10k.get(), 20, 0.025, 0.01, 50.0);
		}
		if (! my pulses) Melder_throw (U"Missing pulses analysis.");
		autoSound train = PointProcess_to_Sound_pulseTrain (my pulses.get(), 1.0 / my lpc -> samplingPeriod, 0.7, 0.05, 30);
		train -> dx = my lpc -> samplingPeriod;   // to be exact
		Sound_PointProcess_fillVoiceless (train.get(), my pulses.get());
		autoSound result = LPC_and_Sound_filter (my lpc.get(), train.get(), true);
		NUMdeemphasize_f (result -> z [1], result -> nx, result -> dx, 50.0);
		Vector_scale (result.get(), 0.99);
		return result;
	} catch (MelderError) {
		Melder_throw (me, U": LPC synthesis not performed.");
	}
}
Example #15
0
Sound Sounds_crossCorrelate (Sound me, Sound thee, enum kSounds_convolve_scaling scaling, enum kSounds_convolve_signalOutsideTimeDomain signalOutsideTimeDomain) {
	try {
		if (my ny > 1 && thy ny > 1 && my ny != thy ny)
			Melder_throw (U"The numbers of channels of the two sounds have to be equal or 1.");
		if (my dx != thy dx)
			Melder_throw (U"The sampling frequencies of the two sounds have to be equal.");
		long numberOfChannels = my ny > thy ny ? my ny : thy ny;
		long n1 = my nx, n2 = thy nx;
		long n3 = n1 + n2 - 1, nfft = 1;
		while (nfft < n3) nfft *= 2;
		autoNUMvector <double> data1 (1, nfft);
		autoNUMvector <double> data2 (1, nfft);
		double my_xlast = my x1 + (n1 - 1) * my dx;
		autoSound him = Sound_create (numberOfChannels, thy xmin - my xmax, thy xmax - my xmin, n3, my dx, thy x1 - my_xlast);
		for (long channel = 1; channel <= numberOfChannels; channel ++) {
			double *a = my z [my ny == 1 ? 1 : channel];
			for (long i = n1; i > 0; i --) data1 [i] = a [i];
			for (long i = n1 + 1; i <= nfft; i ++) data1 [i] = 0.0;
			a = thy z [thy ny == 1 ? 1 : channel];
			for (long i = n2; i > 0; i --) data2 [i] = a [i];
			for (long i = n2 + 1; i <= nfft; i ++) data2 [i] = 0.0;
			NUMrealft (data1.peek(), nfft, 1);
			NUMrealft (data2.peek(), nfft, 1);
			data2 [1] *= data1 [1];
			data2 [2] *= data1 [2];
			for (long i = 3; i <= nfft; i += 2) {
				double temp = data1 [i] * data2 [i] + data1 [i + 1] * data2 [i + 1];   // reverse me by taking the conjugate of data1
				data2 [i + 1] = data1 [i] * data2 [i + 1] - data1 [i + 1] * data2 [i];   // reverse me by taking the conjugate of data1
				data2 [i] = temp;
			}
			NUMrealft (data2.peek(), nfft, -1);
			a = him -> z [channel];
			for (long i = 1; i < n1; i ++) {
				a [i] = data2 [i + (nfft - (n1 - 1))];   // data for the first part ("negative lags") is at the end of data2
			}
			for (long i = 1; i <= n2; i ++) {
				a [i + (n1 - 1)] = data2 [i];   // data for the second part ("positive lags") is at the beginning of data2
			}
		}
		switch (signalOutsideTimeDomain) {
			case kSounds_convolve_signalOutsideTimeDomain_ZERO: {
				// do nothing
			} break;
			case kSounds_convolve_signalOutsideTimeDomain_SIMILAR: {
				for (long channel = 1; channel <= numberOfChannels; channel ++) {
					double *a = his z [channel];
					double edge = n1 < n2 ? n1 : n2;
					for (long i = 1; i < edge; i ++) {
						double factor = edge / i;
						a [i] *= factor;
						a [n3 + 1 - i] *= factor;
					}
				}
			} break;
			//case kSounds_convolve_signalOutsideTimeDomain_PERIODIC: {
				// do nothing
			//} break;
			default: Melder_fatal (U"Sounds_crossCorrelate: unimplemented outside-time-domain strategy ", signalOutsideTimeDomain);
		}
		switch (scaling) {
			case kSounds_convolve_scaling_INTEGRAL: {
				Vector_multiplyByScalar (him.peek(), my dx / nfft);
			} break;
			case kSounds_convolve_scaling_SUM: {
				Vector_multiplyByScalar (him.peek(), 1.0 / nfft);
			} break;
			case kSounds_convolve_scaling_NORMALIZE: {
				double normalizationFactor = Matrix_getNorm (me) * Matrix_getNorm (thee);
				if (normalizationFactor != 0.0) {
					Vector_multiplyByScalar (him.peek(), 1.0 / nfft / normalizationFactor);
				}
			} break;
			case kSounds_convolve_scaling_PEAK_099: {
				Vector_scale (him.peek(), 0.99);
			} break;
			default: Melder_fatal (U"Sounds_crossCorrelate: unimplemented scaling ", scaling);
		}
		return him.transfer();
	} catch (MelderError) {
		Melder_throw (me, U" & ", thee, U": not cross-correlated.");
	}
}
Example #16
0
Sound PointProcess_to_Sound_phonation
	(PointProcess me, double samplingFrequency, double adaptFactor, double maximumPeriod,
	 double openPhase, double collisionPhase, double power1, double power2)
{
	try {
		long sound_nt = 1 + floor ((my xmax - my xmin) * samplingFrequency);   // >= 1
		double dt = 1.0 / samplingFrequency;
		double tmid = (my xmin + my xmax) / 2;
		double t1 = tmid - 0.5 * (sound_nt - 1) * dt;
		double a = (power1 + power2 + 1.0) / (power2 - power1);
		double re = openPhase - collisionPhase;
		autoSound thee = Sound_create (1, my xmin, my xmax, sound_nt, dt, t1);
		/*
		 * Compute "re" by iteration.
		 */
		if (collisionPhase <= 0.0) {
			re = openPhase;
		} else {
			double xmaxFlow = pow (power1 / power2, 1.0 / (power2 - power1));
			double xleft = xmaxFlow;
			double gleft = pow (xleft, power1) - pow (xleft, power2);
			double gderivleft = power1 * pow (xleft, power1 - 1.0) - power2 * pow (xleft, power2 - 1.0);
			double fleft = - gleft / gderivleft;
			double xright = 1.0;
			double gright = pow (xright, power1) - pow (xright, power2);
			double gderivright = power1 * pow (xright, power1 - 1.0) - power2 * pow (xright, power2 - 1.0);
			double fright = - gright / gderivright;
			for (int i = 1; i <= 50; i ++) {
				double xmid = 0.5 * (xleft + xright);
				double gmid = pow (xmid, power1) - pow (xmid, power2);
				double gderivmid = power1 * pow (xmid, power1 - 1.0) - power2 * pow (xmid, power2 - 1.0);
				double fmid = - gmid / gderivmid;
				if (fmid > collisionPhase / openPhase) {
					xleft = xmid;
					fleft = fmid;
				} else {
					xright = xmid;
					fright = fmid;
				}
				re = xmid * openPhase;
			}
		}
		/*
		 * Cycle through the points. Each will become a period.
		 */
		double *sound = thy z [1];
		for (long it = 1; it <= my nt; it ++) {
			double t = my t [it], amplitude = a;
			double period = NUMundefined, te, phase, flow;
			long midSample = Sampled_xToNearestIndex (thee.peek(), t);
			/*
			 * Determine the period: first look left (because that's where the open phase is),
			 * then right.
			 */
			if (it >= 2) {
				period = my t [it] - my t [it - 1];
				if (period > maximumPeriod) {
					period = NUMundefined;
				}
			}
			if (period == NUMundefined) {
				if (it < my nt) {
					period = my t [it + 1] - my t [it];
					if (period > maximumPeriod) {
						period = NUMundefined;
					}
				}
				if (period == NUMundefined) {
					period = 0.5 * maximumPeriod;   /* Some default value. */
				}
			}
			te = re * period;
			/*
			 * Determine the amplitude of this peak.
			 */
			amplitude /= period * openPhase;
			if (it == 1 || my t [it - 1] < my t [it] - maximumPeriod) {
				amplitude *= adaptFactor * adaptFactor;
			} else if (it == 2 || my t [it - 2] < my t [it - 1] - maximumPeriod) {
				amplitude *= adaptFactor;
			}
			/*
			 * Fill in the samples to the left of the current point.
			 */
			{// scope
				long beginSample = midSample - floor (te / thy dx);
				if (beginSample < 1) beginSample = 1;
				long endSample = midSample;
				if (endSample > thy nx) endSample = thy nx;
				for (long isamp = beginSample; isamp <= endSample; isamp ++) {
					double tsamp = thy x1 + (isamp - 1) * thy dx;
					phase = (tsamp - (t - te)) / (period * openPhase);
					if (phase > 0.0)
						sound [isamp] += amplitude * (power1 * pow (phase, power1 - 1.0) - power2 * pow (phase, power2 - 1.0));
				}
			}
			/*
			 * Determine the signal parameters at the current point.
			 */
			phase = te / (period * openPhase);
			flow = amplitude * (period * openPhase) * (pow (phase, power1) - pow (phase, power2));
			/*
			 * Fill in the samples to the right of the current point.
			 */
			if (flow > 0.0) {
				double flowDerivative = amplitude * (power1 * pow (phase, power1 - 1.0) - power2 * pow (phase, power2 - 1.0));
				double ta = - flow / flowDerivative;
				double factorPerSample = exp (- thy dx / ta);
				double value = flowDerivative * factorPerSample;
				long beginSample = midSample + 1;
				if (beginSample < 1) beginSample = 1;
				long endSample = midSample + floor (20 * ta / thy dx);
				if (endSample > thy nx) endSample = thy nx;
				for (long isamp = beginSample; isamp <= endSample; isamp ++) {
					sound [isamp] += value;
					value *= factorPerSample;
				}
			}
		}
		Vector_scale (thee.peek(), 0.9);
		return thee.transfer();
	} catch (MelderError) {
		Melder_throw (me, ": not converted to Sound (phonation).");
	}
}
Example #17
0
Sound Sound_deepenBandModulation (Sound me, double enhancement_dB,
	double flow, double fhigh, double slowModulation, double fastModulation, double bandSmoothing)
{
	try {
		autoSound thee = Data_copy (me);
		double maximumFactor = pow (10, enhancement_dB / 20), alpha = sqrt (log (2.0));
		double alphaslow = alpha / slowModulation, alphafast = alpha / fastModulation;

		for (long channel = 1; channel <= my ny; channel ++) {
			autoSound channelSound = Sound_extractChannel (me, channel);
			autoSpectrum orgspec = Sound_to_Spectrum (channelSound.peek(), true);

			/*
			 * Keep the part of the sound that is outside the filter bank.
			 */
			autoSpectrum spec = Data_copy (orgspec.peek());
			Spectrum_stopHannBand (spec.peek(), flow, fhigh, bandSmoothing);
			autoSound filtered = Spectrum_to_Sound (spec.peek());
			long n = thy nx;
			double *amp = thy z [channel];
			for (long i = 1; i <= n; i ++) amp [i] = filtered -> z [1] [i];

			autoMelderProgress progress (U"Deepen band modulation...");
			double fmin = flow;
			while (fmin < fhigh) {
				/*
				 * Take a one-bark frequency band.
				 */
				double fmid_bark = NUMhertzToBark (fmin) + 0.5, ceiling;
				double fmax = NUMbarkToHertz (NUMhertzToBark (fmin) + 1);
				if (fmax > fhigh) fmax = fhigh;
				Melder_progress (fmin / fhigh, U"Band: ", Melder_fixed (fmin, 0), U" ... ", Melder_fixed (fmax, 0), U" Hz");
				NUMmatrix_copyElements (orgspec -> z, spec -> z, 1, 2, 1, spec -> nx);
				Spectrum_passHannBand (spec.peek(), fmin, fmax, bandSmoothing);
				autoSound band = Spectrum_to_Sound (spec.peek());
				/*
				 * Compute a relative intensity contour.
				 */		
				autoSound intensity = Data_copy (band.peek());
				n = intensity -> nx;
				amp = intensity -> z [1];
				for (long i = 1; i <= n; i ++) amp [i] = 10 * log10 (amp [i] * amp [i] + 1e-6);
				autoSpectrum intensityFilter = Sound_to_Spectrum (intensity.peek(), true);
				n = intensityFilter -> nx;
				for (long i = 1; i <= n; i ++) {
					double frequency = intensityFilter -> x1 + (i - 1) * intensityFilter -> dx;
					double slow = alphaslow * frequency, fast = alphafast * frequency;
					double factor = exp (- fast * fast) - exp (- slow * slow);
					intensityFilter -> z [1] [i] *= factor;
					intensityFilter -> z [2] [i] *= factor;
				}
				intensity.reset (Spectrum_to_Sound (intensityFilter.peek()));
				n = intensity -> nx;
				amp = intensity -> z [1];
				for (long i = 1; i <= n; i ++) amp [i] = pow (10, amp [i] / 2);
				/*
				 * Clip to maximum enhancement.
				 */
				ceiling = 1 + (maximumFactor - 1.0) * (0.5 - 0.5 * cos (NUMpi * fmid_bark / 13));
				for (long i = 1; i <= n; i ++) amp [i] = 1 / (1 / amp [i] + 1 / ceiling);

				n = thy nx;
				amp = thy z [channel];
				for (long i = 1; i <= n; i ++) amp [i] += band -> z [1] [i] * intensity -> z [1] [i];

				fmin = fmax;
			}
		}
		Vector_scale (thee.peek(), 0.99);
		/* Truncate. */
		thy xmin = my xmin;
		thy xmax = my xmax;
		thy nx = my nx;
		thy x1 = my x1;
		return thee.transfer();
	} catch (MelderError) {
		Melder_throw (me, U": band modulation not deepened.");
	}
}
Example #18
0
Sound Sound_autoCorrelate (Sound me, enum kSounds_convolve_scaling scaling, enum kSounds_convolve_signalOutsideTimeDomain signalOutsideTimeDomain) {
	try {
		long numberOfChannels = my ny, n1 = my nx, n2 = n1 + n1 - 1, nfft = 1;
		while (nfft < n2) nfft *= 2;
		autoNUMvector <double> data (1, nfft);
		double my_xlast = my x1 + (n1 - 1) * my dx;
		autoSound thee = Sound_create (numberOfChannels, my xmin - my xmax, my xmax - my xmin, n2, my dx, my x1 - my_xlast);
		for (long channel = 1; channel <= numberOfChannels; channel ++) {
			double *a = my z [channel];
			for (long i = n1; i > 0; i --) data [i] = a [i];
			for (long i = n1 + 1; i <= nfft; i ++) data [i] = 0.0;
			NUMrealft (data.peek(), nfft, 1);
			data [1] *= data [1];
			data [2] *= data [2];
			for (long i = 3; i <= nfft; i += 2) {
				data [i] = data [i] * data [i] + data [i + 1] * data [i + 1];
				data [i + 1] = 0.0;   // reverse me by taking the conjugate of data1
			}
			NUMrealft (data.peek(), nfft, -1);
			a = thy z [channel];
			for (long i = 1; i < n1; i ++) {
				a [i] = data [i + (nfft - (n1 - 1))];   // data for the first part ("negative lags") is at the end of data
			}
			for (long i = 1; i <= n1; i ++) {
				a [i + (n1 - 1)] = data [i];   // data for the second part ("positive lags") is at the beginning of data
			}
		}
		switch (signalOutsideTimeDomain) {
			case kSounds_convolve_signalOutsideTimeDomain_ZERO: {
				// do nothing
			} break;
			case kSounds_convolve_signalOutsideTimeDomain_SIMILAR: {
				for (long channel = 1; channel <= numberOfChannels; channel ++) {
					double *a = thy z [channel];
					double edge = n1;
					for (long i = 1; i < edge; i ++) {
						double factor = edge / i;
						a [i] *= factor;
						a [n2 + 1 - i] *= factor;
					}
				}
			} break;
			//case kSounds_convolve_signalOutsideTimeDomain_PERIODIC: {
				// do nothing
			//} break;
			default: Melder_fatal (U"Sounds_autoCorrelate: unimplemented outside-time-domain strategy ", signalOutsideTimeDomain);
		}
		switch (scaling) {
			case kSounds_convolve_scaling_INTEGRAL: {
				Vector_multiplyByScalar (thee.peek(), my dx / nfft);
			} break;
			case kSounds_convolve_scaling_SUM: {
				Vector_multiplyByScalar (thee.peek(), 1.0 / nfft);
			} break;
			case kSounds_convolve_scaling_NORMALIZE: {
				double normalizationFactor = Matrix_getNorm (me) * Matrix_getNorm (me);
				if (normalizationFactor != 0.0) {
					Vector_multiplyByScalar (thee.peek(), 1.0 / nfft / normalizationFactor);
				}
			} break;
			case kSounds_convolve_scaling_PEAK_099: {
				Vector_scale (thee.peek(), 0.99);
			} break;
			default: Melder_fatal (U"Sounds_autoCorrelate: unimplemented scaling ", scaling);
		}
		return thee.transfer();
	} catch (MelderError) {
		Melder_throw (me, U": autocorrelation not computed.");
	}
}