1use matroska::Matroska;
4use rand::Rng;
5
6use log::{error, info, warn};
7
8use crate::container::info::*;
9use crate::container::play_settings::{PlaySettingsFile, PlaySettingsLegacy, SettingsTrack};
10use crate::dsp::effects::convolution_reverb::{
11 parse_impulse_response_spec, parse_impulse_response_tail_db, ImpulseResponseSpec,
12};
13use crate::dsp::effects::AudioEffect;
14
15#[derive(Debug, Clone)]
17pub struct Prot {
18 pub info: Info,
19 file_path: Option<String>,
20 file_paths: Option<Vec<Vec<String>>>,
21 file_paths_dictionary: Option<Vec<String>>,
22 track_ids: Option<Vec<u32>>,
23 track_paths: Option<Vec<String>>,
24 duration: f64,
25 play_settings: Option<PlaySettingsFile>,
26 impulse_response_spec: Option<ImpulseResponseSpec>,
27 impulse_response_tail_db: Option<f32>,
28 effects: Option<Vec<AudioEffect>>,
29}
30
31impl Prot {
32 pub fn new(file_path: &String) -> Self {
34 let info = Info::new(file_path.clone());
35
36 println!("Info: {:?}", info);
37
38 let mut this = Self {
39 info,
40 file_path: Some(file_path.clone()),
41 file_paths: None,
42 file_paths_dictionary: None,
43 track_ids: None,
44 track_paths: None,
45 duration: 0.0,
46 play_settings: None,
47 impulse_response_spec: None,
48 impulse_response_tail_db: None,
49 effects: None,
50 };
51
52 this.load_play_settings();
53 this.refresh_tracks();
54
55 this
56 }
57
58 pub fn new_from_file_paths(file_paths: &Vec<Vec<String>>) -> Self {
60 let mut file_paths_dictionary = Vec::new();
61 for file_path in file_paths {
64 for path in file_path {
65 if !file_paths_dictionary.contains(path) {
66 file_paths_dictionary.push(path.clone());
67 }
68 }
69 }
70
71 let info = Info::new_from_file_paths(file_paths_dictionary.clone());
72
73 let mut this = Self {
74 info,
75 file_path: None,
76 file_paths: Some(file_paths.clone()),
77 file_paths_dictionary: Some(file_paths_dictionary),
78 track_ids: None,
79 track_paths: None,
80 duration: 0.0,
81 play_settings: None,
82 impulse_response_spec: None,
83 impulse_response_tail_db: None,
84 effects: None,
85 };
86
87 this.refresh_tracks();
88
89 this
90 }
91
92 pub fn refresh_tracks(&mut self) {
99 let mut longest_duration = 0.0;
100
101 if let Some(file_paths) = &self.file_paths {
102 let mut track_paths: Vec<String> = Vec::new();
104 for file_path in file_paths {
105 let random_number = rand::thread_rng().gen_range(0..file_path.len());
106 let track_path = file_path[random_number].clone();
107
108 let index_in_dictionary = self
109 .file_paths_dictionary
110 .as_ref()
111 .unwrap()
112 .iter()
113 .position(|x| *x == track_path)
114 .unwrap();
115 let duration = self.info.get_duration(index_in_dictionary as u32).unwrap();
116
117 if duration > longest_duration {
118 longest_duration = duration;
119 self.duration = longest_duration;
120 }
121
122 track_paths.push(track_path);
123 }
124
125 self.track_paths = Some(track_paths);
126
127 return;
128 }
129
130 if !self.file_path.is_some() {
131 return;
132 }
133
134 let mut track_index_array: Vec<u32> = Vec::new();
135 match self.play_settings.as_ref() {
136 Some(play_settings) => match play_settings {
137 PlaySettingsFile::Legacy(file) => {
138 collect_legacy_tracks(
139 file.settings.inner(),
140 &mut track_index_array,
141 &mut longest_duration,
142 &self.info,
143 &mut self.duration,
144 );
145 }
146 PlaySettingsFile::V1(file) => {
147 collect_tracks_from_ids(
148 &file.settings.inner().tracks,
149 &mut track_index_array,
150 &mut longest_duration,
151 &self.info,
152 &mut self.duration,
153 );
154 }
155 PlaySettingsFile::V2(file) => {
156 collect_tracks_from_ids(
157 &file.settings.inner().tracks,
158 &mut track_index_array,
159 &mut longest_duration,
160 &self.info,
161 &mut self.duration,
162 );
163 }
164 PlaySettingsFile::Unknown { .. } => {
165 error!("Unknown file format");
166 }
167 },
168 None => {
169 warn!("No play_settings.json found; no tracks resolved.");
170 }
171 }
172
173 self.track_ids = Some(track_index_array);
174 }
175
176 pub fn get_effects(&self) -> Option<Vec<AudioEffect>> {
178 self.effects.clone()
179 }
180
181 fn load_play_settings(&mut self) {
182 println!("Loading play settings...");
183 let Some(file_path) = self.file_path.as_ref() else {
184 return;
185 };
186
187 let file = std::fs::File::open(file_path).unwrap();
188 let mka: Matroska = Matroska::open(file).expect("Could not open file");
189
190 let mut parsed = None;
191
192 for attachment in &mka.attachments {
193 if attachment.name == "play_settings.json" {
194 match serde_json::from_slice::<PlaySettingsFile>(&attachment.data) {
195 Ok(play_settings) => {
196 parsed = Some(play_settings);
197 break;
198 }
199 Err(err) => {
200 error!("Failed to parse play_settings.json: {}", err);
201 }
202 }
203 }
204 }
205
206 let Some(play_settings) = parsed else {
207 return;
208 };
209
210 info!("Parsed play_settings.json");
211
212 self.impulse_response_spec = parse_impulse_response_spec(&play_settings);
213 self.impulse_response_tail_db = parse_impulse_response_tail_db(&play_settings);
214
215 match &play_settings {
216 PlaySettingsFile::V1(file) => {
217 self.effects = Some(file.settings.inner().effects.clone());
218 }
219 PlaySettingsFile::V2(file) => {
220 self.effects = Some(file.settings.inner().effects.clone());
221 }
222 _ => {}
223 }
224
225 if let Some(effects) = self.effects.as_ref() {
226 info!(
227 "Loaded play_settings effects ({}): {:?}",
228 effects.len(),
229 effects
230 );
231 }
232
233 self.play_settings = Some(play_settings);
234 }
235
236 pub fn get_impulse_response_spec(&self) -> Option<ImpulseResponseSpec> {
238 self.impulse_response_spec.clone()
239 }
240
241 pub fn get_impulse_response_tail_db(&self) -> Option<f32> {
243 self.impulse_response_tail_db
244 }
245
246 pub fn get_container_path(&self) -> Option<String> {
248 self.file_path.clone()
249 }
250
251 pub fn set_impulse_response_spec(&mut self, spec: ImpulseResponseSpec) {
253 self.impulse_response_spec = Some(spec);
254 }
255
256 pub fn set_impulse_response_tail_db(&mut self, tail_db: f32) {
258 self.impulse_response_tail_db = Some(tail_db);
259 }
260
261 pub fn get_keys(&self) -> Vec<u32> {
263 if let Some(track_paths) = &self.track_paths {
265 return (0..track_paths.len() as u32).collect();
266 }
267
268 if let Some(track_ids) = &self.track_ids {
269 return (0..track_ids.len() as u32).collect();
270 }
271
272 Vec::new()
273 }
274
275 pub fn get_ids(&self) -> Vec<String> {
277 if let Some(track_paths) = &self.track_paths {
278 return track_paths.clone();
279 }
280
281 if let Some(track_ids) = &self.track_ids {
282 return track_ids.into_iter().map(|id| format!("{}", id)).collect();
283 }
284
285 Vec::new()
286 }
287
288 pub fn enumerated_list(&self) -> Vec<(u16, String, Option<u32>)> {
290 let mut list: Vec<(u16, String, Option<u32>)> = Vec::new();
291 if let Some(track_paths) = &self.track_paths {
292 for (index, file_path) in track_paths.iter().enumerate() {
293 list.push((index as u16, String::from(file_path), None));
294 }
295
296 return list;
297 }
298
299 if let Some(track_ids) = &self.track_ids {
300 for (index, track_id) in track_ids.iter().enumerate() {
301 list.push((
302 index as u16,
303 String::from(self.file_path.as_ref().unwrap()),
304 Some(*track_id),
305 ));
306 }
307
308 return list;
309 }
310
311 list
312 }
313
314 pub fn container_track_entries(&self) -> Option<(String, Vec<(u16, u32)>)> {
316 let file_path = self.file_path.as_ref()?;
317 let track_ids = self.track_ids.as_ref()?;
318 let mut entries = Vec::new();
319 for (index, track_id) in track_ids.iter().enumerate() {
320 entries.push((index as u16, *track_id));
321 }
322 Some((file_path.clone(), entries))
323 }
324
325 pub fn get_duration(&self) -> &f64 {
327 &self.duration
328 }
329
330 pub fn get_length(&self) -> usize {
332 if let Some(file_paths) = &self.file_paths {
333 return file_paths.len();
334 }
335
336 if let Some(track_ids) = &self.track_ids {
337 return track_ids.len();
338 }
339
340 0
341 }
342
343 pub fn get_file_paths_dictionary(&self) -> Vec<String> {
345 match &self.file_paths_dictionary {
346 Some(dictionary) => dictionary.to_vec(),
347 None => Vec::new(),
348 }
349 }
350}
351
352fn collect_tracks_from_ids(
353 tracks: &[SettingsTrack],
354 track_index_array: &mut Vec<u32>,
355 longest_duration: &mut f64,
356 info: &Info,
357 total_duration: &mut f64,
358) {
359 for track in tracks {
360 if track.ids.is_empty() {
361 continue;
362 }
363 let random_number = rand::thread_rng().gen_range(0..track.ids.len());
364 let index = track.ids[random_number];
365 if let Some(track_duration) = info.get_duration(index) {
366 if track_duration > *longest_duration {
367 *longest_duration = track_duration;
368 *total_duration = *longest_duration;
369 }
370 }
371 track_index_array.push(index);
372 }
373}
374
375fn collect_legacy_tracks(
376 settings: &PlaySettingsLegacy,
377 track_index_array: &mut Vec<u32>,
378 longest_duration: &mut f64,
379 info: &Info,
380 total_duration: &mut f64,
381) {
382 for track in &settings.tracks {
383 let (Some(starting_index), Some(length)) = (track.starting_index, track.length) else {
384 continue;
385 };
386 let starting_index = starting_index + 1;
387 let index = rand::thread_rng().gen_range(starting_index..(starting_index + length));
388 if let Some(track_duration) = info.get_duration(index) {
389 if track_duration > *longest_duration {
390 *longest_duration = track_duration;
391 *total_duration = *longest_duration;
392 }
393 }
394 track_index_array.push(index);
395 }
396}