CNA-BUG-276: SoundEffect::Play(volume, pitch, pan) clamps pitch, does not check volume and returns false when disposed, where XNA 4.0 throws

CNA snapshot b0e97bb1  ·  Known Issues › Current bugs  ·  source links pinned to b0e97bb1

✓

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

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.

The same subject is explained at several altitudes. These are the neighbouring pages at each one.

User guide
Audio guide
Known issues
Bug index