/*
	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
}
Exemple #2
0
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);
}
Exemple #3
0
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);
}
Exemple #4
0
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 ();
	}
}
Exemple #5
0
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);
}
Exemple #6
0
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".");
	}
}