audio: a volume per channel under the master (effects, wildlife, ambient, interface) - aud_channel_set / aud_emit_on, aud_ui on the interface channel, and Audio.music_volume for the ambience loop on the runtime's music channel
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
87587b00b6
commit
b2a45c2fda
7 changed files with 74 additions and 2 deletions
|
|
@ -18,6 +18,13 @@ aud_emit_at(axe, tree.x, tree.z, 90.0) # heard within 90 m, pa
|
|||
aud_ui(click)
|
||||
```
|
||||
|
||||
## Channels
|
||||
|
||||
A volume per kind of sound, under the master: `AUD_CH_EFFECTS` (what the player does), `AUD_CH_WILDLIFE`,
|
||||
`AUD_CH_AMBIENT` (its loop is the runtime's music channel, `Audio.music_volume`) and `AUD_CH_UI`
|
||||
(`aud_ui` plays on it). `aud_channel_set(ch, v)` holds it to 0..1; `aud_emit_on(ch, h, ...)` is
|
||||
`aud_emit` scaled by it. `aud_emit` itself stays raw, so its numbers are what a test reads.
|
||||
|
||||
## Ports
|
||||
|
||||
```ludic
|
||||
|
|
|
|||
24
packages/ludic.audio/channels.ludic
Normal file
24
packages/ludic.audio/channels.ludic
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# channels.ludic - a volume per kind of sound, under the master: what the player does, the
|
||||
# animals, the ambience (its loop is the runtime's music channel) and the interface
|
||||
export const AUD_CH_EFFECTS: int = 0
|
||||
export const AUD_CH_WILDLIFE: int = 1
|
||||
export const AUD_CH_AMBIENT: int = 2
|
||||
export const AUD_CH_UI: int = 3
|
||||
export const AUD_CH_N: int = 4
|
||||
|
||||
export function aud_channel(audio_st: AudioState, ch: int) -> float {
|
||||
if ch < 0 or ch >= AUD_CH_N { return 1.0 }
|
||||
return audio_st.ch_gain[ch]
|
||||
}
|
||||
|
||||
export function aud_channel_set(audio_st: mut AudioState, ch: int, v: float) -> void {
|
||||
if ch < 0 or ch >= AUD_CH_N { return }
|
||||
let g = Math.clamp(v, 0.0, 1.0)
|
||||
audio_st.ch_gain[ch] = g
|
||||
if ch == AUD_CH_AMBIENT { Audio.music_volume(fixed(g)) }
|
||||
}
|
||||
|
||||
# a sound in the world on a channel: its gain from where it is, scaled by the channel's
|
||||
export function aud_emit_on(audio_st: mut AudioState, ch: int, h: int, gain: float, pitch: float, pan: float) -> void {
|
||||
aud_emit(audio_st, h, gain * aud_channel(audio_st, ch), pitch, pan)
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ export state AudioState {
|
|||
emitted: int = 0
|
||||
tried: int = 0
|
||||
live: int = 0
|
||||
ch_gain: []float = [1.0, 1.0, 1.0, 1.0] # per channel (channels.ludic), under the master
|
||||
}
|
||||
|
||||
export function aud_emit(audio_st: mut AudioState, h: int, gain: float, pitch: float, pan: float) -> void {
|
||||
|
|
@ -32,7 +33,7 @@ export function aud_emit_at(audio_st: mut AudioState, h: int, x: float, z: float
|
|||
export function aud_ui(audio_st: mut AudioState, h: int) -> void {
|
||||
if h == 0 { return }
|
||||
audio_st.emitted += 1
|
||||
Audio.play(h)
|
||||
Audio.play_at(h, fixed(aud_channel(audio_st, AUD_CH_UI)), fixed(1.0), fixed(0.0))
|
||||
}
|
||||
|
||||
export function aud_music(h: int) -> void { if h != 0 { Audio.play_music(h) } }
|
||||
|
|
|
|||
|
|
@ -5,5 +5,6 @@ numbers float
|
|||
import "ports.ludic"
|
||||
import "place.ludic"
|
||||
import "emit.ludic"
|
||||
import "channels.ludic"
|
||||
import "load.ludic"
|
||||
import "wav.ludic"
|
||||
|
|
|
|||
23
packages/ludic.audio/tests/channels_test.ludic
Normal file
23
packages/ludic.audio/tests/channels_test.ludic
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
# channels_test.ludic - a channel scales what is emitted on it, holds to 0..1, and leaves the others
|
||||
import "ludic.audio"
|
||||
program ChannelsTest {
|
||||
numbers float
|
||||
function t_x() -> float { return 0.0 }
|
||||
bind AudioListener { x: fn t_x, z: fn t_x }
|
||||
|
||||
test "a channel's volume scales an emit on it and no other" (audio_st: mut AudioState) {
|
||||
aud_channel_set(audio_st, AUD_CH_WILDLIFE, 0.5)
|
||||
aud_emit_on(audio_st, AUD_CH_WILDLIFE, 7, 0.8, 1.0, 0.0)
|
||||
expect_near(aud_last_gain(audio_st), 0.4, 0.0001)
|
||||
aud_emit_on(audio_st, AUD_CH_EFFECTS, 7, 0.8, 1.0, 0.0)
|
||||
expect_near(aud_last_gain(audio_st), 0.8, 0.0001)
|
||||
}
|
||||
|
||||
test "a channel holds to 0..1, and an unknown one is full" (audio_st: mut AudioState) {
|
||||
aud_channel_set(audio_st, AUD_CH_UI, 3.0)
|
||||
expect_near(aud_channel(audio_st, AUD_CH_UI), 1.0, 0.0001)
|
||||
aud_channel_set(audio_st, AUD_CH_AMBIENT, -1.0)
|
||||
expect_near(aud_channel(audio_st, AUD_CH_AMBIENT), 0.0, 0.0001)
|
||||
expect_near(aud_channel(audio_st, 9), 1.0, 0.0001)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue