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; } }
void LongSound_concatenate (SoundAndLongSoundList me, MelderFile file, int audioFileType, int numberOfBitsPerSamplePoint) { try { long sampleRate, n; /* Integer sampling frequencies only, because of possible rounding errors. */ int numberOfChannels; if (my size < 1) Melder_throw (U"No Sound or LongSound objects to concatenate."); /* * The sampling frequencies and numbers of channels must be equal for all (long)sounds. */ Sampled data = my at [1]; if (data -> classInfo == classSound) { Sound sound = (Sound) data; sampleRate = lround (1.0 / sound -> dx); numberOfChannels = sound -> ny; n = sound -> nx; } else { LongSound longSound = (LongSound) data; sampleRate = longSound -> sampleRate; numberOfChannels = longSound -> numberOfChannels; n = longSound -> nx; } /* * Check whether all the sampling frequencies and channels match. */ for (long i = 2; i <= my size; i ++) { int sampleRatesMatch, numbersOfChannelsMatch; data = my at [i]; if (data -> classInfo == classSound) { Sound sound = (Sound) data; sampleRatesMatch = round (1.0 / sound -> dx) == sampleRate; numbersOfChannelsMatch = sound -> ny == numberOfChannels; n += sound -> nx; } else { LongSound longSound = (LongSound) data; sampleRatesMatch = longSound -> sampleRate == sampleRate; numbersOfChannelsMatch = longSound -> numberOfChannels == numberOfChannels; n += longSound -> nx; } if (! sampleRatesMatch) Melder_throw (U"Sampling frequencies are not equal."); if (! numbersOfChannelsMatch) Melder_throw (U"Cannot mix stereo and mono."); } /* * Create output file and write header. */ autoMelderFile mfile = MelderFile_create (file); if (file -> filePointer) { MelderFile_writeAudioFileHeader (file, audioFileType, sampleRate, n, numberOfChannels, numberOfBitsPerSamplePoint); } for (long i = 1; i <= my size; i ++) { data = my at [i]; if (data -> classInfo == classSound) { Sound sound = (Sound) data; if (file -> filePointer) { MelderFile_writeFloatToAudio (file, sound -> ny, Melder_defaultAudioFileEncoding (audioFileType, numberOfBitsPerSamplePoint), sound -> z, sound -> nx, true); } } else { LongSound longSound = (LongSound) data; writePartToOpenFile (longSound, audioFileType, 1, longSound -> nx, file, 0, numberOfBitsPerSamplePoint); } } MelderFile_writeAudioFileTrailer (file, audioFileType, sampleRate, n, numberOfChannels, numberOfBitsPerSamplePoint); mfile.close (); } catch (MelderError) { Melder_throw (U"Sounds not concatenated and not saved to ", file, U"."); } }