Sound FilterBanks_convolve (FilterBank me, FilterBank thee, enum kSounds_convolve_scaling scaling, enum kSounds_convolve_signalOutsideTimeDomain signalOutsideTimeDomain) { try { autoSound cc = Sounds_convolve ((Sound) me, (Sound) thee, scaling, signalOutsideTimeDomain); return cc.transfer(); } catch (MelderError) { Melder_throw (me, " and ", thee, " not convolved."); } }
autoSound BandFilterSpectrograms_convolve (BandFilterSpectrogram me, BandFilterSpectrogram thee, enum kSounds_convolve_scaling scaling, enum kSounds_convolve_signalOutsideTimeDomain signalOutsideTimeDomain) { try { autoSound sme = BandFilterSpectrogram_as_Sound (me, 1); // to dB autoSound sthee = BandFilterSpectrogram_as_Sound (thee, 1); autoSound cc = Sounds_convolve (sme.get(), sthee.get(), scaling, signalOutsideTimeDomain); return cc; } catch (MelderError) { Melder_throw (me, U" and ", thee, U" not convolved."); } }
Cochleagram Sound_to_Cochleagram_edb (Sound me, double dtime, double dfreq, int hasSynapse, double replenishmentRate, double lossRate, double returnRate, double reprocessingRate) { try { double duration_seconds = my xmax; if (dtime < my dx) dtime = my dx; long ntime = floor (duration_seconds / dtime + 0.5); if (ntime < 2) return NULL; long nfreq = floor (25.6 / dfreq + 0.5); // 25.6 Bark = highest frequency autoCochleagram thee = Cochleagram_create (my xmin, my xmax, ntime, dtime, 0.5 * dtime, dfreq, nfreq); /* Stages 1 and 2: outer- and middle-ear filtering. */ /* From acoustic sound to oval window. */ for (long ifreq = 1; ifreq <= nfreq; ifreq ++) { double *response = thy z [ifreq]; /* Stage 3: basilar membrane filtering by gammatones. */ /* From oval window to basilar membrane response. */ double midFrequency_Bark = (ifreq - 0.5) * dfreq; double midFrequency_Hertz = Excitation_barkToHertz (midFrequency_Bark); autoSound gammatone = createGammatone (midFrequency_Hertz, 1 / my dx); autoSound basil = Sounds_convolve (me, gammatone.peek(), kSounds_convolve_scaling_SUM, kSounds_convolve_signalOutsideTimeDomain_ZERO); /* Stage 4: detection = rectify + integrate + low-pass 500 Hz. */ /* From basilar membrane response to firing rate. */ if (hasSynapse) { double dt = my dx; double M = 1; /* Maximum free transmitter. */ double A = 5, B = 300, g = 2000; /* Determine permeability. */ double y = replenishmentRate; /* Meddis: 5.05 */ double l = lossRate, r = returnRate; /* Meddis: 2500, 6580 */ double x = reprocessingRate; /* Meddis: 66.31 */ double h = 50000; /* Convert cleft contents to firing rate. */ double gdt = 1 - exp (- g * dt), ydt = 1 - exp (- y * dt), ldt = (1 - exp (- (l + r) * dt)) * l / (l + r), rdt = (1 - exp (- (l + r) * dt)) * r / (l + r), xdt = 1 - exp (- x * dt); double kt = g * A / (A + B); /* Membrane permeability. */ double c = M * y * kt / (l * kt + y * (l + r)); /* Cleft contents. */ double q = c * (l + r) / kt; /* Free transmitter. */ double w = c * r / x; /* Reprocessing store. */ for (long itime = 1; itime <= basil -> nx; itime ++) { double splusA = basil -> z [1] [itime] * 10 + A; double replenish = M > q ? ydt * (M - q) : 0; double eject, loss, reuptake, reprocess; kt = splusA > 0 ? gdt * splusA / (splusA + B) : 0; eject = kt * q; loss = ldt * c; reuptake = rdt * c; reprocess = xdt * w; q = q + replenish - eject + reprocess; c = c + eject - loss - reuptake; w = w + reuptake - reprocess; basil -> z [1] [itime] = h * c; } } if (dtime == my dx) { for (long itime = 1; itime <= ntime; itime ++) response [itime] = basil -> z [1] [itime]; } else { double d = dtime / basil -> dx / 2; double factor = -6 / d / d; double area = d * sqrt (NUMpi / 6); double expmin6 = exp (-6), onebyoneminexpmin6 = 1 / (1 - expmin6); for (long itime = 1; itime <= ntime; itime ++) { double t1 = (itime - 1) * dtime, t2 = t1 + dtime, mean = 0; long i1, i2; long n = Matrix_getWindowSamplesX (basil.peek(), t1, t2, & i1, & i2); Melder_assert (n >= 1); if (n <= 2) { for (long isamp = i1; isamp <= i2; isamp ++) mean += basil -> z [1] [isamp]; mean /= n; } else { double mu = floor ((i1 + i2) / 2.0); long muint = mu, dint = d; for (long isamp = muint - dint; isamp <= muint + dint; isamp ++) { double y = 0; if (isamp < 1 || isamp > basil -> nx) Melder_casual ("isamp %ld", isamp); else y = basil -> z [1] [isamp]; mean += y * onebyoneminexpmin6 * (exp (factor * (isamp - muint) * (isamp - muint)) - expmin6); } mean /= area; } response [itime] = mean; } } } return thee.transfer(); } catch (MelderError) { Melder_throw (me, ": not converted to Cochleagram (edb)."); } }
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."); } }