From 6d6407caca701b89c242fdd90bf4079825b5063a Mon Sep 17 00:00:00 2001 From: Matt Kleinschafer Date: Fri, 19 Jul 2024 11:31:27 +1000 Subject: [PATCH] Add more OpenAL backend --- backends/sdl/src/audio.rs | 131 ++++++++++++++++++++++++++++------- crates/audio/src/headless.rs | 38 +++++++++- crates/audio/src/lib.rs | 13 +++- crates/audio/src/sources.rs | 81 +++++++++++++++++++--- 4 files changed, 224 insertions(+), 39 deletions(-) diff --git a/backends/sdl/src/audio.rs b/backends/sdl/src/audio.rs index 1bfe9279..bc540050 100644 --- a/backends/sdl/src/audio.rs +++ b/backends/sdl/src/audio.rs @@ -1,13 +1,12 @@ // Audio backend for SDL2 pub use audio::*; +use common::Vec3; use openal_sys::{ - alBufferData, alDeleteSources, alGenBuffers, alGenSources, alGetSourcei, alSource3f, alSourcef, alSourcei, - ALCcontext, ALCdevice, ALint, ALuint, + alBufferData, alDeleteSources, alGenBuffers, alGenSources, alGetSourcef, alGetSourcefv, alGetSourcei, alSource3f, + alSourcePlay, alSourcef, alSourcei, ALCcontext, ALCdevice, ALboolean, ALfloat, ALint, ALuint, }; -// TODO: finish implementing me - /// An audio backend for SDL2. pub struct SdlAudioBackend { device: *mut ALCdevice, @@ -50,10 +49,8 @@ impl AudioBackend for SdlAudioBackend { fn buffer_write_data(&self, buffer: BufferId, sampler_rate: AudioSampleRate, data: &[u8]) -> Result<(), BufferError> { unsafe { - let buffer = buffer.into(); - alBufferData( - buffer, + buffer.into(), openal_sys::AL_FORMAT_MONO16, data.as_ptr() as *const _, data.len() as i32, @@ -103,6 +100,7 @@ impl AudioBackend for SdlAudioBackend { let mut source: ALuint = 0; alGenSources(1, &mut source as *mut _); + alSourcef(source, openal_sys::AL_GAIN, 1.0); alSourcef(source, openal_sys::AL_PITCH, 1.0); alSource3f(source, openal_sys::AL_POSITION, 0.0, 0.0, 0.0); @@ -119,10 +117,9 @@ impl AudioBackend for SdlAudioBackend { fn source_is_playing(&self, source: SourceId) -> Option { unsafe { - let source = source.into(); let mut state: ALint = 0; - alGetSourcei(source, openal_sys::AL_SOURCE_STATE, &mut state as *mut _); + alGetSourcei(source.into(), openal_sys::AL_SOURCE_STATE, &mut state as *mut _); match state { openal_sys::AL_PLAYING => Some(true), @@ -131,22 +128,112 @@ impl AudioBackend for SdlAudioBackend { } } - fn source_get_volume(&self, source: SourceId) -> Option { + fn source_get_gain(&self, source: SourceId) -> Option { unsafe { - let source = source.into(); - let mut volume: i32 = 0; + let mut gain = 0.0f32; - alGetSourcei(source, openal_sys::AL_GAIN, &mut volume as *mut _); + alGetSourcef(source.into(), openal_sys::AL_GAIN, &mut gain as *mut _); - Some(volume as f32) + Some(gain) } } - fn source_set_volume(&self, source: SourceId, volume: f32) -> Result<(), SourceError> { + fn source_set_gain(&self, source: SourceId, gain: f32) -> Result<(), SourceError> { unsafe { - let source = source.into(); + alSourcef(source.into(), openal_sys::AL_GAIN, gain); + + Ok(()) + } + } + + fn source_get_pitch(&self, source: SourceId) -> Option { + unsafe { + let mut pitch = 0.0f32; + + alGetSourcef(source.into(), openal_sys::AL_PITCH, &mut pitch as *mut _); + + Some(pitch) + } + } + + fn source_set_pitch(&self, source: SourceId, pitch: f32) -> Result<(), SourceError> { + unsafe { + alSourcef(source.into(), openal_sys::AL_PITCH, pitch); + + Ok(()) + } + } + + fn source_get_position(&self, source: SourceId) -> Option { + unsafe { + let mut position = Vec3::ZERO; + + alGetSourcefv(source.into(), openal_sys::AL_POSITION, &mut position.x as *mut ALfloat); + + Some(position) + } + } - alSourcef(source, openal_sys::AL_GAIN, volume); + fn source_set_position(&self, source: SourceId, position: Vec3) -> Result<(), SourceError> { + unsafe { + alSource3f( + source.into(), + openal_sys::AL_POSITION, + position.x, + position.y, + position.z, + ); + + Ok(()) + } + } + + fn source_set_velocity(&self, source: SourceId, velocity: Vec3) -> Result<(), SourceError> { + unsafe { + alSource3f( + source.into(), + openal_sys::AL_VELOCITY, + velocity.x, + velocity.y, + velocity.z, + ); + + Ok(()) + } + } + + fn source_get_velocity(&self, source: SourceId) -> Option { + unsafe { + let mut velocity = Vec3::ZERO; + + alGetSourcefv(source.into(), openal_sys::AL_VELOCITY, &mut velocity.x as *mut ALfloat); + + Some(velocity) + } + } + + fn source_is_looping(&self, source: SourceId) -> Option { + unsafe { + let mut looping: ALint = 0; + + alGetSourcei(source.into(), openal_sys::AL_LOOPING, &mut looping as *mut _); + + match looping as ALboolean { + openal_sys::AL_TRUE => Some(true), + _ => Some(false), + } + } + } + + fn source_set_looping(&self, source: SourceId, looping: bool) -> Result<(), SourceError> { + unsafe { + let looping = if looping { + openal_sys::AL_TRUE + } else { + openal_sys::AL_FALSE + }; + + alSourcei(source.into(), openal_sys::AL_LOOPING, looping as ALint); Ok(()) } @@ -154,10 +241,9 @@ impl AudioBackend for SdlAudioBackend { fn source_get_clip(&self, source: SourceId) -> Option { unsafe { - let source = source.into(); let mut buffer: ALint = 0; - alGetSourcei(source, openal_sys::AL_BUFFER, &mut buffer as *mut _); + alGetSourcei(source.into(), openal_sys::AL_BUFFER, &mut buffer as *mut _); Some(ClipId::from(buffer as u32)) } @@ -165,10 +251,9 @@ impl AudioBackend for SdlAudioBackend { fn source_set_clip(&self, source: SourceId, clip: ClipId) -> Result<(), SourceError> { unsafe { - let source = source.into(); let clip = clip.into(); - alSourcei(source, openal_sys::AL_BUFFER, clip); + alSourcei(source.into(), openal_sys::AL_BUFFER, clip); Ok(()) } @@ -176,9 +261,7 @@ impl AudioBackend for SdlAudioBackend { fn source_play(&self, source: SourceId) -> Result<(), SourceError> { unsafe { - let source = source.into(); - - openal_sys::alSourcePlay(source); + alSourcePlay(source.into()); Ok(()) } diff --git a/crates/audio/src/headless.rs b/crates/audio/src/headless.rs index 228f9124..115966c6 100644 --- a/crates/audio/src/headless.rs +++ b/crates/audio/src/headless.rs @@ -42,11 +42,43 @@ impl AudioBackend for HeadlessAudioBackend { None } - fn source_get_volume(&self, source: SourceId) -> Option { - None + fn source_get_gain(&self, source: SourceId) -> Option { + Some(1.0f32) + } + + fn source_set_gain(&self, source: SourceId, gain: f32) -> Result<(), SourceError> { + Ok(()) + } + + fn source_get_pitch(&self, source: SourceId) -> Option { + Some(1.0f32) + } + + fn source_set_pitch(&self, source: SourceId, pitch: f32) -> Result<(), SourceError> { + Ok(()) + } + + fn source_get_position(&self, source: SourceId) -> Option { + Some(Vec3::ZERO) + } + + fn source_set_position(&self, source: SourceId, position: Vec3) -> Result<(), SourceError> { + Ok(()) + } + + fn source_set_velocity(&self, source: SourceId, velocity: Vec3) -> Result<(), SourceError> { + Ok(()) + } + + fn source_get_velocity(&self, source: SourceId) -> Option { + Some(Vec3::ZERO) + } + + fn source_is_looping(&self, source: SourceId) -> Option { + Some(false) } - fn source_set_volume(&self, source: SourceId, volume: f32) -> Result<(), SourceError> { + fn source_set_looping(&self, source: SourceId, looping: bool) -> Result<(), SourceError> { Ok(()) } diff --git a/crates/audio/src/lib.rs b/crates/audio/src/lib.rs index e1cd8021..371a2fdf 100644 --- a/crates/audio/src/lib.rs +++ b/crates/audio/src/lib.rs @@ -4,6 +4,7 @@ pub use buffers::*; pub use clips::*; +use common::Vec3; pub use sampling::*; pub use sources::*; @@ -66,8 +67,16 @@ pub trait AudioBackend { // sources fn source_create(&self) -> Result; fn source_is_playing(&self, source: SourceId) -> Option; - fn source_get_volume(&self, source: SourceId) -> Option; - fn source_set_volume(&self, source: SourceId, volume: f32) -> Result<(), SourceError>; + fn source_get_gain(&self, source: SourceId) -> Option; + fn source_set_gain(&self, source: SourceId, gain: f32) -> Result<(), SourceError>; + fn source_get_pitch(&self, source: SourceId) -> Option; + fn source_set_pitch(&self, source: SourceId, pitch: f32) -> Result<(), SourceError>; + fn source_get_position(&self, source: SourceId) -> Option; + fn source_set_position(&self, source: SourceId, position: Vec3) -> Result<(), SourceError>; + fn source_set_velocity(&self, source: SourceId, velocity: Vec3) -> Result<(), SourceError>; + fn source_get_velocity(&self, source: SourceId) -> Option; + fn source_is_looping(&self, source: SourceId) -> Option; + fn source_set_looping(&self, source: SourceId, looping: bool) -> Result<(), SourceError>; fn source_get_clip(&self, source: SourceId) -> Option; fn source_set_clip(&self, source: SourceId, clip: ClipId) -> Result<(), SourceError>; fn source_play(&self, source: SourceId) -> Result<(), SourceError>; diff --git a/crates/audio/src/sources.rs b/crates/audio/src/sources.rs index 108b750e..7b6a3ca2 100644 --- a/crates/audio/src/sources.rs +++ b/crates/audio/src/sources.rs @@ -16,28 +16,89 @@ impl AudioSource { } } - /// Returns the ID of this source. + /// Gets the ID of this source. pub fn id(&self) -> SourceId { self.id } - /// Returns whether this source is currently playing. + /// Gets the position of this source. + pub fn position(&self) -> Vec3 { + audio().source_get_position(self.id).unwrap_or_default() + } + + /// Sets the position of this source. + pub fn set_position(&mut self, position: Vec3) { + audio().source_set_position(self.id, position).unwrap(); + } + + /// Gets the velocity of this source. + pub fn velocity(&self) -> Vec3 { + audio().source_get_velocity(self.id).unwrap_or_default() + } + + /// Sets the velocity of this source. + pub fn set_velocity(&mut self, velocity: Vec3) { + audio().source_set_velocity(self.id, velocity).unwrap(); + } + + /// Gets the volume of this source. + pub fn gain(&self) -> f32 { + audio().source_get_gain(self.id).unwrap_or_default() + } + + /// Sets the gain of this source. + pub fn set_gain(&mut self, gain: f32) { + audio().source_set_gain(self.id, gain).unwrap(); + } + + /// Gets the pitch of this source. + pub fn pitch(&self) -> f32 { + audio().source_get_pitch(self.id).unwrap_or_default() + } + + /// Sets the pitch of this source. + pub fn set_pitch(&mut self, pitch: f32) { + audio().source_set_pitch(self.id, pitch).unwrap(); + } + + /// Determines whether this source is looping. + pub fn is_looping(&self) -> bool { + audio().source_is_looping(self.id).unwrap_or_default() + } + + /// Sets whether this source is looping. + pub fn set_looping(&mut self, looping: bool) { + audio().source_set_looping(self.id, looping).unwrap(); + } + + /// Gets whether this source is currently playing. pub fn is_playing(&self) -> bool { audio().source_is_playing(self.id).unwrap_or_default() } - /// Returns the volume of this source. - pub fn volume(&self) -> f32 { - audio().source_get_volume(self.id).unwrap_or_default() + /// Plays this source. + pub fn play(&mut self) { + audio().source_play(self.id).unwrap(); } - /// Sets the volume of this source. - pub fn set_volume(&mut self, volume: f32) { - audio().source_set_volume(self.id, volume).unwrap(); + /// Plays the given audio clip on this source with the current loop setting. + pub fn play_clip(&mut self, clip: &AudioClip) { + audio().source_set_clip(self.id, clip.id()).unwrap(); + audio().source_play(self.id).unwrap(); } - /// Plays the given audio clip on this source. - pub fn play(&mut self, clip: &AudioClip) { + /// Plays the given audio clip on this source once-off. + pub fn play_once(&mut self, clip: &AudioClip) { + self.set_looping(false); + + audio().source_set_clip(self.id, clip.id()).unwrap(); + audio().source_play(self.id).unwrap() + } + + /// Plays the given audio clip on this source in a loop. + pub fn play_looping(&mut self, clip: &AudioClip) { + self.set_looping(true); + audio().source_set_clip(self.id, clip.id()).unwrap(); audio().source_play(self.id).unwrap() }