Search code examples
c#audiotype-conversionwavnaudio

How to convert []Int16 to []float using C# and NAudio?


I finished getting row data from a WAV file. So now, I know the informatipon about the WAV file, such as DataRate and SamplingPerBits, etc.

And I have several kinds of data types after reading the WAV file: 16 bits - []Int16, 8 bits - []byte.

Now I am trying to convert []Int16 to []float!

I found the NAudio.wave function Wave16ToFloatProvider().

I have seen Converting 16 bit to 32-nit floating point. But I couldn't get about it, because I don't need to write WaveFileWriter. So I tried to do without WaveFileWriter. Here is my code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using NAudio;
using NAudio.Wave;

namespace WaveREader
{
    class WaveReader
    {
        WaveFileReader reader = new WaveFileReader("wavetest.wav");
        IWaveProvider stream32 = new Wave16ToFloatProvider(reader);
        byte[] buffer = new byte[8192];
        float[] DATASIXTEEN;
        for (int i = 0; i < buffer.Length; i++)
        {
            DATASIXTEEN = new float[buffer.Length];
            DATASIXTEEN[i] = stream32.Read(buffer, 0, buffer.Length);
        }
    }
}

I think this part would be wrong, DATASIXTEEN[i] = stream32.Read(buffer, 0, buffer.Length);, but I have no idea how to correct it.

Would you give me some advice for it or code by using Wave16ToFloatProvider?

Or would I ask you how to convert without Wave16ToFloatProvider?


Solution

  • The return value from Stream.Read is the count of the number of bytes read, not what you're after. The data you want is in the buffer, but each 32-bit sample is spread across 4 8-bit bytes.

    There are a number of ways to get the data as 32-bit float.

    The first is to use an ISampleProvider which converts the data into the floating point format and gives a simple way to read the data in that format:

    WaveFileReader reader = new WaveFileReader("wavetest.wav");
    ISampleProvider provider = new Pcm16BitToSampleProvider(reader);
    
    int blockSize = 2000;
    float[] buffer = new float[blockSize];
    
    // Read blocks of samples until no more available
    int rc;
    while ((rc = provider.Read(buffer, 0, blockSize)) > 0)
    {
        // Process the array of samples in here.
        // rc is the number of valid samples in the buffer
        // ....
    }
    

    Alternatively, there is a method in WaveFileReader that lets you read floating point samples directly. The downside is that it reads one sample group (, that is, one sample for each channel - one for mono, two for stereo) at a time, which can be time consuming. Reading and processing arrays is faster in most cases.

    WaveFileReader reader = new WaveFileReader("wavetest.wav");
    float[] buffer;
    
    while ((buffer = reader.ReadNextSampleFrame()) != null)
    {
        // Process samples in here.
        // buffer contains one sample per channel
        // ....
    }