////REVIEW: This is some bad code duplication here between Read/WriteFloat&Double but given that there's no //// way to use a type argument here, not sure how to get rid of it. public double ReadDouble(void *statePtr) { Debug.Assert(sizeInBits != 0); var valuePtr = (byte *)statePtr + (int)byteOffset; var fmt = (int)format; switch (fmt) { // If a control with an integer-based representation does not use the full range // of its integer size (e.g. only goes from [0..128]), processors or the parameters // above have to be used to re-process the resulting float values. case kFormatBit: if (sizeInBits == 1) { return(MemoryHelpers.ReadSingleBit(valuePtr, bitOffset) ? 1.0f : 0.0f); } return(MemoryHelpers.ReadMultipleBitsAsNormalizedUInt(valuePtr, bitOffset, sizeInBits)); case kFormatSBit: if (sizeInBits == 1) { return(MemoryHelpers.ReadSingleBit(valuePtr, bitOffset) ? 1.0f : -1.0f); } return(MemoryHelpers.ReadMultipleBitsAsNormalizedUInt(valuePtr, bitOffset, sizeInBits) * 2.0f - 1.0f); case kFormatInt: Debug.Assert(sizeInBits == 32, "INT state must have sizeInBits=32"); Debug.Assert(bitOffset == 0, "INT state must be byte-aligned"); return(NumberHelpers.IntToNormalizedFloat(*(int *)valuePtr, int.MinValue, int.MaxValue) * 2.0f - 1.0f); case kFormatUInt: Debug.Assert(sizeInBits == 32, "UINT state must have sizeInBits=32"); Debug.Assert(bitOffset == 0, "UINT state must be byte-aligned"); return(NumberHelpers.UIntToNormalizedFloat(*(uint *)valuePtr, uint.MinValue, uint.MaxValue)); case kFormatShort: Debug.Assert(sizeInBits == 16, "SHRT state must have sizeInBits=16"); Debug.Assert(bitOffset == 0, "SHRT state must be byte-aligned"); return(NumberHelpers.IntToNormalizedFloat(*(short *)valuePtr, short.MinValue, short.MaxValue) * 2.0f - 1.0f); case kFormatUShort: Debug.Assert(sizeInBits == 16, "USHT state must have sizeInBits=16"); Debug.Assert(bitOffset == 0, "USHT state must be byte-aligned"); return(NumberHelpers.UIntToNormalizedFloat(*(ushort *)valuePtr, ushort.MinValue, ushort.MaxValue)); case kFormatByte: Debug.Assert(sizeInBits == 8, "BYTE state must have sizeInBits=8"); Debug.Assert(bitOffset == 0, "BYTE state must be byte-aligned"); return(NumberHelpers.UIntToNormalizedFloat(*valuePtr, byte.MinValue, byte.MaxValue)); case kFormatSByte: Debug.Assert(sizeInBits == 8, "SBYT state must have sizeInBits=8"); Debug.Assert(bitOffset == 0, "SBYT state must be byte-aligned"); return(NumberHelpers.IntToNormalizedFloat(*(sbyte *)valuePtr, sbyte.MinValue, sbyte.MaxValue) * 2.0f - 1.0f); case kFormatFloat: Debug.Assert(sizeInBits == 32, "FLT state must have sizeInBits=32"); Debug.Assert(bitOffset == 0, "FLT state must be byte-aligned"); return(*(float *)valuePtr); case kFormatDouble: Debug.Assert(sizeInBits == 64, "DBL state must have sizeInBits=64"); Debug.Assert(bitOffset == 0, "DBL state must be byte-aligned"); return(*(double *)valuePtr); // Not supported: // - kFormatLong // - kFormatULong // - kFormatFloat // - kFormatDouble default: throw new Exception($"State format '{format}' is not supported as floating-point format"); } }