如何使用Rust SDL2播放WAV文件?

时间:2015-10-10 17:56:30

标签: audio rust wav sdl-2

我正在尝试使用rust-sdl2播放WAV文件。

我找到了AudioSpecWAV,但没有一种音频初始化方法似乎把它作为一种类型,并且它没有实现AudioCallback。我尝试使用自己的回调来实现这一点,如下所示:

struct MyWav {
    wav: AudioSpecWAV,
    volume: f32,
    pos: usize,
}

impl AudioCallback for MyWav {
    type Channel = f32;

    fn callback(&mut self, out: &mut [f32]) {
        for x in out.iter_mut() {
            *x = match self.wav.buffer().get(self.pos) {
                Some(v) => { self.pos += 1; v as f32 },
                None => { 0.0 }
            }
        }
    }
}

...但我不知道如何解决以下错误:

the traitcore::marker::Sync is not implemented for the type *mut u8

这似乎是audio_buf的{​​{1}}字段,但如果不是AudioSpecWAV我应该如何将缓冲区传递给回调?

(供参考,here is an example of playing a generated sound

1 个答案:

答案 0 :(得分:1)

AudioCallback要求实施者Send。您可以通过在结构中包装AudioSpecWAV并在该结构上为unsafe impl执行Send来实现,或者您可以复制数据。既然你不应该使用不安全的东西,除非你知道你在做什么实际上是安全的,你可能想看一下复制方法。

以下是两种方法的示例:

extern crate sdl2;

use std::thread::{self};

use sdl2::{Sdl};
use sdl2::audio::{self, AudioSpecDesired, AudioSpecWAV, AudioCallback, AudioDevice};

//----------------------------------------------------------------------------//

struct CopiedData {
    bytes: Vec<u8>,
    position: usize
}

impl AudioCallback for CopiedData {
    type Channel = u8;

    fn callback(&mut self, data: &mut [u8]) {
        let (start, end) = (self.position, self.position + data.len());
        self.position += data.len();

        let audio_data = &self.bytes[start..end];
        for (src, dst) in audio_data.iter().zip(data.iter_mut()) {
            *dst = *src;
        }
    }
}

//----------------------------------------------------------------------------//

struct WrappedData {
    audio: AudioSpecWAV,
    position: usize
}

impl AudioCallback for WrappedData {
    type Channel = u8;

    fn callback(&mut self, data: &mut [u8]) {
        let (start, end) = (self.position, self.position + data.len());
        self.position += data.len();

        let audio_data = &self.audio.buffer()[start..end];
        for (src, dst) in audio_data.iter().zip(data.iter_mut()) {
            *dst = *src;
        }
    }
}

unsafe impl Send for WrappedData { }

//----------------------------------------------------------------------------//

pub fn main() {
    let sdl_context = sdl2::init().unwrap();
    let audio_system = sdl_context.audio().unwrap();

    let audio_spec = AudioSpecDesired{ freq: None, channels: None, samples: None };
    let audio_wav = AudioSpecWAV::load_wav("test.wav").unwrap();

    let copied_data = CopiedData{ bytes: audio_wav.buffer().to_vec(), position: 0 };
    //let wrapped_data = WrappedData{ audio: audio_wav, position: 0 };

    let audio_device = audio_system.open_playback(None, audio_spec, move |spec| {
        copied_data
    }).unwrap();

    audio_device.resume();

    thread::sleep_ms(5000);
}

注意:我正在播放的WAV非常响亮(听起来有点失真)并且我不是一个好人,所以我不确定这是否与我的代码或我使用的WAV文件有关总的来说。