diff --git a/src/decoder/plugins/OpusHead.cxx b/src/decoder/plugins/OpusHead.cxx
index 7a1c766a9..e93e754b4 100644
--- a/src/decoder/plugins/OpusHead.cxx
+++ b/src/decoder/plugins/OpusHead.cxx
@@ -39,8 +39,7 @@ ScanOpusHeader(const void *data, size_t size, unsigned &channels_r,
 	if (size < 19 || (h->version & 0xf0) != 0)
 		return false;
 
-	uint16_t gain_bits = FromLE16(h->output_gain);
-	output_gain_r = (gain_bits & 0x8000) ? gain_bits - 0x10000 : gain_bits;
+	output_gain_r = FromLE16S(h->output_gain);
 
 	channels_r = h->channels;
 	pre_skip_r = FromLE16(h->pre_skip);
diff --git a/src/util/ByteOrder.hxx b/src/util/ByteOrder.hxx
index f52c2bd38..121f458f2 100644
--- a/src/util/ByteOrder.hxx
+++ b/src/util/ByteOrder.hxx
@@ -243,4 +243,15 @@ ToLE64(uint64_t value) noexcept
 	return IsLittleEndian() ? value : ByteSwap64(value);
 }
 
+/**
+ * Converts a 16 bit integer from little endian to the host byte order
+ * and returns it as a signed integer.
+ */
+constexpr int16_t
+FromLE16S(uint16_t value) noexcept
+{
+	/* assuming two's complement representation */
+	return static_cast<int16_t>(FromLE16(value));
+}
+
 #endif