const char * Melder8_integer (int64 value) { if (++ ibuffer == NUMBER_OF_BUFFERS) ibuffer = 0; if (sizeof (long) == 8) { int n = snprintf (buffers8 [ibuffer], MAXIMUM_NUMERIC_STRING_LENGTH + 1, "%ld", (long) value); // cast to identical type, to make compiler happy Melder_assert (n > 0); Melder_assert (n <= MAXIMUM_NUMERIC_STRING_LENGTH); } else if (sizeof (long long) == 8) { /* * There are buggy platforms (namely 32-bit Mingw on Windows XP) that support long long and %lld but that convert * the argument to a 32-bit long. * There are also buggy platforms (namely 32-bit gcc on Linux) that support long long and %I64d but that convert * the argument to a 32-bit long. */ static const char *formatString = nullptr; if (! formatString) { char tryBuffer [MAXIMUM_NUMERIC_STRING_LENGTH + 1]; formatString = "%lld"; sprintf (tryBuffer, formatString, 1000000000000LL); if (! strequ (tryBuffer, "1000000000000")) { formatString = "%I64d"; sprintf (tryBuffer, formatString, 1000000000000LL); if (! strequ (tryBuffer, "1000000000000")) { Melder_fatal (U"Found no way to print 64-bit integers on this machine."); } } } int n = snprintf (buffers8 [ibuffer], MAXIMUM_NUMERIC_STRING_LENGTH + 1, formatString, value); Melder_assert (n > 0); Melder_assert (n <= MAXIMUM_NUMERIC_STRING_LENGTH); } else { Melder_fatal (U"Neither long nor long long is 8 bytes on this machine."); } return buffers8 [ibuffer]; }
void * Melder_realloc_f (void *ptr, long size) { void *result; if (size <= 0) Melder_fatal ("(Melder_realloc_f:) Can never allocate %ld bytes.", size); result = realloc (ptr, size); /* Will not show in the statistics... */ if (result == NULL) { if (theRainyDayFund != NULL) free (theRainyDayFund); result = realloc (ptr, size); if (result != NULL) { Melder_flushError ("Praat is very low on memory.\nSave your work and quit Praat.\nIf you don't do that, Praat may crash."); } else { Melder_fatal ("Out of memory. Could not extend room to %ld bytes.", size); } } if (ptr == NULL) { /* Is it like malloc? */ totalNumberOfAllocations += 1; totalAllocationSize += size; } else if (result != ptr) { /* Did realloc do a malloc-and-free? */ totalNumberOfAllocations += 1; totalAllocationSize += size; totalNumberOfDeallocations += 1; totalNumberOfMovingReallocs += 1; } else { totalNumberOfReallocsInSitu += 1; } return result; }
void * Melder_realloc_f (void *ptr, int64 size) { void *result; if (size <= 0) Melder_fatal (U"(Melder_realloc_f:) Can never allocate ", Melder_bigInteger (size), U" bytes."); if (sizeof (size_t) < 8 && size > SIZE_MAX) Melder_fatal (U"(Melder_realloc_f:) Can never allocate ", Melder_bigInteger (size), U" bytes."); result = realloc (ptr, (size_t) size); // will not show in the statistics... if (result == NULL) { if (theRainyDayFund != NULL) { free (theRainyDayFund); theRainyDayFund = NULL; } result = realloc (ptr, (size_t) size); if (result != NULL) { Melder_flushError (U"Praat is very low on memory.\nSave your work and quit Praat.\nIf you don't do that, Praat may crash."); } else { Melder_fatal (U"Out of memory. Could not extend room to ", Melder_bigInteger (size), U" bytes."); } } if (ptr == NULL) { // is it like malloc? totalNumberOfAllocations += 1; totalAllocationSize += size; } else if (result != ptr) { // did realloc do a malloc-and-free? totalNumberOfAllocations += 1; totalAllocationSize += size; totalNumberOfDeallocations += 1; totalNumberOfMovingReallocs += 1; } else { totalNumberOfReallocsInSitu += 1; } return result; }
void * _Thing_check (I, void *klas, const char *fileName, int line) { Thing me = (structThing*)void_me; /* NOT the macro `iam (Thing);' because that would be recursive. */ if (! me) Melder_fatal ("(_Thing_check:) NULL object passed to a function\n" "in file %.100s at line %d.", fileName, line); Thing_Table table = my methods; while (table != klas && table != NULL) table = table -> _parent; if (! table) Melder_fatal ("(_Thing_check:) Object of wrong class (%.50s) passed to a function\n" "in file %.100s at line %d.", Melder_peekWcsToUtf8 (our _className), fileName, line); return me; }
void * _Melder_malloc_f (unsigned long size) { if (size <= 0) Melder_fatal ("(Melder_malloc_f:) Can never allocate %ld bytes.", size); void *result = malloc (size); if (result == NULL) { if (theRainyDayFund != NULL) free (theRainyDayFund); result = malloc (size); if (result != NULL) { Melder_flushError ("Praat is very low on memory.\nSave your work and quit Praat.\nIf you don't do that, Praat may crash."); } else { Melder_fatal ("Out of memory: there is not enough room for another %ld bytes.", size); } } totalNumberOfAllocations += 1; totalAllocationSize += size; return result; }
void * _Melder_malloc_f (int64 size) { if (size <= 0) Melder_fatal (U"(Melder_malloc_f:) Can never allocate ", Melder_bigInteger (size), U" bytes."); if (sizeof (size_t) < 8 && size > SIZE_MAX) Melder_fatal (U"(Melder_malloc_f:) Can never allocate ", Melder_bigInteger (size), U" bytes."); void *result = malloc ((size_t) size); if (result == NULL) { if (theRainyDayFund != NULL) { free (theRainyDayFund); theRainyDayFund = NULL; } result = malloc ((size_t) size); if (result != NULL) { Melder_flushError (U"Praat is very low on memory.\nSave your work and quit Praat.\nIf you don't do that, Praat may crash."); } else { Melder_fatal (U"Out of memory: there is not enough room for another %s bytes.", Melder_bigInteger (size)); } } totalNumberOfAllocations += 1; totalAllocationSize += size; return result; }
void * _Melder_calloc_f (long nelem, long elsize) { void *result; if (nelem <= 0) Melder_fatal ("(Melder_calloc_f:) Can never allocate %ld elements.", nelem); if (elsize <= 0) Melder_fatal ("(Melder_calloc_f:) Can never allocate elements whose size is %ld bytes.", elsize); result = calloc (nelem, elsize); if (result == NULL) { if (theRainyDayFund != NULL) free (theRainyDayFund); result = calloc (nelem, elsize); if (result != NULL) { Melder_flushError ("Praat is very low on memory.\nSave your work and quit Praat.\nIf you don't do that, Praat may crash."); } else { Melder_fatal ("Out of memory: there is not enough room for %ld more elements whose sizes are %ld bytes each.", nelem, elsize); } } totalNumberOfAllocations += 1; totalAllocationSize += nelem * elsize; return result; }
char32 * Melder_dup_f (const char32 *string /* cattable */) { if (! string) return NULL; int64 size = (int64) str32len (string) + 1; if (sizeof (size_t) < 8 && size > SIZE_MAX / sizeof (char32)) Melder_fatal (U"(Melder_dup_f:) Can never allocate ", Melder_bigInteger (size), U" characters."); char32 *result = (char32 *) malloc ((size_t) size * sizeof (char32)); if (result == NULL) { if (theRainyDayFund != NULL) { free (theRainyDayFund); theRainyDayFund = NULL; } result = (char32 *) malloc ((size_t) size * sizeof (char32)); if (result != NULL) { Melder_flushError (U"Praat is very low on memory.\nSave your work and quit Praat.\nIf you don't do that, Praat may crash."); } else { Melder_fatal (U"Out of memory: there is not enough room to duplicate a text of ", Melder_bigInteger (size - 1), U" characters."); } } str32cpy (result, string); totalNumberOfAllocations += 1; totalAllocationSize += size * (int64) sizeof (char32); return result; }
char * Melder_strdup_f (const char *string) { if (! string) return nullptr; int64 size = (int64) strlen (string) + 1; if (sizeof (size_t) < 8 && size > SIZE_MAX) Melder_fatal (U"(Melder_strdup_f:) Can never allocate ", Melder_bigInteger (size), U" bytes."); char *result = (char *) malloc ((size_t) size); if (! result) { if (theRainyDayFund) { free (theRainyDayFund); theRainyDayFund = nullptr; } result = (char *) malloc ((size_t) size * sizeof (char)); if (result) { Melder_flushError (U"Praat is very low on memory.\nSave your work and quit Praat.\nIf you don't do that, Praat may crash."); } else { Melder_fatal (U"Out of memory: there is not enough room to duplicate a text of ", Melder_bigInteger (size - 1), U" characters."); } } strcpy (result, string); totalNumberOfAllocations += 1; totalAllocationSize += size; return result; }
void * _Thing_check (Thing me, ClassInfo klas, const char *fileName, int line) { if (! me) Melder_fatal (U"(_Thing_check:)" U" null object passed to a function\n" U"in file ", Melder_peek8to32 (fileName), U" at line ", line, U"." ); ClassInfo classInfo = my classInfo; while (classInfo != klas && classInfo) classInfo = classInfo -> parent; if (! classInfo) Melder_fatal (U"(_Thing_check:)" U" Object of wrong class (", my classInfo -> className, U") passed to a function\n" U"in file ", Melder_peek8to32 (fileName), U" at line ", line, U"." ); return me; }
void * _Melder_calloc_f (int64 nelem, int64 elsize) { if (nelem <= 0) Melder_fatal (U"(Melder_calloc_f:) Can never allocate ", Melder_bigInteger (nelem), U" elements."); if (elsize <= 0) Melder_fatal (U"(Melder_calloc_f:) Can never allocate elements whose size is ", Melder_bigInteger (elsize), U" bytes."); if ((uint64_t) nelem > SIZE_MAX / (uint64_t) elsize) Melder_fatal (U"(Melder_calloc_f:) Can never allocate ", Melder_bigInteger (nelem), U" elements whose sizes are ", Melder_bigInteger (elsize), U" bytes each."); void *result = calloc ((size_t) nelem, (size_t) elsize); if (result == NULL) { if (theRainyDayFund != NULL) { free (theRainyDayFund); theRainyDayFund = NULL; } result = calloc ((size_t) nelem, (size_t) elsize); if (result != NULL) { Melder_flushError (U"Praat is very low on memory.\nSave your work and quit Praat.\nIf you don't do that, Praat may crash."); } else { Melder_fatal (U"Out of memory: there is not enough room for ", Melder_bigInteger (nelem), U" more elements whose sizes are ", Melder_bigInteger (elsize), U" bytes each."); } } totalNumberOfAllocations += 1; totalAllocationSize += nelem * elsize; return result; }
void Graphics_init (Graphics me, int resolution) { my resolution = resolution; if (resolution == 96) { my resolutionNumber = kGraphics_resolution_96; } else if (resolution == 100) { my resolutionNumber = kGraphics_resolution_100; } else if (resolution == 180) { my resolutionNumber = kGraphics_resolution_180; } else if (resolution == 200) { my resolutionNumber = kGraphics_resolution_200; } else if (resolution == 300) { my resolutionNumber = kGraphics_resolution_300; } else if (resolution == 360) { my resolutionNumber = kGraphics_resolution_360; } else if (resolution == 600) { my resolutionNumber = kGraphics_resolution_600; } else if (resolution == 720) { my resolutionNumber = kGraphics_resolution_720; } else if (resolution == 1200) { my resolutionNumber = kGraphics_resolution_1200; } else { Melder_fatal (U"Unsupported resolution ", resolution, U" dpi."); } my d_x1DC = my d_x1DCmin = 0; my d_x2DC = my d_x2DCmax = 32767; my d_y1DC = my d_y1DCmin = 0; my d_y2DC = my d_y2DCmax = 32767; my d_x1WC = my d_x1NDC = my d_x1wNDC = 0.0; my d_x2WC = my d_x2NDC = my d_x2wNDC = 1.0; my d_y1WC = my d_y1NDC = my d_y1wNDC = 0.0; my d_y2WC = my d_y2NDC = my d_y2wNDC = 1.0; widgetToWindowCoordinates (me); computeTrafo (me); my lineWidth = 1.0; my arrowSize = 1.0; my speckleSize = 1.0; my font = kGraphics_font_HELVETICA; my fontSize = 10; my fontStyle = Graphics_NORMAL; my record = nullptr; my irecord = my nrecord = 0; my percentSignIsItalic = 1; my numberSignIsBold = 1; my circumflexIsSuperscript = 1; my underscoreIsSubscript = 1; my dollarSignIsCode = 0; my atSignIsLink = 0; }
wchar_t * Melder_wcsdup_f (const wchar_t *string) { if (! string) return NULL; long size = wcslen (string) + 1; wchar_t *result = (wchar_t *) malloc (size * sizeof (wchar_t)); if (result == NULL) { if (theRainyDayFund != NULL) free (theRainyDayFund); result = (wchar_t *) malloc (size * sizeof (wchar_t)); if (result != NULL) { Melder_flushError ("Praat is very low on memory.\nSave your work and quit Praat.\nIf you don't do that, Praat may crash."); } else { Melder_fatal ("Out of memory: there is not enough room to duplicate a text of %ld characters.", size - 1); } } wcscpy (result, string); totalNumberOfAllocations += 1; totalAllocationSize += size * sizeof (wchar_t); return result; }
void TimeSoundEditor_init (TimeSoundEditor me, const char32 *title, Function data, Sampled sound, bool ownSound) { my d_ownSound = ownSound; if (sound) { if (ownSound) { Melder_assert (Thing_isa (sound, classSound)); my d_sound.data = Data_copy ((Sound) sound).releaseToAmbiguousOwner(); // deep copy; ownership transferred Matrix_getWindowExtrema (my d_sound.data, 1, my d_sound.data -> nx, 1, my d_sound.data -> ny, & my d_sound.minimum, & my d_sound.maximum); } else if (Thing_isa (sound, classSound)) { my d_sound.data = (Sound) sound; // reference copy; ownership not transferred Matrix_getWindowExtrema (my d_sound.data, 1, my d_sound.data -> nx, 1, my d_sound.data -> ny, & my d_sound.minimum, & my d_sound.maximum); } else if (Thing_isa (sound, classLongSound)) { my d_longSound.data = (LongSound) sound; my d_sound.minimum = -1.0, my d_sound.maximum = 1.0; } else { Melder_fatal (U"Invalid sound class in TimeSoundEditor::init."); } } FunctionEditor_init (me, title, data); }
Sound Sounds_crossCorrelate (Sound me, Sound thee, enum kSounds_convolve_scaling scaling, enum kSounds_convolve_signalOutsideTimeDomain signalOutsideTimeDomain) { try { if (my ny > 1 && thy ny > 1 && my ny != thy ny) Melder_throw (U"The numbers of channels of the two sounds have to be equal or 1."); if (my dx != thy dx) Melder_throw (U"The sampling frequencies of the two sounds have to be equal."); long numberOfChannels = my ny > thy ny ? my ny : thy ny; long n1 = my nx, n2 = thy nx; long n3 = n1 + n2 - 1, nfft = 1; while (nfft < n3) nfft *= 2; autoNUMvector <double> data1 (1, nfft); autoNUMvector <double> data2 (1, nfft); double my_xlast = my x1 + (n1 - 1) * my dx; autoSound him = Sound_create (numberOfChannels, thy xmin - my xmax, thy xmax - my xmin, n3, my dx, thy x1 - my_xlast); for (long channel = 1; channel <= numberOfChannels; channel ++) { double *a = my z [my ny == 1 ? 1 : channel]; for (long i = n1; i > 0; i --) data1 [i] = a [i]; for (long i = n1 + 1; i <= nfft; i ++) data1 [i] = 0.0; a = thy z [thy ny == 1 ? 1 : channel]; for (long i = n2; i > 0; i --) data2 [i] = a [i]; for (long i = n2 + 1; i <= nfft; i ++) data2 [i] = 0.0; NUMrealft (data1.peek(), nfft, 1); NUMrealft (data2.peek(), nfft, 1); data2 [1] *= data1 [1]; data2 [2] *= data1 [2]; for (long i = 3; i <= nfft; i += 2) { double temp = data1 [i] * data2 [i] + data1 [i + 1] * data2 [i + 1]; // reverse me by taking the conjugate of data1 data2 [i + 1] = data1 [i] * data2 [i + 1] - data1 [i + 1] * data2 [i]; // reverse me by taking the conjugate of data1 data2 [i] = temp; } NUMrealft (data2.peek(), nfft, -1); a = him -> z [channel]; for (long i = 1; i < n1; i ++) { a [i] = data2 [i + (nfft - (n1 - 1))]; // data for the first part ("negative lags") is at the end of data2 } for (long i = 1; i <= n2; i ++) { a [i + (n1 - 1)] = data2 [i]; // data for the second part ("positive lags") is at the beginning of data2 } } switch (signalOutsideTimeDomain) { case kSounds_convolve_signalOutsideTimeDomain_ZERO: { // do nothing } break; case kSounds_convolve_signalOutsideTimeDomain_SIMILAR: { for (long channel = 1; channel <= numberOfChannels; channel ++) { double *a = his z [channel]; double edge = n1 < n2 ? n1 : n2; for (long i = 1; i < edge; i ++) { double factor = edge / i; a [i] *= factor; a [n3 + 1 - i] *= factor; } } } break; //case kSounds_convolve_signalOutsideTimeDomain_PERIODIC: { // do nothing //} break; default: Melder_fatal (U"Sounds_crossCorrelate: unimplemented outside-time-domain strategy ", signalOutsideTimeDomain); } switch (scaling) { case kSounds_convolve_scaling_INTEGRAL: { Vector_multiplyByScalar (him.peek(), my dx / nfft); } break; case kSounds_convolve_scaling_SUM: { Vector_multiplyByScalar (him.peek(), 1.0 / nfft); } break; case kSounds_convolve_scaling_NORMALIZE: { double normalizationFactor = Matrix_getNorm (me) * Matrix_getNorm (thee); if (normalizationFactor != 0.0) { Vector_multiplyByScalar (him.peek(), 1.0 / nfft / normalizationFactor); } } break; case kSounds_convolve_scaling_PEAK_099: { Vector_scale (him.peek(), 0.99); } break; default: Melder_fatal (U"Sounds_crossCorrelate: unimplemented scaling ", scaling); } return him.transfer(); } catch (MelderError) { Melder_throw (me, U" & ", thee, U": not cross-correlated."); } }
static void _Thing_addOneReadableClass (ClassInfo readableClass) { if (++ theNumberOfReadableClasses > 1000) Melder_fatal (U"(Thing_recognizeClassesByName:) Too many (1001) readable classes."); theReadableClasses [theNumberOfReadableClasses] = readableClass; readableClass -> sequentialUniqueIdOfReadableClass = theNumberOfReadableClasses; }
int _Melder_assert (const char *condition, const char *fileName, int lineNumber) { return Melder_fatal ("Assertion failed in file \"%s\" at line %d:\n %s\n", fileName, lineNumber, condition); }
bool Thing_isa (Thing me, ClassInfo klas) { if (! me) Melder_fatal (U"(Thing_isa:) Found null object."); return Thing_isSubclass (my classInfo, klas); }
static void _Thing_addOneReadableClass (Thing_Table readableClass) { if (++ numberOfReadableClasses > 1000) Melder_fatal ("(Thing_recognizeClassesByName:) Too many (1001) readable classes."); readableClasses [numberOfReadableClasses] = readableClass; readableClass -> sequentialUniqueIdOfReadableClass = numberOfReadableClasses; }
PointProcess Sound_Pitch_to_PointProcess_cc (Sound sound, Pitch pitch) { PointProcess point = PointProcess_create (sound -> xmin, sound -> xmax, 10); double t = pitch -> xmin; double addedRight = -1e300; double globalPeak = Vector_getAbsoluteExtremum (sound, sound -> xmin, sound -> xmax, 0), peak; /* * Cycle over all voiced intervals. */ for (;;) { double tleft, tright, tmiddle, f0middle, tmax, tsave; if (! Pitch_getVoicedIntervalAfter (pitch, t, & tleft, & tright)) break; /* * Go to the middle of the voice stretch. */ tmiddle = (tleft + tright) / 2; if (! Melder_progress1 ((tmiddle - sound -> xmin) / (sound -> xmax - sound -> xmin), L"Sound & Pitch to PointProcess")) goto end; f0middle = Pitch_getValueAtTime (pitch, tmiddle, kPitch_unit_HERTZ, Pitch_LINEAR); /* * Our first point is near this middle. */ if (f0middle == NUMundefined) { Melder_fatal ("Sound_Pitch_to_PointProcess_cc: tleft %ls, tright %ls, f0middle %ls", Melder_double (tleft), Melder_double (tright), Melder_double (f0middle)); } tmax = Sound_findExtremum (sound, tmiddle - 0.5 / f0middle, tmiddle + 0.5 / f0middle, TRUE, TRUE); Melder_assert (NUMdefined (tmax)); if (! PointProcess_addPoint (point, tmax)) goto end; tsave = tmax; for (;;) { double f0 = Pitch_getValueAtTime (pitch, tmax, kPitch_unit_HERTZ, Pitch_LINEAR), correlation; if (f0 == NUMundefined) break; correlation = Sound_findMaximumCorrelation (sound, tmax, 1.0 / f0, tmax - 1.25 / f0, tmax - 0.8 / f0, & tmax, & peak); if (correlation == -1) /*break*/ tmax -= 1.0 / f0; /* This one period will drop out. */ if (tmax < tleft) { if (correlation > 0.7 && peak > 0.023333 * globalPeak && tmax - addedRight > 0.8 / f0) if (! PointProcess_addPoint (point, tmax)) goto end; break; } if (correlation > 0.3 && (peak == 0.0 || peak > 0.01 * globalPeak)) { if (tmax - addedRight > 0.8 / f0) /* Do not fill in a short originally unvoiced interval twice. */ if (! PointProcess_addPoint (point, tmax)) goto end; } } tmax = tsave; for (;;) { double f0 = Pitch_getValueAtTime (pitch, tmax, kPitch_unit_HERTZ, Pitch_LINEAR), correlation; if (f0 == NUMundefined) break; correlation = Sound_findMaximumCorrelation (sound, tmax, 1.0 / f0, tmax + 0.8 / f0, tmax + 1.25 / f0, & tmax, & peak); if (correlation == -1) /*break*/ tmax += 1.0 / f0; if (tmax > tright) { if (correlation > 0.7 && peak > 0.023333 * globalPeak) { if (! PointProcess_addPoint (point, tmax)) goto end; addedRight = tmax; } break; } if (correlation > 0.3 && (peak == 0.0 || peak > 0.01 * globalPeak)) { if (! PointProcess_addPoint (point, tmax)) goto end; addedRight = tmax; } } t = tright; } end: Melder_progress1 (1.0, NULL); iferror forget (point); return point; }
int Thing_member (I, void *klas) { Thing me = (structThing*)void_me; if (! me) Melder_fatal ("(Thing_member:) Found NULL object."); return Thing_subclass (my methods, klas); }
void TextGrid_anySound_alignInterval (TextGrid me, Function anySound, long tierNumber, long intervalNumber, const char32 *languageName, bool includeWords, bool includePhonemes) { try { IntervalTier headTier = TextGrid_checkSpecifiedTierIsIntervalTier (me, tierNumber); if (intervalNumber < 1 || intervalNumber > headTier -> intervals.size) Melder_throw (U"Interval ", intervalNumber, U" does not exist."); TextInterval interval = headTier -> intervals.at [intervalNumber]; if (! includeWords && ! includePhonemes) Melder_throw (U"Nothing to be done, because you asked neither for word alignment nor for phoneme alignment."); if (str32str (headTier -> name, U"/") ) Melder_throw (U"The current tier already has a slash (\"/\") in its name. Cannot create a word or phoneme tier from it."); autoSound part = anySound -> classInfo == classLongSound ? LongSound_extractPart (static_cast <LongSound> (anySound), interval -> xmin, interval -> xmax, true) : Sound_extractPart (static_cast <Sound> (anySound), interval -> xmin, interval -> xmax, kSound_windowShape_RECTANGULAR, 1.0, true); autoSpeechSynthesizer synthesizer = SpeechSynthesizer_create (languageName, U"default"); double silenceThreshold = -35, minSilenceDuration = 0.1, minSoundingDuration = 0.1; autoTextGrid analysis; if (! Melder_equ (interval -> text, U"")) { try { analysis = SpeechSynthesizer_and_Sound_and_TextInterval_align (synthesizer.get(), part.get(), interval, silenceThreshold, minSilenceDuration, minSoundingDuration); } catch (MelderError) { Melder_clearError (); // ignore all error messages from DTW and the like } } if (analysis) { /* * Clean up the analysis. */ Melder_assert (analysis -> xmin == interval -> xmin); Melder_assert (analysis -> xmax == interval -> xmax); Melder_assert (analysis -> tiers->size == 4); Thing_cast (IntervalTier, analysisWordTier, analysis -> tiers->at [3]); if (! IntervalTier_check (analysisWordTier)) Melder_throw (U"Analysis word tier out of order."); IntervalTier_removeEmptyIntervals (analysisWordTier, nullptr); Melder_assert (analysisWordTier -> xmax == analysis -> xmax); Melder_assert (analysisWordTier -> intervals.size >= 1); TextInterval firstInterval = analysisWordTier -> intervals.at [1]; TextInterval lastInterval = analysisWordTier -> intervals.at [analysisWordTier -> intervals.size]; firstInterval -> xmin = analysis -> xmin; lastInterval -> xmax = analysis -> xmax; if (lastInterval -> xmax != analysis -> xmax) Melder_fatal (U"analysis ends at ", analysis -> xmax, U", but last interval at ", lastInterval -> xmax, U" seconds"); if (! IntervalTier_check (analysisWordTier)) Melder_throw (U"Analysis word tier out of order (2)."); Thing_cast (IntervalTier, analysisPhonemeTier, analysis -> tiers->at [4]); if (! IntervalTier_check (analysisPhonemeTier)) Melder_throw (U"Analysis phoneme tier out of order."); IntervalTier_removeEmptyIntervals (analysisPhonemeTier, analysisWordTier); Melder_assert (analysisPhonemeTier -> xmax == analysis -> xmax); Melder_assert (analysisPhonemeTier -> intervals.size >= 1); firstInterval = analysisPhonemeTier -> intervals.at [1]; lastInterval = analysisPhonemeTier -> intervals.at [analysisPhonemeTier -> intervals.size]; firstInterval -> xmin = analysis -> xmin; lastInterval -> xmax = analysis -> xmax; Melder_assert (lastInterval -> xmax == analysis -> xmax); if (! IntervalTier_check (analysisPhonemeTier)) Melder_throw (U"Analysis phoneme tier out of order (2)."); } long wordTierNumber = 0, phonemeTierNumber = 0; IntervalTier wordTier = nullptr, phonemeTier = nullptr; /* * Include a word tier. */ if (includeWords) { /* * Make sure that the word tier exists. */ autoMelderString newWordTierName; MelderString_copy (& newWordTierName, headTier -> name, U"/word"); for (long itier = 1; itier <= my tiers->size; itier ++) { IntervalTier tier = static_cast <IntervalTier> (my tiers->at [itier]); if (Melder_equ (newWordTierName.string, tier -> name)) { if (tier -> classInfo != classIntervalTier) Melder_throw (U"A tier with the prospective word tier name (", tier -> name, U") already exists, but it is not an interval tier." U"\nPlease change its name or remove it."); wordTierNumber = itier; break; } } if (! wordTierNumber) { autoIntervalTier newWordTier = IntervalTier_create (my xmin, my xmax); Thing_setName (newWordTier.get(), newWordTierName.string); my tiers -> addItemAtPosition_move (newWordTier.move(), wordTierNumber = tierNumber + 1); } Melder_assert (wordTierNumber >= 1 && wordTierNumber <= my tiers->size); wordTier = static_cast <IntervalTier> (my tiers->at [wordTierNumber]); /* * Make sure that the word tier has boundaries at the edges of the interval. */ IntervalTier_insertIntervalDestructively (wordTier, interval -> xmin, interval -> xmax); /* * Copy the contents of the word analysis into the interval in the word tier. */ long wordIntervalNumber = IntervalTier_hasTime (wordTier, interval -> xmin); Melder_assert (wordIntervalNumber != 0); if (analysis) { Thing_cast (IntervalTier, analysisWordTier, analysis -> tiers->at [3]); if (! IntervalTier_check (analysisWordTier)) Melder_throw (U"Analysis word tier out of order (3)."); if (! IntervalTier_check (wordTier)) Melder_throw (U"Word tier out of order (3)."); for (long ianalysisInterval = 1; ianalysisInterval <= analysisWordTier -> intervals.size; ianalysisInterval ++) { TextInterval analysisInterval = analysisWordTier -> intervals.at [ianalysisInterval]; TextInterval wordInterval = nullptr; double tmin = analysisInterval -> xmin, tmax = analysisInterval -> xmax; if (tmax == analysis -> xmax) { wordInterval = wordTier -> intervals.at [wordIntervalNumber]; TextInterval_setText (wordInterval, analysisInterval -> text); } else { wordInterval = wordTier -> intervals.at [wordIntervalNumber]; autoTextInterval newInterval = TextInterval_create (tmin, tmax, analysisInterval -> text); wordInterval -> xmin = tmax; wordTier -> intervals. addItem_move (newInterval.move()); wordIntervalNumber ++; } } if (! IntervalTier_check (analysisWordTier)) Melder_throw (U"Analysis word tier out of order (4)."); if (! IntervalTier_check (wordTier)) Melder_throw (U"Word tier out of order (4)."); } } /* * Include a phoneme tier. */ if (includePhonemes) { /* * Make sure that the phoneme tier exists. */ autoMelderString newPhonemeTierName; MelderString_copy (& newPhonemeTierName, headTier -> name, U"/phon"); for (long itier = 1; itier <= my tiers->size; itier ++) { IntervalTier tier = (IntervalTier) my tiers->at [itier]; if (Melder_equ (newPhonemeTierName.string, tier -> name)) { if (tier -> classInfo != classIntervalTier) Melder_throw (U"A tier with the prospective phoneme tier name (", tier -> name, U") already exists, but it is not an interval tier." U"\nPlease change its name or remove it."); phonemeTierNumber = itier; break; } } if (! phonemeTierNumber) { autoIntervalTier newPhonemeTier = IntervalTier_create (my xmin, my xmax); Thing_setName (newPhonemeTier.get(), newPhonemeTierName.string); my tiers -> addItemAtPosition_move (newPhonemeTier.move(), phonemeTierNumber = wordTierNumber ? wordTierNumber + 1 : tierNumber + 1); } Melder_assert (phonemeTierNumber >= 1 && phonemeTierNumber <= my tiers->size); phonemeTier = static_cast <IntervalTier> (my tiers->at [phonemeTierNumber]); /* * Make sure that the phoneme tier has boundaries at the edges of the interval. */ IntervalTier_insertIntervalDestructively (phonemeTier, interval -> xmin, interval -> xmax); /* * Copy the contents of the phoneme analysis into the interval in the phoneme tier. */ long phonemeIntervalNumber = IntervalTier_hasTime (phonemeTier, interval -> xmin); Melder_assert (phonemeIntervalNumber != 0); if (analysis.get()) { Thing_cast (IntervalTier, analysisPhonemeTier, analysis -> tiers->at [4]); for (long ianalysisInterval = 1; ianalysisInterval <= analysisPhonemeTier -> intervals.size; ianalysisInterval ++) { TextInterval analysisInterval = analysisPhonemeTier -> intervals.at [ianalysisInterval]; TextInterval phonemeInterval = nullptr; double tmin = analysisInterval -> xmin, tmax = analysisInterval -> xmax; if (tmax == analysis -> xmax) { phonemeInterval = phonemeTier -> intervals.at [phonemeIntervalNumber]; TextInterval_setText (phonemeInterval, analysisInterval -> text); } else { phonemeInterval = phonemeTier -> intervals.at [phonemeIntervalNumber]; autoTextInterval newInterval = TextInterval_create (tmin, tmax, analysisInterval -> text); phonemeInterval -> xmin = tmax; phonemeTier -> intervals. addItem_move (newInterval.move()); phonemeIntervalNumber ++; } } } if (includeWords) { /* * Synchronize the boundaries between the word tier and the phoneme tier. */ //for (long iinterval = 1; iinterval <= } } } catch (MelderError) { Melder_throw (me, U" & ", anySound, U": interval not aligned."); } }
Sound Sound_autoCorrelate (Sound me, enum kSounds_convolve_scaling scaling, enum kSounds_convolve_signalOutsideTimeDomain signalOutsideTimeDomain) { try { long numberOfChannels = my ny, n1 = my nx, n2 = n1 + n1 - 1, nfft = 1; while (nfft < n2) nfft *= 2; autoNUMvector <double> data (1, nfft); double my_xlast = my x1 + (n1 - 1) * my dx; autoSound thee = Sound_create (numberOfChannels, my xmin - my xmax, my xmax - my xmin, n2, my dx, my x1 - my_xlast); for (long channel = 1; channel <= numberOfChannels; channel ++) { double *a = my z [channel]; for (long i = n1; i > 0; i --) data [i] = a [i]; for (long i = n1 + 1; i <= nfft; i ++) data [i] = 0.0; NUMrealft (data.peek(), nfft, 1); data [1] *= data [1]; data [2] *= data [2]; for (long i = 3; i <= nfft; i += 2) { data [i] = data [i] * data [i] + data [i + 1] * data [i + 1]; data [i + 1] = 0.0; // reverse me by taking the conjugate of data1 } NUMrealft (data.peek(), nfft, -1); a = thy z [channel]; for (long i = 1; i < n1; i ++) { a [i] = data [i + (nfft - (n1 - 1))]; // data for the first part ("negative lags") is at the end of data } for (long i = 1; i <= n1; i ++) { a [i + (n1 - 1)] = data [i]; // data for the second part ("positive lags") is at the beginning of data } } switch (signalOutsideTimeDomain) { case kSounds_convolve_signalOutsideTimeDomain_ZERO: { // do nothing } break; case kSounds_convolve_signalOutsideTimeDomain_SIMILAR: { for (long channel = 1; channel <= numberOfChannels; channel ++) { double *a = thy z [channel]; double edge = n1; for (long i = 1; i < edge; i ++) { double factor = edge / i; a [i] *= factor; a [n2 + 1 - i] *= factor; } } } break; //case kSounds_convolve_signalOutsideTimeDomain_PERIODIC: { // do nothing //} break; default: Melder_fatal (U"Sounds_autoCorrelate: unimplemented outside-time-domain strategy ", signalOutsideTimeDomain); } switch (scaling) { case kSounds_convolve_scaling_INTEGRAL: { Vector_multiplyByScalar (thee.peek(), my dx / nfft); } break; case kSounds_convolve_scaling_SUM: { Vector_multiplyByScalar (thee.peek(), 1.0 / nfft); } break; case kSounds_convolve_scaling_NORMALIZE: { double normalizationFactor = Matrix_getNorm (me) * Matrix_getNorm (me); if (normalizationFactor != 0.0) { Vector_multiplyByScalar (thee.peek(), 1.0 / nfft / normalizationFactor); } } break; case kSounds_convolve_scaling_PEAK_099: { Vector_scale (thee.peek(), 0.99); } break; default: Melder_fatal (U"Sounds_autoCorrelate: unimplemented scaling ", scaling); } return thee.transfer(); } catch (MelderError) { Melder_throw (me, U": autocorrelation not computed."); } }