views:

328

answers:

3

Hi! I need a fast way in C# leanguage of converting/casting array of bytes encoding one short (int16) value for 2bytes into float representation, as fast as possible. Performance bottleneck was method:

samples[sample] = (float)binraryReader.readInt16();

(huge ammount of IO calls so i had to convert to block read)

Basically i have file containing block of sound samples (~100-600 mb) of type of short, then, as i can only block read set of bytes, i need to construct short from each pair of bytes and then convert that short to float representation as i need to store samples as floats.

my current code looks somtething like this (about 2x performance improvement over method above, but still to long) :

    float[] samples = new float[_samplesPerSplit];
    byte[] data = new byte[_samplesPerSplit * 2];

    for (int c = 0; c < numberOfChunks; c += 1)
    {
        br.Read(data, 0, _samplesPerSplit * 2);

        fixed (byte* bytePtr = data)
        {
            fixed (float* floatPtr = samples)
            {
                byte* rPos = bytePtr;
                float* fPos = floatPtr;

                byte byte0;
                byte byte1;
                short sampleShort;

                for (int sample = 0; sample < _samplesPerSplit; sample += 1)
                {
                    byte1 = *(rPos++);
                    byte0 = *(rPos++);

                    // I occasionaly get 
                    //          "Negating  the minimum value of a 
                    //          twos complement number is invalid" 
                    // error if i skip this check, but it slows down 
                    // whole process even more
                    if (byte0 == 128 && byte1 == 0)
                    {
                        sampleShort = 32767;
                    }
                    else
                    {
                        sampleShort = (short)(((ushort)(byte0)) << 8 | ((ushort)(byte1)));
                    }

                    *(fPos++) = (float)sampleShort;
                }
            }
        }
        ProcessChunk(samples);
    }
+1  A: 

you can try this:

    fixed (byte* bytePtr = data)
    {
        fixed (float* floatPtr = samples)
        {
            short* rPos = (short*)bytePtr;
            float* fPos = floatPtr;

            for (int sample = 0; sample < _samplesPerSplit; sample += 1)
            {
                *fPos++ = (float)(*rPos++);
            }

        }
    }
max
Thanks, seems that im disc hardware limited, but i still got some ~10 or so percents off the time so i think its good now as i cant imagine anything faster :P
Oscar
A: 

Did You try to use Bitwise operation

I do not know much about them but from Wiki and MY previous SO here what I had learned about it:

Bitwise operations are usually significantly faster than multiplication and division operations.

adopilot
He's already using a left shift operator in his second example.
Hinek
A: 

Are you setting the buffer size of the FileStream used to create the BinaryReader? This seems like something that should be disk bound since you're not really doing very much computation

Mike