/* BSD systems provide ftruncate, several others supply chsize, and a few may provide a (possibly undocumented) fcntl option F_FREESP. Under MS-DOS, you can sometimes use write(fd, "", 0). However, there is no portable solution, nor a way to delete blocks at the beginning. */ static void MelderFile_truncate (MelderFile me, long size) { #if defined(_WIN32) HANDLE hFile; DWORD fdwAccess = GENERIC_READ | GENERIC_WRITE, fPos; DWORD fdwShareMode = 0; /* File cannot be shared */ LPSECURITY_ATTRIBUTES lpsa = NULL; DWORD fdwCreate = OPEN_EXISTING; LARGE_INTEGER fileSize; MelderFile_close (me); hFile = CreateFileW (my path, fdwAccess, fdwShareMode, lpsa, fdwCreate, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { Melder_throw ("Can't open file ", MelderFile_messageName (me), "."); } // Set current file pointer to position 'size' fileSize.LowPart = size; fileSize.HighPart = 0; /* Limit the file size to 2^32 - 2 bytes */ fPos = SetFilePointer (hFile, fileSize.LowPart, &fileSize.HighPart, FILE_BEGIN); if (fPos == 0xFFFFFFFF) { Melder_throw ("Can't set the position at size ", size, "for file ", MelderFile_messageName (me), "."); } // Limit the file size as the current position of the file pointer. SetEndOfFile (hFile); CloseHandle (hFile); #elif defined(linux) || defined(macintosh) MelderFile_close (me); if (truncate (Melder_peekWcsToUtf8 (my path), size) == -1) Melder_throw ("Truncating failed for file ", MelderFile_messageName (me), " (", Melder_peekUtf8ToWcs (strerror (errno)), ")."); #else Melder_throw ("Don't know what to do."); #endif }
void structScriptEditor :: v_nameChanged () { bool dirtinessAlreadyShown = GuiWindow_setDirty (d_windowForm, dirty); static MelderString buffer { 0 }; MelderString_copy (& buffer, name [0] ? U"Script" : U"untitled script"); if (editorClass) MelderString_append (& buffer, U" [", environmentName, U"]"); if (name [0]) MelderString_append (& buffer, U" ", MelderFile_messageName (& file)); if (dirty && ! dirtinessAlreadyShown) MelderString_append (& buffer, U" (modified)"); GuiShell_setTitle (d_windowForm, buffer.string); }
void structScriptEditor :: v_nameChanged () { bool dirtinessAlreadyShown = d_windowForm -> f_setDirty (dirty); static MelderString buffer = { 0 }; MelderString_copy (& buffer, name [0] ? L"Script" : L"untitled script"); if (editorClass) MelderString_append (& buffer, L" [", environmentName, L"]"); if (name [0]) MelderString_append (& buffer, L" ", MelderFile_messageName (& file)); if (dirty && ! dirtinessAlreadyShown) MelderString_append (& buffer, L" (modified)"); d_windowForm -> f_setTitle (buffer.string); }
void structTextEditor :: v_nameChanged () { if (v_fileBased ()) { bool dirtinessAlreadyShown = GuiWindow_setDirty (our d_windowForm, our dirty); static MelderString windowTitle { 0 }; if (our name [0] == U'\0') { MelderString_copy (& windowTitle, U"(untitled"); if (dirty && ! dirtinessAlreadyShown) MelderString_append (& windowTitle, U", modified"); MelderString_append (& windowTitle, U")"); } else { MelderString_copy (& windowTitle, U"File ", MelderFile_messageName (& our file)); if (dirty && ! dirtinessAlreadyShown) MelderString_append (& windowTitle, U" (modified)"); } GuiShell_setTitle (our d_windowForm, windowTitle.string); //MelderString_copy (& windowTitle, our dirty && ! dirtinessAlreadyShown ? U"*" : U"", our name [0] == U'\0' ? U"(untitled)" : MelderFile_name (& our file)); } else { TextEditor_Parent :: v_nameChanged (); } }
void UiOutfile::do_ (const wchar_t *defaultName) { wchar_t *outfileName = GuiFileSelect_getOutfileName (NULL, _name, defaultName); if (outfileName == NULL) return; // cancelled if (_allowExecutionHook && ! _allowExecutionHook (_allowExecutionClosure)) { Melder_flushError ("Dialog `%s' cancelled.", _name); return; } Melder_pathToFile (outfileName, & _file); structMelderFile file; MelderFile_copy (& _file, & file); // save, because okCallback could destroy me UiForm::history.write (L"\n"); UiForm::history.write (_invokingButtonTitle); if (! _okCallback (this, NULL, NULL, _invokingButtonTitle, false, _okClosure)) { Melder_error3 (L"File ", MelderFile_messageName (& file), L" not finished."); Melder_flushError (NULL); } UiForm::history.write (L" "); UiForm::history.write (outfileName); Melder_free (outfileName); }
void UiInfile::do_ () { SortedSetOfString infileNames = GuiFileSelect_getInfileNames (_parent, _name, _allowMultipleFiles); if (infileNames == NULL) { Melder_flushError (NULL); return; } for (long ifile = 1; ifile <= infileNames -> size; ifile ++) { SimpleString infileName = (structSimpleString*)infileNames -> item [ifile]; Melder_pathToFile (infileName -> string, & _file); UiForm::history.write (L"\n"); UiForm::history.write (_invokingButtonTitle); UiForm::history.write (L" "); UiForm::history.write (infileName -> string); structMelderFile file; MelderFile_copy (& _file, & file); if (! _okCallback (this, NULL, NULL, _invokingButtonTitle, false, _okClosure)) { Melder_error3 (L"File ", MelderFile_messageName (& file), L" not finished."); Melder_flushError (NULL); } } forget (infileNames); }
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, U"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 (U"Incorrect number of items."); } if (it1 < 0 || it2 <= it1) { Melder_throw (U"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 (U"File \"", MelderFile_messageName (file), U"\": Start time set to previous end " U"time for label at line ", linesRead, U"."); } // standard: new TextInterval const char *labelstring = (strncmp (label, "h#", 2) ? label : TIMIT_DELIMITER); IntervalTier_add (timit, xmin, xmax, Melder_peek8to32 (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 (U"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(), U"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_peek8to32 (timitLabelToIpaLabel (Melder_peek32to8 (interval -> text)))); } Collection_addItem (my tiers, ipa.transfer()); // Then: add to collection Thing_setName (timit, U"phn"); // rename wrd } f.close (file); return me.transfer(); } catch (MelderError) { Melder_throw (U"TextGrid not read from file ", file, U"."); } }
void LongSounds_appendToExistingSoundFile (Collection me, MelderFile file) { long pre_append_endpos = 0, numberOfBitsPerSamplePoint = 16; try { if (my size < 1) { Melder_throw ("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, numberOfSamples; int numberOfChannels, encoding; int audioFileType = MelderFile_checkSoundFile (file, &numberOfChannels, &encoding, &sampleRate_d, &startOfData, &numberOfSamples); if (audioFileType == 0) { Melder_throw ("Not a sound file."); } // Check whether all the sample rates and channels match. long sampleRate = 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 ("Sample rates do not match."); } if (! numbersOfChannelsMatch) { Melder_throw ("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 ("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 ("File ", MelderFile_messageName (file), L" restored to original size (", strerror (error), ")."); } throw; } }
autoMatrix Matrix_readFromIDXFormatFile (MelderFile file) { /* From: http://yann.lecun.com/exdb/mnist/ The IDX file format is a simple format for vectors and multidimensional matrices of various numerical types. The basic format is magic number size in dimension 0 size in dimension 1 size in dimension 2 .... size in dimension N data The magic number is an integer (MSB first). The first 2 bytes are always 0. The third byte codes the type of the data: 0x08: unsigned byte 0x09: signed byte 0x0B: short (2 bytes) 0x0C: int (4 bytes) 0x0D: float (4 bytes) 0x0E: double (8 bytes) The 4-th byte codes the number of dimensions of the vector/matrix: 1 for vectors, 2 for matrices.... The sizes in each dimension are 4-byte integers (MSB first, big endian, like in most non-Intel processors). The data is stored like in a C array, i.e. the index in the last dimension changes the fastest. */ try { autofile f = Melder_fopen (file, "r"); unsigned int b1 = bingetu1 (f); // 0 unsigned int b2 = bingetu1 (f); // 0 if (b1 != 0 || b2 != 0) { Melder_throw (U"Starting two bytes should be zero."); } unsigned int b3 = bingetu1 (f); // data type unsigned int b4 = bingetu1 (f); // number of dimensions long ncols = bingeti32 (f), nrows = 1; // ok if vector if (b4 > 1) { nrows = ncols; ncols = bingeti32 (f); } while (b4 > 2) { // accumulate all other dimensions in the columns long n2 = bingeti32 (f); ncols *= n2; // put the matrix in one row -- b4; } autoMatrix me = Matrix_create (0.0, ncols, ncols, 1, 0.5, 0, nrows, nrows, 1.0, 0.5); if (b3 == 0x08) { // unsigned byte for (long irow = 1; irow <= nrows; irow ++) { for (long icol = 1; icol <= ncols; icol ++) { my z [irow] [icol] = bingetu1 (f); } } } else if (b3 == 0x09) { // signed byte for (long irow = 1; irow <= nrows; irow ++) { for (long icol = 1; icol <= ncols; icol ++) { my z [irow] [icol] = bingeti1 (f); } } } else if (b3 == 0x0B) { // short (2 bytes) for (long irow = 1; irow <= nrows; irow ++) { for (long icol = 1; icol <= ncols; icol ++) { my z [irow] [icol] = bingeti2 (f); } } } else if (b3 == 0x0C) { // int (4 bytes) for (long irow = 1; irow <= nrows; irow ++) { for (long icol = 1; icol <= ncols; icol ++) { my z [irow] [icol] = bingeti32 (f); } } } else if (b3 == 0x0D) { // float (4 bytes) for (long irow = 1; irow <= nrows; irow ++) { for (long icol = 1; icol <= ncols; icol ++) { my z [irow] [icol] = bingetr4 (f); } } } else if (b3 == 0x0E) { // double (8 bytes) for (long irow = 1; irow <= nrows; irow ++) { for (long icol = 1; icol <= ncols; icol ++) { my z [irow] [icol] = bingetr8 (f); } } } else { Melder_throw (U"Not a valid data type."); } f.close (file); return me; } catch (MelderError) { Melder_throw (U"Cannot read from IDX format file ", MelderFile_messageName (file), U"."); } }