Skip to content

Commit

Permalink
Merge pull request Rust-SDL2#970 from jstasiak/chunks-from-buffers
Browse files Browse the repository at this point in the history
Provide memory buffer -> mixer Chunk conversion methods
  • Loading branch information
Cobrand authored Apr 2, 2020
2 parents 3ccab7a + 0aaf103 commit cffd708
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 4 deletions.
21 changes: 18 additions & 3 deletions examples/mixer-demo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,24 @@ fn demo(music_file: &Path, sound_file: Option<&Path>) -> Result<(), String> {
println!("music volume => {:?}", sdl2::mixer::Music::get_volume());
println!("play => {:?}", music.play(1));

if let Some(sound_file_path) = sound_file {
let sound_chunk = sdl2::mixer::Chunk::from_file(sound_file_path)
.map_err(|e| format!("Cannot load sound file: {:?}", e))?;
{
let sound_chunk = match sound_file {
Some(sound_file_path) => sdl2::mixer::Chunk::from_file(sound_file_path)
.map_err(|e| format!("Cannot load sound file: {:?}", e))?,
None => {
// One second of 500Hz sine wave using equation A * sin(2 * PI * f * t)
// (played at half the volume to save people's ears).
let buffer = (0..frequency)
.map(|i| {
(0.1 * i16::max_value() as f32
* (2.0 * 3.14 * 500.0 * (i as f32 / frequency as f32)).sin())
as i16
})
.collect();
sdl2::mixer::Chunk::from_raw_buffer(buffer)
.map_err(|e| format!("Cannot get chunk from buffer: {:?}", e))?
}
};

println!("chunk volume => {:?}", sound_chunk.get_volume());
println!("playing sound twice");
Expand Down
28 changes: 27 additions & 1 deletion src/sdl2/mixer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
//! ```
use std::marker::PhantomData;
use std::convert::TryInto;
use std::default;
use std::fmt;
use std::ffi::{CString, CStr};
Expand All @@ -29,6 +30,7 @@ use std::borrow::ToOwned;
use std::path::Path;
use libc::c_void;
use libc::{c_int, c_double, c_uint};
use ::audio::AudioFormatNum;
use ::get_error;
use ::rwops::RWops;
use ::version::Version;
Expand Down Expand Up @@ -229,7 +231,15 @@ pub struct Chunk {
impl Drop for Chunk {
fn drop(&mut self) {
if self.owned {
unsafe { mixer::Mix_FreeChunk(self.raw) }
unsafe {
// Mix_QuickLoad_* functions don't set the allocated flag, but from_raw_buffer
// *does* take ownership of the data, so we need to deallocate the buffers here,
// because Mix_FreeChunk won't and we'd be leaking memory otherwise.
if (*self.raw).allocated == 0 {
drop(Box::from_raw((*self.raw).abuf));
}
mixer::Mix_FreeChunk(self.raw);
}
}
}
}
Expand All @@ -238,6 +248,22 @@ impl Chunk {
/// Load file for use as a sample.
pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Chunk, String> {
let raw = unsafe { mixer::Mix_LoadWAV_RW(RWops::from_file(path, "rb")?.raw(), 0) };
Self::from_owned_raw(raw)
}

/// Load chunk from a buffer containing raw audio data in the mixer format. The length of the
/// buffer has to fit in 32-bit unsigned integer. The chunk takes ownership of the buffer.
///
/// It's your responsibility to provide the audio data in the right format, as no conversion
/// will take place when using this method.
pub fn from_raw_buffer<T: AudioFormatNum>(buffer: Box<[T]>) -> Result<Chunk, String> {
use std::mem::size_of;
let len: u32 = (buffer.len() * size_of::<T>()).try_into().unwrap();
let raw = unsafe { mixer::Mix_QuickLoad_RAW(Box::into_raw(buffer) as *mut u8, len) };
Self::from_owned_raw(raw)
}

fn from_owned_raw(raw: *mut mixer::Mix_Chunk) -> Result<Chunk, String> {
if raw.is_null() {
Err(get_error())
} else {
Expand Down

0 comments on commit cffd708

Please sign in to comment.