init, load multiple files and merge into one audio stream
This commit is contained in:
commit
fc714de35c
7 changed files with 1117 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/target
|
1010
Cargo.lock
generated
Normal file
1010
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
9
Cargo.toml
Normal file
9
Cargo.toml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
[package]
|
||||||
|
name = "snoud"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rodio = { version = "0.16.0", default_features = false, features = ["mp3"] }
|
BIN
sound/rain.mp3
Normal file
BIN
sound/rain.mp3
Normal file
Binary file not shown.
BIN
sound/thunder.mp3
Normal file
BIN
sound/thunder.mp3
Normal file
Binary file not shown.
BIN
sound/wind.mp3
Normal file
BIN
sound/wind.mp3
Normal file
Binary file not shown.
97
src/main.rs
Normal file
97
src/main.rs
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
use rodio::source::{Repeat, Source};
|
||||||
|
use rodio::{Decoder, OutputStream};
|
||||||
|
use std::fs::File;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
type Volume = f32;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let files: Vec<String> = vec![
|
||||||
|
"sound/rain.mp3".into(),
|
||||||
|
"sound/thunder.mp3".into(),
|
||||||
|
"sound/wind.mp3".into(),
|
||||||
|
];
|
||||||
|
let source = Snoud::new(&files);
|
||||||
|
|
||||||
|
let (_stream, stream_handle) = OutputStream::try_default().unwrap();
|
||||||
|
|
||||||
|
stream_handle.play_raw(source.convert_samples()).unwrap();
|
||||||
|
|
||||||
|
// let sink = Sink::try_new(&stream_handle).unwrap();
|
||||||
|
// sink.append(source);
|
||||||
|
// sink.play();
|
||||||
|
loop {
|
||||||
|
std::thread::sleep(Duration::from_millis(200));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Snoud {
|
||||||
|
channels: Vec<SoundChannel>,
|
||||||
|
sample_rate: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SoundChannel {
|
||||||
|
source: Repeat<Decoder<File>>,
|
||||||
|
paused: bool,
|
||||||
|
volume: Volume,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SoundChannel {
|
||||||
|
fn new(name: &String) -> Self {
|
||||||
|
let file = File::open(name).expect("File not found");
|
||||||
|
let source = Decoder::new(file)
|
||||||
|
.expect("Could not decode file")
|
||||||
|
.repeat_infinite();
|
||||||
|
Self {
|
||||||
|
source,
|
||||||
|
paused: false,
|
||||||
|
volume: 1.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for Snoud {
|
||||||
|
type Item = i16;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let mut out: Self::Item = 0;
|
||||||
|
for c in &mut self.channels {
|
||||||
|
if c.paused {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let mut sample: Self::Item = c.source.next().unwrap();
|
||||||
|
sample = (f32::from(sample) * c.volume) as Self::Item;
|
||||||
|
out = out.saturating_add(sample);
|
||||||
|
}
|
||||||
|
Some(out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Source for Snoud {
|
||||||
|
fn channels(&self) -> u16 {
|
||||||
|
2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sample_rate(&self) -> u32 {
|
||||||
|
self.sample_rate
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current_frame_len(&self) -> Option<usize> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn total_duration(&self) -> Option<Duration> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Snoud {
|
||||||
|
fn new(filenames: &[String]) -> Self {
|
||||||
|
let channels = filenames.iter().map(SoundChannel::new).collect();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
sample_rate: 48000,
|
||||||
|
channels,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue