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."); } }