|
-
Mar 20th, 2013, 05:47 AM
#1
Thread Starter
Fanatic Member
[RESOLVED] Concatenate .wav files via byte array
I want to concatenate two .wav files. The file format for a .wav is bytes 0 to 39 file details, bytes 40 to 43 length of the data chunk, 44 onwards is the data.
The method I have chosen is:
1. load two wavs as byte arrays (byt1 and byt2)
2. copy the header from byt1 and store it
3. copy the data portion of byt1 to another byte array (finalData)
4. copy the data from byt2 and add it to the end if FinalData.
5. Create a final finished byte array representation of the wav (Output)
6. Copy the previously saved header to Output.
7. store the length of FinalData.
8. Add FinalData to the end of Output
9. Convert the previously saved length (int32=4 bytes) to byte array
10. Overwrite bytes 40-43 of Output with the new length
11. Save the final file to disk.
When I run the program, there are no errors until it tries to play the file, then it says the header is corrupt. Since both wav files are created in exactly the same way, things like sample rate etc are the same, the only thing that should change is the length and therefore I should have no problem retaining the information in the header. Giving a corrupt header error probably means that the length is wrong but I have checked and checked and can't find a mistake in my maths.
this is my first foray into Byte arrays so I need another pair of more experienced eyes to look over my code please.
vb.net Code:
Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
Dim Byt1() As Byte = IO.File.ReadAllBytes("h.wav")
Dim Byt2() As Byte = IO.File.ReadAllBytes("e.wav")
Join(Byt1, Byt2)
Byt1 = IO.File.ReadAllBytes("temp.wav")
Byt2 = IO.File.ReadAllBytes("l.wav")
Join(Byt1, Byt2)
Byt1 = IO.File.ReadAllBytes("temp.wav")
Byt2 = IO.File.ReadAllBytes("ow.wav")
Join(Byt1, Byt2)
Dim snd As New System.Media.SoundPlayer("temp.wav")
snd.Play()
End Sub
Private Sub Join(ByRef byt1() As Byte, byt2() As Byte)
Dim Lgth As Integer
Dim SaveHeader(43) As Byte
'Save the header
System.Array.Copy(Byt1, 0, SaveHeader, 0, 43)
Dim FinalData(byt1.Length - 44) As Byte
'Save the data from the first file
System.Array.Copy(Byt1, 44, FinalData, 0, Byt1.Length - 44)
'Save the data from the second file
ReDim Preserve FinalData(byt1.Length + byt2.Length - 44)
System.Array.Copy(byt2, 44, FinalData, byt1.Length - 44, byt2.Length - 44)
'save length of new data
Lgth = FinalData.Length
'create array to hold final output
Dim Output() As Byte
ReDim Output(FinalData.Length + 43)
'add header
System.Array.Copy(SaveHeader, Output, 43)
'add data
System.Array.Copy(FinalData, 0, Output, 44, FinalData.Length)
'adjust data length
Dim bytes() As Byte = BitConverter.GetBytes(Lgth)
System.Array.Copy(bytes, 0, Output, 40, 4)
ByteArrayToFile("temp.wav", Output)
End Sub
' <summary>
' Function to save byte array to a file
' </summary>
' <param name="_FileName">File name to save byte array</param>
' <param name="_ByteArray">Byte array to save to external file</param>
' <returns>Return true if byte array save successfully, if not return false</returns>
Public Sub ByteArrayToFile(ByVal _FileName As String, ByVal _ByteArray() As Byte)
Try
'Dim myInt As Int32
'myint = BitConverter.ToInt32(_ByteArray, 40)
'MsgBox("Length of file " & BitConverter.ToString(BitConverter.GetBytes(_ByteArray.Length)) & ". Length stored in header " & BitConverter.ToString(BitConverter.GetBytes(myInt)))
'' Open file for readin
Dim _FileStream As New System.IO.FileStream(_FileName, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write)
' Writes a block of bytes to this stream using data from a byte array.
_FileStream.Write(_ByteArray, 0, _ByteArray.Length)
' close file stream
_FileStream.Close()
Catch _Exception As Exception
' Error
Console.WriteLine("Exception caught in process: {0}", _Exception.ToString())
End Try
' error occured, return false
End Sub
Last edited by Españolita; Mar 20th, 2013 at 05:51 AM.
-
Mar 20th, 2013, 10:20 AM
#2
Re: Concatenate .wav files via byte array
Hey Españolita,
I think you may have a couple of problems there.
You seem to be doing what I typically do; getting confused over array upper bounds and array lengths. By this I mean that an array with a Length of 44 (44 elements) has an upper bound of 43 (the highest index value you can access). Zero indexing can be a pain in the bum at times. 
Also, looking at the .wav format as explained here, I think you may need to alter two length fields in the final file Header (at offsets 4 and 40).
So your join sub should look like:
Code:
Private Sub Join(ByRef byt1() As Byte, byt2() As Byte)
Dim Lgth As Integer
Dim SaveHeader(43) As Byte
'Save the header
System.Array.Copy(byt1, 0, SaveHeader, 0, 44)
Dim FinalData(byt1.Length - 44 - 1) As Byte
'Save the data from the first file
System.Array.Copy(byt1, 44, FinalData, 0, byt1.Length - 44)
'Save the data from the second file
ReDim Preserve FinalData(byt1.Length - 44 + byt2.Length - 44 - 1)
System.Array.Copy(byt2, 44, FinalData, byt1.Length - 44, byt2.Length - 44)
'save length of new data
Lgth = FinalData.Length
'create array to hold final output
Dim Output() As Byte
ReDim Output(FinalData.Length + 44 - 1)
'add header
System.Array.Copy(SaveHeader, Output, 44)
'add data
System.Array.Copy(FinalData, 0, Output, 44, FinalData.Length)
Dim bytes() As Byte
'adjust data length (Subchunk2Size)
bytes = BitConverter.GetBytes(Lgth)
System.Array.Copy(bytes, 0, Output, 40, 4)
'adjust data length (ChunkSize)
bytes = BitConverter.GetBytes(Lgth + 36)
System.Array.Copy(bytes, 0, Output, 4, 4)
ByteArrayToFile("temp.wav", Output)
End Sub
That said, would you not consider using Lists, (and also avoid writing temporary files)?
vb.net Code:
Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click Dim wav1 As List(Of Byte) = IO.File.ReadAllBytes("h.wav").ToList Dim wav2 As List(Of Byte) = IO.File.ReadAllBytes("e.wav").ToList wav1 = Join(wav1, wav2) wav1 = Join(wav1, IO.File.ReadAllBytes("l.wav").ToList) wav1 = Join(wav1, IO.File.ReadAllBytes("ow.wav").ToList) File.WriteAllBytes("test.wav", wav1.ToArray) Dim snd As New System.Media.SoundPlayer("test.wav") snd.Play() End Sub Private Function Join(ByVal wavBytes As List(Of Byte), ByVal wav2 As List(Of Byte)) As List(Of Byte) ' add on the second file excluding its header bytes wavBytes.AddRange(wav2.Skip(44).Take(wav2.Count - 44)) ' rewrite the ChunkSize and Subchunk2Size fields of the Header Dim chunkSize As Integer = wavBytes.Count - 8 Dim subChunk2Size As Integer = wavBytes.Count - 44 Dim chunkSizeBytes() As Byte = BitConverter.GetBytes(chunkSize) Dim subChunk2SizeBytes() As Byte = BitConverter.GetBytes(subChunk2Size) For i = 0 To 3 wavBytes(4 + i) = chunkSizeBytes(i) wavBytes(40 + i) = subChunk2SizeBytes(i) Next Return wavBytes End Function
You could also avoid saving the combined .wav to file by replacing
Code:
File.WriteAllBytes("test.wav", wav1.ToArray)
Dim snd As New System.Media.SoundPlayer("test.wav")
snd.Play()
with
Code:
Using ms As New MemoryStream(wav1.ToArray)
Using snd As New System.Media.SoundPlayer(ms)
snd.Play()
End Using
End Using
Last edited by Inferrd; Mar 20th, 2013 at 10:25 AM.
-
Mar 20th, 2013, 01:48 PM
#3
Thread Starter
Fanatic Member
Re: Concatenate .wav files via byte array
What an absolute star!!! Thank you so much. After creating this thread, I saw another which mentioned using lists and it was on my "Upgrade list" after I got the basics of this sorted out. You were absolutely right about confusing UpperBounds and Array Lengths. I'm afraid I simply copied and pasted your code and it works brilliantly. But rest assured, I will analyse the code because that first part (chunks length at index 4) really confuses me.
Also you must be a mindreader, because that last little bit about playing directly from memory was also on my "Upgrade list". This is my first foray into this kind of thing and I found it a bit overwhelming.
I would have given you some more rep but I need to spread it around a bit first 
-
Oct 17th, 2014, 10:17 AM
#4
Registered User
Re: Concatenate .wav files via byte array
 Originally Posted by Españolita
What an absolute star!!! Thank you so much. After creating this thread, I saw another which mentioned using lists and it was on my "Upgrade list" after I got the basics of this sorted out. You were absolutely right about confusing UpperBounds and Array Lengths. I'm afraid I simply copied and pasted your code and it works brilliantly. But rest assured, I will analyse the code because that first part (chunks length at index 4) really confuses me.
Also you must be a mindreader, because that last little bit about playing directly from memory was also on my "Upgrade list". This is my first foray into this kind of thing and I found it a bit overwhelming.
I would have given you some more rep but I need to spread it around a bit first  
I have set of wav files in a folder with different length. I want to join as single file. kindly provide code for this
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|