1use std::sync::{Arc, RwLock};
2
3use crate::asset::{self, audio::Samples};
4use crate::random::{self, Distribute};
5
6use luminance_sdl2::sdl2::Sdl;
7use luminance_sdl2::sdl2::audio::{AudioCallback, AudioDevice, AudioSpecDesired};
8
9pub const SAMPLE_RATE: i32 = 48000;
10
11macro_rules! impl_builder {
12 ( $( $field:ident : $type:ty ),* $(,)? ) => {
13 $(
14 pub fn $field(mut self, $field: $type) -> Self {
15 self.$field = $field;
16 self
17 }
18 )*
19 }
20}
21
22#[derive(Clone)]
24pub struct AudioSource {
25 position: f32,
27 looping: bool,
29 samples: Arc<RwLock<Samples>>,
31
32 gain: f32,
33 gain_variance: f32,
34 pitch: f32,
35 pitch_variance: f32,
36
37 remove: bool,
43}
44
45impl AudioSource {
46 pub fn new(audio: &asset::Audio) -> Self {
47 Self {
48 position: 0.0,
49 looping: false,
50 samples: audio.samples(),
51 gain: 1.0,
52 gain_variance: 0.0,
53 pitch: 1.0,
54 pitch_variance: 0.0,
55 remove: false,
56 }
57 }
58
59 impl_builder!(
60 looping: bool,
61 gain: f32,
62 gain_variance: f32,
63 pitch: f32,
64 pitch_variance: f32,
65 );
66}
67
68pub struct Audio {
70 sources: Vec<AudioSource>,
71 gain: f32,
72}
73
74impl Audio {
75 pub fn init(sdl: &Sdl) -> AudioDevice<Self> {
76 let audio_subsystem = sdl.audio().unwrap();
77 let desired = AudioSpecDesired {
78 freq: Some(SAMPLE_RATE),
79 channels: Some(2),
80 samples: Some(1024),
81 };
82
83 audio_subsystem.open_playback(None, &desired, |spec| {
84 assert_eq!(spec.freq, SAMPLE_RATE); Self {
86 sources: Vec::new(),
87 gain: 1.0,
88 }
89 }).unwrap()
90 }
91
92 pub fn play(&mut self, mut source: AudioSource) {
101 if source.gain_variance != 0.0 {
102 source.gain += random::Uniform.between(-source.gain_variance, source.gain_variance);
103 }
104 if source.pitch_variance != 0.0 {
105 source.pitch += random::Uniform.between(-source.pitch_variance, source.pitch_variance);
106 }
107 assert!(source.pitch > 0.0);
108 self.sources.push(source);
109 }
110
111 pub fn gain(&self) -> f32 {
112 self.gain
113 }
114
115 pub fn gain_mut(&mut self) -> &mut f32 {
116 &mut self.gain
117 }
118}
119
120impl AudioCallback for Audio {
121 type Channel = f32;
122
123 fn callback(&mut self, out: &mut [Self::Channel]) {
124 for x in out.iter_mut() {
126 *x = 0.0;
127 }
128
129 'sources: for source in self.sources.iter_mut() {
130 let samples = source.samples.read().unwrap();
131 for x in out.iter_mut() {
132 source.position += source.pitch * samples.sample_rate() as f32 / SAMPLE_RATE as f32 ;
134 let position = source.position as usize; let data = samples.data();
136 let num_samples = data.len();
137
138 if num_samples <= position && !source.looping {
140 source.remove = true;
141 continue 'sources;
142 }
143
144 let (a, b) = if source.looping {
145 source.position -= (source.position as usize - position) as f32;
147 (&data[position % num_samples], &data[(position + 1) % num_samples])
148 } else {
149 (data.get(position).unwrap_or(&0.0), data.get(position + 1).unwrap_or(&0.0))
150 };
151
152 let fade = source.position.rem_euclid(1.0);
154 *x += (1.0 - fade) * a * source.gain * self.gain;
155 *x += (fade) * b * source.gain * self.gain;
156 }
157 }
158
159 let mut i = 0;
161 while i != self.sources.len() {
162 if self.sources[i].remove {
163 self.sources.remove(i);
164 } else {
165 i += 1;
166 }
167 }
168 }
169}