diff --git a/core/src/backend/audio.rs b/core/src/backend/audio.rs index 883fa2ad7..aca7ad192 100644 --- a/core/src/backend/audio.rs +++ b/core/src/backend/audio.rs @@ -580,21 +580,12 @@ impl From for SoundTransform { fn from(other: display_object::SoundTransform) -> Self { const SCALE: f32 = display_object::SoundTransform::MAX_VOLUME.pow(2) as f32; - // It seems like Flash stores sound transform values in 30-bit unsigned integers: - // * Negative values are equivalent to their absolute value. - // * Specifically, 0x40000000, -0x40000000 and -0x80000000 are equivalent to zero. - // * The volume multiplication wraps around at `u32::MAX`. - let left_to_left = (other.left_to_left << 2) >> 2; - let left_to_right = (other.left_to_right << 2) >> 2; - let right_to_left = (other.right_to_left << 2) >> 2; - let right_to_right = (other.right_to_right << 2) >> 2; - let volume = (other.volume << 2) >> 2; - + // The volume multiplication wraps around at `u32::MAX`. Self { - left_to_left: left_to_left.wrapping_mul(volume) as f32 / SCALE, - left_to_right: left_to_right.wrapping_mul(volume) as f32 / SCALE, - right_to_left: right_to_left.wrapping_mul(volume) as f32 / SCALE, - right_to_right: right_to_right.wrapping_mul(volume) as f32 / SCALE, + left_to_left: other.left_to_left.wrapping_mul(other.volume) as f32 / SCALE, + left_to_right: other.left_to_right.wrapping_mul(other.volume) as f32 / SCALE, + right_to_left: other.right_to_left.wrapping_mul(other.volume) as f32 / SCALE, + right_to_right: other.right_to_right.wrapping_mul(other.volume) as f32 / SCALE, } } } diff --git a/core/src/display_object.rs b/core/src/display_object.rs index e1a0d5d99..052c757a1 100644 --- a/core/src/display_object.rs +++ b/core/src/display_object.rs @@ -1554,11 +1554,17 @@ impl SoundTransform { /// Applies another SoundTransform on top of this SoundTransform. pub fn concat(&mut self, other: &SoundTransform) { + const MAX_VOLUME: i64 = SoundTransform::MAX_VOLUME as i64; + + // It seems like Flash masks the results below to 30-bit integers: + // * Negative values are equivalent to their absolute value (their sign bit is unset). + // * Specifically, 0x40000000, -0x40000000 and -0x80000000 are equivalent to zero. + const MASK: i32 = (1 << 30) - 1; + + self.volume = (i64::from(self.volume) * i64::from(other.volume) / MAX_VOLUME) as i32 & MASK; + // This is a 2x2 matrix multiply between the transforms. // Done with integer math to match Flash behavior. - const MAX_VOLUME: i64 = SoundTransform::MAX_VOLUME as i64; - self.volume = (i64::from(self.volume) * i64::from(other.volume) / MAX_VOLUME) as i32; - let ll0: i64 = self.left_to_left.into(); let lr0: i64 = self.left_to_right.into(); let rl0: i64 = self.right_to_left.into(); @@ -1567,10 +1573,10 @@ impl SoundTransform { let lr1: i64 = other.left_to_right.into(); let rl1: i64 = other.right_to_left.into(); let rr1: i64 = other.right_to_right.into(); - self.left_to_left = ((ll0 * ll1 + rl0 * lr1) / MAX_VOLUME) as i32; - self.left_to_right = ((lr0 * ll1 + rr0 * lr1) / MAX_VOLUME) as i32; - self.right_to_left = ((ll0 * rl1 + rl0 * rr1) / MAX_VOLUME) as i32; - self.right_to_right = ((lr0 * rl1 + rr0 * rr1) / MAX_VOLUME) as i32; + self.left_to_left = ((ll0 * ll1 + rl0 * lr1) / MAX_VOLUME) as i32 & MASK; + self.left_to_right = ((lr0 * ll1 + rr0 * lr1) / MAX_VOLUME) as i32 & MASK; + self.right_to_left = ((ll0 * rl1 + rl0 * rr1) / MAX_VOLUME) as i32 & MASK; + self.right_to_right = ((lr0 * rl1 + rr0 * rr1) / MAX_VOLUME) as i32 & MASK; } /// Returns the pan of this transform.