proteus_lib/playback/engine/
mod.rs1use dasp_ring_buffer::Bounded;
4use rodio::buffer::SamplesBuffer;
5use std::collections::HashMap;
6use std::sync::atomic::AtomicBool;
7use std::sync::atomic::AtomicU64;
8use std::sync::{mpsc::Receiver, Arc, Condvar, Mutex};
9
10use crate::audio::buffer::{init_buffer_map, TrackBuffer};
11use crate::container::prot::Prot;
12
13mod mix;
14mod premix;
15mod state;
16
17pub use state::{DspChainMetrics, PlaybackBufferSettings};
18
19use mix::{spawn_mix_thread, MixThreadArgs};
20
21#[derive(Debug, Clone)]
23pub struct PlayerEngine {
24 pub finished_tracks: Arc<Mutex<Vec<u16>>>,
25 start_time: f64,
26 abort: Arc<AtomicBool>,
27 buffer_map: Arc<Mutex<HashMap<u16, TrackBuffer>>>,
28 buffer_notify: Arc<Condvar>,
29 effects_buffer: Arc<Mutex<Bounded<Vec<f32>>>>,
30 track_weights: Arc<Mutex<HashMap<u16, f32>>>,
31 track_channel_gains: Arc<Mutex<HashMap<u16, Vec<f32>>>>,
32 effects_reset: Arc<AtomicU64>,
33 prot: Arc<Mutex<Prot>>,
34 buffer_settings: Arc<Mutex<PlaybackBufferSettings>>,
35 effects: Arc<Mutex<Vec<crate::dsp::effects::AudioEffect>>>,
36 dsp_metrics: Arc<Mutex<DspChainMetrics>>,
37}
38
39impl PlayerEngine {
40 pub fn new(
42 prot: Arc<Mutex<Prot>>,
43 abort_option: Option<Arc<AtomicBool>>,
44 start_time: f64,
45 buffer_settings: Arc<Mutex<PlaybackBufferSettings>>,
46 effects: Arc<Mutex<Vec<crate::dsp::effects::AudioEffect>>>,
47 dsp_metrics: Arc<Mutex<DspChainMetrics>>,
48 effects_reset: Arc<AtomicU64>,
49 ) -> Self {
50 let buffer_map = init_buffer_map();
51 let buffer_notify = Arc::new(Condvar::new());
52 let track_weights = Arc::new(Mutex::new(HashMap::new()));
53 let track_channel_gains = Arc::new(Mutex::new(HashMap::new()));
54 let finished_tracks: Arc<Mutex<Vec<u16>>> = Arc::new(Mutex::new(Vec::new()));
55 let abort = if abort_option.is_some() {
56 abort_option.unwrap()
57 } else {
58 Arc::new(AtomicBool::new(false))
59 };
60
61 let prot_unlocked = prot.lock().unwrap();
62 let start_buffer_ms = buffer_settings.lock().unwrap().start_buffer_ms;
63 let channels = prot_unlocked.info.channels as usize;
64 let start_samples = ((prot_unlocked.info.sample_rate as f32 * start_buffer_ms) / 1000.0)
65 as usize
66 * channels;
67 let buffer_size = (prot_unlocked.info.sample_rate as usize * 10).max(start_samples * 2);
68 let effects_buffer = Arc::new(Mutex::new(dasp_ring_buffer::Bounded::from(vec![
69 0.0;
70 buffer_size
71 ])));
72 drop(prot_unlocked);
73
74 Self {
75 finished_tracks,
76 start_time,
77 buffer_map,
78 buffer_notify,
79 effects_buffer,
80 track_weights,
81 track_channel_gains,
82 effects_reset,
83 abort,
84 prot,
85 buffer_settings,
86 effects,
87 dsp_metrics,
88 }
89 }
90
91 pub fn reception_loop(&mut self, f: &dyn Fn((SamplesBuffer, f64))) {
93 let prot = self.prot.lock().unwrap();
94 let keys = prot.get_keys();
95 drop(prot);
96 self.ready_buffer_map(&keys);
97 let receiver = self.get_receiver();
98
99 for (mixer, length_in_seconds) in receiver {
100 f((mixer, length_in_seconds));
101 }
102 }
103
104 pub fn start_receiver(&mut self) -> Receiver<(SamplesBuffer, f64)> {
106 let prot = self.prot.lock().unwrap();
107 let keys = prot.get_keys();
108 drop(prot);
109 self.ready_buffer_map(&keys);
110 self.get_receiver()
111 }
112
113 fn get_receiver(&self) -> Receiver<(SamplesBuffer, f64)> {
114 let prot = self.prot.lock().unwrap();
115 let audio_info = prot.info.clone();
116 drop(prot);
117
118 spawn_mix_thread(MixThreadArgs {
119 audio_info,
120 buffer_map: self.buffer_map.clone(),
121 buffer_notify: self.buffer_notify.clone(),
122 effects_buffer: self.effects_buffer.clone(),
123 track_weights: self.track_weights.clone(),
124 track_channel_gains: self.track_channel_gains.clone(),
125 effects_reset: self.effects_reset.clone(),
126 finished_tracks: self.finished_tracks.clone(),
127 prot: self.prot.clone(),
128 abort: self.abort.clone(),
129 start_time: self.start_time,
130 buffer_settings: self.buffer_settings.clone(),
131 effects: self.effects.clone(),
132 dsp_metrics: self.dsp_metrics.clone(),
133 })
134 }
135
136 pub fn get_duration(&self) -> f64 {
138 let prot = self.prot.lock().unwrap();
139 *prot.get_duration()
140 }
141
142 fn ready_buffer_map(&mut self, keys: &Vec<u32>) {
143 self.buffer_map = init_buffer_map();
144 self.track_weights.lock().unwrap().clear();
145 self.track_channel_gains.lock().unwrap().clear();
146
147 let prot = self.prot.lock().unwrap();
148 let sample_rate = prot.info.sample_rate;
149 let channels = prot.info.channels as usize;
150 let track_mix_settings = prot.get_track_mix_settings();
151 let start_buffer_ms = self.buffer_settings.lock().unwrap().start_buffer_ms;
152 drop(prot);
153 let start_samples = ((sample_rate as f32 * start_buffer_ms) / 1000.0) as usize * channels;
154 let buffer_size = (sample_rate as usize * 10).max(start_samples * 2);
155
156 for key in keys {
157 let ring_buffer = Arc::new(Mutex::new(dasp_ring_buffer::Bounded::from(vec![
158 0.0;
159 buffer_size
160 ])));
161 self.buffer_map
162 .lock()
163 .unwrap()
164 .insert(*key as u16, ring_buffer);
165 self.track_weights.lock().unwrap().insert(*key as u16, 1.0);
166 let (level, pan) = track_mix_settings
167 .get(&(*key as u16))
168 .copied()
169 .unwrap_or((1.0, 0.0));
170 let gains = compute_track_channel_gains(level, pan, channels);
171 self.track_channel_gains
172 .lock()
173 .unwrap()
174 .insert(*key as u16, gains);
175 }
176 }
177
178 pub fn finished_buffering(&self) -> bool {
180 let finished_tracks = self.finished_tracks.lock().unwrap();
181 let prot = self.prot.lock().unwrap();
182 let keys = prot.get_keys();
183 drop(prot);
184
185 for key in keys {
186 if !finished_tracks.contains(&(key as u16)) {
187 return false;
188 }
189 }
190
191 true
192 }
193}
194
195fn compute_track_channel_gains(level: f32, pan: f32, channels: usize) -> Vec<f32> {
196 let level = level.max(0.0);
197 if channels <= 1 {
198 return vec![level];
199 }
200
201 let pan = pan.clamp(-1.0, 1.0);
202 let left = if pan > 0.0 { 1.0 - pan } else { 1.0 };
203 let right = if pan < 0.0 { 1.0 + pan } else { 1.0 };
204
205 let mut gains = vec![level; channels];
206 gains[0] = level * left;
207 gains[1] = level * right;
208 gains
209}