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."); } }
Sound Sound_resample (Sound me, double samplingFrequency, long precision) { double *data = NULL; double upfactor = samplingFrequency * my dx; long numberOfSamples = floor ((my xmax - my xmin) * samplingFrequency + 0.5), i; Sound thee = NULL, filtered = NULL; if (fabs (upfactor - 2) < 1e-6) return Sound_upsample (me); if (fabs (upfactor - 1) < 1e-6) return (structSound *)Data_copy (me); if (numberOfSamples < 1) return (structSound *)Melder_errorp ("Cannot resample to 0 samples."); thee = Sound_create (my ny, my xmin, my xmax, numberOfSamples, 1.0 / samplingFrequency, 0.5 * (my xmin + my xmax - (numberOfSamples - 1) / samplingFrequency)); cherror if (upfactor < 1.0) { /* Need anti-aliasing filter? */ long nfft = 1, antiTurnAround = 1000; while (nfft < my nx + antiTurnAround * 2) nfft *= 2; data = NUMdvector (1, nfft); cherror filtered = Sound_create (my ny, my xmin, my xmax, my nx, my dx, my x1); cherror for (long channel = 1; channel <= my ny; channel ++) { for (long i = 1; i <= nfft; i ++) { data [i] = 0; } NUMdvector_copyElements (my z [channel], data + antiTurnAround, 1, my nx); NUMrealft (data, nfft, 1); cherror /* Go to the frequency domain. */ for (long i = floor (upfactor * nfft); i <= nfft; i ++) { data [i] = 0; /* Filter away high frequencies. */ } data [2] = 0.0; NUMrealft (data, nfft, -1); cherror /* 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; /* Reference copy. Remove at end. */ }
static void do_write (TimeSoundEditor me, MelderFile file, int format, int numberOfBitsPerSamplePoint) { if (my d_startSelection >= my d_endSelection) Melder_throw (U"No samples selected."); if (my d_longSound.data) { LongSound_writePartToAudioFile (my d_longSound.data, format, my d_startSelection, my d_endSelection, file, numberOfBitsPerSamplePoint); } else if (my d_sound.data) { Sound sound = my d_sound.data; double margin = 0.0; long nmargin = (long) floor (margin / sound -> dx); long first, last, numberOfSamples = Sampled_getWindowSamples (sound, my d_startSelection, my d_endSelection, & first, & last) + nmargin * 2; first -= nmargin; last += nmargin; if (numberOfSamples) { autoSound save = Sound_create (sound -> ny, 0.0, numberOfSamples * sound -> dx, numberOfSamples, sound -> dx, 0.5 * sound -> dx); long offset = first - 1; if (first < 1) first = 1; if (last > sound -> nx) last = sound -> nx; for (long channel = 1; channel <= sound -> ny; channel ++) { for (long i = first; i <= last; i ++) { save -> z [channel] [i - offset] = sound -> z [channel] [i]; } } Sound_writeToAudioFile (save.peek(), file, format, numberOfBitsPerSamplePoint); } } }
Sound Sound_createAsPureTone (long numberOfChannels, double startingTime, double endTime, double sampleRate, double frequency, double amplitude, double fadeInDuration, double fadeOutDuration) { try { double numberOfSamples_f = round ((endTime - startingTime) * sampleRate); if (numberOfSamples_f > (double) INT32_MAX) Melder_throw (U"Cannot create sounds with more than ", Melder_bigInteger (INT32_MAX), U" samples, because they cannot be saved to disk."); autoSound me = Sound_create (numberOfChannels, startingTime, endTime, (long) numberOfSamples_f, 1 / sampleRate, startingTime + 0.5 / sampleRate); for (long isamp = 1; isamp <= my nx; isamp ++) { double time = my x1 + (isamp - 1) * my dx; double value = amplitude * sin (NUM2pi * frequency * time); double timeFromStart = time - startingTime; if (timeFromStart < fadeInDuration) value *= 0.5 - 0.5 * cos (NUMpi * timeFromStart / fadeInDuration); double timeFromEnd = endTime - time; if (timeFromEnd < fadeOutDuration) value *= 0.5 - 0.5 * cos (NUMpi * timeFromEnd / fadeOutDuration); for (long ichan = 1; ichan <= my ny; ichan ++) { my z [ichan] [isamp] = value; } } return me.transfer(); } catch (MelderError) { Melder_throw (U"Sound not created from tone complex."); } }
Sound Sound_upsample (Sound me) { double *data = NULL; Sound thee = NULL; long nfft = 1; while (nfft < my nx + 2000) nfft *= 2; thee = Sound_create (my ny, my xmin, my xmax, my nx * 2, my dx / 2, my x1); cherror data = NUMdvector (1, 2 * nfft); cherror for (long channel = 1; channel <= my ny; channel ++) { NUMdvector_copyElements (my z [channel], data + 1000, 1, my nx); NUMrealft (data, nfft, 1); cherror long imin = (long) (nfft * 0.95); for (long i = imin + 1; i <= nfft; i ++) { data [i] *= ((double) (nfft - i)) / (nfft - imin); } data [2] = 0.0; NUMrealft (data, 2 * nfft, -1); cherror double factor = 1.0 / nfft; for (long i = 1; i <= thy nx; i ++) { thy z [channel] [i] = data [i + 2000] * factor; } } end: NUMdvector_free (data, 1); iferror forget (thee); return thee; }
Sound Sounds_combineToStereo (Sound me, Sound thee) { if (my ny != 1 || thy ny != 1) return (structSound *)Melder_errorp ("Can only combine mono sounds. Stereo sound not created."); if (my dx != thy dx) return (structSound *)Melder_errorp ("Sampling frequencies do not match. Sounds not combined."); double dx = my dx; // or thy dx, which is the same double xmin = my xmin < thy xmin ? my xmin : thy xmin; double xmax = my xmax > thy xmax ? my xmax : thy xmax; long myInitialZeroes = floor ((my xmin - xmin) / dx); long thyInitialZeroes = floor ((thy xmin - xmin) / dx); double myx1 = my x1 - my dx * myInitialZeroes; double thyx1 = thy x1 - thy dx * thyInitialZeroes; double x1 = 0.5 * (myx1 + thyx1); long mynx = my nx + myInitialZeroes; long thynx = thy nx + thyInitialZeroes; long nx = mynx > thynx ? mynx : thynx; Sound him = Sound_create (2, xmin, xmax, nx, dx, x1); cherror for (long i = 1; i <= my nx; i ++) { his z [1] [i + myInitialZeroes] = my z [1] [i]; } for (long i = 1; i <= thy nx; i ++) { his z [2] [i + thyInitialZeroes] = thy z [1] [i]; } end: iferror forget (him); return him; }
Sound Sound_upsample (Sound me) { try { long nfft = 1; while (nfft < my nx + 2000) nfft *= 2; autoSound thee = Sound_create (my ny, my xmin, my xmax, my nx * 2, my dx / 2, my x1 - my dx / 4); for (long channel = 1; channel <= my ny; channel ++) { autoNUMvector <double> data (1, 2 * nfft); // zeroing is important... NUMvector_copyElements (my z [channel], & data [1000], 1, my nx); // ...because this fills only part of the sound NUMrealft (data.peek(), nfft, 1); long imin = (long) (nfft * 0.95); for (long i = imin + 1; i <= nfft; i ++) { data [i] *= ((double) (nfft - i)) / (nfft - imin); } data [2] = 0.0; NUMrealft (data.peek(), 2 * nfft, -1); double factor = 1.0 / nfft; for (long i = 1; i <= thy nx; i ++) { thy z [channel] [i] = data [i + 2000] * factor; } } return thee.transfer(); } catch (MelderError) { Melder_throw (me, U": not upsampled."); } }
Sound Sound_createSimple (long numberOfChannels, double duration, double samplingFrequency) { Melder_assert (duration >= 0.0); Melder_assert (samplingFrequency > 0.0); double numberOfSamples_f = round (duration * samplingFrequency); if (numberOfSamples_f > (double) INT32_MAX) Melder_throw (U"Cannot create sounds with more than ", Melder_bigInteger (INT32_MAX), U" samples, because they cannot be saved to disk."); return Sound_create (numberOfChannels, 0.0, duration, (long) (int32_t) numberOfSamples_f, 1 / samplingFrequency, 0.5 / samplingFrequency); }
Sound Matrix_to_Sound_mono (Matrix me, long row) { Sound thee = Sound_create (1, my xmin, my xmax, my nx, my dx, my x1); if (! thee) return NULL; if (row < 0) row = my ny + 1 + row; if (row < 1) row = 1; if (row > my ny) row = my ny; NUMdvector_copyElements (my z [row], thy z [1], 1, my nx); return thee; }
autoComplexSpectrogram Sound_to_ComplexSpectrogram (Sound me, double windowLength, double timeStep) { try { double samplingFrequency = 1.0 / my dx, myDuration = my xmax - my xmin, t1; if (windowLength > myDuration) { Melder_throw (U"Your sound is too short:\nit should be at least as long as one window length."); } long nsamp_window = (long) floor (windowLength / my dx); long halfnsamp_window = nsamp_window / 2 - 1; nsamp_window = halfnsamp_window * 2; if (nsamp_window < 2) { Melder_throw (U"Your analysis window is too short: less than two samples."); } long numberOfFrames; Sampled_shortTermAnalysis (me, windowLength, timeStep, &numberOfFrames, &t1); // Compute sampling of the spectrum long numberOfFrequencies = halfnsamp_window + 1; double df = samplingFrequency / (numberOfFrequencies - 1); autoComplexSpectrogram thee = ComplexSpectrogram_create (my xmin, my xmax, numberOfFrames, timeStep, t1, 0.0, 0.5 * samplingFrequency, numberOfFrequencies, df, 0.0); // autoSound analysisWindow = Sound_create (1, 0.0, nsamp_window * my dx, nsamp_window, my dx, 0.5 * my dx); for (long iframe = 1; iframe <= numberOfFrames; iframe++) { double t = Sampled_indexToX (thee.get(), iframe); long leftSample = Sampled_xToLowIndex (me, t), rightSample = leftSample + 1; long startSample = rightSample - halfnsamp_window; long endSample = leftSample + halfnsamp_window; Melder_assert (startSample >= 1); Melder_assert (endSample <= my nx); for (long j = 1; j <= nsamp_window; j++) { analysisWindow -> z[1][j] = my z[1][startSample - 1 + j]; } // window ? autoSpectrum spec = Sound_to_Spectrum (analysisWindow.get(), 0); thy z[1][iframe] = spec -> z[1][1] * spec -> z[1][1]; thy phase[1][iframe] = 0.0; for (long ifreq = 2; ifreq <= numberOfFrequencies - 1; ifreq++) { double x = spec -> z[1][ifreq], y = spec -> z[2][ifreq]; thy z[ifreq][iframe] = x * x + y * y; // power thy phase[ifreq][iframe] = atan2 (y, x); // phase [-pi,+pi] } // even number of samples thy z[numberOfFrequencies][iframe] = spec -> z[1][numberOfFrequencies] * spec -> z[1][numberOfFrequencies]; thy phase[numberOfFrequencies][iframe] = 0.0; } return thee; } catch (MelderError) { Melder_throw (me, U": no ComplexSpectrogram created."); } }
Sound Sounds_crossCorrelate_short (Sound me, Sound thee, double tmin, double tmax, int normalize) { try { if (my dx != thy dx) Melder_throw (U"Sampling frequencies are not equal."); if (my ny != thy ny) Melder_throw (U"Numbers of channels are not equal."); double dt = my dx; double dphase = (thy x1 - my x1) / dt; dphase -= floor (dphase); // a number between 0 and 1 long i1 = (long) ceil (tmin / dt - dphase); // index of first sample if sample at dphase has index 0 long i2 = (long) floor (tmax / dt - dphase); // index of last sample if sample at dphase has index 0 long nt = i2 - i1 + 1; if (nt < 1) Melder_throw (U"Window too small."); double t1 = (dphase + i1) * dt; autoSound him = Sound_create (1, tmin, tmax, nt, dt, t1); for (long i = 1; i <= nt; i ++) { long di = i - 1 + i1; for (long ime = 1; ime <= my nx; ime ++) { if (ime + di < 1) continue; if (ime + di > thy nx) break; for (long channel = 1; channel <= my ny; channel ++) { his z [1] [i] += my z [channel] [ime] * thy z [channel] [ime + di]; } } } if (normalize) { double mypower = 0.0, thypower = 0.0; for (long channel = 1; channel <= my ny; channel ++) { for (long i = 1; i <= my nx; i ++) { double value = my z [channel] [i]; mypower += value * value; } for (long i = 1; i <= thy nx; i ++) { double value = thy z [channel] [i]; thypower += value * value; } } if (mypower != 0.0 && thypower != 0.0) { double factor = 1.0 / (sqrt (mypower) * sqrt (thypower)); for (long i = 1; i <= nt; i ++) { his z [1] [i] *= factor; } } } else { double factor = dt / my ny; for (long i = 1; i <= nt; i ++) { his z [1] [i] *= factor; } } return him.transfer(); } catch (MelderError) { Melder_throw (me, U": not cross-correlated."); } }
Sound Sounds_combineToStereo (Collection me) { try { long totalNumberOfChannels = 0; double sharedSamplingPeriod = 0.0; for (long isound = 1; isound <= my size; isound ++) { Sound sound = (Sound) my item [isound]; totalNumberOfChannels += sound -> ny; if (sharedSamplingPeriod == 0.0) { sharedSamplingPeriod = sound -> dx; } else if (sound -> dx != sharedSamplingPeriod) { Melder_throw (U"To combine sounds, their sampling frequencies must be equal.\n" U"You could resample one or more of the sounds before combining."); } } double sharedMinimumTime = NUMundefined, sharedMaximumTime = NUMundefined; for (long isound = 1; isound <= my size; isound ++) { Sound sound = (Sound) my item [isound]; if (isound == 1) { sharedMinimumTime = sound -> xmin; sharedMaximumTime = sound -> xmax; } else { if (sound -> xmin < sharedMinimumTime) sharedMinimumTime = sound -> xmin; if (sound -> xmax > sharedMaximumTime) sharedMaximumTime = sound -> xmax; } } autoNUMvector <double> numberOfInitialZeroes (1, my size); long sharedNumberOfSamples = 0; double sumOfFirstTimes = 0.0; for (long isound = 1; isound <= my size; isound ++) { Sound sound = (Sound) my item [isound]; numberOfInitialZeroes [isound] = floor ((sound -> xmin - sharedMinimumTime) / sharedSamplingPeriod); double newFirstTime = sound -> x1 - sound -> dx * numberOfInitialZeroes [isound]; sumOfFirstTimes += newFirstTime; long newNumberOfSamplesThroughLastNonzero = sound -> nx + (long) floor (numberOfInitialZeroes [isound]); if (newNumberOfSamplesThroughLastNonzero > sharedNumberOfSamples) sharedNumberOfSamples = newNumberOfSamplesThroughLastNonzero; } double sharedTimeOfFirstSample = sumOfFirstTimes / my size; // this is an approximation autoSound thee = Sound_create (totalNumberOfChannels, sharedMinimumTime, sharedMaximumTime, sharedNumberOfSamples, sharedSamplingPeriod, sharedTimeOfFirstSample); long channelNumber = 0; for (long isound = 1; isound <= my size; isound ++) { Sound sound = (Sound) my item [isound]; long offset = (long) floor (numberOfInitialZeroes [isound]); for (long ichan = 1; ichan <= sound -> ny; ichan ++) { channelNumber ++; for (long isamp = 1; isamp <= sound -> nx; isamp ++) { thy z [channelNumber] [isamp + offset] = sound -> z [ichan] [isamp]; } } } return thee.transfer(); } catch (MelderError) { Melder_throw (U"Sounds not combined to stereo."); } }
autoSound BandFilterSpectrogram_as_Sound (BandFilterSpectrogram me, int unit) { try { autoSound thee = Sound_create (my ny, my xmin, my xmax, my nx, my dx, my x1); for (long i = 1; i <= my ny; i ++) { for (long j = 1; j <= my nx; j ++) thy z[i][j] = my v_getValueAtSample (j, i, unit); } return thee; } catch (MelderError) { Melder_throw (me, U": no Sound created."); } }
Sound Sound_extractChannel (Sound me, long ichan) { Sound thee = NULL; //start: if (ichan <= 0 || ichan > my ny) error3 (L"Cannot extract channel ", Melder_integer (ichan), L"."); thee = Sound_create (1, my xmin, my xmax, my nx, my dx, my x1); cherror for (long isamp = 1; isamp <= my nx; isamp ++) { thy z [1] [isamp] = my z [ichan] [isamp]; } end: iferror forget (thee); return thee; }
Sound FilterBank_as_Sound (FilterBank me) { try { autoSound thee = Sound_create (my ny, my xmin, my xmax, my nx, my dx, my x1); for (long i = 1; i <= my ny; i++) { for (long j = 1; j <= my nx; j++) thy z[i][j] = my z[i][j]; } return thee.transfer(); } catch (MelderError) { Melder_throw (me, ": no Sound created."); } }
Sound Matrix_to_Sound_mono (Matrix me, long row) { try { autoSound thee = Sound_create (1, my xmin, my xmax, my nx, my dx, my x1); if (row < 0) row = my ny + 1 + row; if (row < 1) row = 1; if (row > my ny) row = my ny; NUMvector_copyElements (my z [row], thy z [1], 1, my nx); return thee.transfer(); } catch (MelderError) { Melder_throw (me, U": not converted to Sound."); } }
Sound Sound_extractChannel (Sound me, long ichan) { try { if (ichan <= 0 || ichan > my ny) Melder_throw (U"There is no channel ", ichan, U"."); autoSound thee = Sound_create (1, my xmin, my xmax, my nx, my dx, my x1); for (long isamp = 1; isamp <= my nx; isamp ++) { thy z [1] [isamp] = my z [ichan] [isamp]; } return thee.transfer(); } catch (MelderError) { Melder_throw (me, U": channel ", ichan, U" not extracted."); } }
static autoSound buffer_to_Sound (int *wav, long numberOfSamples, double samplingFrequency) { try { double dx = 1.0 / samplingFrequency; double xmax = numberOfSamples * dx; autoSound thee = Sound_create (1, 0.0, xmax, numberOfSamples, dx, dx / 2.0); for (long i = 1; i <= numberOfSamples; i++) { thy z[1][i] = wav[i] / 32768.0; } return thee; } catch (MelderError) { Melder_throw (U"Sound not created from synthesizer data."); } }
autoPitch Pitch_smooth (Pitch me, double bandWidth) { try { autoPitch interp = Pitch_interpolate (me); autoMatrix matrix1 = Pitch_to_Matrix (interp.peek()); autoSound sound1 = Sound_create (1, 2 * matrix1->xmin - matrix1->xmax, 2 * matrix1->xmax - matrix1->xmin, 3 * matrix1->nx, matrix1->dx, matrix1->x1 - 2 * matrix1->nx * matrix1->dx); long firstVoiced = 0, lastVoiced = 0; for (long i = 1; i <= matrix1 -> nx; i ++) { double f = matrix1 -> z [1] [i]; if (f != 0.0) { if (! firstVoiced) firstVoiced = i; lastVoiced = i; sound1 -> z [1] [i + matrix1 -> nx] = f; } } /* Extrapolate. */ double fextrap = matrix1 -> z [1] [firstVoiced]; firstVoiced += matrix1 -> nx; for (long i = 1; i < firstVoiced; i ++) sound1 -> z [1] [i] = fextrap; fextrap = matrix1 -> z [1] [lastVoiced]; lastVoiced += matrix1 -> nx; for (long i = lastVoiced + 1; i <= sound1 -> nx; i ++) sound1 -> z [1] [i] = fextrap; /* Smooth. */ autoSpectrum spectrum = Sound_to_Spectrum (sound1.peek(), true); for (long i = 1; i <= spectrum -> nx; i ++) { double f = (i - 1) * spectrum -> dx, fT = f / bandWidth, factor = exp (- fT * fT); spectrum -> z [1] [i] *= factor; spectrum -> z [2] [i] *= factor; } autoSound sound2 = Spectrum_to_Sound (spectrum.peek()); autoMatrix matrix2 = Matrix_create (my xmin, my xmax, my nx, my dx, my x1, 1, 1, 1, 1, 1); for (long i = 1; i <= my nx; i ++) { double originalF0 = my frame [i]. candidate [1]. frequency; matrix2 -> z [1] [i] = originalF0 > 0.0 && originalF0 < my ceiling ? sound2 -> z [1] [i + matrix2 -> nx] : 0.0; } autoPitch thee = Matrix_to_Pitch (matrix2.peek()); thy ceiling = my ceiling; return thee; } catch (MelderError) { Melder_throw (me, U": not smoothed."); } }
Sound Sound_convertToStereo (Sound me) { if (my ny == 2) return (structSound *)Data_copy (me); if (my ny > 2) { return (structSound *)Melder_errorp ("Don't know how to convert a Sound with %ld channels to stereo.", my ny); } Sound thee = NULL; Melder_assert (my ny == 1); thee = Sound_create (2, my xmin, my xmax, my nx, my dx, my x1); cherror for (long i = 1; i <= my nx; i ++) { thy z [1] [i] = thy z [2] [i] = my z [1] [i]; } end: iferror forget (thee); return thee; }
Sound Sound_convertToStereo (Sound me) { if (my ny == 2) return Data_copy (me); try { if (my ny > 2) { Melder_throw (U"The Sound has ", my ny, U" channels; don't know which to choose."); } Melder_assert (my ny == 1); autoSound thee = Sound_create (2, my xmin, my xmax, my nx, my dx, my x1); for (long i = 1; i <= my nx; i ++) { thy z [1] [i] = thy z [2] [i] = my z [1] [i]; } return thee.transfer(); } catch (MelderError) { Melder_throw (me, U": not converted to stereo."); } }
autoSound LongSound_extractPart (LongSound me, double tmin, double tmax, int preserveTimes) { try { if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; } if (tmin < my xmin) tmin = my xmin; if (tmax > my xmax) tmax = my xmax; long imin, imax; long n = Sampled_getWindowSamples (me, tmin, tmax, & imin, & imax); if (n < 1) Melder_throw (U"Less than 1 sample in window."); autoSound thee = Sound_create (my numberOfChannels, tmin, tmax, n, my dx, my x1 + (imin - 1) * my dx); if (! preserveTimes) thy xmin = 0.0, thy xmax -= tmin, thy x1 -= tmin; LongSound_readAudioToFloat (me, thy z, imin, n); return thee; } catch (MelderError) { Melder_throw (me, U": Sound not extracted."); } }
Sound Sound_extractPart (Sound me, double t1, double t2, enum kSound_windowShape windowShape, double relativeWidth, bool preserveTimes) { try { /* * We do not clip to the Sound's time domain. * Any samples outside it are taken to be zero. */ /* * Autowindow. */ if (t1 == t2) { t1 = my xmin; t2 = my xmax; }; /* * Allow window tails outside specified domain. */ if (relativeWidth != 1.0) { double margin = 0.5 * (relativeWidth - 1) * (t2 - t1); t1 -= margin; t2 += margin; } /* * Determine index range. We use all the real or virtual samples that fit within [t1..t2]. */ long ix1 = 1 + (long) ceil ((t1 - my x1) / my dx); long ix2 = 1 + (long) floor ((t2 - my x1) / my dx); if (ix2 < ix1) Melder_throw (U"Extracted Sound would contain no samples."); /* * Create sound, optionally shifted to [0..t2-t1]. */ autoSound thee = Sound_create (my ny, t1, t2, ix2 - ix1 + 1, my dx, my x1 + (ix1 - 1) * my dx); if (! preserveTimes) { thy xmin = 0.0; thy xmax -= t1; thy x1 -= t1; } /* * Copy only *real* samples into the new sound. * The *virtual* samples will remain at zero. */ for (long channel = 1; channel <= my ny; channel ++) { NUMvector_copyElements (my z [channel], thy z [channel] + 1 - ix1, ( ix1 < 1 ? 1 : ix1 ), ( ix2 > my nx ? my nx : ix2 )); } /* * Multiply by a window that extends throughout the target domain. */ Sound_multiplyByWindow (thee.peek(), windowShape); return thee.transfer(); } catch (MelderError) { Melder_throw (me, U": part not extracted."); } }
Sound Sound_createFromToneComplex (double startingTime, double endTime, double sampleRate, int phase, double frequencyStep, double firstFrequency, double ceiling, long numberOfComponents) { try { if (frequencyStep == 0.0) Melder_throw (U"Frequency step must not be zero."); /* * Translate default firstFrequency. */ if (firstFrequency <= 0.0) firstFrequency = frequencyStep; double firstOmega = 2 * NUMpi * firstFrequency; /* * Translate default ceiling. */ double omegaStep = 2 * NUMpi * frequencyStep, nyquistFrequency = 0.5 * sampleRate; if (ceiling <= 0.0 || ceiling > nyquistFrequency) ceiling = nyquistFrequency; /* * Translate number of components. */ long maximumNumberOfComponents = (long) floor ((ceiling - firstFrequency) / frequencyStep) + 1; if (numberOfComponents <= 0 || numberOfComponents > maximumNumberOfComponents) numberOfComponents = maximumNumberOfComponents; if (numberOfComponents < 1) Melder_throw (U"Zero sine waves."); /* * Generate the Sound. */ double factor = 0.99 / numberOfComponents; autoSound me = Sound_create (1, startingTime, endTime, lround ((endTime - startingTime) * sampleRate), 1 / sampleRate, startingTime + 0.5 / sampleRate); double *amplitude = my z [1]; for (long isamp = 1; isamp <= my nx; isamp ++) { double value = 0.0, t = Sampled_indexToX (me.peek(), isamp); double omegaStepT = omegaStep * t, firstOmegaT = firstOmega * t; if (phase == Sound_TONE_COMPLEX_SINE) for (long icomp = 1; icomp <= numberOfComponents; icomp ++) value += sin (firstOmegaT + (icomp - 1) * omegaStepT); else for (long icomp = 1; icomp <= numberOfComponents; icomp ++) value += cos (firstOmegaT + (icomp - 1) * omegaStepT); amplitude [isamp] = value * factor; } return me.transfer(); } catch (MelderError) { Melder_throw (U"Sound not created from tone complex."); } }
Sound Sounds_append (Sound me, double silenceDuration, Sound thee) { try { long nx_silence = lround (silenceDuration / my dx), nx = my nx + nx_silence + thy nx; if (my ny != thy ny) Melder_throw (U"The numbers of channels are not equal (e.g. one is mono, the other stereo)."); if (my dx != thy dx) Melder_throw (U"The sampling frequencies are not equal."); autoSound him = Sound_create (my ny, 0, nx * my dx, nx, my dx, 0.5 * my dx); for (long channel = 1; channel <= my ny; channel ++) { NUMvector_copyElements (my z [channel], his z [channel], 1, my nx); NUMvector_copyElements (thy z [channel], his z [channel] + my nx + nx_silence, 1, thy nx); } return him.transfer(); } catch (MelderError) { Melder_throw (me, U" & ", thee, U": not appended."); } }
Spectrum Cepstrum_to_Spectrum (Cepstrum me) { try { autoSound x = Sound_create (1, my xmin, my xmax, my nx, my dx, my x1); NUMvector_copyElements (my z[1], x -> z[1], 1, my nx); autoSpectrum thee = Sound_to_Spectrum (x.peek(), TRUE); for (long i = 1; i <= thy nx; i++) { double ar = exp (thy z[1][i]); double ai = thy z[2][i]; thy z[1][i] = ar * cos (ai); thy z[2][i] = ar * sin (ai); } return thee.transfer(); } catch (MelderError) { Melder_throw (me, ": no Spectrum created."); } }
Sound PointProcess_to_Sound_pulseTrain (PointProcess me, double samplingFrequency, double adaptFactor, double adaptTime, long interpolationDepth) { 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; autoSound thee = Sound_create (1, my xmin, my xmax, sound_nt, dt, t1); double *sound = thy z [1]; for (long it = 1; it <= my nt; it ++) { double t = my t [it], amplitude = 0.9, angle, halfampsinangle; long mid = Sampled_xToNearestIndex (thee.peek(), t); if (it <= 2 || my t [it - 2] < my t [it] - adaptTime) { amplitude *= adaptFactor; if (it == 1 || my t [it - 1] < my t [it] - adaptTime) amplitude *= adaptFactor; } long begin = mid - interpolationDepth, end = mid + interpolationDepth; if (begin < 1) begin = 1; if (end > thy nx) end = thy nx; angle = NUMpi * (Sampled_indexToX (thee.peek(), begin) - t) / thy dx; halfampsinangle = 0.5 * amplitude * sin (angle); for (long j = begin; j <= end; j ++) { if (fabs (angle) < 1e-6) sound [j] += amplitude; else if (angle < 0.0) sound [j] += halfampsinangle * (1 + cos (angle / (mid - begin + 1))) / angle; else sound [j] += halfampsinangle * (1 + cos (angle / (end - mid + 1))) / angle; angle += NUMpi; halfampsinangle = - halfampsinangle; } } return thee.transfer(); } catch (MelderError) { Melder_throw (me, ": pulse train not synthesized."); } }
static ERPTier EEG_PointProcess_to_ERPTier (EEG me, PointProcess events, double fromTime, double toTime) { try { autoERPTier thee = Thing_new (ERPTier); Function_init (thee.peek(), fromTime, toTime); thy numberOfChannels = my numberOfChannels - EEG_getNumberOfExtraSensors (me); Melder_assert (thy numberOfChannels > 0); thy channelNames = NUMvector <wchar_t *> (1, thy numberOfChannels); for (long ichan = 1; ichan <= thy numberOfChannels; ichan ++) { thy channelNames [ichan] = Melder_wcsdup (my channelNames [ichan]); } long numberOfEvents = events -> nt; thy events = SortedSetOfDouble_create (); double soundDuration = toTime - fromTime; double samplingPeriod = my sound -> dx; long numberOfSamples = floor (soundDuration / samplingPeriod) + 1; if (numberOfSamples < 1) Melder_throw (L"Time window too short."); double midTime = 0.5 * (fromTime + toTime); double soundPhysicalDuration = numberOfSamples * samplingPeriod; double firstTime = midTime - 0.5 * soundPhysicalDuration + 0.5 * samplingPeriod; // distribute the samples evenly over the time domain for (long ievent = 1; ievent <= numberOfEvents; ievent ++) { double eegEventTime = events -> t [ievent]; autoERPPoint event = Thing_new (ERPPoint); event -> number = eegEventTime; event -> erp = Sound_create (thy numberOfChannels, fromTime, toTime, numberOfSamples, samplingPeriod, firstTime); double erpEventTime = 0.0; double eegSample = 1 + (eegEventTime - my sound -> x1) / samplingPeriod; double erpSample = 1 + (erpEventTime - firstTime) / samplingPeriod; long sampleDifference = round (eegSample - erpSample); for (long ichannel = 1; ichannel <= thy numberOfChannels; ichannel ++) { for (long isample = 1; isample <= numberOfSamples; isample ++) { long jsample = isample + sampleDifference; event -> erp -> z [ichannel] [isample] = jsample < 1 || jsample > my sound -> nx ? 0.0 : my sound -> z [ichannel] [jsample]; } } Collection_addItem (thy events, event.transfer()); } return thee.transfer(); } catch (MelderError) { Melder_throw (me, ": ERP analysis not performed."); } }
autoSound Sound_and_MixingMatrix_mix (Sound me, MixingMatrix thee) { try { if (my ny != thy numberOfColumns) { Melder_throw (U"The number of components in the MixingMatrix and the number of channels in the Sound must be equal."); } autoSound him = Sound_create (thy numberOfRows, my xmin, my xmax, my nx, my dx, my x1); for (long i = 1; i <= thy numberOfRows; i++) { for (long j = 1; j <= my nx; j++) { double mix = 0; for (long k = 1; k <= my ny; k++) { mix += thy data[i][k] * my z[k][j]; } his z[i][j] = mix; } } return him; } catch (MelderError) { Melder_throw (me, U": not mixed."); } }
autoSound PitchTier_to_Sound_sine (PitchTier me, double tmin, double tmax, double samplingFrequency) { try { if (tmax <= tmin) tmin = my xmin, tmax = my xmax; long numberOfSamples = 1 + (long) floor ((my xmax - my xmin) * samplingFrequency); // >= 1 double samplingPeriod = 1.0 / samplingFrequency; double tmid = (tmin + tmax) / 2.0; double t1 = tmid - 0.5 * (numberOfSamples - 1) * samplingPeriod; autoSound thee = Sound_create (1, tmin, tmax, numberOfSamples, samplingPeriod, t1); double phase = 0.0; for (long isamp = 2; isamp <= numberOfSamples; isamp ++) { double tleft = t1 + (isamp - 1.5) * samplingPeriod; double fleft = RealTier_getValueAtTime (me, tleft); phase += fleft * thy dx; thy z [1] [isamp] = 0.5 * sin (2.0 * NUMpi * phase); } return thee; } catch (MelderError) { Melder_throw (me, U": not converted to Sound (sine)."); } }