diff --git a/app/src/util/binary.h b/app/src/util/binary.h index 734ab1d0..6dc1b58e 100644 --- a/app/src/util/binary.h +++ b/app/src/util/binary.h @@ -58,4 +58,19 @@ sc_float_to_u16fp(float f) { return (uint16_t) u; } +/** + * Convert a float between -1 and 1 to a signed 16-bit fixed-point value + */ +static inline int16_t +sc_float_to_i16fp(float f) { + assert(f >= -1.0f && f <= 1.0f); + int32_t i = f * 0x1p15f; // 2^15 + assert(i >= -0x8000); + if (i >= 0x7fff) { + assert(i == 0x8000); // for f == 1.0f + i = 0x7fff; + } + return (int16_t) i; +} + #endif diff --git a/app/tests/test_binary.c b/app/tests/test_binary.c index 6e52da72..82a9c1e0 100644 --- a/app/tests/test_binary.c +++ b/app/tests/test_binary.c @@ -78,6 +78,25 @@ static void test_float_to_u16fp(void) { assert(sc_float_to_u16fp(1.0f) == 0xffff); } +static void test_float_to_i16fp(void) { + assert(sc_float_to_i16fp(0.0f) == 0); + assert(sc_float_to_i16fp(0.03125f) == 0x400); + assert(sc_float_to_i16fp(0.0625f) == 0x800); + assert(sc_float_to_i16fp(0.125f) == 0x1000); + assert(sc_float_to_i16fp(0.25f) == 0x2000); + assert(sc_float_to_i16fp(0.5f) == 0x4000); + assert(sc_float_to_i16fp(0.75f) == 0x6000); + assert(sc_float_to_i16fp(1.0f) == 0x7fff); + + assert(sc_float_to_i16fp(-0.03125f) == -0x400); + assert(sc_float_to_i16fp(-0.0625f) == -0x800); + assert(sc_float_to_i16fp(-0.125f) == -0x1000); + assert(sc_float_to_i16fp(-0.25f) == -0x2000); + assert(sc_float_to_i16fp(-0.5f) == -0x4000); + assert(sc_float_to_i16fp(-0.75f) == -0x6000); + assert(sc_float_to_i16fp(-1.0f) == -0x8000); +} + int main(int argc, char *argv[]) { (void) argc; (void) argv; @@ -90,5 +109,6 @@ int main(int argc, char *argv[]) { test_read64be(); test_float_to_u16fp(); + test_float_to_i16fp(); return 0; } diff --git a/server/src/main/java/com/genymobile/scrcpy/Binary.java b/server/src/main/java/com/genymobile/scrcpy/Binary.java index db946664..29534f59 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Binary.java +++ b/server/src/main/java/com/genymobile/scrcpy/Binary.java @@ -24,4 +24,15 @@ public final class Binary { // 0x1p16f is 2^16 as float return unsignedShort == 0xffff ? 1f : (unsignedShort / 0x1p16f); } + + /** + * Convert signed 16-bit fixed-point to a float between -1 and 1 + * + * @param value encoded value + * @return Float value between -1 and 1 + */ + public static float i16FixedPointToFloat(short value) { + // 0x1p15f is 2^15 as float + return value == 0x7fff ? 1f : (value / 0x1p15f); + } } diff --git a/server/src/test/java/com/genymobile/scrcpy/BinaryTest.java b/server/src/test/java/com/genymobile/scrcpy/BinaryTest.java index b2d3d72d..569a2f2c 100644 --- a/server/src/test/java/com/genymobile/scrcpy/BinaryTest.java +++ b/server/src/test/java/com/genymobile/scrcpy/BinaryTest.java @@ -17,4 +17,26 @@ public class BinaryTest { Assert.assertEquals(0.75f, Binary.u16FixedPointToFloat((short) 0xc000), delta); Assert.assertEquals(1.0f, Binary.u16FixedPointToFloat((short) 0xffff), delta); } + + @Test + public void testI16FixedPointToFloat() { + final float delta = 0.0f; // on these values, there MUST be no rounding error + + Assert.assertEquals(0.0f, Binary.i16FixedPointToFloat((short) 0), delta); + Assert.assertEquals(0.03125f, Binary.i16FixedPointToFloat((short) 0x400), delta); + Assert.assertEquals(0.0625f, Binary.i16FixedPointToFloat((short) 0x800), delta); + Assert.assertEquals(0.125f, Binary.i16FixedPointToFloat((short) 0x1000), delta); + Assert.assertEquals(0.25f, Binary.i16FixedPointToFloat((short) 0x2000), delta); + Assert.assertEquals(0.5f, Binary.i16FixedPointToFloat((short) 0x4000), delta); + Assert.assertEquals(0.75f, Binary.i16FixedPointToFloat((short) 0x6000), delta); + Assert.assertEquals(1.0f, Binary.i16FixedPointToFloat((short) 0x7fff), delta); + + Assert.assertEquals(-0.03125f, Binary.i16FixedPointToFloat((short) -0x400), delta); + Assert.assertEquals(-0.0625f, Binary.i16FixedPointToFloat((short) -0x800), delta); + Assert.assertEquals(-0.125f, Binary.i16FixedPointToFloat((short) -0x1000), delta); + Assert.assertEquals(-0.25f, Binary.i16FixedPointToFloat((short) -0x2000), delta); + Assert.assertEquals(-0.5f, Binary.i16FixedPointToFloat((short) -0x4000), delta); + Assert.assertEquals(-0.75f, Binary.i16FixedPointToFloat((short) -0x6000), delta); + Assert.assertEquals(-1.0f, Binary.i16FixedPointToFloat((short) -0x8000), delta); + } }