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; } }