简体   繁体   中英

Replicate Wave file using Naudio - Copy/Append Latest Available bytes

I have an Active wave recording wave-file.wav happening to the Source folder. I need to replicate this file to Destination folder with a new name wave-file-copy.wav .

The recording and replication should happen in parallel. I have implemented a scheduled job, which will run in every 10 minutes and copy the source file to destination .

private static void CopyWaveFile(string destinationFile, string sourceFile){
        using (var fs = File.Open(sourceFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)){
            using (var reader = new WaveFileReader(fs)){
                using (var writer = new WaveFileWriter(destinationFile, reader.WaveFormat)){
                    reader.Position = 0;
                    var endPos = (int)reader.Length;
                    var buffer = new byte[1024];
                    while (reader.Position < endPos){
                        var bytesRequired = (int)(endPos - reader.Position);
                        if (bytesRequired <= 0) continue;
                        var bytesToRead = Math.Min(bytesRequired, buffer.Length);
                        var bytesRead = reader.Read(buffer, 0, bytesToRead);
                        if (bytesRead > 0){
                            writer.Write(buffer, 0, bytesRead);
                        }
                    }
                }
            }
        }
    }

The copy operation is working fine, even though the source file is being updated continuously.

Time taken for the copy operation is increasing in linear time, because i am copying the entire file every time.

I am trying to implement a new function ConcatenateWavFiles() , which should update the content of destination file, with the latest available bytes of source recording.

I have tried few sample codes - the approach i am using is :

  1. Read destination file meta info, and get the length.
  2. Set the length of destination file as reader.Position of source file waveReader
  3. Read the source file till end, starting from position.

     public static void ConcatenateWavFiles(string destinationFile, string sourceFile){ WaveFileWriter waveFileWriter = null; var sourceReadOffset = GetWaveFileSize(destinationFile); try{ using (var fs = File.Open(sourceFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { using (var reader = new WaveFileReader(fs)) { waveFileWriter = new WaveFileWriter(destinationFile, reader.WaveFormat); if (!reader.WaveFormat.Equals(waveFileWriter.WaveFormat)){ throw new InvalidOperationException( "Can't append WAV Files that don't share the same format"); } var startPos = sourceReadOffset - sourceReadOffset % reader.WaveFormat.BlockAlign; var endPos = (int) reader.Length; reader.Position = startPos; var bytesRequired = (int)(endPos - reader.Position); var buffer = new byte[bytesRequired]; if (bytesRequired > 0) { var bytesToRead = Math.Min(bytesRequired, buffer.Length); var bytesRead = reader.Read(buffer, 0, bytesToRead); if (bytesRead > 0) { waveFileWriter.Write(buffer, startPos, bytesRead); } } } } } finally{ if (waveFileWriter != null){ waveFileWriter.Dispose(); } } } 

I was able to get the new content.

Is it possible to append the latest content to existing destination file?

If possible what am I doing wrong in the code?

My code throws the following exception - Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection.

I couldn't find a solution to wave audio file replication with NAudio Library.

But I have implemented a solution using C# MemoryStreams and FileStreams.

  1. Copy the Source file to destination, if destination file doesn't exist.
  2. Append all the latest bytes (recorded after the last operation) to the destination file.
  3. Modify the Wave File Header to to reflect the last appended bytes. (Else the duration of the file will not be updated, only the file size will increase.
  4. Repeat this append operation in regular intervals.

     public void ReplicateFile(string destinationFile, string sourceFile){ if (!Directory.Exists(GetRoutePathFromFile(sourceFile))) return; if (!File.Exists(sourceFile)) return; if (Directory.Exists(GetRoutePathFromFile(destinationFile))){ if (File.Exists(destinationFile)){ UpdateLatestWaveFileContent(destinationFile, sourceFile); }else{ CopyWaveFile(destinationFile, sourceFile); } }else{ Directory.CreateDirectory(GetRoutePathFromFile(destinationFile)); CopyWaveFile(destinationFile, sourceFile); } } private static string GetRoutePathFromFile(string file){ var rootPath = Directory.GetParent(file); return rootPath.FullName; } private static void CopyWaveFile(string destination, string source){ var sourceMemoryStream = new MemoryStream(); using (var fs = File.Open(source, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)){ fs.CopyTo(sourceMemoryStream); } using (var fs = new FileStream(destination, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.ReadWrite)){ sourceMemoryStream.WriteTo(fs); } } private static void UpdateLatestWaveFileContent(string destinationFile, string sourceFile){ var sourceMemoryStream = new MemoryStream(); long offset = 0; using (var fs = File.Open(destinationFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)){ offset = fs.Length; } using (var fs = File.Open(sourceFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)){ fs.CopyTo(sourceMemoryStream); } var length = sourceMemoryStream.Length - offset; var buffer = sourceMemoryStream.GetBuffer(); using (var fs = new FileStream(destinationFile, FileMode.Append, FileAccess.Write, FileShare.ReadWrite)){ fs.Write(buffer, (int)offset, (int)length); } var bytes = new byte[45]; for (var i = 0; i < 45; i++){ bytes[i] = buffer[i]; } ModifyHeaderDataLength(destinationFile, 0, bytes); } private static void ModifyHeaderDataLength(string filename, int position, byte[] data){ using (Stream stream = File.Open(filename, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite)) { stream.Position = position; stream.Write(data, 0, data.Length); } } 

Try Reading the Source File one or two Wav blocks prior to the actual end of the source file.

The case could be that the code is judging the end of the source file too close for comfort.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM