use std::cmp::min;
use blip_buf::BlipBuf;
use crate::audio::Audio;
use crate::pyxel::{CHANNELS, SOUNDS};
use crate::settings::{AUDIO_CLOCK_RATE, AUDIO_SAMPLE_RATE};
pub type SharedSeq = shared_type!(Vec<u32>);
#[derive(Clone)]
pub struct Music {
pub seqs: Vec<SharedSeq>,
}
pub type SharedMusic = shared_type!(Music);
impl Music {
pub fn new() -> SharedMusic {
new_shared_type!(Self { seqs: Vec::new() })
}
pub fn set(&mut self, seqs: &[Vec<u32>]) {
self.seqs = seqs
.iter()
.map(|seq| new_shared_type!(seq.clone()))
.collect();
let num_channels = CHANNELS.lock().len();
while self.seqs.len() < num_channels {
self.seqs.push(new_shared_type!(Vec::new()));
}
}
pub fn save(
&self,
filename: &str,
duration_sec: f32,
use_ffmpeg: Option<bool>,
) -> Result<(), String> {
assert!(duration_sec > 0.0);
let num_samples = (duration_sec * AUDIO_SAMPLE_RATE as f32).round() as u32;
if num_samples == 0 {
return Ok(());
}
let seqs: Vec<_> = (0..self.seqs.len())
.map(|i| {
let pyxel_sounds = SOUNDS.lock();
self.seqs[i]
.lock()
.iter()
.map(|&sound_index| pyxel_sounds[sound_index as usize].clone())
.collect::<Vec<_>>()
})
.collect();
let mut samples = vec![0; num_samples as usize];
let mut blip_buf = BlipBuf::new(num_samples);
blip_buf.set_rates(AUDIO_CLOCK_RATE as f64, AUDIO_SAMPLE_RATE as f64);
let channels = CHANNELS.lock();
channels.iter().for_each(|channel| channel.lock().stop());
{
let mut channels: Vec<_> = channels.iter().map(|channel| channel.lock()).collect();
for i in 0..min(channels.len(), seqs.len()) {
channels[i].play(seqs[i].clone(), None, true, false);
}
}
Audio::render_samples(&channels, &mut blip_buf, &mut samples);
let result = Audio::save_samples(filename, &samples, use_ffmpeg.unwrap_or(false));
channels.iter().for_each(|channel| channel.lock().stop());
result
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_music_new() {
let music = Music::new();
assert_eq!(music.lock().seqs.len(), 0);
}
#[test]
fn test_music_set() {
let music = Music::new();
music
.lock()
.set(&[vec![0, 1, 2], vec![1, 2, 3], vec![2, 3, 4]]);
for i in 0..3 {
assert_eq!(
&*music.lock().seqs[i as usize].lock(),
&vec![i, i + 1, i + 2]
);
}
}
}