Files

88 lines
2.8 KiB
Rust
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
extern crate sdl2;
use sdl2::audio::{AudioCVT, AudioCallback, AudioSpecDesired, AudioSpecWAV};
use std::borrow::Cow;
use std::path::{Path, PathBuf};
use std::time::Duration;
// NOTE: You probably want to investigate the
// mixer feature for real use cases.
struct Sound {
data: Vec<u8>,
volume: f32,
pos: usize,
}
impl AudioCallback for Sound {
type Channel = u8;
fn callback(&mut self, out: &mut [u8]) {
for dst in out.iter_mut() {
// With channel type u8 the "silence" value is 128 (middle of the 0-2^8 range) so we need
// to both fill in the silence and scale the wav data accordingly. Filling the silence
// once the wav is finished is trivial, applying the volume is more tricky. We need to:
// * Change the range of the values from [0, 255] to [-128, 127] so we can multiply
// * Apply the volume by multiplying, this gives us range [-128*volume, 127*volume]
// * Move the resulting range to a range centered around the value 128, the final range
// is [128 - 128*volume, 128 + 127*volume] – scaled and correctly positioned
//
// Using value 0 instead of 128 would result in clicking. Scaling by simply multiplying
// would not give correct results.
let pre_scale = *self.data.get(self.pos).unwrap_or(&128);
let scaled_signed_float = (pre_scale as f32 - 128.0) * self.volume;
let scaled = (scaled_signed_float + 128.0) as u8;
*dst = scaled;
self.pos += 1;
}
}
}
fn main() -> Result<(), String> {
let wav_file: Cow<'static, Path> = match std::env::args().nth(1) {
None => Cow::from(Path::new("./assets/sine.wav")),
Some(s) => Cow::from(PathBuf::from(s)),
};
let sdl_context = sdl2::init()?;
let audio_subsystem = sdl_context.audio()?;
let desired_spec = AudioSpecDesired {
freq: Some(44_100),
channels: Some(1), // mono
samples: None, // default
};
let device = audio_subsystem.open_playback(None, &desired_spec, |spec| {
let wav = AudioSpecWAV::load_wav(wav_file).expect("Could not load test WAV file");
let cvt = AudioCVT::new(
wav.format,
wav.channels,
wav.freq,
spec.format,
spec.channels,
spec.freq,
)
.expect("Could not convert WAV file");
let data = cvt.convert(wav.buffer().to_vec());
// initialize the audio callback
Sound {
data,
volume: 0.25,
pos: 0,
}
})?;
// Start playback
device.resume();
// Play for a second
std::thread::sleep(Duration::from_millis(1_000));
// Device is automatically closed when dropped
Ok(())
}