void PitchTier_shiftFrequencies (PitchTier me, double tmin, double tmax, double shift, int unit) { try { for (long i = 1; i <= my points -> size; i ++) { RealPoint point = (RealPoint) my points -> item [i]; double frequency = point -> value; if (point -> number < tmin || point -> number > tmax) continue; switch (unit) { case kPitch_unit_HERTZ: { frequency += shift; if (frequency <= 0.0) Melder_throw ("The resulting frequency has to be greater than 0 Hz."); } break; case kPitch_unit_MEL: { frequency = NUMhertzToMel (frequency) + shift; if (frequency <= 0.0) Melder_throw ("The resulting frequency has to be greater than 0 mel."); frequency = NUMmelToHertz (frequency); } break; case kPitch_unit_LOG_HERTZ: { frequency = pow (10.0, log10 (frequency) + shift); } break; case kPitch_unit_SEMITONES_1: { frequency = NUMsemitonesToHertz (NUMhertzToSemitones (frequency) + shift); } break; case kPitch_unit_ERB: { frequency = NUMhertzToErb (frequency) + shift; if (frequency <= 0.0) Melder_throw ("The resulting frequency has to be greater than 0 ERB."); frequency = NUMerbToHertz (frequency); } } point -> value = frequency; } } catch (MelderError) { Melder_throw (me, ": not all frequencies were shifted."); } }
static double SpecialToHertz (double value, int pitchUnit) { return pitchUnit == kPitch_unit_HERTZ ? value : pitchUnit == kPitch_unit_HERTZ_LOGARITHMIC ? pow (10.0, value) : pitchUnit == kPitch_unit_MEL ? NUMmelToHertz (value) : pitchUnit == kPitch_unit_LOG_HERTZ ? pow (10.0, value) : pitchUnit == kPitch_unit_SEMITONES_1 ? 1.0 * exp (value * (NUMln2 / 12.0)) : pitchUnit == kPitch_unit_SEMITONES_100 ? 100.0 * exp (value * (NUMln2 / 12.0)) : pitchUnit == kPitch_unit_SEMITONES_200 ? 200.0 * exp (value * (NUMln2 / 12.0)) : pitchUnit == kPitch_unit_SEMITONES_440 ? 440.0 * exp (value * (NUMln2 / 12.0)) : pitchUnit == kPitch_unit_ERB ? NUMerbToHertz (value) : NUMundefined; }
double structPitch :: v_convertSpecialToStandardUnit (double value, long ilevel, int unit) { if (ilevel == Pitch_LEVEL_FREQUENCY) { return unit == kPitch_unit_HERTZ ? value : unit == kPitch_unit_HERTZ_LOGARITHMIC ? pow (10.0, value) : unit == kPitch_unit_MEL ? NUMmelToHertz (value) : unit == kPitch_unit_LOG_HERTZ ? pow (10.0, value) : unit == kPitch_unit_SEMITONES_1 ? 1.0 * exp (value * (NUMln2 / 12.0)): unit == kPitch_unit_SEMITONES_100 ? 100.0 * exp (value * (NUMln2 / 12.0)): unit == kPitch_unit_SEMITONES_200 ? 200.0 * exp (value * (NUMln2 / 12.0)): unit == kPitch_unit_SEMITONES_440 ? 440.0 * exp (value * (NUMln2 / 12.0)): unit == kPitch_unit_ERB ? NUMerbToHertz (value) : NUMundefined; } else { return NUMundefined; } }
autoPitch SPINET_to_Pitch (SPINET me, double harmonicFallOffSlope, double ceiling, int maxnCandidates) { try { long nPointsPerOctave = 48; double fmin = NUMerbToHertz (Sampled2_rowToY (me, 1)); double fmax = NUMerbToHertz (Sampled2_rowToY (me, my ny)); double fminl2 = NUMlog2 (fmin), fmaxl2 = NUMlog2 (fmax); double points = (fmaxl2 - fminl2) * nPointsPerOctave; double dfl2 = (fmaxl2 - fminl2) / (points - 1); long nFrequencyPoints = (long) floor (points); long maxHarmonic = (long) floor (fmax / fmin); double maxStrength = 0.0, unvoicedCriterium = 0.45, maxPower = 0.0; if (nFrequencyPoints < 2) { Melder_throw (U"Frequency range too small."); } if (ceiling <= fmin) { Melder_throw (U"Ceiling is smaller than centre frequency of lowest filter."); } autoPitch thee = Pitch_create (my xmin, my xmax, my nx, my dx, my x1, ceiling, maxnCandidates); autoNUMvector<double> power (1, my nx); autoNUMvector<double> pitch (1, nFrequencyPoints); autoNUMvector<double> sumspec (1, nFrequencyPoints); autoNUMvector<double> y (1, my ny); autoNUMvector<double> yv2 (1, my ny); autoNUMvector<double> fl2 (1, my ny); // From ERB's to log (f) for (long i = 1; i <= my ny; i++) { double f = NUMerbToHertz (my y1 + (i - 1) * my dy); fl2[i] = NUMlog2 (f); } // Determine global maximum power in frame for (long j = 1; j <= my nx; j++) { double p = 0.0; for (long i = 1; i <= my ny; i++) { p += my s[i][j]; } if (p > maxPower) { maxPower = p; } power[j] = p; } if (maxPower == 0.0) { Melder_throw (U"No power"); } for (long j = 1; j <= my nx; j++) { Pitch_Frame pitchFrame = &thy frame[j]; pitchFrame -> intensity = power[j] / maxPower; for (long i = 1; i <= my ny; i++) { y[i] = my s[i][j]; } NUMspline (fl2.peek(), y.peek(), my ny, 1e30, 1e30, yv2.peek()); for (long k = 1; k <= nFrequencyPoints; k++) { double f = fminl2 + (k - 1) * dfl2; NUMsplint (fl2.peek(), y.peek(), yv2.peek(), my ny, f, & pitch[k]); sumspec[k] = 0.0; } // Formula (8): weighted harmonic summation. for (long m = 1; m <= maxHarmonic; m++) { double hm = 1 - harmonicFallOffSlope * NUMlog2 (m); long kb = 1 + (long) floor (nPointsPerOctave * NUMlog2 (m)); for (long k = kb; k <= nFrequencyPoints; k++) { if (pitch[k] > 0.0) { sumspec[k - kb + 1] += pitch[k] * hm; } } } // into Pitch object Pitch_Frame_init (pitchFrame, maxnCandidates); pitchFrame -> nCandidates = 0; /* !!!!! */ Pitch_Frame_addPitch (pitchFrame, 0, 0, maxnCandidates); /* unvoiced */ for (long k = 2; k <= nFrequencyPoints - 1; k++) { double y1 = sumspec[k - 1], y2 = sumspec[k], y3 = sumspec[k + 1]; if (y2 > y1 && y2 >= y3) { double denum = y1 - 2.0 * y2 + y3, tmp = y3 - 4.0 * y2; double x = dfl2 * (y1 - y3) / (2 * denum); double f = pow (2.0, fminl2 + (k - 1) * dfl2 + x); double strength = (2.0 * y1 * (4.0 * y2 + y3) - y1 * y1 - tmp * tmp) / (8.0 * denum); if (strength > maxStrength) { maxStrength = strength; } Pitch_Frame_addPitch (pitchFrame, f, strength, maxnCandidates); } } } // Scale the pitch strengths for (long j = 1; j <= my nx; j++) { double f0, localStrength; Pitch_Frame_getPitch (&thy frame[j], &f0, &localStrength); Pitch_Frame_resizeStrengths (&thy frame[j], localStrength / maxStrength, unvoicedCriterium); } return thee; } catch (MelderError) { Melder_throw (me, U": no Pitch created."); } }
Pitch SPINET_to_Pitch (SPINET me, double harmonicFallOffSlope, double ceiling, int maxnCandidates) { Pitch thee = NULL; long i, j, k, m, nPointsPerOctave = 48; double fmin = NUMerbToHertz (Sampled2_rowToY (me, 1)); double fmax = NUMerbToHertz (Sampled2_rowToY (me, my ny)); double fminl2 = NUMlog2 (fmin), fmaxl2 = NUMlog2 (fmax); double points = (fmaxl2 - fminl2) * nPointsPerOctave; double dfl2 = (fmaxl2 - fminl2) / (points - 1); long nFrequencyPoints = points; long maxHarmonic = fmax / fmin; double maxStrength = 0, unvoicedCriterium = 0.45; double maxPower = 0, *sumspec = NULL, *power = NULL; double *y = NULL, *y2 = NULL, *pitch = NULL, *fl2 = NULL; if (nFrequencyPoints < 2) return Melder_errorp1 (L"SPINET_to_Pitch: frequency range too small."); if (ceiling <= fmin) return Melder_errorp1 (L"SPINET_to_Pitch: ceiling is smaller than centre " "frequency of lowest filter."); if (! (thee = Pitch_create (my xmin, my xmax, my nx, my dx, my x1, ceiling, maxnCandidates)) || ! (power = NUMdvector (1, my nx)) || ! (pitch = NUMdvector (1, nFrequencyPoints)) || ! (sumspec = NUMdvector (1, nFrequencyPoints)) || ! (y = NUMdvector (1, my ny)) || ! (y2 = NUMdvector (1, my ny)) || ! (fl2 = NUMdvector (1, my ny))) goto cleanup; /* From ERB's to log (f) */ for (i=1; i <= my ny; i++) { double f = NUMerbToHertz (my y1 + (i - 1) * my dy); fl2[i] = NUMlog2 (f); } /* Determine global maximum power in frame */ for (j=1; j <= my nx; j++) { double p = 0; for (i=1; i <= my ny; i++) p += my s[i][j]; if (p > maxPower) maxPower = p; power[j] = p; } if (maxPower == 0) goto cleanup; for (j=1; j <= my nx; j++) { Pitch_Frame pitchFrame = &thy frame[j]; pitchFrame->intensity = power[j] / maxPower; for (i=1; i <= my ny; i++) y[i] = my s[i][j]; if (! NUMspline (fl2, y, my ny, 1e30, 1e30, y2)) goto cleanup; for (k=1; k <= nFrequencyPoints; k++) { double f = fminl2 + (k-1) * dfl2; NUMsplint (fl2, y, y2, my ny, f, & pitch[k]); sumspec[k] = 0; } /* Formula (8): weighted harmonic summation. */ for (m=1; m <= maxHarmonic; m++) { double hm = 1 - harmonicFallOffSlope * NUMlog2 (m); long kb = 1 + floor (nPointsPerOctave * NUMlog2 (m)); for (k=kb; k <= nFrequencyPoints; k++) { if (pitch[k] > 0) sumspec[k-kb+1] += pitch[k] * hm; } } /* into Pitch object */ if (! Pitch_Frame_init (pitchFrame, maxnCandidates)) goto cleanup; pitchFrame->nCandidates = 0; /* !!!!! */ Pitch_Frame_addPitch (pitchFrame, 0, 0, maxnCandidates); /* unvoiced */ for (k=2; k <= nFrequencyPoints-1; k++) { double y1 = sumspec[k-1], y2 = sumspec[k], y3 = sumspec[k+1]; if (y2 > y1 && y2 >= y3) { double denum = y1 - 2 * y2 + y3, tmp = y3 - 4 * y2; double x = dfl2 * (y1 - y3) / (2 * denum); double f = pow (2, fminl2 + (k - 1) * dfl2 + x); double strength = (2 * y1 * (4 * y2 + y3) - y1 * y1 - tmp * tmp) / (8 * denum); if (strength > maxStrength) maxStrength = strength; Pitch_Frame_addPitch (pitchFrame, f, strength, maxnCandidates); } } } /* Scale the pitch strengths */ for (j=1; j <= my nx; j++) { double f0, localStrength; Pitch_Frame_getPitch (&thy frame[j], &f0, &localStrength); Pitch_Frame_resizeStrengths (&thy frame[j], localStrength / maxStrength, unvoicedCriterium); } cleanup: NUMdvector_free (pitch, 1); NUMdvector_free (sumspec, 1); NUMdvector_free (y, 1); NUMdvector_free (y2, 1); NUMdvector_free (fl2, 1);NUMdvector_free (power, 1); if (! Melder_hasError()) return thee; forget (thee); return Melder_errorp1 (L"SPINET_to_Pitch: not performed."); }
SPINET Sound_to_SPINET (Sound me, double timeStep, double windowDuration, double minimumFrequencyHz, double maximumFrequencyHz, long nFilters, double excitationErbProportion, double inhibitionErbProportion) { Sound window = NULL, frame = NULL; SPINET thee = NULL; long i, j, k, numberOfFrames; double firstTime, b = 1.02, samplingFrequency = 1 / my dx; double *f = NULL, *bw = NULL, *aex = NULL, *ain = NULL; if (timeStep < my dx) timeStep = my dx; if (maximumFrequencyHz > samplingFrequency / 2) maximumFrequencyHz = samplingFrequency / 2; if (! Sampled_shortTermAnalysis (me, windowDuration, timeStep, &numberOfFrames, &firstTime) || ! (thee = SPINET_create (my xmin, my xmax, numberOfFrames, timeStep, firstTime, minimumFrequencyHz, maximumFrequencyHz, nFilters, excitationErbProportion, inhibitionErbProportion)) || ! (window = Sound_createGaussian (windowDuration, samplingFrequency)) || ! (frame = Sound_createSimple (1, windowDuration, samplingFrequency)) || ! (f = NUMdvector (1, nFilters)) || ! (bw = NUMdvector (1, nFilters)) || ! (aex = NUMdvector (1, nFilters)) || ! (ain = NUMdvector (1, nFilters))) goto cleanup; /* Cochlear filterbank: gammatone */ for (i=1; i <= nFilters; i++) { f[i] = NUMerbToHertz (thy y1 + (i - 1) * thy dy); bw[i] = 2 * NUMpi * b * (f[i] * (6.23e-6 * f[i] + 93.39e-3) + 28.52); } Melder_progress1 (0.0, L"SPINET analysis"); for (i=1; i <= nFilters; i++) { Sound gammaTone = NULL, filtered = NULL; /* Contribution of outer & middle ear and phase locking */ double bb = (f[i] / 1000) * exp (- f[i] / 1000); /* Time where gammafunction envelope has its maximum */ double tgammaMax = (thy gamma - 1) / bw[i]; /* Amplitude at tgammaMax */ double gammaMaxAmplitude = pow ((thy gamma - 1) / (NUMe * bw[i]), (thy gamma - 1)); double timeCorrection = tgammaMax - windowDuration / 2; if (! (gammaTone = Sound_createGammaTone (0, 0.1, samplingFrequency, thy gamma, b, f[i], 0, 0, 0)) || /* filtering can be made 30% faster by taking Spectrum(me) outside the loop */ ! (filtered = Sounds_convolve (me, gammaTone, kSounds_convolve_scaling_SUM, kSounds_convolve_signalOutsideTimeDomain_ZERO))) { forget (gammaTone); goto cleanup; } /* To energy measure: weigh with broad-band transfer function */ for (j=1; j <= numberOfFrames; j++) { Sound_into_Sound (filtered, frame, Sampled_indexToX (thee, j) + timeCorrection); Sounds_multiply (frame, window); thy y[i][j] = Sound_power (frame) * bb / gammaMaxAmplitude; } forget (filtered); forget (gammaTone); if (! Melder_progress5 ((double)i / nFilters, L"SPINET: filter ", Melder_integer (i), L" from ", Melder_integer (nFilters), L".")) goto cleanup; } /* Excitatory and inhibitory area functions */ for (i=1; i <= nFilters; i++) { for (k=1; k <= nFilters; k++) { double fr = (f[k] - f[i]) / bw[i]; aex[i] += fgamma (fr / thy excitationErbProportion, thy gamma); ain[i] += fgamma (fr / thy inhibitionErbProportion, thy gamma); } } /* On-center off-surround interactions */ for (j=1; j <= numberOfFrames; j++) for (i=1; i <= nFilters; i++) { double a = 0; for (k=1; k <= nFilters; k++) { double fr = (f[k] - f[i]) / bw[i]; double hexsq = fgamma (fr / thy excitationErbProportion, thy gamma); double hinsq = fgamma (fr / thy inhibitionErbProportion, thy gamma); a += thy y[k][j] * (hexsq / aex[i] - hinsq / ain[i]); } thy s[i][j] = a > 0 ? a : 0; } Melder_progress1 (1.0, NULL); cleanup: NUMdvector_free (aex, 1); NUMdvector_free (ain, 1); NUMdvector_free (f, 1); NUMdvector_free (bw, 1); forget (window); forget (frame); if (! Melder_hasError()) return thee; forget (thee); return Melder_errorp1 (L"Sound_to_SPINET: not performed."); }
SPINET Sound_to_SPINET (Sound me, double timeStep, double windowDuration, double minimumFrequencyHz, double maximumFrequencyHz, long nFilters, double excitationErbProportion, double inhibitionErbProportion) { try { double firstTime, b = 1.02, samplingFrequency = 1 / my dx; if (timeStep < my dx) { timeStep = my dx; } if (maximumFrequencyHz > samplingFrequency / 2) { maximumFrequencyHz = samplingFrequency / 2; } long numberOfFrames; Sampled_shortTermAnalysis (me, windowDuration, timeStep, &numberOfFrames, &firstTime); autoSPINET thee = SPINET_create (my xmin, my xmax, numberOfFrames, timeStep, firstTime, minimumFrequencyHz, maximumFrequencyHz, nFilters, excitationErbProportion, inhibitionErbProportion); autoSound window = Sound_createGaussian (windowDuration, samplingFrequency); autoSound frame = Sound_createSimple (1, windowDuration, samplingFrequency); autoNUMvector<double> f (1, nFilters); autoNUMvector<double> bw (1, nFilters); autoNUMvector<double> aex (1, nFilters); autoNUMvector<double> ain (1, nFilters); // Cochlear filterbank: gammatone for (long i = 1; i <= nFilters; i++) { f[i] = NUMerbToHertz (thy y1 + (i - 1) * thy dy); bw[i] = 2 * NUMpi * b * (f[i] * (6.23e-6 * f[i] + 93.39e-3) + 28.52); } autoMelderProgress progress (L"SPINET analysis"); for (long i = 1; i <= nFilters; i++) { double bb = (f[i] / 1000) * exp (- f[i] / 1000); // outer & middle ear and phase locking double tgammaMax = (thy gamma - 1) / bw[i]; // Time where gammafunction envelope has maximum double gammaMaxAmplitude = pow ( (thy gamma - 1) / (NUMe * bw[i]), (thy gamma - 1)); // tgammaMax double timeCorrection = tgammaMax - windowDuration / 2; autoSound gammaTone = Sound_createGammaTone (0, 0.1, samplingFrequency, thy gamma, b, f[i], 0, 0, 0); autoSound filtered = Sounds_convolve (me, gammaTone.peek(), kSounds_convolve_scaling_SUM, kSounds_convolve_signalOutsideTimeDomain_ZERO); // To energy measure: weigh with broad-band transfer function for (long j = 1; j <= numberOfFrames; j++) { Sound_into_Sound (filtered.peek(), frame.peek(), Sampled_indexToX (thee.peek(), j) + timeCorrection); Sounds_multiply (frame.peek(), window.peek()); thy y[i][j] = Sound_power (frame.peek()) * bb / gammaMaxAmplitude; } Melder_progress ( (double) i / nFilters, L"SPINET: filter ", Melder_integer (i), L" from ", Melder_integer (nFilters), L"."); } // Excitatory and inhibitory area functions for (long i = 1; i <= nFilters; i++) { for (long k = 1; k <= nFilters; k++) { double fr = (f[k] - f[i]) / bw[i]; aex[i] += fgamma (fr / thy excitationErbProportion, thy gamma); ain[i] += fgamma (fr / thy inhibitionErbProportion, thy gamma); } } // On-center off-surround interactions for (long j = 1; j <= numberOfFrames; j++) for (long i = 1; i <= nFilters; i++) { double a = 0; for (long k = 1; k <= nFilters; k++) { double fr = (f[k] - f[i]) / bw[i]; double hexsq = fgamma (fr / thy excitationErbProportion, thy gamma); double hinsq = fgamma (fr / thy inhibitionErbProportion, thy gamma); a += thy y[k][j] * (hexsq / aex[i] - hinsq / ain[i]); } thy s[i][j] = a > 0 ? a : 0; } return thee.transfer(); } catch (MelderError) { Melder_throw (me, ": no SPINET created."); } }