Reading 24-bit samples from a .WAV file

I understand how to read 8-bit, 16-bit and 32-bit samples (PCM and floating point) from a .wav file, because (conveniently) .Net Framework has a built-in integral type for these exact sizes. But I do not know how to read (and store) 24-bit (3 bytes) samples.

How can I read 24-bit sound? Maybe somehow I can change my current method (below) to read 32-bit sound to solve my problem?

 private List<float> Read32BitSamples(FileStream stream, int sampleStartIndex, int sampleEndIndex) { var samples = new List<float>(); var bytes = ReadChannelBytes(stream, Channels.Left, sampleStartIndex, sampleEndIndex); // Reads bytes of a single channel. if (audioFormat == WavFormat.PCM) // audioFormat determines whether to process sample bytes as PCM or floating point. { for (var i = 0; i < bytes.Length / 4; i++) { samples.Add(BitConverter.ToInt32(bytes, i * 4) / 2147483648f); } } else { for (var i = 0; i < bytes.Length / 4; i++) { samples.Add(BitConverter.ToSingle(bytes, i * 4)); } } return samples; } 
+6
source share
1 answer

Reading (and saving) 24-bit samples is very simple. Now, as you rightly said, the 3-byte integral type does not exist within the framework, which means that you are left with two options; either create your own type, or you can put your 24-bit samples by inserting an empty byte ( 0 ) at the beginning of your array of sample bytes, resulting in 32-bit samples (so you can use int to store / manipulate them ) A.

I will explain and demonstrate how to do this later (which is also, in my opinion, a simpler approach).


First we need to see how the 24-bit sample will be stored in int ,

~ ~ ~ ~ ~ ~ ~ ~ ~ ~ MSB ~ ~ 2 nd MSB ~ ~ 2 nd LSB ~ ~ LSB ~ ~

24-bit sample: 11001101 01101001 01011100 00000000

32-bit sample: 11001101 01101001 01011100 00101001

MSB = Most significant byte, LSB = Lest Signal Byte.

As you can see, the LSB of the 24-bit pattern is 0 , so all you need to do is declare a byte[] with 4 elements and then read 3 bytes of the pattern into an array (starting at element 1 ) so that your array looks lower (actually a bit moves 8 places to the left),

myArray [0]: 00000000

myArray [1]: 01011100

myArray [2]: 01101001

myArray [3]: 11001101

When you have a full array of bytes, you can pass it to BitConverter.ToInt32(myArray, 0); then you will need to shift the pattern 8 places to the right to get the pattern in its correct 24-bit gateway representation (from -8388608 to 8388608 ); then divide by 8388608 to have it as a floating point value.

So, putting everything together, you should get something like this,

Notice, I wrote the following code with the intention of being β€œeasy to use”, so this is not the most efficient method, for a quicker solution, see the code below this.

 private List<float> Read24BitSamples(FileStream stream, int startIndex, int endIndex) { var samples = new List<float>(); var bytes = ReadChannelBytes(stream, Channels.Left, startIndex, endIndex); var temp = new List<byte>(); var paddedBytes = new byte[bytes.Length / 3 * 4]; // Right align our samples to 32-bit (effectively bit shifting 8 places to the left). for (var i = 0; i < bytes.Length; i += 3) { temp.Add(0); // LSB temp.Add(bytes[i]); // 2nd LSB temp.Add(bytes[i + 1]); // 2nd MSB temp.Add(bytes[i + 2]); // MSB } // BitConverter requires collection to be an array. paddedBytes = temp.ToArray(); temp = null; bytes = null; for (var i = 0; i < paddedBytes.Length / 4; i++) { samples.Add(BitConverter.ToInt32(paddedBytes, i * 4) / 2147483648f); // Skip the bit shift and just divide, since our sample has been "shited" 8 places to the right we need to divide by 2147483648, not 8388608. } return samples; } 


For a faster implementation of 1, you can do the following:

 private List<float> Read24BitSamples(FileStream stream, int startIndex, int endIndex) { var bytes = ReadChannelBytes(stream, Channels.Left, startIndex, endIndex); var samples = new float[bytes.Length / 3]; for (var i = 0; i < bytes.Length; i += 3) { samples[i / 3] = (bytes[i] << 8 | bytes[i + 1] << 16 | bytes[i + 2] << 24) / 2147483648f; } return samples.ToList(); } 



1 After comparing the above code with the previous method, this solution is approximately 450-550% faster.

+6
source

Source: https://habr.com/ru/post/970652/


All Articles