CNA-BUG-276: SoundEffect::Play(volume, pitch, pan) clamps pitch, does not check volume and returns false when disposed, where XNA 4.0 throws
Evidence basis: source-verified at the pinned commit; tests exist (not executed for this page). Claims on this page were checked by reading the CNA source at commit b0e97bb1; unless a sentence says otherwise, nothing here was built or executed. Nothing on this page was executed unless the Evidence section says so.
XNA 4.0's SoundEffect.Play(float, float, float) throws ObjectDisposedException when disposed and ArgumentOutOfRangeException for volume or pitch out of range; CNA returns false when disposed, clamps pitch and passes volume through.
- Identifier
CNA-BUG-276- Category
- Bug
- Subsystem
- Audio & media
- Status
- Open
- Verified against
- CNA
b0e97bb1(b0e97bb1bb876f9b3edd6f4ff1ef3067908ae8ac) - Severity
- Low (a triage suggestion, not a project priority)
- Evidence basis
- Source-verified: read at TARGET, not executed
- Tests touching this area
- Yes: see Current tests
- Affected contract
- SoundEffect::Play(float volume, float pitch, float pan) and the C route cna_sound_effect_play_with_settings
Expected behaviour
XNA 4.0's SoundEffect.Play(float, float, float) (decompiled Microsoft.Xna.Framework.Audio.SoundEffect; read, not executed) throws ObjectDisposedException when the effect is disposed and assigns the arguments through the SoundEffectInstance Volume, Pitch and Pan setters, which throw ArgumentOutOfRangeException outside [0, 1], [-1, 1] and [-1, 1]. CNA's own SoundEffectInstance setters follow those ranges since KF-12 (49119a34c).
Actual behaviour at TARGET
SoundEffect::Play(float, float, float) in SoundEffect.cpp returns false for a disposed effect, range-checks only pan, clamps pitch to [-1, 1] (its comment: "Pitch is clamped rather than validated") and hands volume to the mixer track's gain without a check. So Play(1.0f, 5.0f, 0.0f) plays where XNA throws, a volume of 2 or -1 is accepted, and a call on a disposed effect is refused silently instead of raising. The same values on a SoundEffectInstance throw, so the two paths disagree. audio.h documents the C route cna_sound_effect_play_with_settings with the same asymmetry ("pan is range-checked and pitch is clamped").
Source locations
modules/audio/src/Xna/SoundEffect.cpp— SoundEffect::Play(float, float, float): pan checked, pitch clamped, volume unchecked, false when disposedmodules/audio/src/Xna/SoundEffectInstance.cpp— the Pitch setter throws ArgumentOutOfRangeException (KF-12)modules/c-api/include/CNA/C/audio.h— cna_sound_effect_play_with_settings: pan range-checked, pitch clampedmodules/audio/tests/Microsoft/Xna/Framework/Audio/SoundEffectTests.cpp— PlayClampsPitchInsteadOfThrowing and DisposeIsIdempotentAndPlayReturnsFalse pin the current behaviour
Evidence
Read at b0e97bb1 and compared with the decompiled XNA 4.0 SoundEffect.Play(float, float, float) and the SoundEffectInstance setters; nothing was built or executed. The comment of SoundEffectTest.PlayClampsPitchInsteadOfThrowing still describes the instance's Pitch setter as clamping, which it no longer does.
Focused reproduction
// Illustrative; not compiled or run.
auto ok = effect.Play(1.0f, 5.0f, 0.0f); // XNA: ArgumentOutOfRangeException; CNA: true, pitch clamped to 1
effect.Dispose();
ok = effect.Play(1.0f, 0.0f, 0.0f); // XNA: ObjectDisposedException; CNA: false
Current tests
SoundEffectTest.PlayClampsPitchInsteadOfThrowing, PlayThrowsOnPanOutOfRange and DisposeIsIdempotentAndPlayReturnsFalse in SoundEffectTests.cpp pin the current behaviour; no test checks the volume range.
Regression test
Expect ArgumentOutOfRangeException from Play for a volume of -0.1 or 1.1 and a pitch of -1.1 or 1.1, and ObjectDisposedException after Dispose(), replacing the clamp and return-false tests; align the C route's documentation.
Blast radius
Code ported from XNA that relies on Play to reject bad arguments or a disposed effect, and code whose arithmetic produces an out-of-range pitch or volume: the sound plays, clamped or amplified, instead of failing. Calls with in-range values on a live effect are unaffected.
Workaround
Validate volume and pitch before calling Play, or play through a SoundEffectInstance, whose setters check the ranges.
Related pages
The same subject is explained at several altitudes. These are the neighbouring pages at each one.
- User guide
- Audio guide
- Known issues
- Bug index