Beispiel #1
0
        // Dst must be large enough to accept up to 512 samples (1024 for stereo)
        private static unsafe void DecodeChunk(ContentStream stream, short *dst, ref Chunk c, bool stereo)
        {
            uint rem = c.FrameCount * (stereo ? 2u : 1);

            if (c.Type == SMALL_TYPE)
            {
                // Local accumulators
                short acc1 = c.Channel1, acc2 = c.Channel2;

                // Read in 8 deltas at a time, and accumulate them
                for (uint si = 0; si < rem; si += 8)
                {
                    if (stereo)
                    {
                        dst[si]     = (short)(acc1 + stream.ReadSByte());
                        dst[si + 1] = (short)(acc2 + stream.ReadSByte());
                        dst[si + 2] = (short)(dst[si] + stream.ReadSByte());
                        dst[si + 3] = (short)(dst[si + 1] + stream.ReadSByte());
                        dst[si + 4] = (short)(dst[si + 2] + stream.ReadSByte());
                        dst[si + 5] = (short)(dst[si + 3] + stream.ReadSByte());
                        dst[si + 6] = (short)(dst[si + 4] + stream.ReadSByte());
                        dst[si + 7] = (short)(dst[si + 5] + stream.ReadSByte());
                        acc1        = dst[si + 6];
                        acc2        = dst[si + 7];
                    }
                    else                     // mono
                    {
                        dst[si]     = (short)(acc1 + stream.ReadSByte());
                        dst[si + 1] = (short)(dst[si] + stream.ReadSByte());
                        dst[si + 2] = (short)(dst[si + 1] + stream.ReadSByte());
                        dst[si + 3] = (short)(dst[si + 2] + stream.ReadSByte());
                        dst[si + 4] = (short)(dst[si + 3] + stream.ReadSByte());
                        dst[si + 5] = (short)(dst[si + 4] + stream.ReadSByte());
                        dst[si + 6] = (short)(dst[si + 5] + stream.ReadSByte());
                        dst[si + 7] = (short)(dst[si + 6] + stream.ReadSByte());
                        acc1        = dst[si + 7];
                    }
                }
            }
            else if (c.Type == MED_TYPE)
            {
                // Local accumulators
                short acc1 = c.Channel1, acc2 = c.Channel2;

                // Used to hold the current 8 samples in their packed forms (8 samples in 12 bytes)
                byte *tmp = stackalloc byte[12];

                // Read/decode/accumulate 8 samples at a time
                for (uint si = 0; si < rem; si += 8)
                {
                    // Read the packed samples (12 bytes total, the types dont matter, chosen for brevity)
                    *((ulong *)tmp)      = stream.ReadUInt64();
                    *((uint *)(tmp + 8)) = stream.ReadUInt32();

                    // Extract the packed values
                    int p1 = *((int *)tmp);
                    int p2 = *((int *)(tmp + 3));
                    int p3 = *((int *)(tmp + 6));
                    int p4 = *((int *)(tmp + 9));

                    // Extract the differences from the packed values (arith. right shift to get 2s compliment)
                    int d1 = ((p1 & 0xFFF) << 20) >> 20;
                    int d2 = ((p1 & 0xFFF000) << 8) >> 20;
                    int d3 = ((p2 & 0xFFF) << 20) >> 20;
                    int d4 = ((p2 & 0xFFF000) << 8) >> 20;
                    int d5 = ((p3 & 0xFFF) << 20) >> 20;
                    int d6 = ((p3 & 0xFFF000) << 8) >> 20;
                    int d7 = ((p4 & 0xFFF) << 20) >> 20;
                    int d8 = ((p4 & 0xFFF000) << 8) >> 20;

                    // Perform the accumulation
                    if (stereo)
                    {
                        dst[si]     = (short)(acc1 + d1);
                        dst[si + 1] = (short)(acc2 + d2);
                        dst[si + 2] = (short)(dst[si] + d3);
                        dst[si + 3] = (short)(dst[si + 1] + d4);
                        dst[si + 4] = (short)(dst[si + 2] + d5);
                        dst[si + 5] = (short)(dst[si + 3] + d6);
                        dst[si + 6] = (short)(dst[si + 4] + d7);
                        dst[si + 7] = (short)(dst[si + 5] + d8);
                        acc1        = dst[si + 6];
                        acc2        = dst[si + 7];
                    }
                    else                     // mono
                    {
                        dst[si]     = (short)(acc1 + d1);
                        dst[si + 1] = (short)(dst[si] + d2);
                        dst[si + 2] = (short)(dst[si + 1] + d3);
                        dst[si + 3] = (short)(dst[si + 2] + d4);
                        dst[si + 4] = (short)(dst[si + 3] + d5);
                        dst[si + 5] = (short)(dst[si + 4] + d6);
                        dst[si + 6] = (short)(dst[si + 5] + d7);
                        dst[si + 7] = (short)(dst[si + 6] + d8);
                        acc1        = dst[si + 7];
                    }
                }
            }
            else             // Full samples
            {
                // Directly read the samples
                for (uint si = 0; si < rem; si += 8)
                {
                    dst[si]     = stream.ReadInt16();
                    dst[si + 1] = stream.ReadInt16();
                    dst[si + 2] = stream.ReadInt16();
                    dst[si + 3] = stream.ReadInt16();
                    dst[si + 4] = stream.ReadInt16();
                    dst[si + 5] = stream.ReadInt16();
                    dst[si + 6] = stream.ReadInt16();
                    dst[si + 7] = stream.ReadInt16();
                }
            }

            // Save the channels
            if (stereo)
            {
                c.Channel1 = dst[rem - 2];
                c.Channel2 = dst[rem - 1];
            }
            else
            {
                c.Channel1 = dst[rem - 1];
            }
        }