1

I am receiving a string representing an array of audio samples from a browser captured via getUserMedia. getUserMedia is recording at 48000, and I am interleaving 2 channels before I send the string values to the server. I turn this string into a float[] like so:

string[] raw = buffer.ToString().Split(new char[]{ ',' });
float[] fArray = new float[raw.Length];
for (int x = 0; x < raw.Length; x++)
{
     float sampleVal = float.Parse(raw[x]);
     fArray[x] = sampleVal;
}

What I would like to do is convert the float[] array into a byte[] array so that I can pass it to a BufferedWaveProvider (48000, 16, 1) for playback. Here's how I am currently trying to do the conversion:

byte[] bSamples = new byte[fArray.Length * 2];
for (int x = 0; x < fArray.Length; x += 2)
{
    short sSample = (short)Math.Floor(fArray[x] * 32767);

    byte[] tmp = BitConverter.GetBytes(sSample);
    bSamples[x] = tmp[0];
    bSamples[x + 1] = tmp[1];
}

Using the code above, only is garbage produced. Can anyone point me in the right direction for doing such a conversion?

I've seen this, but it didn't get me where I need to go.

Community
  • 1
  • 1
Bill Warren
  • 21
  • 1
  • 6
  • I've made a little progress on this. The conversion loop should look more like this: int destOffset = 0; byte[] destArray = new byte[fArray.Length * 2]; for (int x = 0; x < fArray.Length; x++) { float sample32 = fArray[x]; byte[] tmp = BitConverter.GetBytes((short)(sample32 * 32768f)); destArray[destOffset] = tmp[0]; destArray[destOffset + 1] = tmp[1]; destOffset = destOffset +2; } But this still doesn't produce anything close to was recorded. – Bill Warren Jan 27 '16 at 20:04
  • Update 2: If I change my input source (getUserMedia) to use only 1 channel, instead of interleaving 2 channels, I can reproduce the sound. – Bill Warren Jan 27 '16 at 21:30
  • Consider _editing_ the question with the updates instead of posting them as comments. It makes for a more coherent and useful question for future readers. – chwarr Feb 10 '17 at 05:25

2 Answers2

1

It's too late, but still useful - I've posted a conversion code from float[] samples array to byte[] array there https://stackoverflow.com/a/42151979/4778700

Community
  • 1
  • 1
ai_enabled
  • 71
  • 5
0

It looks like your indexing isn't quite right in the second loop. You're looping over the float samples, and using the same index in the short output:

for (int x = 0; x < fArray.Length; x += 2)

Another thing (let's assume that the floating-point input is true IEEE 32-bit float samples in the range [-1.0,1.0], so we won't worry about converting). Is it stereo input? If so, then you'll need to combine the samples before converting to 'short'. That's easy to do. Just average successive pairs of float values (left channel/right channel).

The size of the output array should be correct. Technically, it'd be something like this:

int inchannels = 2;  // doesn't have to be a variable, but shows 'stereo' input.
int numsamples = fArray.Length / inchannels;
byte [] bSamples = new byte [numsamples * sizeof(Int16)];

Then you should be able to do the conversion as follows. Note that this assumes a stereo input, so it averages the float samples.

int outindex = 0;
for( int inindex = 0; inindex < fArray.Length; inindex += 2 )
{
    // 'insample' is the average of left and right channels.  This isn't
    // entirely accurate - if one channel is 0.0, then we should just use
    // the other channel verbatim.  But this is close enough.
    float insample = (fArray[inindex] + fArray[inindex+1]) / 2.0f;

    // The output sample.  It's probably better to use Int16.MaxValue
    // than the hard-coded value.
    Int16 outsample = (Int16)(insample * (float)Int16.MaxValue);

    // I'm old-school, so I'm a fan of 'unsafe'.  But you can use the
    // BitConverter that you were already using.  Actually, I would've
    // probably done this entire conversion in 'unsafe' mode.
    unsafe
    {
        fixed( byte * pbyte = &bSamples[outindex] )
        {
            Int16 * p = (Int16 *)pbyte;
            *p = outsample;
            outindex += sizeof(Int16);
        }
    }
}
Bob C
  • 391
  • 2
  • 10