void praat_addAction4 (ClassInfo class1, int n1, ClassInfo class2, int n2, ClassInfo class3, int n3, ClassInfo class4, int n4, const char32 *title, const char32 *after, unsigned long flags, UiCallback callback) { try { int depth = flags, key = 0; bool unhidable = false, hidden = false, attractive = false; unsigned long motifFlags = 0; if (flags > 7) { depth = ((flags & praat_DEPTH_7) >> 16); unhidable = (flags & praat_UNHIDABLE) != 0; hidden = (flags & praat_HIDDEN) != 0 && ! unhidable; key = flags & 0x000000FF; motifFlags = key ? flags & (0x002000FF | GuiMenu_BUTTON_STATE_MASK) : flags & GuiMenu_BUTTON_STATE_MASK; attractive = (motifFlags & praat_ATTRACTIVE) != 0; } fixSelectionSpecification (& class1, & n1, & class2, & n2, & class3, & n3); if (callback && ! title) Melder_throw (U"An action command with callback has no title. Classes: ", class1 ? class1 -> className : U"", U" ", class2 ? class2 -> className : U"", U" ", class3 ? class3 -> className : U"", U" ", class4 ? class4 -> className : U"", U"."); if (! class1) Melder_throw (U"The action command \"", title, U"\" has no first class."); /* * Determine the position of the new command. */ long position; if (after) { // search for existing command with same selection long found = lookUpMatchingAction (class1, class2, class3, class4, after); if (found == 0) Melder_throw (U"The action command \"", title, U"\" cannot be put after \"", after, U"\",\n" U"because the latter command does not exist."); position = found + 1; // after 'after' } else { position = theActions -> size + 1; // at end } /* * Make new command. */ autoPraat_Command action = Thing_new (Praat_Command); action -> class1 = class1; action -> n1 = n1; action -> class2 = class2; action -> n2 = n2; action -> class3 = class3; action -> n3 = n3; action -> class4 = class4; action -> n4 = n4; action -> title = Melder_dup_f (title); action -> depth = depth; action -> callback = callback; // null for a separator action -> button = nullptr; action -> script = nullptr; action -> hidden = hidden; action -> unhidable = unhidable; action -> attractive = attractive; /* * Insert new command. */ Ordered_addItemAtPosition_move (theActions, action.move(), position); } catch (MelderError) {
void Data_writeText (Daata me, MelderFile openFile) { my v_writeText (openFile); if (ferror (openFile -> filePointer)) Melder_throw (U"I/O error."); }
Sound Sound_recordFixedTime (int inputSource, double gain, double balance, double sampleRate, double duration) { bool inputUsesPortAudio = MelderAudio_getInputUsesPortAudio (); PaStream *portaudioStream = NULL; #if defined (macintosh) #elif defined (_WIN32) HWAVEIN hWaveIn = 0; #else int fd = -1; /* Other systems use stream I/O with a file descriptor. */ int fd_mixer = -1; #endif try { long numberOfSamples, i; int mulaw = FALSE; int can16bit = TRUE; int fakeMonoByStereo = FALSE; /* Will be set to TRUE for systems (like MacOS X) that do not allow direct mono recording. */ /* Declare system-dependent data structures. */ static bool paInitialized = false; volatile struct Sound_recordFixedTime_Info info = { 0 }; PaStreamParameters streamParameters = { 0 }; #if defined (macintosh) (void) gain; (void) balance; #elif defined (_WIN32) WAVEFORMATEX waveFormat; WAVEHDR waveHeader; MMRESULT err; (void) inputSource; (void) gain; (void) balance; #elif defined (linux) #define min(a,b) a > b ? b : a int dev_mask; int fd_mixer = -1; int val; #endif /* Check representation of shorts. */ if (sizeof (short) != 2) Melder_throw (U"Cannot record a sound on this computer."); /* Check sampling frequency. */ bool supportsSamplingFrequency = true; if (inputUsesPortAudio) { #if defined (macintosh) if (sampleRate != 44100 && sampleRate != 48000 && sampleRate != 96000) supportsSamplingFrequency = false; #endif } else { #if defined (macintosh) if (sampleRate != 44100) supportsSamplingFrequency = false; #elif defined (linux) if (sampleRate != 8000 && sampleRate != 11025 && sampleRate != 16000 && sampleRate != 22050 && sampleRate != 32000 && sampleRate != 44100 && sampleRate != 48000) supportsSamplingFrequency = false; #elif defined (_WIN32) if (sampleRate != 8000 && sampleRate != 11025 && sampleRate != 16000 && sampleRate != 22050 && sampleRate != 32000 && sampleRate != 44100 && sampleRate != 48000 && sampleRate != 96000) supportsSamplingFrequency = false; #endif } if (! supportsSamplingFrequency) Melder_throw (U"Your audio hardware does not support a sampling frequency of ", sampleRate, U" Hz."); /* * Open phase 1. * On some systems, the info is filled in before the audio port is opened. * On other systems, the info is filled in after the port is opened. */ if (inputUsesPortAudio) { if (! paInitialized) { PaError err = Pa_Initialize (); if (err) Melder_throw (U"Pa_Initialize: ", Melder_peek8to32 (Pa_GetErrorText (err))); paInitialized = true; } } else { #if defined (macintosh) #elif defined (_WIN32) #else /* We must open the port now, because we use an ioctl to set the info to an open port. */ fd = open (DEV_AUDIO, O_RDONLY); if (fd == -1) { if (errno == EBUSY) Melder_throw (U"Audio device in use by another program."); else #ifdef linux Melder_throw (U"Cannot open audio device.\nPlease switch on PortAudio in the Sound Recording Preferences."); #else Melder_throw (U"Cannot open audio device."); #endif } /* The device immediately started recording into its buffer, but probably at the wrong rate etc. */ /* Pause and flush this rubbish. */ #if defined (linux) ioctl (fd, SNDCTL_DSP_RESET, NULL); #endif #endif } /* Set the input source; the default is the microphone. */ if (inputUsesPortAudio) { if (inputSource < 1 || inputSource > Pa_GetDeviceCount ()) Melder_throw (U"Unknown device #", inputSource, U"."); streamParameters. device = inputSource - 1; } else { #if defined (macintosh) #elif defined (linux) fd_mixer = open ("/dev/mixer", O_WRONLY); if (fd_mixer == -1) Melder_throw (U"Cannot open /dev/mixer."); dev_mask = inputSource == 1 ? SOUND_MASK_MIC : SOUND_MASK_LINE; if (ioctl (fd_mixer, SOUND_MIXER_WRITE_RECSRC, & dev_mask) == -1) Melder_throw (U"Cannot set recording device in mixer"); #endif } /* Set gain and balance. */ if (inputUsesPortAudio) { /* Taken from Audio Control Panel. */ } else { #if defined (macintosh) || defined (_WIN32) /* Taken from Audio Control Panel. */ #elif defined (linux) val = (gain <= 0.0 ? 0 : gain >= 1.0 ? 100 : floor (gain * 100 + 0.5)); balance = balance <= 0 ? 0 : balance >= 1 ? 1 : balance; if (balance >= 0.5) { val = (int)(((int)(val*balance/(1-balance)) << 8) | val); } else { val = (int)(val | ((int)(val*(1-balance)/balance) << 8)); } val = (int)((min(2-2*balance,1))*val) | ((int)((min(2*balance,1))*val) << 8); if (inputSource == 1) { /* MIC */ if (ioctl (fd_mixer, MIXER_WRITE (SOUND_MIXER_MIC), & val) == -1) Melder_throw (U"Cannot set gain and balance."); } else { /* LINE */ if (ioctl (fd_mixer, MIXER_WRITE (SOUND_MIXER_LINE), & val) == -1) Melder_throw (U"Cannot set gain and balance."); } close (fd_mixer); fd_mixer = -1; #endif } /* Set the sampling frequency. */ if (inputUsesPortAudio) { // Set while opening. } else { #if defined (macintosh) #elif defined (linux) int sampleRate_int = (int) sampleRate; if (ioctl (fd, SNDCTL_DSP_SPEED, & sampleRate_int) == -1) Melder_throw (U"Cannot set sampling frequency to ", sampleRate, U" Hz."); #elif defined (_WIN32) waveFormat. nSamplesPerSec = sampleRate; #endif } /* Set the number of channels to 1 (mono), if possible. */ if (inputUsesPortAudio) { streamParameters. channelCount = 1; } else { #if defined (macintosh) #elif defined (linux) val = 1; if (ioctl (fd, SNDCTL_DSP_CHANNELS, & val) == -1) Melder_throw (U"Cannot set to mono."); #elif defined (_WIN32) waveFormat. nChannels = 1; #endif } /* Set the encoding to 16-bit linear (or to 8-bit linear, if 16-bit is not available). */ if (inputUsesPortAudio) { streamParameters. sampleFormat = paInt16; } else { #if defined (macintosh) #elif defined (linux) #if __BYTE_ORDER == __BIG_ENDIAN val = AFMT_S16_BE; #else val = AFMT_S16_LE; #endif if (ioctl (fd, SNDCTL_DSP_SETFMT, & val) == -1) Melder_throw (U"Cannot set 16-bit linear."); #elif defined (_WIN32) waveFormat. wFormatTag = WAVE_FORMAT_PCM; waveFormat. wBitsPerSample = 16; waveFormat. nBlockAlign = waveFormat. nChannels * waveFormat. wBitsPerSample / 8; waveFormat. nAvgBytesPerSec = waveFormat. nBlockAlign * waveFormat. nSamplesPerSec; #endif } /* Create a buffer for recording, and the resulting sound. */ numberOfSamples = lround (sampleRate * duration); if (numberOfSamples < 1) Melder_throw (U"Duration too short."); autoNUMvector <short> buffer (1, numberOfSamples * (fakeMonoByStereo ? 2 : 1)); autoSound me = Sound_createSimple (1, numberOfSamples / sampleRate, sampleRate); // STEREO BUG Melder_assert (my nx == numberOfSamples); /* * Open phase 2. * This starts recording now. */ if (inputUsesPortAudio) { streamParameters. suggestedLatency = Pa_GetDeviceInfo (inputSource - 1) -> defaultLowInputLatency; #if defined (macintosh) PaMacCoreStreamInfo macCoreStreamInfo = { 0 }; macCoreStreamInfo. size = sizeof (PaMacCoreStreamInfo); macCoreStreamInfo. hostApiType = paCoreAudio; macCoreStreamInfo. version = 0x01; macCoreStreamInfo. flags = paMacCoreChangeDeviceParameters | paMacCoreFailIfConversionRequired; streamParameters. hostApiSpecificStreamInfo = & macCoreStreamInfo; #endif info. numberOfSamples = numberOfSamples; info. numberOfSamplesRead = 0; info. buffer = buffer.peek(); PaError err = Pa_OpenStream (& portaudioStream, & streamParameters, NULL, sampleRate, 0, paNoFlag, portaudioStreamCallback, (void *) & info); if (err) Melder_throw (U"open ", Melder_peek8to32 (Pa_GetErrorText (err))); Pa_StartStream (portaudioStream); if (err) Melder_throw (U"start ", Melder_peek8to32 (Pa_GetErrorText (err))); } else { #if defined (macintosh) #elif defined (_WIN32) waveFormat. cbSize = 0; err = waveInOpen (& hWaveIn, WAVE_MAPPER, & waveFormat, 0, 0, CALLBACK_NULL); if (err != MMSYSERR_NOERROR) Melder_throw (U"Error ", err, U" while opening."); #endif } for (i = 1; i <= numberOfSamples; i ++) trace (U"Started ", buffer [i]); /* Read the sound into the buffer. */ if (inputUsesPortAudio) { // The callback will do this. Just wait. while (/*getNumberOfSamplesRead (& info)*/ info. numberOfSamplesRead < numberOfSamples) { //Pa_Sleep (1); //Melder_casual ("filled %ld/%ld", getNumberOfSamplesRead (& info), numberOfSamples); } for (i = 1; i <= numberOfSamples; i ++) trace (U"Recorded ", buffer [i]); } else { #if defined (macintosh) #elif defined (_WIN32) waveHeader. dwFlags = 0; waveHeader. lpData = (char *) & buffer [1]; waveHeader. dwBufferLength = numberOfSamples * 2; waveHeader. dwLoops = 0; waveHeader. lpNext = NULL; waveHeader. reserved = 0; err = waveInPrepareHeader (hWaveIn, & waveHeader, sizeof (WAVEHDR)); if (err != MMSYSERR_NOERROR) Melder_throw (U"Error ", err, U" while preparing header."); err = waveInAddBuffer (hWaveIn, & waveHeader, sizeof (WAVEHDR)); if (err != MMSYSERR_NOERROR) Melder_throw (U"Error ", err, U" while listening."); err = waveInStart (hWaveIn); if (err != MMSYSERR_NOERROR) Melder_throw (U"Error ", err, U" while starting."); while (! (waveHeader. dwFlags & WHDR_DONE)) { Pa_Sleep (1); } err = waveInUnprepareHeader (hWaveIn, & waveHeader, sizeof (WAVEHDR)); if (err != MMSYSERR_NOERROR) Melder_throw (U"Error ", err, U" while unpreparing header."); #else if (mulaw) read (fd, (char *) & buffer [1], numberOfSamples); else { long bytesLeft = 2 * numberOfSamples, dbytes, bytesRead = 0; while (bytesLeft) { //Melder_casual ("Reading %ld bytes", bytesLeft > 4000 ? 4000 : bytesLeft); dbytes = read (fd, & ((char *) buffer.peek()) [2 + bytesRead], bytesLeft > 4000 ? 4000 : bytesLeft); //Melder_casual("Read %ld bytes", dbytes); if (dbytes <= 0) break; bytesLeft -= dbytes; bytesRead += dbytes; }; } #endif } /* Copy the buffered data to the sound object, and discard the buffer. */ if (fakeMonoByStereo) for (i = 1; i <= numberOfSamples; i ++) my z [1] [i] = ((long) buffer [i + i - 1] + buffer [i + i]) * (1.0 / 65536); else if (mulaw) for (i = 1; i <= numberOfSamples; i ++) my z [1] [i] = ulaw2linear [((unsigned char *) buffer.peek()) [i]] * (1.0 / 32768); else if (can16bit) for (i = 1; i <= numberOfSamples; i ++) my z [1] [i] = buffer [i] * (1.0 / 32768); else for (i = 1; i <= numberOfSamples; i ++) my z [1] [i] = ((int) ((unsigned char *) buffer.peek()) [i + 1] - 128) * (1.0 / 128); /* Close the audio device. */ if (inputUsesPortAudio) { Pa_StopStream (portaudioStream); Pa_CloseStream (portaudioStream); } else { #if defined (macintosh) #elif defined (_WIN32) err = waveInClose (hWaveIn); if (err != MMSYSERR_NOERROR) Melder_throw (U"Error ", err, U" while closing."); #else close (fd); #endif } /* Hand the resulting sound to the caller. */ return me.transfer(); } catch (MelderError) { if (inputUsesPortAudio) { if (portaudioStream) Pa_StopStream (portaudioStream); if (portaudioStream) Pa_CloseStream (portaudioStream); } else { #if defined (macintosh) #elif defined (_WIN32) if (hWaveIn != 0) waveInClose (hWaveIn); #else if (fd_mixer != -1) close (fd_mixer); if (fd != -1) close (fd); #endif } Melder_throw (U"Sound not recorded."); } }
static void Diagonalizer_and_CrossCorrelationTable_qdiag (Diagonalizer me, CrossCorrelationTables thee, double *cweights, long maxNumberOfIterations, double delta) { try { CrossCorrelationTable c0 = (CrossCorrelationTable) thy item[1]; double **w = my data; long dimension = c0 -> numberOfColumns; autoEigen eigen = Thing_new (Eigen); autoCrossCorrelationTables ccts = Data_copy (thee); autoNUMmatrix<double> pinv (1, dimension, 1, dimension); autoNUMmatrix<double> d (1, dimension, 1, dimension); autoNUMmatrix<double> p (1, dimension, 1, dimension); autoNUMmatrix<double> m1 (1, dimension, 1, dimension); autoNUMmatrix<double> wc (1, dimension, 1, dimension); autoNUMvector<double> wvec (1, dimension); autoNUMvector<double> wnew (1, dimension); autoNUMvector<double> mvec (1, dimension); for (long i = 1; i <= dimension; i++) // Transpose W for (long j = 1; j <= dimension; j++) { wc[i][j] = w[j][i]; } // d = diag(diag(W'*C0*W)); // W = W*d^(-1/2); NUMdmatrix_normalizeColumnVectors (wc.peek(), dimension, dimension, c0 -> data); // scale eigenvectors for sphering // [vb,db] = eig(C0); // P = db^(-1/2)*vb'; Eigen_initFromSymmetricMatrix (eigen.peek(), c0 -> data, dimension); for (long i = 1; i <= dimension; i++) { if (eigen -> eigenvalues[i] < 0) { Melder_throw ("Covariance matrix not positive definite, eigenvalue[", Melder_integer(i), "] is negative."); } double scalef = 1 / sqrt (eigen -> eigenvalues[i]); for (long j = 1; j <= dimension; j++) { p[dimension - i + 1][j] = scalef * eigen -> eigenvectors[i][j]; } } // P*C[i]*P' for (long ic = 1; ic <= thy size; ic++) { CrossCorrelationTable cov1 = (CrossCorrelationTable) thy item[ic]; CrossCorrelationTable cov2 = (CrossCorrelationTable) ccts -> item[ic]; NUMdmatrices_multiply_VCVp (cov2 -> data, p.peek(), dimension, dimension, cov1 -> data, 1); } // W = P'\W == inv(P') * W NUMpseudoInverse (p.peek(), dimension, dimension, pinv.peek(), 0); NUMdmatrices_multiply_VpC (w, pinv.peek(), dimension, dimension, wc.peek(), dimension); // initialisation for order KN^3 for (long ic = 2; ic <= thy size; ic++) { CrossCorrelationTable cov = (CrossCorrelationTable) ccts -> item[ic]; // C * W NUMdmatrices_multiply_VC (m1.peek(), cov -> data, dimension, dimension, w, dimension); // D += scalef * M1*M1' NUMdmatrices_multiplyScaleAdd (d.peek(), m1.peek(), dimension, dimension, 2 * cweights[ic]); } long iter = 0; double delta_w; autoMelderProgress progress (L"Simultaneous diagonalization of many CrossCorrelationTables..."); try { do { // the standard diagonality measure is rather expensive to calculate so we compare the norms of // differences of eigenvectors. delta_w = 0; for (long kol = 1; kol <= dimension; kol++) { for (long i = 1; i <= dimension; i++) { wvec[i] = w[i][kol]; } update_one_column (ccts.peek(), d.peek(), cweights, wvec.peek(), -1, mvec.peek()); Eigen_initFromSymmetricMatrix (eigen.peek(), d.peek(), dimension); // Eigenvalues already sorted; get eigenvector of smallest ! for (long i = 1; i <= dimension; i++) { wnew[i] = eigen -> eigenvectors[dimension][i]; } update_one_column (ccts.peek(), d.peek(), cweights, wnew.peek(), 1, mvec.peek()); for (long i = 1; i <= dimension; i++) { w[i][kol] = wnew[i]; } // compare norms of eigenvectors. We have to compare ||wvec +/- w_new|| because eigenvectors // may change sign. double normp = 0, normm = 0; for (long j = 1; j <= dimension; j++) { double dm = wvec[j] - wnew[j], dp = wvec[j] + wnew[j]; normp += dm * dm; normm += dp * dp; } normp = normp < normm ? normp : normm; normp = sqrt (normp); delta_w = normp > delta_w ? normp : delta_w; } iter++; Melder_progress ((double) iter / (double) (maxNumberOfIterations + 1), L"Iteration: ", Melder_integer (iter), L", norm: ", Melder_double (delta_w)); } while (delta_w > delta && iter < maxNumberOfIterations); } catch (MelderError) { Melder_clearError (); } // Revert the sphering W = P'*W; // Take transpose to make W*C[i]W' diagonal instead of W'*C[i]*W => (P'*W)'=W'*P NUMmatrix_copyElements (w, wc.peek(), 1, dimension, 1, dimension); NUMdmatrices_multiply_VpC (w, wc.peek(), dimension, dimension, p.peek(), dimension); // W = W'*P: final result // Calculate the "real" diagonality measure // double dm = CrossCorrelationTables_and_Diagonalizer_getDiagonalityMeasure (thee, me, cweights, 1, thy size); } catch (MelderError) { Melder_throw (me, " & ", thee, ": no joint diagonalization (qdiag)."); } }
TextGrid TextGrid_readFromTIMITLabelFile (MelderFile file, int phnFile) { try { double dt = 1.0 / 16000; /* 1 / (TIMIT samplingFrequency) */ double xmax = dt; autofile f = Melder_fopen (file, "r"); // Ending time will only be known after all labels have been read. // We start with a sufficiently long duration (one hour) and correct this later. autoTextGrid me = TextGrid_create (0, 3600, L"wrd", 0); IntervalTier timit = (IntervalTier) my tiers -> item[1]; long linesRead = 0; char line[200], label[200]; while (fgets (line, 199, f)) { long it1, it2; linesRead++; if (sscanf (line, "%ld%ld%s", &it1, &it2, label) != 3) { Melder_throw ("Incorrect number of items."); } if (it1 < 0 || it2 <= it1) { Melder_throw (L"Incorrect time at line ", linesRead); } xmax = it2 * dt; double xmin = it1 * dt; long ni = timit -> intervals -> size - 1; if (ni < 1) { ni = 1; // Some files do not start with a first line "0 <number2> h#". // Instead they start with "<number1> <number2> h#", where number1 > 0. // We override number1 with 0. */ if (xmin > 0 && phnFile) { xmin = 0; } } TextInterval interval = (TextInterval) timit -> intervals -> item[ni]; if (xmin < interval -> xmax && linesRead > 1) { xmin = interval -> xmax; Melder_warning (L"File \"", MelderFile_messageName (file), L"\": Start time set to previous end " "time for label at line ", Melder_integer (linesRead), L"."); } // standard: new TextInterval const char *labelstring = (strncmp (label, "h#", 2) ? label : TIMIT_DELIMITER); IntervalTier_add (timit, xmin, xmax, Melder_peekUtf8ToWcs (labelstring)); } // Now correct the end times, based on last read interval. // (end time was set to large value!) if (timit -> intervals -> size < 2) { Melder_throw ("Empty TextGrid"); } Collection_removeItem (timit -> intervals, timit -> intervals -> size); TextInterval interval = (TextInterval) timit -> intervals -> item[timit -> intervals -> size]; timit -> xmax = interval -> xmax; my xmax = xmax; if (phnFile) { // Create tier 2 with IPA symbols autoIntervalTier ipa = Data_copy (timit); Thing_setName (ipa.peek(), L"ipa"); // First change the data in ipa for (long i = 1; i <= ipa -> intervals -> size; i++) { interval = (TextInterval) timit -> intervals -> item[i]; TextInterval_setText ( (TextInterval) ipa -> intervals -> item[i], Melder_peekUtf8ToWcs (timitLabelToIpaLabel (Melder_peekWcsToUtf8 (interval -> text)))); } Collection_addItem (my tiers, ipa.transfer()); // Then: add to collection Thing_setName (timit, L"phn"); // rename wrd } f.close (file); return me.transfer(); } catch (MelderError) { Melder_throw ("TextGrid not read from file ", file, "."); } }
void LongSounds_appendToExistingSoundFile (Collection me, MelderFile file) { long pre_append_endpos = 0, numberOfBitsPerSamplePoint = 16; try { if (my size < 1) { Melder_throw (U"No Sound or LongSound objects to append."); } /* We have to open with "r+" mode because this will position the stream at the beginning of the file. The "a" mode does not allow us to seek before the end-of-file. For Linux: If the file is already opened (e.g. by a LongSound) object we should deny access! Under Windows deny access is default?! */ autofile f = Melder_fopen (file, "r+b"); file -> filePointer = f; // essential !! double sampleRate_d; long startOfData; int32 numberOfSamples; int numberOfChannels, encoding; int audioFileType = MelderFile_checkSoundFile (file, &numberOfChannels, &encoding, &sampleRate_d, &startOfData, &numberOfSamples); if (audioFileType == 0) { Melder_throw (U"Not a sound file."); } // Check whether all the sample rates and channels match. long sampleRate = (long) floor (sampleRate_d); for (long i = 1; i <= my size; i++) { int sampleRatesMatch, numbersOfChannelsMatch; Sampled data = (Sampled) my item [i]; if (data -> classInfo == classSound) { Sound sound = (Sound) data; sampleRatesMatch = floor (1.0 / sound -> dx + 0.5) == sampleRate; numbersOfChannelsMatch = sound -> ny == numberOfChannels; numberOfSamples += sound -> nx; } else { LongSound longSound = (LongSound) data; sampleRatesMatch = longSound -> sampleRate == sampleRate; numbersOfChannelsMatch = longSound -> numberOfChannels == numberOfChannels; numberOfSamples += longSound -> nx; } if (! sampleRatesMatch) { Melder_throw (U"Sample rates do not match."); } if (! numbersOfChannelsMatch) { Melder_throw (U"Cannot mix stereo and mono."); } } // Search the end of the file, count the number of bytes and append. MelderFile_seek (file, 0, SEEK_END); pre_append_endpos = MelderFile_tell (file); errno = 0; for (long i = 1; i <= my size; i++) { Sampled data = (Sampled) my item [i]; if (data -> classInfo == classSound) { Sound sound = (Sound) data; MelderFile_writeFloatToAudio (file, sound -> ny, Melder_defaultAudioFileEncoding (audioFileType, numberOfBitsPerSamplePoint), sound -> z, sound -> nx, true); } else { LongSound longSound = (LongSound) data; writePartToOpenFile16 (longSound, audioFileType, 1, longSound -> nx, file); } if (errno != 0) { Melder_throw (U"Error during writing."); } } // Update header MelderFile_rewind (file); MelderFile_writeAudioFileHeader (file, audioFileType, sampleRate, numberOfSamples, numberOfChannels, numberOfBitsPerSamplePoint); MelderFile_writeAudioFileTrailer (file, audioFileType, sampleRate, numberOfSamples, numberOfChannels, numberOfBitsPerSamplePoint); f.close (file); return; } catch (MelderError) { if (errno != 0 && pre_append_endpos > 0) { // Restore file at original size int error = errno; MelderFile_truncate (file, pre_append_endpos); Melder_throw (U"File ", MelderFile_messageName (file), U" restored to original size (", Melder_peek8to32 (strerror (error)), U")."); } throw; } }
autoEEG EEG_readFromBdfFile (MelderFile file) { try { autofile f = Melder_fopen (file, "rb"); char buffer [81]; fread (buffer, 1, 8, f); buffer [8] = '\0'; bool is24bit = buffer [0] == (char) 255; fread (buffer, 1, 80, f); buffer [80] = '\0'; trace (U"Local subject identification: \"", Melder_peek8to32 (buffer), U"\""); fread (buffer, 1, 80, f); buffer [80] = '\0'; trace (U"Local recording identification: \"", Melder_peek8to32 (buffer), U"\""); fread (buffer, 1, 8, f); buffer [8] = '\0'; trace (U"Start date of recording: \"", Melder_peek8to32 (buffer), U"\""); fread (buffer, 1, 8, f); buffer [8] = '\0'; trace (U"Start time of recording: \"", Melder_peek8to32 (buffer), U"\""); fread (buffer, 1, 8, f); buffer [8] = '\0'; long numberOfBytesInHeaderRecord = atol (buffer); trace (U"Number of bytes in header record: ", numberOfBytesInHeaderRecord); fread (buffer, 1, 44, f); buffer [44] = '\0'; trace (U"Version of data format: \"", Melder_peek8to32 (buffer), U"\""); fread (buffer, 1, 8, f); buffer [8] = '\0'; long numberOfDataRecords = strtol (buffer, nullptr, 10); trace (U"Number of data records: ", numberOfDataRecords); fread (buffer, 1, 8, f); buffer [8] = '\0'; double durationOfDataRecord = atof (buffer); trace (U"Duration of a data record: ", durationOfDataRecord); fread (buffer, 1, 4, f); buffer [4] = '\0'; long numberOfChannels = atol (buffer); trace (U"Number of channels in data record: ", numberOfChannels); if (numberOfBytesInHeaderRecord != (numberOfChannels + 1) * 256) Melder_throw (U"Number of bytes in header record (", numberOfBytesInHeaderRecord, U") doesn't match number of channels (", numberOfChannels, U")."); autostring32vector channelNames (1, numberOfChannels); for (long ichannel = 1; ichannel <= numberOfChannels; ichannel ++) { fread (buffer, 1, 16, f); buffer [16] = '\0'; // labels of the channels /* * Strip all final spaces. */ for (int i = 15; i >= 0; i --) { if (buffer [i] == ' ') { buffer [i] = '\0'; } else { break; } } channelNames [ichannel] = Melder_8to32 (buffer); trace (U"Channel <<", channelNames [ichannel], U">>"); } bool hasLetters = str32equ (channelNames [numberOfChannels], U"EDF Annotations"); double samplingFrequency = NUMundefined; for (long channel = 1; channel <= numberOfChannels; channel ++) { fread (buffer, 1, 80, f); buffer [80] = '\0'; // transducer type } for (long channel = 1; channel <= numberOfChannels; channel ++) { fread (buffer, 1, 8, f); buffer [8] = '\0'; // physical dimension of channels } autoNUMvector <double> physicalMinimum (1, numberOfChannels); for (long ichannel = 1; ichannel <= numberOfChannels; ichannel ++) { fread (buffer, 1, 8, f); buffer [8] = '\0'; physicalMinimum [ichannel] = atof (buffer); } autoNUMvector <double> physicalMaximum (1, numberOfChannels); for (long ichannel = 1; ichannel <= numberOfChannels; ichannel ++) { fread (buffer, 1, 8, f); buffer [8] = '\0'; physicalMaximum [ichannel] = atof (buffer); } autoNUMvector <double> digitalMinimum (1, numberOfChannels); for (long ichannel = 1; ichannel <= numberOfChannels; ichannel ++) { fread (buffer, 1, 8, f); buffer [8] = '\0'; digitalMinimum [ichannel] = atof (buffer); } autoNUMvector <double> digitalMaximum (1, numberOfChannels); for (long ichannel = 1; ichannel <= numberOfChannels; ichannel ++) { fread (buffer, 1, 8, f); buffer [8] = '\0'; digitalMaximum [ichannel] = atof (buffer); } for (long channel = 1; channel <= numberOfChannels; channel ++) { fread (buffer, 1, 80, f); buffer [80] = '\0'; // prefiltering } long numberOfSamplesPerDataRecord = 0; for (long channel = 1; channel <= numberOfChannels; channel ++) { fread (buffer, 1, 8, f); buffer [8] = '\0'; // number of samples in each data record long numberOfSamplesInThisDataRecord = atol (buffer); if (samplingFrequency == NUMundefined) { numberOfSamplesPerDataRecord = numberOfSamplesInThisDataRecord; samplingFrequency = numberOfSamplesInThisDataRecord / durationOfDataRecord; } if (numberOfSamplesInThisDataRecord / durationOfDataRecord != samplingFrequency) Melder_throw (U"Number of samples per data record in channel ", channel, U" (", numberOfSamplesInThisDataRecord, U") doesn't match sampling frequency of channel 1 (", samplingFrequency, U")."); } for (long channel = 1; channel <= numberOfChannels; channel ++) { fread (buffer, 1, 32, f); buffer [32] = '\0'; // reserved } double duration = numberOfDataRecords * durationOfDataRecord; autoEEG him = EEG_create (0, duration); his numberOfChannels = numberOfChannels; autoSound me = Sound_createSimple (numberOfChannels, duration, samplingFrequency); Melder_assert (my nx == numberOfSamplesPerDataRecord * numberOfDataRecords); autoNUMvector <unsigned char> dataBuffer (0L, 3 * numberOfSamplesPerDataRecord - 1); for (long record = 1; record <= numberOfDataRecords; record ++) { for (long channel = 1; channel <= numberOfChannels; channel ++) { double factor = channel == numberOfChannels ? 1.0 : physicalMinimum [channel] / digitalMinimum [channel]; if (channel < numberOfChannels - EEG_getNumberOfExtraSensors (him.peek())) factor /= 1000000.0; if (is24bit) { fread (& dataBuffer [0], 3, numberOfSamplesPerDataRecord, f); unsigned char *p = & dataBuffer [0]; for (long i = 1; i <= numberOfSamplesPerDataRecord; i ++) { long sample = i + (record - 1) * numberOfSamplesPerDataRecord; Melder_assert (sample <= my nx); uint8_t lowByte = *p ++, midByte = *p ++, highByte = *p ++; uint32_t externalValue = ((uint32_t) highByte << 16) | ((uint32_t) midByte << 8) | (uint32_t) lowByte; if ((highByte & 128) != 0) // is the 24-bit sign bit on? externalValue |= 0xFF000000; // extend negative sign to 32 bits my z [channel] [sample] = (int32_t) externalValue * factor; } } else { fread (& dataBuffer [0], 2, numberOfSamplesPerDataRecord, f); unsigned char *p = & dataBuffer [0]; for (long i = 1; i <= numberOfSamplesPerDataRecord; i ++) { long sample = i + (record - 1) * numberOfSamplesPerDataRecord; Melder_assert (sample <= my nx); uint8 lowByte = *p ++, highByte = *p ++; uint16 externalValue = (uint16) ((uint16) highByte << 8) | (uint16) lowByte; my z [channel] [sample] = (int16) externalValue * factor; } } } } int numberOfStatusBits = 8; for (long i = 1; i <= my nx; i ++) { unsigned long value = (long) my z [numberOfChannels] [i]; if (value & 0x0000FF00) { numberOfStatusBits = 16; } } autoTextGrid thee; if (hasLetters) { thee = TextGrid_create (0, duration, U"Mark Trigger", U"Mark Trigger"); autoMelderString letters; double time = NUMundefined; for (long i = 1; i <= my nx; i ++) { unsigned long value = (long) my z [numberOfChannels] [i]; for (int byte = 1; byte <= numberOfStatusBits / 8; byte ++) { unsigned long mask = byte == 1 ? 0x000000ff : 0x0000ff00; char32 kar = byte == 1 ? (value & mask) : (value & mask) >> 8; if (kar != U'\0' && kar != 20) { MelderString_appendCharacter (& letters, kar); } else if (letters. string [0] != U'\0') { if (letters. string [0] == U'+') { if (NUMdefined (time)) { try { TextGrid_insertPoint (thee.peek(), 1, time, U""); } catch (MelderError) { Melder_throw (U"Did not insert empty mark (", letters. string, U") on Mark tier."); } time = NUMundefined; // defensive } time = Melder_atof (& letters. string [1]); MelderString_empty (& letters); } else { if (! NUMdefined (time)) { Melder_throw (U"Undefined time for label at sample ", i, U"."); } try { if (Melder_nequ (letters. string, U"Trigger-", 8)) { try { TextGrid_insertPoint (thee.peek(), 2, time, & letters. string [8]); } catch (MelderError) { Melder_clearError (); trace (U"Duplicate trigger at ", time, U" seconds: ", & letters. string [8]); } } else { TextGrid_insertPoint (thee.peek(), 1, time, & letters. string [0]); } } catch (MelderError) { Melder_throw (U"Did not insert mark (", letters. string, U") on Trigger tier."); } time = NUMundefined; // crucial MelderString_empty (& letters); } } } } if (NUMdefined (time)) { TextGrid_insertPoint (thee.peek(), 1, time, U""); time = NUMundefined; // defensive } } else { thee = TextGrid_create (0, duration, numberOfStatusBits == 8 ? U"S1 S2 S3 S4 S5 S6 S7 S8" : U"S1 S2 S3 S4 S5 S6 S7 S8 S9 S10 S11 S12 S13 S14 S15 S16", U""); for (int bit = 1; bit <= numberOfStatusBits; bit ++) { unsigned long bitValue = 1 << (bit - 1); IntervalTier tier = (IntervalTier) thy tiers -> item [bit]; for (long i = 1; i <= my nx; i ++) { unsigned long previousValue = i == 1 ? 0 : (long) my z [numberOfChannels] [i - 1]; unsigned long thisValue = (long) my z [numberOfChannels] [i]; if ((thisValue & bitValue) != (previousValue & bitValue)) { double time = i == 1 ? 0.0 : my x1 + (i - 1.5) * my dx; if (time != 0.0) TextGrid_insertBoundary (thee.peek(), bit, time); if ((thisValue & bitValue) != 0) TextGrid_setIntervalText (thee.peek(), bit, tier -> intervals -> size, U"1"); } } } } f.close (file); his channelNames = channelNames.transfer(); his sound = me.move(); his textgrid = thee.move(); if (EEG_getNumberOfCapElectrodes (him.peek()) == 32) { EEG_setChannelName (him.peek(), 1, U"Fp1"); EEG_setChannelName (him.peek(), 2, U"AF3"); EEG_setChannelName (him.peek(), 3, U"F7"); EEG_setChannelName (him.peek(), 4, U"F3"); EEG_setChannelName (him.peek(), 5, U"FC1"); EEG_setChannelName (him.peek(), 6, U"FC5"); EEG_setChannelName (him.peek(), 7, U"T7"); EEG_setChannelName (him.peek(), 8, U"C3"); EEG_setChannelName (him.peek(), 9, U"CP1"); EEG_setChannelName (him.peek(), 10, U"CP5"); EEG_setChannelName (him.peek(), 11, U"P7"); EEG_setChannelName (him.peek(), 12, U"P3"); EEG_setChannelName (him.peek(), 13, U"Pz"); EEG_setChannelName (him.peek(), 14, U"PO3"); EEG_setChannelName (him.peek(), 15, U"O1"); EEG_setChannelName (him.peek(), 16, U"Oz"); EEG_setChannelName (him.peek(), 17, U"O2"); EEG_setChannelName (him.peek(), 18, U"PO4"); EEG_setChannelName (him.peek(), 19, U"P4"); EEG_setChannelName (him.peek(), 20, U"P8"); EEG_setChannelName (him.peek(), 21, U"CP6"); EEG_setChannelName (him.peek(), 22, U"CP2"); EEG_setChannelName (him.peek(), 23, U"C4"); EEG_setChannelName (him.peek(), 24, U"T8"); EEG_setChannelName (him.peek(), 25, U"FC6"); EEG_setChannelName (him.peek(), 26, U"FC2"); EEG_setChannelName (him.peek(), 27, U"F4"); EEG_setChannelName (him.peek(), 28, U"F8"); EEG_setChannelName (him.peek(), 29, U"AF4"); EEG_setChannelName (him.peek(), 30, U"Fp2"); EEG_setChannelName (him.peek(), 31, U"Fz"); EEG_setChannelName (him.peek(), 32, U"Cz"); } else if (EEG_getNumberOfCapElectrodes (him.peek()) == 64) { EEG_setChannelName (him.peek(), 1, U"Fp1"); EEG_setChannelName (him.peek(), 2, U"AF7"); EEG_setChannelName (him.peek(), 3, U"AF3"); EEG_setChannelName (him.peek(), 4, U"F1"); EEG_setChannelName (him.peek(), 5, U"F3"); EEG_setChannelName (him.peek(), 6, U"F5"); EEG_setChannelName (him.peek(), 7, U"F7"); EEG_setChannelName (him.peek(), 8, U"FT7"); EEG_setChannelName (him.peek(), 9, U"FC5"); EEG_setChannelName (him.peek(), 10, U"FC3"); EEG_setChannelName (him.peek(), 11, U"FC1"); EEG_setChannelName (him.peek(), 12, U"C1"); EEG_setChannelName (him.peek(), 13, U"C3"); EEG_setChannelName (him.peek(), 14, U"C5"); EEG_setChannelName (him.peek(), 15, U"T7"); EEG_setChannelName (him.peek(), 16, U"TP7"); EEG_setChannelName (him.peek(), 17, U"CP5"); EEG_setChannelName (him.peek(), 18, U"CP3"); EEG_setChannelName (him.peek(), 19, U"CP1"); EEG_setChannelName (him.peek(), 20, U"P1"); EEG_setChannelName (him.peek(), 21, U"P3"); EEG_setChannelName (him.peek(), 22, U"P5"); EEG_setChannelName (him.peek(), 23, U"P7"); EEG_setChannelName (him.peek(), 24, U"P9"); EEG_setChannelName (him.peek(), 25, U"PO7"); EEG_setChannelName (him.peek(), 26, U"PO3"); EEG_setChannelName (him.peek(), 27, U"O1"); EEG_setChannelName (him.peek(), 28, U"Iz"); EEG_setChannelName (him.peek(), 29, U"Oz"); EEG_setChannelName (him.peek(), 30, U"POz"); EEG_setChannelName (him.peek(), 31, U"Pz"); EEG_setChannelName (him.peek(), 32, U"CPz"); EEG_setChannelName (him.peek(), 33, U"Fpz"); EEG_setChannelName (him.peek(), 34, U"Fp2"); EEG_setChannelName (him.peek(), 35, U"AF8"); EEG_setChannelName (him.peek(), 36, U"AF4"); EEG_setChannelName (him.peek(), 37, U"AFz"); EEG_setChannelName (him.peek(), 38, U"Fz"); EEG_setChannelName (him.peek(), 39, U"F2"); EEG_setChannelName (him.peek(), 40, U"F4"); EEG_setChannelName (him.peek(), 41, U"F6"); EEG_setChannelName (him.peek(), 42, U"F8"); EEG_setChannelName (him.peek(), 43, U"FT8"); EEG_setChannelName (him.peek(), 44, U"FC6"); EEG_setChannelName (him.peek(), 45, U"FC4"); EEG_setChannelName (him.peek(), 46, U"FC2"); EEG_setChannelName (him.peek(), 47, U"FCz"); EEG_setChannelName (him.peek(), 48, U"Cz"); EEG_setChannelName (him.peek(), 49, U"C2"); EEG_setChannelName (him.peek(), 50, U"C4"); EEG_setChannelName (him.peek(), 51, U"C6"); EEG_setChannelName (him.peek(), 52, U"T8"); EEG_setChannelName (him.peek(), 53, U"TP8"); EEG_setChannelName (him.peek(), 54, U"CP6"); EEG_setChannelName (him.peek(), 55, U"CP4"); EEG_setChannelName (him.peek(), 56, U"CP2"); EEG_setChannelName (him.peek(), 57, U"P2"); EEG_setChannelName (him.peek(), 58, U"P4"); EEG_setChannelName (him.peek(), 59, U"P6"); EEG_setChannelName (him.peek(), 60, U"P8"); EEG_setChannelName (him.peek(), 61, U"P10"); EEG_setChannelName (him.peek(), 62, U"PO8"); EEG_setChannelName (him.peek(), 63, U"PO4"); EEG_setChannelName (him.peek(), 64, U"O2"); } return him; } catch (MelderError) {
void NUMlinprog_run (NUMlinprog me) { try { glp_smcp parm; glp_init_smcp (& parm); parm. msg_lev = GLP_MSG_OFF; my status = glp_simplex (my linearProgram, & parm); switch (my status) { case GLP_EBADB: Melder_throw (U"Unable to start the search, because the initial basis is invalid."); case GLP_ESING: Melder_throw (U"Unable to start the search, because the basis matrix is singular."); case GLP_ECOND: Melder_throw (U"Unable to start the search, because the basis matrix is ill-conditioned."); case GLP_EBOUND: Melder_throw (U"Unable to start the search, because some variables have incorrect bounds."); case GLP_EFAIL: Melder_throw (U"Search prematurely terminated due to solver failure."); case GLP_EOBJLL: Melder_throw (U"Search prematurely terminated: lower limit reached."); case GLP_EOBJUL: Melder_throw (U"Search prematurely terminated: upper limit reached."); case GLP_EITLIM: Melder_throw (U"Search prematurely terminated: iteration limit exceeded."); case GLP_ETMLIM: Melder_throw (U"Search prematurely terminated: time limit exceeded."); case GLP_ENOPFS: Melder_throw (U"The problem has no primal feasible solution."); case GLP_ENODFS: Melder_throw (U"The problem has no dual feasible solution."); default: break; } my status = glp_get_status (my linearProgram); switch (my status) { case GLP_INFEAS: Melder_throw (U"Solution is infeasible."); case GLP_NOFEAS: Melder_throw (U"Problem has no feasible solution."); case GLP_UNBND: Melder_throw (U"Problem has unbounded solution."); case GLP_UNDEF: Melder_throw (U"Solution is undefined."); default: break; } if (my status == GLP_FEAS) { Melder_warning (U"Linear programming solution is feasible but not optimal."); } } catch (MelderError) { Melder_throw (U"Linear programming: not run."); } }
static Intensity Sound_to_Intensity_ (Sound me, double minimumPitch, double timeStep, int subtractMeanPressure) { try { /* * Preconditions. */ if (! NUMdefined (minimumPitch)) Melder_throw ("(Sound-to-Intensity:) Minimum pitch undefined."); if (! NUMdefined (timeStep)) Melder_throw ("(Sound-to-Intensity:) Time step undefined."); if (timeStep < 0.0) Melder_throw ("(Sound-to-Intensity:) Time step should be zero or positive instead of ", timeStep, "."); if (my dx <= 0.0) Melder_throw ("(Sound-to-Intensity:) The Sound's time step should be positive."); if (minimumPitch <= 0.0) Melder_throw ("(Sound-to-Intensity:) Minimum pitch should be positive."); /* * Defaults. */ if (timeStep == 0.0) timeStep = 0.8 / minimumPitch; // default: four times oversampling Hanning-wise double windowDuration = 6.4 / minimumPitch; Melder_assert (windowDuration > 0.0); double halfWindowDuration = 0.5 * windowDuration; long halfWindowSamples = halfWindowDuration / my dx; autoNUMvector <double> amplitude (- halfWindowSamples, halfWindowSamples); autoNUMvector <double> window (- halfWindowSamples, halfWindowSamples); for (long i = - halfWindowSamples; i <= halfWindowSamples; i ++) { double x = i * my dx / halfWindowDuration, root = 1 - x * x; window [i] = root <= 0.0 ? 0.0 : NUMbessel_i0_f ((2 * NUMpi * NUMpi + 0.5) * sqrt (root)); } long numberOfFrames; double thyFirstTime; try { Sampled_shortTermAnalysis (me, windowDuration, timeStep, & numberOfFrames, & thyFirstTime); } catch (MelderError) { Melder_throw ("The duration of the sound in an intensity analysis should be at least 6.4 divided by the minimum pitch (", minimumPitch, " Hz), " "i.e. at least ", 6.4 / minimumPitch, " s, instead of ", my xmax - my xmin, " s."); } autoIntensity thee = Intensity_create (my xmin, my xmax, numberOfFrames, timeStep, thyFirstTime); for (long iframe = 1; iframe <= numberOfFrames; iframe ++) { double midTime = Sampled_indexToX (thee.peek(), iframe); long midSample = Sampled_xToNearestIndex (me, midTime); long leftSample = midSample - halfWindowSamples, rightSample = midSample + halfWindowSamples; double sumxw = 0.0, sumw = 0.0, intensity; if (leftSample < 1) leftSample = 1; if (rightSample > my nx) rightSample = my nx; for (long channel = 1; channel <= my ny; channel ++) { for (long i = leftSample; i <= rightSample; i ++) { amplitude [i - midSample] = my z [channel] [i]; } if (subtractMeanPressure) { double sum = 0.0; for (long i = leftSample; i <= rightSample; i ++) { sum += amplitude [i - midSample]; } double mean = sum / (rightSample - leftSample + 1); for (long i = leftSample; i <= rightSample; i ++) { amplitude [i - midSample] -= mean; } } for (long i = leftSample; i <= rightSample; i ++) { sumxw += amplitude [i - midSample] * amplitude [i - midSample] * window [i - midSample]; sumw += window [i - midSample]; } } intensity = sumxw / sumw; if (intensity != 0.0) intensity /= 4e-10; thy z [1] [iframe] = intensity < 1e-30 ? -300 : 10 * log10 (intensity); } return thee.transfer(); } catch (MelderError) { Melder_throw (me, ": intensity analysis not performed."); } }
autoSpectrum Sound_to_Spectrum (Sound me, int fast) { try { long numberOfSamples = my nx; const long numberOfChannels = my ny; if (fast) { numberOfSamples = 2; while (numberOfSamples < my nx) numberOfSamples *= 2; } long numberOfFrequencies = numberOfSamples / 2 + 1; // 4 samples -> cos0 cos1 sin1 cos2; 5 samples -> cos0 cos1 sin1 cos2 sin2 autoNUMvector <double> data (1, numberOfSamples); if (numberOfChannels == 1) { const double *channel = my z [1]; for (long i = 1; i <= my nx; i ++) { data [i] = channel [i]; } /* All samples from `my nx + 1` through `numberOfSamples` should be set to zero, but they are already zero. */ // so do nothing } else { for (long ichan = 1; ichan <= numberOfChannels; ichan ++) { const double *channel = my z [ichan]; for (long i = 1; i <= my nx; i ++) { data [i] += channel [i]; } } for (long i = 1; i <= my nx; i ++) { data [i] /= numberOfChannels; } } autoNUMfft_Table fourierTable; NUMfft_Table_init (& fourierTable, numberOfSamples); NUMfft_forward (& fourierTable, data.peek()); autoSpectrum thee = Spectrum_create (0.5 / my dx, numberOfFrequencies); thy dx = 1.0 / (my dx * numberOfSamples); // override double *re = thy z [1]; double *im = thy z [2]; double scaling = my dx; re [1] = data [1] * scaling; im [1] = 0.0; for (long i = 2; i < numberOfFrequencies; i ++) { re [i] = data [i + i - 2] * scaling; // data [2], data [4], ... im [i] = data [i + i - 1] * scaling; // data [3], data [5], ... } if ((numberOfSamples & 1) != 0) { if (numberOfSamples > 1) { re [numberOfFrequencies] = data [numberOfSamples - 1] * scaling; im [numberOfFrequencies] = data [numberOfSamples] * scaling; } } else { re [numberOfFrequencies] = data [numberOfSamples] * scaling; im [numberOfFrequencies] = 0.0; } return thee; } catch (MelderError) { Melder_throw (me, U": not converted to Spectrum."); } }
Ltas PointProcess_Sound_to_Ltas (PointProcess pulses, Sound sound, double maximumFrequency, double bandWidth, double shortestPeriod, double longestPeriod, double maximumPeriodFactor) { try { long numberOfPeriods = pulses -> nt - 2, totalNumberOfEnergies = 0; autoLtas ltas = Ltas_create (maximumFrequency / bandWidth, bandWidth); ltas -> xmax = maximumFrequency; autoLtas numbers = Data_copy (ltas.peek()); if (numberOfPeriods < 1) Melder_throw ("Cannot compute an Ltas if there are no periods in the point process."); autoMelderProgress progress (L"Ltas analysis..."); for (long ipulse = 2; ipulse < pulses -> nt; ipulse ++) { double leftInterval = pulses -> t [ipulse] - pulses -> t [ipulse - 1]; double rightInterval = pulses -> t [ipulse + 1] - pulses -> t [ipulse]; double intervalFactor = leftInterval > rightInterval ? leftInterval / rightInterval : rightInterval / leftInterval; Melder_progress ((double) ipulse / pulses -> nt, L"Sound & PointProcess: To Ltas: pulse ", Melder_integer (ipulse), L" out of ", Melder_integer (pulses -> nt)); if (leftInterval >= shortestPeriod && leftInterval <= longestPeriod && rightInterval >= shortestPeriod && rightInterval <= longestPeriod && intervalFactor <= maximumPeriodFactor) { /* * We have a period! Compute the spectrum. */ autoSound period = Sound_extractPart (sound, pulses -> t [ipulse] - 0.5 * leftInterval, pulses -> t [ipulse] + 0.5 * rightInterval, kSound_windowShape_RECTANGULAR, 1.0, FALSE); autoSpectrum spectrum = Sound_to_Spectrum (period.peek(), FALSE); for (long ifreq = 1; ifreq <= spectrum -> nx; ifreq ++) { double frequency = spectrum -> xmin + (ifreq - 1) * spectrum -> dx; double realPart = spectrum -> z [1] [ifreq]; double imaginaryPart = spectrum -> z [2] [ifreq]; double energy = (realPart * realPart + imaginaryPart * imaginaryPart) * 2.0 * spectrum -> dx /* OLD: * sound -> nx */; long iband = ceil (frequency / bandWidth); if (iband >= 1 && iband <= ltas -> nx) { ltas -> z [1] [iband] += energy; numbers -> z [1] [iband] += 1; totalNumberOfEnergies += 1; } } } else { numberOfPeriods -= 1; } } if (numberOfPeriods < 1) Melder_throw ("There are no periods in the point process."); for (long iband = 1; iband <= ltas -> nx; iband ++) { if (numbers -> z [1] [iband] == 0.0) { ltas -> z [1] [iband] = NUMundefined; } else { /* * Each bin now contains a total energy in Pa2 sec. * To convert this to power density, we */ double totalEnergyInThisBand = ltas -> z [1] [iband]; if (0 /* i.e. if you just want to have a spectrum of the voiced parts... */) { double energyDensityInThisBand = totalEnergyInThisBand / ltas -> dx; double powerDensityInThisBand = energyDensityInThisBand / (sound -> xmax - sound -> xmin); ltas -> z [1] [iband] = 10.0 * log10 (powerDensityInThisBand / 4.0e-10); } else { /* * And this is what we really want. The total energy has to be redistributed. */ double meanEnergyInThisBand = totalEnergyInThisBand / numbers -> z [1] [iband]; double meanNumberOfEnergiesPerBand = (double) totalNumberOfEnergies / ltas -> nx; double redistributedEnergyInThisBand = meanEnergyInThisBand * meanNumberOfEnergiesPerBand; double redistributedEnergyDensityInThisBand = redistributedEnergyInThisBand / ltas -> dx; double redistributedPowerDensityInThisBand = redistributedEnergyDensityInThisBand / (sound -> xmax - sound -> xmin); ltas -> z [1] [iband] = 10.0 * log10 (redistributedPowerDensityInThisBand / 4.0e-10); /* OLD: ltas -> z [1] [iband] = 10.0 * log10 (ltas -> z [1] [iband] / numbers -> z [1] [iband] * sound -> nx);*/ } } } for (long iband = 1; iband <= ltas -> nx; iband ++) { if (ltas -> z [1] [iband] == NUMundefined) { long ibandleft = iband - 1, ibandright = iband + 1; while (ibandleft >= 1 && ltas -> z [1] [ibandleft] == NUMundefined) ibandleft --; while (ibandright <= ltas -> nx && ltas -> z [1] [ibandright] == NUMundefined) ibandright ++; if (ibandleft < 1 && ibandright > ltas -> nx) Melder_throw ("Cannot create an Ltas without energy in any bins."); if (ibandleft < 1) { ltas -> z [1] [iband] = ltas -> z [1] [ibandright]; } else if (ibandright > ltas -> nx) { ltas -> z [1] [iband] = ltas -> z [1] [ibandleft]; } else { double frequency = ltas -> x1 + (iband - 1) * ltas -> dx; double fleft = ltas -> x1 + (ibandleft - 1) * ltas -> dx; double fright = ltas -> x1 + (ibandright - 1) * ltas -> dx; ltas -> z [1] [iband] = ((fright - frequency) * ltas -> z [1] [ibandleft] + (frequency - fleft) * ltas -> z [1] [ibandright]) / (fright - fleft); } } } return ltas.transfer(); } catch (MelderError) { Melder_throw (sound, " & ", pulses, ": LTAS analysis not performed."); } }
FeatureWeights FeatureWeights_computeWrapperExt ( /////////////////////////////// // Parameters // /////////////////////////////// KNN nn, // Classifier // Pattern pp, // test pattern // Categories c, // test categories // long k, // k(!) // int d, // distance weighting // long nseeds, // the number of seeds // double alfa, // shrinkage factor // double stop, // stop at // int mode // mode (co/serial) // ) { if (! nn) return nullptr; try { double pivot = 0.5; double range = 0.5; autoNUMvector <double> results (0L, nseeds); autoThingVector <FeatureWeights> cs (0L, nseeds); for (long y = 0; y <= nseeds; y++) { cs [y] = FeatureWeights_create (pp -> nx); } for (long x = 1; x <= pp -> nx; x ++) cs [nseeds] -> fweights -> data [1] [x] = pivot; results [nseeds] = FeatureWeights_evaluate (cs [nseeds], nn, pp, c, k, d); while (range > 0 && results [nseeds] < stop) { long best = nseeds; if (mode == 2) { for (long x = 1; x <= pp->nx; x++) { for (long y = 0; y < nseeds; y++) { cs[y]->fweights->data[1][x] = NUMrandomUniform(OlaMAX(0, cs[nseeds]->fweights->data[1][x] - range), OlaMIN(1, cs[nseeds]->fweights->data[1][x] + range)); results[y] = FeatureWeights_evaluate(cs[y], nn, pp, c, k, d); } for (long q = 0; q < nseeds; q++) if (results[q] > results[best]) best = q; if (results[best] > results[nseeds]) { for (long x = 1; x <= pp->nx; x++) cs[nseeds]->fweights->data[1][x] = cs[best]->fweights->data[1][x]; results[nseeds] = results[best]; } } } else { for (long y = 0; y < nseeds; y++) { for (long x = 1; x <= pp->nx; x++) { cs[y]->fweights->data[1][x] = NUMrandomUniform(OlaMAX(0, cs[nseeds]->fweights->data[1][x] - range), OlaMIN(1, cs[nseeds]->fweights->data[1][x] + range)); } results[y] = FeatureWeights_evaluate (cs [y], nn, pp, c, k, d); } for (long q = 0; q < nseeds; q++) if (results[q] > results[best]) best = q; if (results[best] > results[nseeds]) { for (long x = 1; x <= pp->nx; x++) cs[nseeds]->fweights->data[1][x] = cs[best]->fweights->data[1][x]; results[nseeds] = results[best]; } } range -= alfa; } FeatureWeights result = cs [nseeds]; cs [nseeds] = nullptr; // prevent destruction return result; } catch (MelderError) { Melder_throw (U"FeatureWeights: wrapper not computed."); } }
autoSound ComplexSpectrogram_to_Sound (ComplexSpectrogram me, double stretchFactor) { try { /* original number of samples is odd: imaginary part of last spectral value is zero -> * phase is either zero or +/-pi */ double pi = atan2 (0.0, - 0.5); double samplingFrequency = 2.0 * my ymax; double lastFrequency = my y1 + (my ny - 1) * my dy, lastPhase = my phase[my ny][1]; int originalNumberOfSamplesProbablyOdd = (lastPhase != 0.0 && lastPhase != pi && lastPhase != -pi) || my ymax - lastFrequency > 0.25 * my dx; if (my y1 != 0.0) { Melder_throw (U"A Fourier-transformable ComplexSpectrogram must have a first frequency of 0 Hz, not ", my y1, U" Hz."); } long nsamp_window = 2 * my ny - (originalNumberOfSamplesProbablyOdd ? 1 : 2 ); long halfnsamp_window = nsamp_window / 2; double synthesisWindowDuration = nsamp_window / samplingFrequency; autoSpectrum spectrum = Spectrum_create (my ymax, my ny); autoSound synthesisWindow = Sound_createSimple (1, synthesisWindowDuration, samplingFrequency); double newDuration = (my xmax - my xmin) * stretchFactor; autoSound thee = Sound_createSimple (1, newDuration, samplingFrequency); //TODO double thyStartTime; for (long iframe = 1; iframe <= my nx; iframe++) { // "original" sound : double tmid = Sampled_indexToX (me, iframe); long leftSample = Sampled_xToLowIndex (thee.get(), tmid); long rightSample = leftSample + 1; long startSample = rightSample - halfnsamp_window; double startTime = Sampled_indexToX (thee.get(), startSample); if (iframe == 1) { thyStartTime = Sampled_indexToX (thee.get(), startSample); } //long endSample = leftSample + halfnsamp_window; // New Sound with stretch long thyStartSample = Sampled_xToLowIndex (thee.get(),thyStartTime); double thyEndTime = thyStartTime + my dx * stretchFactor; long thyEndSample = Sampled_xToLowIndex (thee.get(), thyEndTime); long stretchedStepSizeSamples = thyEndSample - thyStartSample + 1; //double extraTime = (thyStartSample - startSample + 1) * thy dx; double extraTime = (thyStartTime - startTime); spectrum -> z[1][1] = sqrt (my z[1][iframe]); for (long ifreq = 2; ifreq <= my ny; ifreq++) { double f = my y1 + (ifreq - 1) * my dy; double a = sqrt (my z[ifreq][iframe]); double phi = my phase[ifreq][iframe], intPart; double extraPhase = 2.0 * pi * modf (extraTime * f, &intPart); // fractional part phi += extraPhase; spectrum -> z[1][ifreq] = a * cos (phi); spectrum -> z[2][ifreq] = a * sin (phi); } autoSound synthesis = Spectrum_to_Sound (spectrum.get()); // Where should the sound be placed? long thyEndSampleP = (long) floor (fmin (thyStartSample + synthesis -> nx - 1, thyStartSample + stretchedStepSizeSamples - 1)); // guard against extreme stretches if (iframe == my nx) { thyEndSampleP = (long) floor (fmin (thy nx, thyStartSample + synthesis -> nx - 1)); // ppgb: waarom naar beneden afgerond? } for (long j = thyStartSample; j <= thyEndSampleP; j++) { thy z[1][j] = synthesis -> z[1][j - thyStartSample + 1]; } thyStartTime += my dx * stretchFactor; } return thee; } catch (MelderError) { Melder_throw (me, U": no Sound created."); } }
autoSound Sound_Point_Pitch_Duration_to_Sound (Sound me, PointProcess pulses, PitchTier pitch, DurationTier duration, double maxT) { try { long ipointleft, ipointright; double deltat = 0, handledTime = my xmin; double startOfSourceNoise, endOfSourceNoise, startOfTargetNoise, endOfTargetNoise; double durationOfSourceNoise, durationOfTargetNoise; double startOfSourceVoice, endOfSourceVoice, startOfTargetVoice, endOfTargetVoice; double durationOfSourceVoice, durationOfTargetVoice; double startingPeriod, finishingPeriod, ttarget, voicelessPeriod; if (duration -> points.size == 0) Melder_throw (U"No duration points."); /* * Create a Sound long enough to hold the longest possible duration-manipulated sound. */ autoSound thee = Sound_create (1, my xmin, my xmin + 3 * (my xmax - my xmin), 3 * my nx, my dx, my x1); /* * Below, I'll abbreviate the voiced interval as "voice" and the voiceless interval as "noise". */ if (pitch && pitch -> points.size) for (ipointleft = 1; ipointleft <= pulses -> nt; ipointleft = ipointright + 1) { /* * Find the beginning of the voice. */ startOfSourceVoice = pulses -> t [ipointleft]; /* The first pulse of the voice. */ startingPeriod = 1.0 / RealTier_getValueAtTime (pitch, startOfSourceVoice); startOfSourceVoice -= 0.5 * startingPeriod; /* The first pulse is in the middle of a period. */ /* * Measure one noise. */ startOfSourceNoise = handledTime; endOfSourceNoise = startOfSourceVoice; durationOfSourceNoise = endOfSourceNoise - startOfSourceNoise; startOfTargetNoise = startOfSourceNoise + deltat; endOfTargetNoise = startOfTargetNoise + RealTier_getArea (duration, startOfSourceNoise, endOfSourceNoise); durationOfTargetNoise = endOfTargetNoise - startOfTargetNoise; /* * Copy the noise. */ voicelessPeriod = NUMrandomUniform (0.008, 0.012); ttarget = startOfTargetNoise + 0.5 * voicelessPeriod; while (ttarget < endOfTargetNoise) { double tsource; double tleft = startOfSourceNoise, tright = endOfSourceNoise; int i; for (i = 1; i <= 15; i ++) { double tsourcemid = 0.5 * (tleft + tright); double ttargetmid = startOfTargetNoise + RealTier_getArea (duration, startOfSourceNoise, tsourcemid); if (ttargetmid < ttarget) tleft = tsourcemid; else tright = tsourcemid; } tsource = 0.5 * (tleft + tright); copyBell (me, tsource, voicelessPeriod, voicelessPeriod, thee.peek(), ttarget); voicelessPeriod = NUMrandomUniform (0.008, 0.012); ttarget += voicelessPeriod; } deltat += durationOfTargetNoise - durationOfSourceNoise; /* * Find the end of the voice. */ for (ipointright = ipointleft + 1; ipointright <= pulses -> nt; ipointright ++) if (pulses -> t [ipointright] - pulses -> t [ipointright - 1] > maxT) break; ipointright --; endOfSourceVoice = pulses -> t [ipointright]; /* The last pulse of the voice. */ finishingPeriod = 1.0 / RealTier_getValueAtTime (pitch, endOfSourceVoice); endOfSourceVoice += 0.5 * finishingPeriod; /* The last pulse is in the middle of a period. */ /* * Measure one voice. */ durationOfSourceVoice = endOfSourceVoice - startOfSourceVoice; /* * This will be copied to an interval with a different location and duration. */ startOfTargetVoice = startOfSourceVoice + deltat; endOfTargetVoice = startOfTargetVoice + RealTier_getArea (duration, startOfSourceVoice, endOfSourceVoice); durationOfTargetVoice = endOfTargetVoice - startOfTargetVoice; /* * Copy the voiced part. */ ttarget = startOfTargetVoice + 0.5 * startingPeriod; while (ttarget < endOfTargetVoice) { double tsource, period; long isourcepulse; double tleft = startOfSourceVoice, tright = endOfSourceVoice; int i; for (i = 1; i <= 15; i ++) { double tsourcemid = 0.5 * (tleft + tright); double ttargetmid = startOfTargetVoice + RealTier_getArea (duration, startOfSourceVoice, tsourcemid); if (ttargetmid < ttarget) tleft = tsourcemid; else tright = tsourcemid; } tsource = 0.5 * (tleft + tright); period = 1.0 / RealTier_getValueAtTime (pitch, tsource); isourcepulse = PointProcess_getNearestIndex (pulses, tsource); copyBell2 (me, pulses, isourcepulse, period, period, thee.peek(), ttarget, maxT); ttarget += period; } deltat += durationOfTargetVoice - durationOfSourceVoice; handledTime = endOfSourceVoice; } /* * Copy the remaining unvoiced part, if we are at the end. */ startOfSourceNoise = handledTime; endOfSourceNoise = my xmax; durationOfSourceNoise = endOfSourceNoise - startOfSourceNoise; startOfTargetNoise = startOfSourceNoise + deltat; endOfTargetNoise = startOfTargetNoise + RealTier_getArea (duration, startOfSourceNoise, endOfSourceNoise); durationOfTargetNoise = endOfTargetNoise - startOfTargetNoise; voicelessPeriod = NUMrandomUniform (0.008, 0.012); ttarget = startOfTargetNoise + 0.5 * voicelessPeriod; while (ttarget < endOfTargetNoise) { double tsource; double tleft = startOfSourceNoise, tright = endOfSourceNoise; for (int i = 1; i <= 15; i ++) { double tsourcemid = 0.5 * (tleft + tright); double ttargetmid = startOfTargetNoise + RealTier_getArea (duration, startOfSourceNoise, tsourcemid); if (ttargetmid < ttarget) tleft = tsourcemid; else tright = tsourcemid; } tsource = 0.5 * (tleft + tright); copyBell (me, tsource, voicelessPeriod, voicelessPeriod, thee.peek(), ttarget); voicelessPeriod = NUMrandomUniform (0.008, 0.012); ttarget += voicelessPeriod; } /* * Find the number of trailing zeroes and hack the sound's time domain. */ thy xmax = thy xmin + RealTier_getArea (duration, my xmin, my xmax); if (fabs (thy xmax - my xmax) < 1e-12) thy xmax = my xmax; /* Common situation. */ thy nx = Sampled_xToLowIndex (thee.peek(), thy xmax); if (thy nx > 3 * my nx) thy nx = 3 * my nx; return thee; } catch (MelderError) { Melder_throw (me, U": not manipulated."); } }
CCA TableOfReal_to_CCA (TableOfReal me, long ny) { try { long n = my numberOfRows, nx = my numberOfColumns - ny; if (ny < 1 || ny > my numberOfColumns - 1) { Melder_throw (U"Dimension of first part not correct."); } if (ny > nx) Melder_throw (U"The dimension of the dependent part (", ny, U") must be less than or equal to " "the dimension of the independent part (", nx, U")."); if (n < ny) { Melder_throw (U"The number of observations must be larger then ", ny, U"."); } TableOfReal_areAllCellsDefined (me, 0, 0, 0, 0); // Use svd as (temporary) storage, and copy data autoSVD svdy = SVD_create (n, ny); autoSVD svdx = SVD_create (n, nx); for (long i = 1; i <= n; i++) { for (long j = 1; j <= ny; j++) { svdy -> u[i][j] = my data[i][j]; } for (long j = 1; j <= nx; j++) { svdx -> u[i][j] = my data[i][ny + j]; } } double **uy = svdy -> u; double **vy = svdy -> v; double **ux = svdx -> u; double **vx = svdx -> v; double fnormy = NUMfrobeniusnorm (n, ny, uy); double fnormx = NUMfrobeniusnorm (n, nx, ux); if (fnormy == 0 || fnormx == 0) { Melder_throw (U"One of the parts of the table contains only zeros."); } /* Centre the data and svd it. */ NUMcentreColumns (uy, 1, n, 1, ny, NULL); NUMcentreColumns (ux, 1, n, 1, nx, NULL); SVD_compute (svdy.peek()); SVD_compute (svdx.peek()); long numberOfZeroedy = SVD_zeroSmallSingularValues (svdy.peek(), 0); long numberOfZeroedx = SVD_zeroSmallSingularValues (svdx.peek(), 0); /* Form the matrix C = ux' uy (use svd-object storage) */ autoSVD svdc = SVD_create (nx, ny); double **uc = svdc -> u; double **vc = svdc -> v; for (long i = 1; i <= nx; i++) { for (long j = 1; j <= ny; j++) { double t = 0; for (long q = 1; q <= n; q++) { t += ux[q][i] * uy[q][j]; } uc[i][j] = t; } } SVD_compute (svdc.peek()); long numberOfZeroedc = SVD_zeroSmallSingularValues (svdc.peek(), 0); long numberOfCoefficients = ny - numberOfZeroedc; autoCCA thee = CCA_create (numberOfCoefficients, ny, nx); thy yLabels = strings_to_Strings (my columnLabels, 1, ny); thy xLabels = strings_to_Strings (my columnLabels, ny + 1, my numberOfColumns); double **evecy = thy y -> eigenvectors; double **evecx = thy x -> eigenvectors; thy numberOfObservations = n; /* Y = Vy * inv(Dy) * Vc X = Vx * inv(Dx) * Uc For the eigenvectors we want a row representation: colums(Y) = rows(Y') = rows(Vc' * inv(Dy) * Vy') colums(X) = rows(X') = rows(Uc' * inv(Dx) * Vx') rows(Y') = evecy[i][j] = Vc[k][i] * Vy[j][k] / Dy[k] rows(X') = evecx[i][j] = Uc[k][i] * Vx[j][k] / Dx[k] */ for (long i = 1; i <= numberOfCoefficients; i++) { double ccc = svdc -> d[i]; thy y -> eigenvalues[i] = thy x -> eigenvalues[i] = ccc * ccc; for (long j = 1; j <= ny; j++) { double t = 0; for (long q = 1; q <= ny - numberOfZeroedy; q++) { t += vc[q][i] * vy[j][q] / svdy -> d[q]; } evecy[i][j] = t; } for (long j = 1; j <= nx; j++) { double t = 0; for (long q = 1; q <= nx - numberOfZeroedx; q++) { t += uc[q][i] * vx[j][q] / svdx -> d[q]; } evecx[i][j] = t; } } /* Normalize eigenvectors. */ NUMnormalizeRows (thy y -> eigenvectors, numberOfCoefficients, ny, 1); NUMnormalizeRows (thy x -> eigenvectors, numberOfCoefficients, nx, 1); Melder_assert (thy x -> dimension == thy xLabels -> numberOfStrings && thy y -> dimension == thy yLabels -> numberOfStrings); return thee.transfer(); } catch (MelderError) { Melder_throw (me, U": CCA not created."); } }
Pitch Sound_to_Pitch_shs (Sound me, double timeStep, double minimumPitch, double maximumFrequency, double ceiling, long maxnSubharmonics, long maxnCandidates, double compressionFactor, long nPointsPerOctave) { try { double firstTime, newSamplingFrequency = 2 * maximumFrequency; double windowDuration = 2 / minimumPitch, halfWindow = windowDuration / 2; double atans = nPointsPerOctave * NUMlog2 (65.0 / 50.0) - 1; // Number of speech samples in the downsampled signal in each frame: // 100 for windowDuration == 0.04 and newSamplingFrequency == 2500 long nx = lround (windowDuration * newSamplingFrequency); // The minimum number of points for the fft is 256. long nfft = 1; while ( (nfft *= 2) < nx || nfft <= 128) { ; } long nfft2 = nfft / 2 + 1; double frameDuration = nfft / newSamplingFrequency; double df = newSamplingFrequency / nfft; // The number of points on the octave scale double fminl2 = NUMlog2 (minimumPitch), fmaxl2 = NUMlog2 (maximumFrequency); long nFrequencyPoints = (long) floor ((fmaxl2 - fminl2) * nPointsPerOctave); double dfl2 = (fmaxl2 - fminl2) / (nFrequencyPoints - 1); autoSound sound = Sound_resample (me, newSamplingFrequency, 50); long numberOfFrames; Sampled_shortTermAnalysis (sound.peek(), windowDuration, timeStep, &numberOfFrames, &firstTime); autoSound frame = Sound_createSimple (1, frameDuration, newSamplingFrequency); autoSound hamming = Sound_createHamming (nx / newSamplingFrequency, newSamplingFrequency); autoPitch thee = Pitch_create (my xmin, my xmax, numberOfFrames, timeStep, firstTime, ceiling, maxnCandidates); autoNUMvector<double> cc (1, numberOfFrames); autoNUMvector<double> specAmp (1, nfft2); autoNUMvector<double> fl2 (1, nfft2); autoNUMvector<double> yv2 (1, nfft2); autoNUMvector<double> arctg (1, nFrequencyPoints); autoNUMvector<double> al2 (1, nFrequencyPoints); Melder_assert (frame->nx >= nx); Melder_assert (hamming->nx == nx); // Compute the absolute value of the globally largest amplitude w.r.t. the global mean. double globalMean, globalPeak; Sound_localMean (sound.peek(), sound -> xmin, sound -> xmax, &globalMean); Sound_localPeak (sound.peek(), sound -> xmin, sound -> xmax, globalMean, &globalPeak); /* For the cubic spline interpolation we need the frequencies on an octave scale, i.e., a log2 scale. All frequencies must be DIFFERENT, otherwise the cubic spline interpolation will give corrupt results. Because log2(f==0) is not defined, we use the heuristic: f[2]-f[1] == f[3]-f[2]. */ for (long i = 2; i <= nfft2; i++) { fl2[i] = NUMlog2 ( (i - 1) * df); } fl2[1] = 2 * fl2[2] - fl2[3]; // Calculate frequencies regularly spaced on a log2-scale and // the frequency weighting function. for (long i = 1; i <= nFrequencyPoints; i++) { arctg[i] = 0.5 + atan (3 * (i - atans) / nPointsPerOctave) / NUMpi; } // Perform the analysis on all frames. for (long i = 1; i <= numberOfFrames; i++) { Pitch_Frame pitchFrame = &thy frame[i]; double hm = 1, f0, pitch_strength, localMean, localPeak; double tmid = Sampled_indexToX (thee.peek(), i); /* The center of this frame */ long nx_tmp = frame -> nx; // Copy a frame from the sound, apply a hamming window. Get local 'intensity' frame -> nx = nx; /*begin vies */ Sound_into_Sound (sound.peek(), frame.peek(), tmid - halfWindow); Sounds_multiply (frame.peek(), hamming.peek()); Sound_localMean (sound.peek(), tmid - 3 * halfWindow, tmid + 3 * halfWindow, &localMean); Sound_localPeak (sound.peek(), tmid - halfWindow, tmid + halfWindow, localMean, &localPeak); pitchFrame -> intensity = localPeak > globalPeak ? 1 : localPeak / globalPeak; frame -> nx = nx_tmp; /* einde vies */ // Get the Fourier spectrum. autoSpectrum spec = Sound_to_Spectrum (frame.peek(), 1); Melder_assert (spec->nx == nfft2); // From complex spectrum to amplitude spectrum. for (long j = 1; j <= nfft2; j++) { double rs = spec -> z[1][j], is = spec -> z[2][j]; specAmp[j] = sqrt (rs * rs + is * is); } // Enhance the peaks in the spectrum. spec_enhance_SHS (specAmp.peek(), nfft2); // Smooth the enhanced spectrum. spec_smoooth_SHS (specAmp.peek(), nfft2); // Go to a logarithmic scale and perform cubic spline interpolation to get // spectral values for the increased number of frequency points. NUMspline (fl2.peek(), specAmp.peek(), nfft2, 1e30, 1e30, yv2.peek()); for (long j = 1; j <= nFrequencyPoints; j++) { double f = fminl2 + (j - 1) * dfl2; NUMsplint (fl2.peek(), specAmp.peek(), yv2.peek(), nfft2, f, &al2[j]); } // Multiply by frequency selectivity of the auditory system. for (long j = 1; j <= nFrequencyPoints; j++) al2[j] = al2[j] > 0 ? al2[j] * arctg[j] : 0; // The subharmonic summation. Shift spectra in octaves and sum. Pitch_Frame_init (pitchFrame, maxnCandidates); autoNUMvector<double> sumspec (1, nFrequencyPoints); pitchFrame -> nCandidates = 0; /* !!!!! */ for (long m = 1; m <= maxnSubharmonics + 1; m++) { long kb = 1 + (long) floor (nPointsPerOctave * NUMlog2 (m)); for (long k = kb; k <= nFrequencyPoints; k++) { sumspec[k - kb + 1] += al2[k] * hm; } hm *= compressionFactor; } // First register the voiceless candidate (always present). Pitch_Frame_addPitch (pitchFrame, 0, 0, maxnCandidates); /* Get the best local estimates for the pitch as the maxima of the subharmonic sum spectrum by parabolic interpolation on three points: The formula for a parabole with a maximum is: y(x) = a - b (x - c)^2 with a, b, c >= 0 The three points are (-x, y1), (0, y2) and (x, y3). The solution for a (the maximum) and c (the position) is: a = (2 y1 (4 y2 + y3) - y1^2 - (y3 - 4 y2)^2)/( 8 (y1 - 2 y2 + y3) c = dx (y1 - y3) / (2 (y1 - 2 y2 + y3)) (b = (2 y2 - y1 - y3) / (2 dx^2) ) */ 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 * 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); Pitch_Frame_addPitch (pitchFrame, f, strength, maxnCandidates); } } /* Check whether f0 corresponds to an actual periodicity T = 1 / f0: correlate two signal periods of duration T, one starting at the middle of the interval and one starting T seconds before. If there is periodicity the correlation coefficient should be high. However, some sounds do not show any regularity, or very low frequency and regularity, and nevertheless have a definite pitch, e.g. Shepard sounds. */ Pitch_Frame_getPitch (pitchFrame, &f0, &pitch_strength); if (f0 > 0) { cc[i] = Sound_correlateParts (sound.peek(), tmid - 1.0 / f0, tmid, 1.0 / f0); } } // Base V/UV decision on correlation coefficients. // Resize the pitch strengths w.r.t. the cc. double vuvCriterium = 0.52; for (long i = 1; i <= numberOfFrames; i++) { Pitch_Frame_resizeStrengths (& thy frame[i], cc[i], vuvCriterium); } return thee.transfer(); } catch (MelderError) { Melder_throw (me, U": no Pitch (shs) created."); } }
Transition Distributions_to_Transition (Distributions underlying, Distributions surface, long environment, Transition adjacency, int greedy) { try { if (underlying == NULL) return NULL; /* * Preconditions: range check and matrix matching. */ if (environment < 1 || environment > underlying -> numberOfColumns) Melder_throw ("Environment (", environment, ") out of range (1-", underlying -> numberOfColumns, ")."); if (surface && (underlying -> numberOfColumns != surface -> numberOfColumns || underlying -> numberOfRows != surface -> numberOfRows)) Melder_throw ("Sizes of underlying and surface distributions do not match."); if (adjacency && adjacency -> numberOfStates != underlying -> numberOfColumns) Melder_throw ("Number of states (", adjacency -> numberOfStates, ") in adjacency matrix " "does not match number of distributions (", underlying -> numberOfColumns, ")"); /* * Defaults. */ if (surface == NULL) surface = underlying; /* * Create the output object. */ autoTransition thee = Transition_create (underlying -> numberOfColumns); /* * Copy labels and set name. */ for (long i = 1; i <= thy numberOfStates; i ++) { thy stateLabels [i] = Melder_wcsdup (underlying -> columnLabels [i]); } Thing_setName (thee.peek(), underlying -> columnLabels [environment]); /* * Compute the off-diagonal elements of the transition matrix in environment 'environment'. */ for (long i = 1; i <= thy numberOfStates; i ++) { /* * How many states are available for the learner to step to (excluding current state)? */ long numberOfAdjacentStates; if (adjacency) { numberOfAdjacentStates = 0; for (long j = 1; j <= thy numberOfStates; j ++) if (i != j && adjacency -> data [i] [j]) numberOfAdjacentStates ++; } else { numberOfAdjacentStates = thy numberOfStates - 1; } /* * Try all possible steps to adjacent states. */ for (long j = 1; j <= thy numberOfStates; j ++) if (i != j) { /* * Local: grammar step only possible to adjacent grammar. */ if (adjacency && adjacency -> data [i] [j] == 0) continue; /* * Compute element (i, j): sum over all possible data. */ for (long m = 1; m <= underlying -> numberOfRows; m ++) { /* * Error-driven: grammar step only triggered by positive evidence. * If the datum does not conflict with the current hypothesis (i), ignore it. */ if (underlying -> data [m] [i]) continue; /* * Greedy: grammar step only taken if new grammar accepts datum. */ if (greedy && underlying -> data [m] [j] == 0) continue; /* * The step is taken if this datum occurs and this grammar (j) is chosen. */ thy data [i] [j] += surface -> data [m] [environment] / numberOfAdjacentStates; } } } /* * Compute the elements on the diagonal, so that the sum of each row is unity. */ for (long i = 1; i <= thy numberOfStates; i ++) { double sum = 0.0; for (long j = 1; j <= thy numberOfStates; j ++) if (j != i) sum += thy data [i] [j]; thy data [i] [i] = sum > 1.0 ? 0.0 : 1.0 - sum; // guard against rounding errors } return thee.transfer(); } catch (MelderError) { Melder_throw (underlying, ": Transition not computed."); } }
OTGrammar OTGrammar_create_tongueRoot_grammar (int small_large, int equal_random_infant_Wolof) { try { int ncons = small_large == 1 ? 5 : 9, itab, v1, v2; autoOTGrammar me = Thing_new (OTGrammar); my constraints = NUMvector <structOTGrammarConstraint> (1, my numberOfConstraints = ncons); my constraints [1]. name = Melder_dup (U"*[rtr / hi]"); my constraints [2]. name = Melder_dup (U"*[atr / lo]"); my constraints [3]. name = Melder_dup (U"P\\s{ARSE}\n(rtr)"); my constraints [4]. name = Melder_dup (U"P\\s{ARSE}\n(atr)"); my constraints [5]. name = Melder_dup (U"*G\\s{ESTURE}\n(contour)"); if (ncons == 9) { my constraints [6]. name = Melder_dup (U"*[rtr / mid]"); my constraints [7]. name = Melder_dup (U"*[rtr / lo]"); my constraints [8]. name = Melder_dup (U"*[atr / mid]"); my constraints [9]. name = Melder_dup (U"*[atr / hi]"); } if (equal_random_infant_Wolof == 1) { // equal? for (long icons = 1; icons <= ncons; icons ++) my constraints [icons]. ranking = 100.0; } else if (equal_random_infant_Wolof == 2) { // random? for (long icons = 1; icons <= ncons; icons ++) my constraints [icons]. ranking = NUMrandomGauss (100.0, 10.0); } else if (equal_random_infant_Wolof == 3) { // infant (= cannot speak) ? for (long icons = 1; icons <= ncons; icons ++) my constraints [icons]. ranking = 100.0; // structural constraints my constraints [3]. ranking = 50.0; // faithfulness constraints my constraints [4]. ranking = 50.0; } else { // adult Wolof my constraints [1]. ranking = 100.0; my constraints [2]. ranking = 10.0; my constraints [3]. ranking = 50.0; my constraints [4]. ranking = 20.0; my constraints [5]. ranking = 30.0; if (ncons == 9) { my constraints [6]. ranking = 0.0; my constraints [7]. ranking = -10.0; my constraints [8]. ranking = 0.0; my constraints [9]. ranking = -10.0; } } if (ncons == 9) { my fixedRankings = NUMvector <structOTGrammarFixedRanking> (1, my numberOfFixedRankings = 4); my fixedRankings [1]. higher = 1, my fixedRankings [1]. lower = 6; my fixedRankings [2]. higher = 6, my fixedRankings [2]. lower = 7; my fixedRankings [3]. higher = 2, my fixedRankings [3]. lower = 8; my fixedRankings [4]. higher = 8, my fixedRankings [4]. lower = 9; } my tableaus = NUMvector <structOTGrammarTableau> (1, my numberOfTableaus = 36); itab = 1; for (v1 = 0; v1 < 6; v1 ++) for (v2 = 0; v2 < 6; v2 ++) { OTGrammarTableau tableau = & my tableaus [itab]; tableau -> input = Melder_dup (Melder_cat (vowels [v1], U"t", vowels [v2])); tableau -> candidates = NUMvector <structOTGrammarCandidate> (1, tableau -> numberOfCandidates = 4); /* * Generate the four tongue-root variants as output candidates. */ OTGrammarCandidate_init (& tableau -> candidates [1], ncons, v1, v2); /* Faithful: no PARSE constraints violated. */ OTGrammarCandidate_init (& tableau -> candidates [2], ncons, fliptr (v1), v2); /* First vowel flipped: violated one PARSE constraint. */ OTGrammarCandidate_init (& tableau -> candidates [3], ncons, v1, fliptr (v2)); /* Second vowel flipped. */ OTGrammarCandidate_init (& tableau -> candidates [4], ncons, fliptr (v1), fliptr (v2)); /* Both vowels flipped. */ /* * Count PARSE violations. */ if (isatr (v1)) { tableau -> candidates [2]. marks [4] ++; tableau -> candidates [4]. marks [4] ++; } else { tableau -> candidates [2]. marks [3] ++; tableau -> candidates [4]. marks [3] ++; } if (isatr (v2)) { tableau -> candidates [3]. marks [4] ++; tableau -> candidates [4]. marks [4] ++; } else { tableau -> candidates [3]. marks [3] ++; tableau -> candidates [4]. marks [3] ++; } itab ++; } OTGrammar_checkIndex (me.peek()); OTGrammar_newDisharmonies (me.peek(), 0.0); for (long icons = 1; icons <= my numberOfConstraints; icons ++) my constraints [icons]. plasticity = 1.0; return me.transfer(); } catch (MelderError) { Melder_throw (U"Tongue root grammar not created."); } }
static autoStrings Strings_createAsFileOrDirectoryList (const char32 *path /* cattable */, int type) { #if USE_STAT /* * Initialize. */ DIR *d = nullptr; try { autoMelderString filePath, searchDirectory, left, right; /* * Parse the path. * Example: in /Users/paul/sounds/h*.wav", * the search directory is "/Users/paul/sounds", * the left environment is "h", and the right environment is ".wav". */ MelderString_copy (& searchDirectory, path); char32 *asterisk = str32rchr (searchDirectory. string, '*'); if (asterisk) { *asterisk = '\0'; searchDirectory. length = asterisk - searchDirectory. string; // probably superfluous, but correct char32 *lastSlash = str32rchr (searchDirectory. string, Melder_DIRECTORY_SEPARATOR); if (lastSlash) { *lastSlash = '\0'; // This fixes searchDirectory. searchDirectory. length = lastSlash - searchDirectory. string; // probably superfluous, but correct MelderString_copy (& left, lastSlash + 1); } else { MelderString_copy (& left, searchDirectory. string); // quickly save... MelderString_empty (& searchDirectory); // ...before destruction } MelderString_copy (& right, asterisk + 1); } char buffer8 [kMelder_MAXPATH+1]; Melder_str32To8bitFileRepresentation_inline (searchDirectory. string, buffer8); d = opendir (buffer8 [0] ? buffer8 : "."); if (! d) Melder_throw (U"Cannot open directory ", searchDirectory. string, U"."); //Melder_casual (U"opened"); autoStrings me = Thing_new (Strings); my strings = NUMvector <char32 *> (1, 1000000); struct dirent *entry; while (!! (entry = readdir (d))) { MelderString_copy (& filePath, searchDirectory. string [0] ? searchDirectory. string : U"."); MelderString_appendCharacter (& filePath, Melder_DIRECTORY_SEPARATOR); char32 buffer32 [kMelder_MAXPATH+1]; Melder_8bitFileRepresentationToStr32_inline (entry -> d_name, buffer32); MelderString_append (& filePath, buffer32); //Melder_casual (U"read ", filePath. string); Melder_str32To8bitFileRepresentation_inline (filePath. string, buffer8); struct stat stats; if (stat (buffer8, & stats) != 0) { //Melder_throw (U"Cannot look at file ", filePath. string, U"."); //stats. st_mode = -1L; } //Melder_casual (U"statted ", filePath. string); //Melder_casual (U"file ", filePath. string, U" mode ", stats. st_mode / 4096); if ((type == Strings_createAsFileOrDirectoryList_TYPE_FILE && S_ISREG (stats. st_mode)) || (type == Strings_createAsFileOrDirectoryList_TYPE_DIRECTORY && S_ISDIR (stats. st_mode))) { Melder_8bitFileRepresentationToStr32_inline (entry -> d_name, buffer32); int64 length = str32len (buffer32); if (buffer32 [0] != U'.' && (left. length == 0 || str32nequ (buffer32, left. string, left. length)) && (right. length == 0 || (length >= right. length && str32equ (buffer32 + (length - right. length), right. string)))) { my strings [++ my numberOfStrings] = Melder_dup (buffer32); } } } closedir (d); Strings_sort (me.get()); return me; } catch (MelderError) { if (d) closedir (d); // "finally" throw; } #elif defined (_WIN32) try { char32 searchPath [kMelder_MAXPATH+1]; int len = str32len (path); bool hasAsterisk = !! str32chr (path, U'*'); bool endsInSeparator = ( len != 0 && path [len - 1] == U'\\' ); autoStrings me = Thing_new (Strings); my strings = NUMvector <char32 *> (1, 1000000); Melder_sprint (searchPath, kMelder_MAXPATH+1, path, hasAsterisk || endsInSeparator ? U"" : U"\\", hasAsterisk ? U"" : U"*"); WIN32_FIND_DATAW findData; HANDLE searchHandle = FindFirstFileW (Melder_peek32toW (searchPath), & findData); if (searchHandle != INVALID_HANDLE_VALUE) { do { if ((type == Strings_createAsFileOrDirectoryList_TYPE_FILE && (findData. dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) || (type == Strings_createAsFileOrDirectoryList_TYPE_DIRECTORY && (findData. dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)) { if (findData. cFileName [0] != L'.') { my strings [++ my numberOfStrings] = Melder_dup (Melder_peekWto32 (findData. cFileName)); } } } while (FindNextFileW (searchHandle, & findData)); FindClose (searchHandle); } Strings_sort (me.get()); return me; } catch (MelderError) { throw; } #endif }
Sound PointProcess_to_Sound_phonation (PointProcess me, double samplingFrequency, double adaptFactor, double maximumPeriod, double openPhase, double collisionPhase, double power1, double power2) { 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; double a = (power1 + power2 + 1.0) / (power2 - power1); double re = openPhase - collisionPhase; autoSound thee = Sound_create (1, my xmin, my xmax, sound_nt, dt, t1); /* * Compute "re" by iteration. */ if (collisionPhase <= 0.0) { re = openPhase; } else { double xmaxFlow = pow (power1 / power2, 1.0 / (power2 - power1)); double xleft = xmaxFlow; double gleft = pow (xleft, power1) - pow (xleft, power2); double gderivleft = power1 * pow (xleft, power1 - 1.0) - power2 * pow (xleft, power2 - 1.0); double fleft = - gleft / gderivleft; double xright = 1.0; double gright = pow (xright, power1) - pow (xright, power2); double gderivright = power1 * pow (xright, power1 - 1.0) - power2 * pow (xright, power2 - 1.0); double fright = - gright / gderivright; for (int i = 1; i <= 50; i ++) { double xmid = 0.5 * (xleft + xright); double gmid = pow (xmid, power1) - pow (xmid, power2); double gderivmid = power1 * pow (xmid, power1 - 1.0) - power2 * pow (xmid, power2 - 1.0); double fmid = - gmid / gderivmid; if (fmid > collisionPhase / openPhase) { xleft = xmid; fleft = fmid; } else { xright = xmid; fright = fmid; } re = xmid * openPhase; } } /* * Cycle through the points. Each will become a period. */ double *sound = thy z [1]; for (long it = 1; it <= my nt; it ++) { double t = my t [it], amplitude = a; double period = NUMundefined, te, phase, flow; long midSample = Sampled_xToNearestIndex (thee.peek(), t); /* * Determine the period: first look left (because that's where the open phase is), * then right. */ if (it >= 2) { period = my t [it] - my t [it - 1]; if (period > maximumPeriod) { period = NUMundefined; } } if (period == NUMundefined) { if (it < my nt) { period = my t [it + 1] - my t [it]; if (period > maximumPeriod) { period = NUMundefined; } } if (period == NUMundefined) { period = 0.5 * maximumPeriod; /* Some default value. */ } } te = re * period; /* * Determine the amplitude of this peak. */ amplitude /= period * openPhase; if (it == 1 || my t [it - 1] < my t [it] - maximumPeriod) { amplitude *= adaptFactor * adaptFactor; } else if (it == 2 || my t [it - 2] < my t [it - 1] - maximumPeriod) { amplitude *= adaptFactor; } /* * Fill in the samples to the left of the current point. */ {// scope long beginSample = midSample - floor (te / thy dx); if (beginSample < 1) beginSample = 1; long endSample = midSample; if (endSample > thy nx) endSample = thy nx; for (long isamp = beginSample; isamp <= endSample; isamp ++) { double tsamp = thy x1 + (isamp - 1) * thy dx; phase = (tsamp - (t - te)) / (period * openPhase); if (phase > 0.0) sound [isamp] += amplitude * (power1 * pow (phase, power1 - 1.0) - power2 * pow (phase, power2 - 1.0)); } } /* * Determine the signal parameters at the current point. */ phase = te / (period * openPhase); flow = amplitude * (period * openPhase) * (pow (phase, power1) - pow (phase, power2)); /* * Fill in the samples to the right of the current point. */ if (flow > 0.0) { double flowDerivative = amplitude * (power1 * pow (phase, power1 - 1.0) - power2 * pow (phase, power2 - 1.0)); double ta = - flow / flowDerivative; double factorPerSample = exp (- thy dx / ta); double value = flowDerivative * factorPerSample; long beginSample = midSample + 1; if (beginSample < 1) beginSample = 1; long endSample = midSample + floor (20 * ta / thy dx); if (endSample > thy nx) endSample = thy nx; for (long isamp = beginSample; isamp <= endSample; isamp ++) { sound [isamp] += value; value *= factorPerSample; } } } Vector_scale (thee.peek(), 0.9); return thee.transfer(); } catch (MelderError) { Melder_throw (me, ": not converted to Sound (phonation)."); } }
/* This routine is modeled after qdiag.m from Andreas Ziehe, Pavel Laskov, Guido Nolte, Klaus-Robert Müller, A Fast Algorithm for Joint Diagonalization with Non-orthogonal Transformations and its Application to Blind Source Separation, Journal of Machine Learning Research 5 (2004), 777–800. */ static void Diagonalizer_and_CrossCorrelationTables_ffdiag (Diagonalizer me, CrossCorrelationTables thee, long maxNumberOfIterations, double delta) { try { long iter = 0, dimension = my numberOfRows; double **v = my data; autoCrossCorrelationTables ccts = CrossCorrelationTables_and_Diagonalizer_diagonalize (thee, me); autoNUMmatrix<double> w (1, dimension, 1, dimension); autoNUMmatrix<double> vnew (1, dimension, 1, dimension); autoNUMmatrix<double> cc (1, dimension, 1, dimension); for (long i = 1; i <= dimension; i++) { w[i][i] = 1; } autoMelderProgress progress (L"Simultaneous diagonalization of many CrossCorrelationTables..."); double dm_new = CrossCorrelationTables_getDiagonalityMeasure (ccts.peek(), NULL, 0, 0); try { double dm_old, theta = 1, dm_start = dm_new; do { dm_old = dm_new; for (long i = 1; i <= dimension; i++) { for (long j = i + 1; j <= dimension; j++) { double zii = 0, zij = 0, zjj = 0, yij = 0, yji = 0; // zij = zji for (long k = 1; k <= ccts -> size; k++) { CrossCorrelationTable ct = (CrossCorrelationTable) ccts -> item [k]; zii += ct -> data[i][i] * ct -> data[i][i]; zij += ct -> data[i][i] * ct -> data[j][j]; zjj += ct -> data[j][j] * ct -> data[j][j]; yij += ct -> data[j][j] * ct -> data[i][j]; yji += ct -> data[i][i] * ct -> data[i][j]; } double denom = zjj * zii - zij * zij; if (denom != 0) { w[i][j] = (zij * yji - zii * yij) / denom; w[j][i] = (zij * yij - zjj * yji) / denom; } } } double norma = 0; for (long i = 1; i <= dimension; i++) { double normai = 0; for (long j = 1; j <= dimension; j++) { if (i != j) { normai += fabs (w[i][j]); } } if (normai > norma) { norma = normai; } } // evaluate the norm if (norma > theta) { double normf = 0; for (long i = 1; i <= dimension; i++) for (long j = 1; j <= dimension; j++) if (i != j) { normf += w[i][j] * w[i][j]; } double scalef = theta / sqrt (normf); for (long i = 1; i <= dimension; i++) { for (long j = 1; j <= dimension; j++) { if (i != j) { w[i][j] *= scalef; } } } } // update V NUMmatrix_copyElements (v, vnew.peek(), 1, dimension, 1, dimension); NUMdmatrices_multiply_VC (v, w.peek(), dimension, dimension, vnew.peek(), dimension); for (long k = 1; k <= ccts -> size; k++) { CrossCorrelationTable ct = (CrossCorrelationTable) ccts -> item[k]; NUMmatrix_copyElements (ct -> data, cc.peek(), 1, dimension, 1, dimension); NUMdmatrices_multiply_VCVp (ct -> data, w.peek(), dimension, dimension, cc.peek(), 1); } dm_new = CrossCorrelationTables_getDiagonalityMeasure (ccts.peek(), 0, 0, 0); iter++; Melder_progress ((double) iter / (double) maxNumberOfIterations, L"Iteration: ", Melder_integer (iter), L", measure: ", Melder_double (dm_new), L"\n fractional measure: ", Melder_double (dm_new / dm_start)); } while (fabs ((dm_old - dm_new) / dm_new) > delta && iter < maxNumberOfIterations); } catch (MelderError) { Melder_clearError (); } } catch (MelderError) { Melder_throw (me, " & ", thee, ": no joint diagonalization (ffdiag)."); } }
LPC LPC_and_Sound_to_LPC_robust (LPC thee, Sound me, double analysisWidth, double preEmphasisFrequency, double k, int itermax, double tol, int wantlocation) { struct huber_struct struct_huber = { 0 }; try { double t1, samplingFrequency = 1.0 / my dx, tol_svd = 0.000001; double location = 0, windowDuration = 2 * analysisWidth; /* Gaussian window */ long nFrames, frameErrorCount = 0, iter = 0; long p = thy maxnCoefficients; if (my xmin != thy xmin || my xmax != thy xmax) { Melder_throw ("Time domains differ."); } if (my dx != thy samplingPeriod) { Melder_throw ("Sampling intervals differ."); } if (floor (windowDuration / my dx) < p + 1) { Melder_throw ("Analysis window too short."); } Sampled_shortTermAnalysis (me, windowDuration, thy dx, & nFrames, & t1); if (nFrames != thy nx || t1 != thy x1) { Melder_throw ("Incorrect retrieved analysis width"); } autoSound sound = Data_copy (me); autoSound sframe = Sound_createSimple (1, windowDuration, samplingFrequency); autoSound window = Sound_createGaussian (windowDuration, samplingFrequency); autoLPC him = Data_copy (thee); huber_struct_init (&struct_huber, windowDuration, p, samplingFrequency, location, wantlocation); struct_huber.k = k; struct_huber.tol = tol; struct_huber.tol_svd = tol_svd; struct_huber.itermax = itermax; autoMelderProgress progess (L"LPC analysis"); Sound_preEmphasis (sound.peek(), preEmphasisFrequency); for (long i = 1; i <= nFrames; i++) { LPC_Frame lpc = (LPC_Frame) & thy d_frames[i]; LPC_Frame lpcto = (LPC_Frame) & his d_frames[i]; double t = Sampled_indexToX (thee, i); Sound_into_Sound (sound.peek(), sframe.peek(), t - windowDuration / 2); Vector_subtractMean (sframe.peek()); Sounds_multiply (sframe.peek(), window.peek()); try { LPC_Frames_and_Sound_huber (lpc, sframe.peek(), lpcto, & struct_huber); } catch (MelderError) { frameErrorCount++; } iter += struct_huber.iter; if ( (i % 10) == 1) { Melder_progress ( (double) i / nFrames, L"LPC analysis of frame ", Melder_integer (i), L" out of ", Melder_integer (nFrames), L"."); } } if (frameErrorCount) Melder_warning (L"Results of ", Melder_integer (frameErrorCount), L" frame(s) out of ", Melder_integer (nFrames), L" could not be optimised."); MelderInfo_writeLine4 (L"Number of iterations: ", Melder_integer (iter), L"\n Average per frame: ", Melder_double (((double) iter) / nFrames)); huber_struct_destroy (&struct_huber); return him.transfer(); } catch (MelderError) { huber_struct_destroy (&struct_huber); Melder_throw (me, ": no robust LPC created."); } }
void LPC_Frame_into_Spectrum (LPC_Frame me, Spectrum thee, double bandwidthReduction, double deEmphasisFrequency) { if (my nCoefficients == 0) { for (long i = 1; i <= thy nx; i++) { thy z[1][i] = thy z[2][i] = 0; } return; } // When deEmphasisFrequency is effective we need 1 extra position in the fftbuffer. long nfft = 2 * (thy nx - 1), ndata = my nCoefficients + 1; double scale = 1.0 / sqrt (2 * thy xmax * thy dx); if (ndata >= nfft - 1 && (deEmphasisFrequency < thy xmax || ndata > nfft)) { Melder_throw (U"Spectrum size not large enough."); } autoNUMvector<double> fftbuffer (1, nfft); // Copy 1, a[1], ... a[p] into fftbuffer fftbuffer[1] = 1; for (long i = 2; i <= ndata; i++) { fftbuffer[i] = my a[i - 1]; } if (deEmphasisFrequency < thy xmax) { // Multiply (1, a[1] z^-1, ... a[p] z^-p) by (1 - b z^-1) double b = exp (- 2.0 * NUMpi * deEmphasisFrequency / thy xmax); ndata ++; for (long i = ndata; i > 1; i--) { fftbuffer[i] -= b * fftbuffer[i - 1]; } } /* Calculate sum (k=0..ndata; a[k] (z)^-k) along a contour with radius r: sum (k=0..ndata; a[k] (rz)^-k) = sum (k=0..ndata; (a[k]r^-k) z^-k) */ double g = exp (NUMpi * bandwidthReduction / (thy dx * nfft)); /* r = 1/g */ for (long i = 2; i <= ndata; i++) { fftbuffer[i] *= pow (g, i - 1); } /* Perform the fft. The LPC spectrum is obtained by inverting this spectrum. The imaginary parts of the frequencies 0 and Nyquist are 0. */ NUMforwardRealFastFourierTransform (fftbuffer.peek(), nfft); if (my gain > 0) { scale *= sqrt (my gain); } thy z[1][1] = scale / fftbuffer[1]; thy z[2][1] = 0; for (long i = 2; i <= nfft / 2; i++) { // We use: 1 / (a + ib) = (a - ib) / (a^2 + b^2) double re = fftbuffer[i + i - 1], im = fftbuffer[i + i]; double invSquared = scale / (re * re + im * im); thy z[1][i] = re * invSquared; thy z[2][i] = -im * invSquared; } thy z[1][thy nx] = scale / fftbuffer[2]; thy z[2][thy nx] = 0; }
void EditDistanceTable_findPath (EditDistanceTable me, TableOfReal *directions) { try { /* What do we have to do to source to get target? * Origin [0][0] is at bottom-left corner * Target vertical, source horizontal * Going in the vertical direction is a deletion, horizontal is insertion, diagonal is substitution */ long numberOfSources = my numberOfColumns - 1, numberOfTargets = my numberOfRows - 1; autoNUMmatrix<short> psi (0, numberOfTargets, 0, numberOfSources); autoNUMmatrix<double> delta (0, numberOfTargets, 0, numberOfSources); for (long j = 1; j <= numberOfSources; j++) { delta[0][j] = delta[0][j - 1] + EditCostsTable_getDeletionCost (my editCostsTable, my columnLabels[j+1]); psi[0][j] = WARPING_fromLeft; } for (long i = 1; i <= numberOfTargets; i++) { delta[i][0] = delta[i - 1][0] + EditCostsTable_getInsertionCost (my editCostsTable, my rowLabels[i+1]); psi[i][0] = WARPING_fromBelow; } for (long j = 1; j <= numberOfSources; j++) { for (long i = 1; i <= numberOfTargets; i++) { // the substitution, deletion and insertion costs. double left = delta[i][j - 1] + EditCostsTable_getInsertionCost (my editCostsTable, my rowLabels[i+1]); double bottom = delta[i - 1][j] + EditCostsTable_getDeletionCost (my editCostsTable, my columnLabels[j+1]); double mindist = delta[i - 1][j - 1] + EditCostsTable_getSubstitutionCost (my editCostsTable, my rowLabels[i+1], my columnLabels[j+1]); // diag psi[i][j] = WARPING_fromDiag; if (bottom < mindist) { mindist = bottom; psi[i][j] = WARPING_fromBelow; } if (left < mindist) { mindist = left; psi[i][j] = WARPING_fromLeft; } delta[i][j] = mindist; } } // find minimum distance in last column long iy = numberOfTargets, ix = numberOfSources; WarpingPath_reset (my warpingPath); WarpingPath_getPath (my warpingPath, psi.peek(), iy, ix); WarpingPath_shiftPathByOne (my warpingPath); for (long i = 0; i <= numberOfTargets; i++) { for (long j = 0; j <= numberOfSources; j++) { my data[i+1][j+1] = delta[i][j]; } } if (directions != 0) { autoTableOfReal him = EditDistanceTable_to_TableOfReal (me); for (long i = 0; i <= numberOfTargets; i++) { for (long j = 0; j <= numberOfSources; j++) { his data[i+1][j+1] = psi[i][j]; } } *directions = him.transfer(); } } catch (MelderError) { Melder_throw (me, ": minimum path not found."); } }
void Data_writeBinary (Daata me, FILE *f) { my v_writeBinary (f); if (ferror (f)) Melder_throw (U"I/O error."); }
static void menu_cb_getJitter_ddp (PointEditor me, EDITOR_ARGS_DIRECT) { if (my d_startSelection == my d_endSelection) Melder_throw (U"To measure jitter, make a selection first."); Melder_informationReal (PointProcess_getJitter_ddp ((PointProcess) my data, my d_startSelection, my d_endSelection, 1e-4, 0.02, 1.3), nullptr); }
void Pitch_pathFinder (Pitch me, double silenceThreshold, double voicingThreshold, double octaveCost, double octaveJumpCost, double voicedUnvoicedCost, double ceiling, int pullFormants) { if (Melder_debug == 33) Melder_casual ("Pitch path finder:\nSilence threshold = %g\nVoicing threshold = %g\nOctave cost = %g\nOctave jump cost = %g\n" "Voiced/unvoiced cost = %g\nCeiling = %g\nPull formants = %d", silenceThreshold, voicingThreshold, octaveCost, octaveJumpCost, voicedUnvoicedCost, ceiling, pullFormants); try { long maxnCandidates = Pitch_getMaxnCandidates (me); long place; volatile double maximum, value; double ceiling2 = pullFormants ? 2 * ceiling : ceiling; /* Next three lines 20011015 */ double timeStepCorrection = 0.01 / my dx; octaveJumpCost *= timeStepCorrection; voicedUnvoicedCost *= timeStepCorrection; my ceiling = ceiling; autoNUMmatrix <double> delta (1, my nx, 1, maxnCandidates); autoNUMmatrix <long> psi (1, my nx, 1, maxnCandidates); for (long iframe = 1; iframe <= my nx; iframe ++) { Pitch_Frame frame = & my frame [iframe]; double unvoicedStrength = silenceThreshold <= 0 ? 0 : 2 - frame->intensity / (silenceThreshold / (1 + voicingThreshold)); unvoicedStrength = voicingThreshold + (unvoicedStrength > 0 ? unvoicedStrength : 0); for (long icand = 1; icand <= frame->nCandidates; icand ++) { Pitch_Candidate candidate = & frame->candidate [icand]; int voiceless = candidate->frequency == 0 || candidate->frequency > ceiling2; delta [iframe] [icand] = voiceless ? unvoicedStrength : candidate->strength - octaveCost * NUMlog2 (ceiling / candidate->frequency); } } /* Look for the most probable path through the maxima. */ /* There is a cost for the voiced/unvoiced transition, */ /* and a cost for a frequency jump. */ for (long iframe = 2; iframe <= my nx; iframe ++) { Pitch_Frame prevFrame = & my frame [iframe - 1], curFrame = & my frame [iframe]; double *prevDelta = delta [iframe - 1], *curDelta = delta [iframe]; long *curPsi = psi [iframe]; for (long icand2 = 1; icand2 <= curFrame -> nCandidates; icand2 ++) { double f2 = curFrame -> candidate [icand2]. frequency; maximum = -1e30; place = 0; for (long icand1 = 1; icand1 <= prevFrame -> nCandidates; icand1 ++) { double f1 = prevFrame -> candidate [icand1]. frequency; double transitionCost; bool previousVoiceless = f1 <= 0 || f1 >= ceiling2; bool currentVoiceless = f2 <= 0 || f2 >= ceiling2; if (currentVoiceless) { if (previousVoiceless) { transitionCost = 0; // both voiceless } else { transitionCost = voicedUnvoicedCost; // voiced-to-unvoiced transition } } else { if (previousVoiceless) { transitionCost = voicedUnvoicedCost; // unvoiced-to-voiced transition if (Melder_debug == 30) { /* * Try to take into account a frequency jump across a voiceless stretch. */ long place1 = icand1; for (long jframe = iframe - 2; jframe >= 1; jframe --) { place1 = psi [jframe + 1] [place1]; f1 = my frame [jframe]. candidate [place1]. frequency; if (f1 > 0 && f1 < ceiling) { transitionCost += octaveJumpCost * fabs (NUMlog2 (f1 / f2)) / (iframe - jframe); break; } } } } else { transitionCost = octaveJumpCost * fabs (NUMlog2 (f1 / f2)); // both voiced } } value = prevDelta [icand1] - transitionCost + curDelta [icand2]; //if (Melder_debug == 33) Melder_casual ("Frame %ld, current candidate %ld (delta %g), previous candidate %ld (delta %g), " // "transition cost %g, value %g, maximum %g", iframe, icand2, curDelta [icand2], icand1, prevDelta [icand1], transitionCost, value, maximum); if (value > maximum) { maximum = value; place = icand1; } else if (value == maximum) { if (Melder_debug == 33) Melder_casual ("A tie in frame %ld, current candidate %ld, previous candidate %ld", iframe, icand2, icand1); } } curDelta [icand2] = maximum; curPsi [icand2] = place; } } /* Find the end of the most probable path. */ place = 1; maximum = delta [my nx] [place]; for (long icand = 2; icand <= my frame [my nx]. nCandidates; icand ++) { if (delta [my nx] [icand] > maximum) { place = icand; maximum = delta [my nx] [place]; } } /* Backtracking: follow the path backwards. */ for (long iframe = my nx; iframe >= 1; iframe --) { if (Melder_debug == 33) Melder_casual ("Frame %ld: swapping candidates 1 and %ld", iframe, place); Pitch_Frame frame = & my frame [iframe]; structPitch_Candidate help = frame -> candidate [1]; frame -> candidate [1] = frame -> candidate [place]; frame -> candidate [place] = help; place = psi [iframe] [place]; // This assignment is challenging to CodeWarrior 11. } /* Pull formants: devoice frames with frequencies between ceiling and ceiling2. */ if (ceiling2 > ceiling) { if (Melder_debug == 33) Melder_casual ("Pulling formants..."); for (long iframe = my nx; iframe >= 1; iframe --) { Pitch_Frame frame = & my frame [iframe]; Pitch_Candidate winner = & frame -> candidate [1]; double f = winner -> frequency; if (f > ceiling && f <= ceiling2) { for (long icand = 2; icand <= frame -> nCandidates; icand ++) { Pitch_Candidate loser = & frame -> candidate [icand]; if (loser -> frequency == 0.0) { structPitch_Candidate help = * winner; * winner = * loser; * loser = help; break; } } } } } } catch (MelderError) { Melder_throw (me, ": path not found."); } }
static void menu_cb_getShimmer_dda (PointEditor me, EDITOR_ARGS_DIRECT) { if (my d_startSelection == my d_endSelection) Melder_throw (U"To measure shimmer, make a selection first."); Melder_informationReal (PointProcess_Sound_getShimmer_dda ((PointProcess) my data, my d_sound.data, my d_startSelection, my d_endSelection, 1e-4, 0.02, 1.3, 1.6), nullptr); }
// Cut parts from me marked by labels in thee autoIntervalTier IntervalTier_and_IntervalTier_cutPartsMatchingLabel (IntervalTier me, IntervalTier thee, const char32 *label, double precision) { try { if (my xmin != thy xmin || my xmax != thy xmax) { Melder_throw (U"Domains must be equal."); } autoNUMvector<double> durations (1, my intervals.size); for (long i = 1; i <= my intervals.size; i ++) { TextInterval ti = my intervals.at [i]; durations[i] = ti -> xmax - ti -> xmin; } long myInterval = 1; for (long j = 1; j <= thy intervals.size; j ++) { TextInterval cut = thy intervals.at [j]; if (Melder_equ (cut -> text, label)) { // trim while (myInterval <= my intervals.size) { TextInterval ti = my intervals.at [myInterval]; if (ti -> xmin > cut -> xmin - precision && ti -> xmax < cut -> xmax + precision) { // 1. interval completely within cut durations[myInterval] = 0; myInterval++; } else if (ti -> xmin < cut -> xmin + precision && cut -> xmin < ti -> xmax + precision) { // 2. cut start is within interval if (cut -> xmax > ti -> xmax - precision) { // interval end is in cut, interval start before durations[myInterval] -= ti -> xmax - cut -> xmin; myInterval++; } else { // 3. cut completely within interval durations[myInterval] -= cut -> xmax - cut -> xmin; break; } } else if (cut -> xmax > ti -> xmin - precision && cut -> xmin < ti -> xmax + precision) { // +1+2 : cut end is within interval, cut start before durations[myInterval] -= cut -> xmax - ti -> xmin; break; } else if (ti -> xmax < cut -> xmin + precision) { myInterval++; } } } } double totalDuration = 0; for (long i = 1; i <= my intervals.size; i ++) { if (durations[i] < precision) { durations[i] = 0; } totalDuration += durations[i]; } autoIntervalTier him = IntervalTier_create (0, totalDuration); double time = 0; long hisInterval = 1; for (long i = 1; i <= my intervals.size; i ++) { if (durations[i] <= 0) continue; TextInterval ti = my intervals.at [i]; time += durations[i]; if (fabs (time - totalDuration) > precision) { IntervalTier_splitInterval (him.peek(), time, ti -> text, hisInterval, precision); hisInterval++; } else { // last interval TextInterval histi = his intervals.at [hisInterval]; TextInterval_setText (histi, ti -> text); } } return him; } catch (MelderError) { Melder_throw (me, U": parts not cut."); } }
autoPowerCepstrogram Sound_to_PowerCepstrogram_hillenbrand (Sound me, double minimumPitch, double dt) { try { // minimum analysis window has 3 periods of lowest pitch double analysisWidth = 3 / minimumPitch; if (analysisWidth > my dx * my nx) { analysisWidth = my dx * my nx; } double samplingFrequency = 1.0 / my dx; autoSound thee; if (samplingFrequency > 30000) { samplingFrequency = samplingFrequency / 2.0; thee = Sound_resample (me, samplingFrequency, 1); } else { thee = Data_copy (me); } // pre-emphasis with fixed coefficient 0.9 for (long i = thy nx; i > 1; i--) { thy z[1][i] -= 0.9 * thy z[1][i - 1]; } long nosInWindow = (long) floor (analysisWidth * samplingFrequency), nFrames; if (nosInWindow < 8) { Melder_throw (U"Analysis window too short."); } double t1; Sampled_shortTermAnalysis (thee.get(), analysisWidth, dt, & nFrames, & t1); autoNUMvector<double> hamming (1, nosInWindow); for (long i = 1; i <= nosInWindow; i++) { hamming[i] = 0.54 -0.46 * cos(2 * NUMpi * (i - 1) / (nosInWindow - 1)); } long nfft = 8; // minimum possible while (nfft < nosInWindow) { nfft *= 2; } long nfftdiv2 = nfft / 2; autoNUMvector<double> fftbuf (1, nfft); // "complex" array autoNUMvector<double> spectrum (1, nfftdiv2 + 1); // +1 needed autoNUMfft_Table fftTable; NUMfft_Table_init (&fftTable, nfft); // sound to spectrum double qmax = 0.5 * nfft / samplingFrequency, dq = qmax / (nfftdiv2 + 1); autoPowerCepstrogram him = PowerCepstrogram_create (my xmin, my xmax, nFrames, dt, t1, 0, qmax, nfftdiv2+1, dq, 0); autoMelderProgress progress (U"Cepstrogram analysis"); for (long iframe = 1; iframe <= nFrames; iframe++) { double tbegin = t1 + (iframe - 1) * dt - analysisWidth / 2; tbegin = tbegin < thy xmin ? thy xmin : tbegin; long istart = Sampled_xToLowIndex (thee.get(), tbegin); // ppgb: afronding naar beneden? istart = istart < 1 ? 1 : istart; long iend = istart + nosInWindow - 1; iend = iend > thy nx ? thy nx : iend; for (long i = 1; i <= nosInWindow; i++) { fftbuf[i] = thy z[1][istart + i - 1] * hamming[i]; } for (long i = nosInWindow + 1; i <= nfft; i++) { fftbuf[i] = 0; } NUMfft_forward (&fftTable, fftbuf.peek()); complexfftoutput_to_power (fftbuf.peek(), nfft, spectrum.peek(), true); // log10(|fft|^2) // subtract average double specmean = spectrum[1]; for (long i = 2; i <= nfftdiv2 + 1; i++) { specmean += spectrum[i]; } specmean /= nfftdiv2 + 1; for (long i = 1; i <= nfftdiv2 + 1; i++) { spectrum[i] -= specmean; } /* * Here we diverge from Hillenbrand as he takes the fft of half of the spectral values. * H. forgets that the actual spectrum has nfft/2+1 values. Thefore, we take the inverse * transform because this keeps the number of samples a power of 2. * At the same time this results in twice as many numbers in the quefrency domain, i.e. we end up with nfft/2+1 * numbers while H. has only nfft/4! */ fftbuf[1] = spectrum[1]; for (long i = 2; i < nfftdiv2 + 1; i++) { fftbuf[i+i-2] = spectrum[i]; fftbuf[i+i-1] = 0; } fftbuf[nfft] = spectrum[nfftdiv2 + 1]; NUMfft_backward (&fftTable, fftbuf.peek()); for (long i = 1; i <= nfftdiv2 + 1; i++) { his z[i][iframe] = fftbuf[i] * fftbuf[i]; } if ((iframe % 10) == 1) { Melder_progress ((double) iframe / nFrames, U"Cepstrogram analysis of frame ", iframe, U" out of ", nFrames, U"."); } } return him; } catch (MelderError) { Melder_throw (me, U": no Cepstrogram created."); } }