Sound Sound_resample (Sound me, double samplingFrequency, long precision) { double upfactor = samplingFrequency * my dx; if (fabs (upfactor - 2) < 1e-6) return Sound_upsample (me); if (fabs (upfactor - 1) < 1e-6) return Data_copy (me); try { long numberOfSamples = lround ((my xmax - my xmin) * samplingFrequency); if (numberOfSamples < 1) Melder_throw (U"The resampled Sound would have no samples."); autoSound filtered = NULL; if (upfactor < 1.0) { // need anti-aliasing filter? long nfft = 1, antiTurnAround = 1000; while (nfft < my nx + antiTurnAround * 2) nfft *= 2; autoNUMvector <double> data (1, nfft); filtered.reset (Sound_create (my ny, my xmin, my xmax, my nx, my dx, my x1)); for (long channel = 1; channel <= my ny; channel ++) { for (long i = 1; i <= nfft; i ++) { data [i] = 0; } NUMvector_copyElements (my z [channel], & data [antiTurnAround], 1, my nx); NUMrealft (data.peek(), nfft, 1); // go to the frequency domain for (long i = (long) floor (upfactor * nfft); i <= nfft; i ++) { data [i] = 0; // filter away high frequencies } data [2] = 0.0; NUMrealft (data.peek(), nfft, -1); // return to the time domain double factor = 1.0 / nfft; double *to = filtered -> z [channel]; for (long i = 1; i <= my nx; i ++) { to [i] = data [i + antiTurnAround] * factor; } } me = filtered.peek(); // reference copy; remove at end } autoSound thee = Sound_create (my ny, my xmin, my xmax, numberOfSamples, 1.0 / samplingFrequency, 0.5 * (my xmin + my xmax - (numberOfSamples - 1) / samplingFrequency)); for (long channel = 1; channel <= my ny; channel ++) { double *from = my z [channel]; double *to = thy z [channel]; if (precision <= 1) { for (long i = 1; i <= numberOfSamples; i ++) { double x = Sampled_indexToX (thee.peek(), i); double index = Sampled_xToIndex (me, x); long leftSample = (long) floor (index); double fraction = index - leftSample; to [i] = leftSample < 1 || leftSample >= my nx ? 0.0 : (1 - fraction) * from [leftSample] + fraction * from [leftSample + 1]; } } else { for (long i = 1; i <= numberOfSamples; i ++) { double x = Sampled_indexToX (thee.peek(), i); double index = Sampled_xToIndex (me, x); to [i] = NUM_interpolate_sinc (my z [channel], my nx, index, precision); } } } return thee.transfer(); } catch (MelderError) { Melder_throw (me, U": not resampled."); } }
autoSpectrum Spectrum_shiftFrequencies (Spectrum me, double shiftBy, double newMaximumFrequency, long interpolationDepth) { try { double xmax = my xmax; long numberOfFrequencies = my nx; if (newMaximumFrequency != 0) { numberOfFrequencies = (long) floor (newMaximumFrequency / my dx) + 1; xmax = newMaximumFrequency; } autoSpectrum thee = Spectrum_create (xmax, numberOfFrequencies); // shiftBy >= 0 for (long i = 1; i <= thy nx; i++) { double thyf = thy x1 + (i - 1) * thy dx; double myf = thyf - shiftBy; if (myf >= my xmin && myf <= my xmax) { double index = Sampled_xToIndex (me, myf); thy z[1][i] = NUM_interpolate_sinc (my z[1], my nx, index, interpolationDepth); thy z[2][i] = NUM_interpolate_sinc (my z[2], my nx, index, interpolationDepth); } } // Make imaginary part of first and last sample zero // so Spectrum_to_Sound uses FFT if numberOfSamples was power of 2! double amp = sqrt (thy z[1][1] * thy z[1][1] + thy z[2][1] * thy z[2][1]); thy z[1][1] = amp; thy z[2][1] = 0; amp = sqrt (thy z[1][thy nx] * thy z[1][thy nx] + thy z[2][thy nx] * thy z[2][thy nx]); thy z[1][thy nx] = amp; thy z[2][thy nx] = 0; return thee; } catch (MelderError) { Melder_throw (me, U": not shifted."); } }
// // Vector_getValueAtX () returns the average of all the interpolated channels. // double Vector_getValueAtX (Vector me, double x, long ilevel, int interpolation) { double leftEdge = my x1 - 0.5 * my dx, rightEdge = leftEdge + my nx * my dx; if (x < leftEdge || x > rightEdge) return NUMundefined; if (ilevel > Vector_CHANNEL_AVERAGE) { Melder_assert (ilevel <= my ny); return NUM_interpolate_sinc (my z [ilevel], my nx, Sampled_xToIndex (me, x), interpolation == Vector_VALUE_INTERPOLATION_SINC70 ? NUM_VALUE_INTERPOLATE_SINC70 : interpolation == Vector_VALUE_INTERPOLATION_SINC700 ? NUM_VALUE_INTERPOLATE_SINC700 : interpolation); } double sum = 0.0; for (long channel = 1; channel <= my ny; channel ++) { sum += NUM_interpolate_sinc (my z [channel], my nx, Sampled_xToIndex (me, x), interpolation == Vector_VALUE_INTERPOLATION_SINC70 ? NUM_VALUE_INTERPOLATE_SINC70 : interpolation == Vector_VALUE_INTERPOLATION_SINC700 ? NUM_VALUE_INTERPOLATE_SINC700 : interpolation); } return sum / my ny; }
autoPolynomial LPC_to_Polynomial (LPC me, double time) { try { long iFrame = Sampled_xToIndex (me, time); if (iFrame < 1 || iFrame > my nx) { Melder_throw (U"invalid frame number."); } autoPolynomial thee = LPC_Frame_to_Polynomial (&my d_frames[iFrame]); return thee; } catch (MelderError) { Melder_throw (me, U":no Polynomial created."); } }
void ParamCurve_draw (ParamCurve me, Graphics g, double t1, double t2, double dt, double x1, double x2, double y1, double y2, int garnish) { if (t2 <= t1) { double tx1 = my x -> x1; double ty1 = my y -> x1; double tx2 = my x -> x1 + (my x -> nx - 1) * my x -> dx; double ty2 = my y -> x1 + (my y -> nx - 1) * my y -> dx; t1 = tx1 > ty1 ? tx1 : ty1; t2 = tx2 < ty2 ? tx2 : ty2; } if (x2 <= x1) Matrix_getWindowExtrema (my x, 0, 0, 1, 1, & x1, & x2); if (x1 == x2) { x1 -= 1.0; x2 += 1.0; } if (y2 <= y1) Matrix_getWindowExtrema (my y, 0, 0, 1, 1, & y1, & y2); if (y1 == y2) { y1 -= 1.0; y2 += 1.0; } if (dt <= 0.0) dt = my x -> dx < my y -> dx ? my x -> dx : my y -> dx; long numberOfPoints = (long) ceil ((t2 - t1) / dt) + 1; if (numberOfPoints > 0) { autoNUMvector <double> x (1, numberOfPoints); autoNUMvector <double> y (1, numberOfPoints); for (long i = 1; i <= numberOfPoints; i ++) { double t = i == numberOfPoints ? t2 : t1 + (i - 1) * dt; double index = Sampled_xToIndex (my x, t); x [i] = NUM_interpolate_sinc (my x -> z [1], my x -> nx, index, 50); index = Sampled_xToIndex (my y, t); y [i] = NUM_interpolate_sinc (my y -> z [1], my y -> nx, index, 50); } Graphics_setWindow (g, x1, x2, y1, y2); Graphics_setInner (g); Graphics_polyline (g, numberOfPoints, & x [1], & y [1]); Graphics_unsetInner (g); } if (garnish) { Graphics_drawInnerBox (g); Graphics_marksBottom (g, 2, 1, 1, 0); Graphics_marksLeft (g, 2, 1, 1, 0); } }
VocalTract LPC_to_VocalTract (LPC me, double time, double length, int wakita) { VocalTract thee = NULL; struct structTube_Frame area_struct; Tube_Frame area = & area_struct; LPC_Frame lpc; long i, m, iframe = Sampled_xToIndex (me, time); if (iframe < 1) iframe = 1; if (iframe > my nx) iframe = my nx; memset (& area_struct, 0, sizeof(area_struct)); lpc = & my frame[iframe]; m = lpc -> nCoefficients; if (! Tube_Frame_init (area, m, length) || ! LPC_Frame_into_Tube_Frame_area (lpc, area)) goto end; thee = VocalTract_create (m, area -> length / m); if (thee == NULL) goto end; /* area[lips..glottis] (m^2) to VocalTract[glottis..lips] (m^2) */ for (i = 1; i <= m; i++) { thy z[1][i] = area -> c[m + 1 - i]; } if (wakita) { double wakita_length = LPC_Frame_getVTL_wakita (lpc, my samplingPeriod, length); if (wakita_length == NUMundefined) { Melder_warning1 (L"Vocal tract length could not be calculated.\nRelevant tract dimensions will be undefined."); thy xmax = thy x1 = thy dx = NUMundefined; } } end: Tube_Frame_destroy (area); return thee; }
double Sampled_getValueAtX (Sampled me, double x, long ilevel, int unit, int interpolate) { if (x < my xmin || x > my xmax) return NUMundefined; if (interpolate) { double ireal = Sampled_xToIndex (me, x); long ileft = floor (ireal), inear, ifar; double phase = ireal - ileft; if (phase < 0.5) { inear = ileft, ifar = ileft + 1; } else { ifar = ileft, inear = ileft + 1; phase = 1.0 - phase; } if (inear < 1 || inear > my nx) return NUMundefined; // x out of range? double fnear = my v_getValueAtSample (inear, ilevel, unit); if (fnear == NUMundefined) return NUMundefined; // function value not defined? if (ifar < 1 || ifar > my nx) return fnear; // at edge? Extrapolate double ffar = my v_getValueAtSample (ifar, ilevel, unit); if (ffar == NUMundefined) return fnear; // neighbour undefined? Extrapolate return fnear + phase * (ffar - fnear); // interpolate } return Sampled_getValueAtSample (me, Sampled_xToNearestIndex (me, x), ilevel, unit); }
double Sampled_getValueAtX (I, double x, long ilevel, int unit, int interpolate) { iam (Sampled); if (x < my xmin || x > my xmax) return NUMundefined; if (interpolate) { double ireal = Sampled_xToIndex (me, x), phase, fnear, ffar; long ileft = floor (ireal), inear, ifar; phase = ireal - ileft; if (phase < 0.5) { inear = ileft, ifar = ileft + 1; } else { ifar = ileft, inear = ileft + 1; phase = 1.0 - phase; } if (inear < 1 || inear > my nx) return NUMundefined; /* X out of range? */ fnear = our getValueAtSample (me, inear, ilevel, unit); if (fnear == NUMundefined) return NUMundefined; /* Function value not defined? */ if (ifar < 1 || ifar > my nx) return fnear; /* At edge? Extrapolate. */ ffar = our getValueAtSample (me, ifar, ilevel, unit); if (ffar == NUMundefined) return fnear; /* Neighbour undefined? Extrapolate. */ return fnear + phase * (ffar - fnear); /* Interpolate. */ } return Sampled_getValueAtSample (me, Sampled_xToNearestIndex (me, x), ilevel, unit); }
autoSound Spectrogram_to_Sound (Spectrogram me, double fsamp) { try { double dt = 1 / fsamp; long n = (long) floor ((my xmax - my xmin) / dt); if (n < 0) return autoSound (); autoSound thee = Sound_create (1, my xmin, my xmax, n, dt, 0.5 * dt); for (long i = 1; i <= n; i ++) { double t = Sampled_indexToX (thee.peek(), i); double rframe = Sampled_xToIndex (me, t), phase, value = 0.0; long leftFrame, rightFrame; if (rframe < 1 || rframe >= my nx) continue; leftFrame = (long) floor (rframe), rightFrame = leftFrame + 1, phase = rframe - leftFrame; for (long j = 1; j <= my ny; j ++) { double f = Matrix_rowToY (me, j); double power = my z [j] [leftFrame] * (1 - phase) + my z [j] [rightFrame] * phase; value += sqrt (power) * sin (2 * NUMpi * f * t); } thy z [1] [i] = value; } return thee; } catch (MelderError) { Melder_throw (me, U": not converted to Sound."); } }
static autoSpectrum Spectrum_shiftFrequencies2 (Spectrum me, double shiftBy, bool changeMaximumFrequency) { try { double xmax = my xmax; long numberOfFrequencies = my nx, interpolationDepth = 50; if (changeMaximumFrequency) { xmax += shiftBy; numberOfFrequencies += (xmax - my xmax) / my dx; } autoSpectrum thee = Spectrum_create (xmax, numberOfFrequencies); // shiftBy >= 0 for (long i = 1; i <= thy nx; i++) { double thyf = thy x1 + (i - 1) * thy dx; double myf = thyf - shiftBy; if (myf >= my xmin && myf <= my xmax) { double index = Sampled_xToIndex (me, myf); thy z[1][i] = NUM_interpolate_sinc (my z[1], my nx, index, interpolationDepth); thy z[2][i] = NUM_interpolate_sinc (my z[2], my nx, index, interpolationDepth); } } return thee; } catch (MelderError) { Melder_throw (me, U": not shifted."); } }
PowerCepstrogram Sound_to_PowerCepstrogram_hillenbrand (Sound me, double minimumPitch, double dt) { try { // minimum analysis window has 3 periods of lowest pitch double analysisWidth = 3 / minimumPitch; if (analysisWidth > my dx * my nx) { analysisWidth = my dx * my nx; } double t1, samplingFrequency = 1 / my dx; autoSound thee; if (samplingFrequency > 30000) { samplingFrequency = samplingFrequency / 2; thee.reset (Sound_resample (me, samplingFrequency, 1)); } else { thee.reset (Data_copy (me)); } // pre-emphasis with fixed coefficient 0.9 for (long i = thy nx; i > 1; i--) { thy z[1][i] -= 0.9 * thy z[1][i - 1]; } long nosInWindow = analysisWidth * samplingFrequency, nFrames; if (nosInWindow < 8) { Melder_throw ("Analysis window too short."); } Sampled_shortTermAnalysis (thee.peek(), analysisWidth, dt, & nFrames, & t1); autoNUMvector<double> hamming (1, nosInWindow); for (long i = 1; i <= nosInWindow; i++) { hamming[i] = 0.54 -0.46 * cos(2 * NUMpi * (i - 1) / (nosInWindow - 1)); } long nfft = 8; // minimum possible while (nfft < nosInWindow) { nfft *= 2; } long nfftdiv2 = nfft / 2; autoNUMvector<double> fftbuf (1, nfft); // "complex" array autoNUMvector<double> spectrum (1, nfftdiv2 + 1); // +1 needed autoNUMfft_Table fftTable; NUMfft_Table_init (&fftTable, nfft); // sound to spectrum double qmax = 0.5 * nfft / samplingFrequency, dq = qmax / (nfftdiv2 + 1); autoPowerCepstrogram him = PowerCepstrogram_create (my xmin, my xmax, nFrames, dt, t1, 0, qmax, nfftdiv2+1, dq, 0); autoMelderProgress progress (L"Cepstrogram analysis"); for (long iframe = 1; iframe <= nFrames; iframe++) { double tbegin = t1 + (iframe - 1) * dt - analysisWidth / 2; tbegin = tbegin < thy xmin ? thy xmin : tbegin; long istart = Sampled_xToIndex (thee.peek(), tbegin); istart = istart < 1 ? 1 : istart; long iend = istart + nosInWindow - 1; iend = iend > thy nx ? thy nx : iend; for (long i = 1; i <= nosInWindow; i++) { fftbuf[i] = thy z[1][istart + i - 1] * hamming[i]; } for (long i = nosInWindow + 1; i <= nfft; i++) { fftbuf[i] = 0; } NUMfft_forward (&fftTable, fftbuf.peek()); complexfftoutput_to_power (fftbuf.peek(), nfft, spectrum.peek(), true); // log10(|fft|^2) // subtract average double specmean = spectrum[1]; for (long i = 2; i <= nfftdiv2 + 1; i++) { specmean += spectrum[i]; } specmean /= nfftdiv2 + 1; for (long i = 1; i <= nfftdiv2 + 1; i++) { spectrum[i] -= specmean; } /* * Here we diverge from Hillenbrand as he takes the fft of half of the spectral values. * H. forgets that the actual spectrum has nfft/2+1 values. Thefore, we take the inverse * transform because this keeps the number of samples a power of 2. * At the same time this results in twice as much numbers in the quefrency domain, i.e. we end with nfft/2+1 * numbers while H. has only nfft/4! */ fftbuf[1] = spectrum[1]; for (long i = 2; i < nfftdiv2 + 1; i++) { fftbuf[i+i-2] = spectrum[i]; fftbuf[i+i-1] = 0; } fftbuf[nfft] = spectrum[nfftdiv2 + 1]; NUMfft_backward (&fftTable, fftbuf.peek()); for (long i = 1; i <= nfftdiv2 + 1; i++) { his z[i][iframe] = fftbuf[i] * fftbuf[i]; } if ((iframe % 10) == 1) { Melder_progress ((double) iframe / nFrames, L"Cepstrogram analysis of frame ", Melder_integer (iframe), L" out of ", Melder_integer (nFrames), L"."); } } return him.transfer(); } catch (MelderError) { Melder_throw (me, ": no Cepstrogram created."); } }
static void Sampled_getSum2AndDefinitionRange (Sampled me, double xmin, double xmax, long ilevel, int unit, double mean, int interpolate, double *return_sum2, double *return_definitionRange) { /* This function computes the area under the linearly interpolated squared difference curve between xmin and xmax. Outside [x1-dx/2, xN+dx/2], the curve is undefined and neither times nor values are counted. In [x1-dx/2,x1] and [xN,xN+dx/2], the curve is linearly extrapolated. */ long imin, imax, isamp; double sum2 = 0.0, definitionRange = 0.0; Function_unidirectionalAutowindow (me, & xmin, & xmax); if (Function_intersectRangeWithDomain (me, & xmin, & xmax)) { if (interpolate) { if (Sampled_getWindowSamples (me, xmin, xmax, & imin, & imax)) { double leftEdge = my x1 - 0.5 * my dx, rightEdge = leftEdge + my nx * my dx; for (isamp = imin; isamp <= imax; isamp ++) { double value = my v_getValueAtSample (isamp, ilevel, unit); // a fast way to integrate a linearly interpolated curve; works everywhere except at the edges if (NUMdefined (value)) { value -= mean; value *= value; definitionRange += 1.0; sum2 += value; } } /* * Corrections within the first and last sampling intervals. */ if (xmin > leftEdge) { // otherwise, constant extrapolation over 0.5 sample is OK double phase = (my x1 + (imin - 1) * my dx - xmin) / my dx; // this fraction of sampling interval is still to be determined double rightValue = Sampled_getValueAtSample (me, imin, ilevel, unit); double leftValue = Sampled_getValueAtSample (me, imin - 1, ilevel, unit); if (NUMdefined (rightValue)) { rightValue -= mean; rightValue *= rightValue; definitionRange -= 0.5; // delete constant extrapolation over 0.5 sample sum2 -= 0.5 * rightValue; if (NUMdefined (leftValue)) { leftValue -= mean; leftValue *= leftValue; definitionRange += phase; // add current fraction sum2 += phase * (rightValue + 0.5 * phase * (leftValue - rightValue)); // interpolate to outside sample } else { if (phase > 0.5) phase = 0.5; definitionRange += phase; // add current fraction, but never more than 0.5 sum2 += phase * rightValue; } } else if (NUMdefined (leftValue) && phase > 0.5) { leftValue -= mean; leftValue *= leftValue; definitionRange += phase - 0.5; sum2 += (phase - 0.5) * leftValue; } } if (xmax < rightEdge) { // otherwise, constant extrapolation is OK double phase = (xmax - (my x1 + (imax - 1) * my dx)) / my dx; // this fraction of sampling interval is still to be determined double leftValue = Sampled_getValueAtSample (me, imax, ilevel, unit); double rightValue = Sampled_getValueAtSample (me, imax + 1, ilevel, unit); if (NUMdefined (leftValue)) { leftValue -= mean; leftValue *= leftValue; definitionRange -= 0.5; // delete constant extrapolation over 0.5 sample sum2 -= 0.5 * leftValue; if (NUMdefined (rightValue)) { rightValue -= mean; rightValue *= rightValue; definitionRange += phase; // add current fraction sum2 += phase * (leftValue + 0.5 * phase * (rightValue - leftValue)); // interpolate to outside sample } else { if (phase > 0.5) phase = 0.5; definitionRange += phase; // add current fraction, but never more than 0.5 sum2 += phase * leftValue; } } else if (NUMdefined (rightValue) && phase > 0.5) { rightValue -= mean; rightValue *= rightValue; definitionRange += phase - 0.5; sum2 += (phase - 0.5) * rightValue; } } } else { // no sample centres between xmin and xmax /* * Try to return the mean of the interpolated values at these two points. * Thus, a small (xmin, xmax) range gives the same value as the (xmin+xmax)/2 point. */ double leftValue = Sampled_getValueAtSample (me, imax, ilevel, unit); double rightValue = Sampled_getValueAtSample (me, imin, ilevel, unit); double phase1 = (xmin - (my x1 + (imax - 1) * my dx)) / my dx; double phase2 = (xmax - (my x1 + (imax - 1) * my dx)) / my dx; if (imin == imax + 1) { // not too far from sample definition region if (NUMdefined (leftValue)) { leftValue -= mean; leftValue *= leftValue; if (NUMdefined (rightValue)) { rightValue -= mean; rightValue *= rightValue; definitionRange += phase2 - phase1; sum2 += (phase2 - phase1) * (leftValue + 0.5 * (phase1 + phase2) * (rightValue - leftValue)); } else if (phase1 < 0.5) { if (phase2 > 0.5) phase2 = 0.5; definitionRange += phase2 - phase1; sum2 += (phase2 - phase1) * leftValue; } } else if (NUMdefined (rightValue) && phase2 > 0.5) { rightValue -= mean; rightValue *= rightValue; if (phase1 < 0.5) phase1 = 0.5; definitionRange += phase2 - phase1; sum2 += (phase2 - phase1) * rightValue; } } } } else { // no interpolation double rimin = Sampled_xToIndex (me, xmin), rimax = Sampled_xToIndex (me, xmax); if (rimax >= 0.5 && rimin < my nx + 0.5) { imin = rimin < 0.5 ? 0 : (long) floor (rimin + 0.5); imax = rimax >= my nx + 0.5 ? my nx + 1 : (long) floor (rimax + 0.5); for (isamp = imin + 1; isamp < imax; isamp ++) { double value = my v_getValueAtSample (isamp, ilevel, unit); if (NUMdefined (value)) { value -= mean; value *= value; definitionRange += 1.0; sum2 += value; } } if (imin == imax) { double value = my v_getValueAtSample (imin, ilevel, unit); if (NUMdefined (value)) { double phase = rimax - rimin; value -= mean; value *= value; definitionRange += phase; sum2 += phase * value; } } else { if (imin >= 1) { double value = my v_getValueAtSample (imin, ilevel, unit); if (NUMdefined (value)) { double phase = imin - rimin + 0.5; value -= mean; value *= value; definitionRange += phase; sum2 += phase * value; } } if (imax <= my nx) { double value = my v_getValueAtSample (imax, ilevel, unit); if (NUMdefined (value)) { double phase = rimax - imax + 0.5; value -= mean; value *= value; definitionRange += phase; sum2 += phase * value; } } } } } } if (return_sum2) *return_sum2 = sum2; if (return_definitionRange) *return_definitionRange = definitionRange; }