// 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]; } }