Exemple #1
0
static void LongSound_init (LongSound me, MelderFile file) {
	MelderFile_copy (file, & my file);
	MelderFile_open (file);   // BUG: should be auto, but that requires an implemented .transfer()
	my f = file -> filePointer;
	my audioFileType = MelderFile_checkSoundFile (file, & my numberOfChannels, & my encoding, & my sampleRate, & my startOfData, & my nx);
	if (my audioFileType == 0)
		Melder_throw (U"File not recognized (LongSound only supports AIFF, AIFC, WAV, NeXT/Sun, NIST and FLAC).");
	if (my encoding == Melder_SHORTEN || my encoding == Melder_POLYPHONE)
		Melder_throw (U"LongSound does not support sound files compressed with \"shorten\".");
	if (my nx < 1)
		Melder_throw (U"Audio file contains 0 samples.");
	my xmin = 0.0;
	my dx = 1 / my sampleRate;
	my xmax = my nx * my dx;
	my x1 = 0.5 * my dx;
	my numberOfBytesPerSamplePoint = Melder_bytesPerSamplePoint (my encoding);
	my bufferLength = prefs_bufferLength;
	for (;;) {
		my nmax = my bufferLength * my numberOfChannels * my sampleRate * (1 + 3 * MARGIN);
		try {
			my buffer = NUMvector <int16> (0, my nmax * my numberOfChannels);
			break;
		} catch (MelderError) {
			my bufferLength *= 0.5;   // try 30, 15, or 7.5 seconds
			if (my bufferLength < 5.0)   // too short to be good
				throw;
			Melder_clearError ();   // delete out-of-memory message
		}
	}
	my imin = 1;
	my imax = 0;
	my flacDecoder = nullptr;
	if (my audioFileType == Melder_FLAC) {
		my flacDecoder = FLAC__stream_decoder_new ();
		FLAC__stream_decoder_init_FILE (my flacDecoder, my f, _LongSound_FLAC_write, nullptr, _LongSound_FLAC_error, me);
	}
	my mp3f = nullptr;
	if (my audioFileType == Melder_MP3) {
		my mp3f = mp3f_new ();
		mp3f_set_file (my mp3f, my f);
		mp3f_set_callback (my mp3f, _LongSound_MP3_convert, me);
		if (! mp3f_analyze (my mp3f))
			Melder_throw (U"Unable to analyze MP3 file.");
		Melder_warning (U"Time measurements in MP3 files can be off by several tens of milliseconds. "
			U"Please convert to WAV file if you need time precision or annotation.");
	}
}
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;
	}
}