1use matroska::Matroska;
4use rand::Rng;
5use std::collections::HashMap;
6
7use log::{error, info, warn};
8
9use crate::container::info::*;
10use crate::container::play_settings::{PlaySettingsFile, PlaySettingsLegacy, SettingsTrack};
11use crate::dsp::effects::convolution_reverb::{
12 parse_impulse_response_spec, parse_impulse_response_tail_db, ImpulseResponseSpec,
13};
14use crate::dsp::effects::AudioEffect;
15
16#[derive(Debug, Clone)]
18pub struct Prot {
19 pub info: Info,
20 file_path: Option<String>,
21 file_paths: Option<Vec<PathsTrack>>,
22 file_paths_dictionary: Option<Vec<String>>,
23 track_ids: Option<Vec<u32>>,
24 track_paths: Option<Vec<String>>,
25 duration: f64,
26 play_settings: Option<PlaySettingsFile>,
27 impulse_response_spec: Option<ImpulseResponseSpec>,
28 impulse_response_tail_db: Option<f32>,
29 effects: Option<Vec<AudioEffect>>,
30}
31
32impl Prot {
33 pub fn new(file_path: &String) -> Self {
35 let info = Info::new(file_path.clone());
36
37 println!("Info: {:?}", info);
38
39 let mut this = Self {
40 info,
41 file_path: Some(file_path.clone()),
42 file_paths: None,
43 file_paths_dictionary: None,
44 track_ids: None,
45 track_paths: None,
46 duration: 0.0,
47 play_settings: None,
48 impulse_response_spec: None,
49 impulse_response_tail_db: None,
50 effects: None,
51 };
52
53 this.load_play_settings();
54 this.refresh_tracks();
55
56 this
57 }
58
59 pub fn new_from_file_paths(file_paths: Vec<PathsTrack>) -> Self {
61 let mut file_paths_dictionary = Vec::new();
62 for track in file_paths.clone() {
65 for path in &track.file_paths {
66 if !file_paths_dictionary.contains(path) {
67 file_paths_dictionary.push(path.clone());
68 }
69 }
70 }
71
72 let info = Info::new_from_file_paths(file_paths_dictionary.clone());
73
74 let mut this = Self {
75 info,
76 file_path: None,
77 file_paths: Some(file_paths),
78 file_paths_dictionary: Some(file_paths_dictionary),
79 track_ids: None,
80 track_paths: None,
81 duration: 0.0,
82 play_settings: None,
83 impulse_response_spec: None,
84 impulse_response_tail_db: None,
85 effects: None,
86 };
87
88 this.refresh_tracks();
89
90 this
91 }
92
93 pub fn new_from_file_paths_legacy(file_paths: &Vec<Vec<String>>) -> Self {
95 let mut paths_track_list = Vec::new();
96 for track in file_paths {
97 paths_track_list.push(PathsTrack::new_from_file_paths(track.clone()));
98 }
99 Self::new_from_file_paths(paths_track_list)
100 }
101
102 pub fn refresh_tracks(&mut self) {
109 let mut longest_duration = 0.0;
110
111 if let Some(file_paths) = &self.file_paths {
112 let mut track_paths: Vec<String> = Vec::new();
114 for track in file_paths {
115 if track.file_paths.is_empty() {
116 continue;
117 }
118 let selections = track.selections_count as usize;
119 if selections == 0 {
120 continue;
121 }
122 for _ in 0..selections {
123 let random_number = rand::thread_rng().gen_range(0..track.file_paths.len());
124 let track_path = track.file_paths[random_number].clone();
125
126 let index_in_dictionary = self
127 .file_paths_dictionary
128 .as_ref()
129 .unwrap()
130 .iter()
131 .position(|x| *x == track_path)
132 .unwrap();
133 let duration = self.info.get_duration(index_in_dictionary as u32).unwrap();
134
135 if duration > longest_duration {
136 longest_duration = duration;
137 self.duration = longest_duration;
138 }
139
140 track_paths.push(track_path);
141 }
142 }
143
144 self.track_paths = Some(track_paths);
145
146 return;
147 }
148
149 if !self.file_path.is_some() {
150 return;
151 }
152
153 let mut track_index_array: Vec<u32> = Vec::new();
154 match self.play_settings.as_ref() {
155 Some(play_settings) => match play_settings {
156 PlaySettingsFile::Legacy(file) => {
157 collect_legacy_tracks(
158 file.settings.inner(),
159 &mut track_index_array,
160 &mut longest_duration,
161 &self.info,
162 &mut self.duration,
163 );
164 }
165 PlaySettingsFile::V1(file) => {
166 collect_tracks_from_ids(
167 &file.settings.inner().tracks,
168 &mut track_index_array,
169 &mut longest_duration,
170 &self.info,
171 &mut self.duration,
172 );
173 }
174 PlaySettingsFile::V2(file) => {
175 collect_tracks_from_ids(
176 &file.settings.inner().tracks,
177 &mut track_index_array,
178 &mut longest_duration,
179 &self.info,
180 &mut self.duration,
181 );
182 }
183 PlaySettingsFile::V3(file) => {
184 collect_tracks_from_ids(
185 &file.settings.inner().tracks,
186 &mut track_index_array,
187 &mut longest_duration,
188 &self.info,
189 &mut self.duration,
190 );
191 }
192 PlaySettingsFile::Unknown { .. } => {
193 error!("Unknown file format");
194 }
195 },
196 None => {
197 warn!("No play_settings.json found; no tracks resolved.");
198 }
199 }
200
201 self.track_ids = Some(track_index_array);
202 }
203
204 pub fn get_effects(&self) -> Option<Vec<AudioEffect>> {
206 self.effects.clone()
207 }
208
209 fn load_play_settings(&mut self) {
210 println!("Loading play settings...");
211 let Some(file_path) = self.file_path.as_ref() else {
212 return;
213 };
214
215 let file = std::fs::File::open(file_path).unwrap();
216 let mka: Matroska = Matroska::open(file).expect("Could not open file");
217
218 let mut parsed = None;
219
220 for attachment in &mka.attachments {
221 if attachment.name == "play_settings.json" {
222 match serde_json::from_slice::<PlaySettingsFile>(&attachment.data) {
223 Ok(play_settings) => {
224 parsed = Some(play_settings);
225 break;
226 }
227 Err(err) => {
228 error!("Failed to parse play_settings.json: {}", err);
229 }
230 }
231 }
232 }
233
234 let Some(play_settings) = parsed else {
235 return;
236 };
237
238 info!("Parsed play_settings.json");
239
240 self.impulse_response_spec = parse_impulse_response_spec(&play_settings);
241 self.impulse_response_tail_db = parse_impulse_response_tail_db(&play_settings);
242
243 match &play_settings {
244 PlaySettingsFile::V1(file) => {
245 self.effects = Some(file.settings.inner().effects.clone());
246 }
247 PlaySettingsFile::V2(file) => {
248 self.effects = Some(file.settings.inner().effects.clone());
249 }
250 PlaySettingsFile::V3(file) => {
251 self.effects = Some(file.settings.inner().effects.clone());
252 }
253 _ => {}
254 }
255
256 if let Some(effects) = self.effects.as_ref() {
257 info!(
258 "Loaded play_settings effects ({}): {:?}",
259 effects.len(),
260 effects
261 );
262 }
263
264 self.play_settings = Some(play_settings);
265 }
266
267 pub fn get_impulse_response_spec(&self) -> Option<ImpulseResponseSpec> {
269 self.impulse_response_spec.clone()
270 }
271
272 pub fn get_impulse_response_tail_db(&self) -> Option<f32> {
274 self.impulse_response_tail_db
275 }
276
277 pub fn get_container_path(&self) -> Option<String> {
279 self.file_path.clone()
280 }
281
282 pub fn set_impulse_response_spec(&mut self, spec: ImpulseResponseSpec) {
284 self.impulse_response_spec = Some(spec);
285 }
286
287 pub fn set_impulse_response_tail_db(&mut self, tail_db: f32) {
289 self.impulse_response_tail_db = Some(tail_db);
290 }
291
292 pub fn get_keys(&self) -> Vec<u32> {
294 if let Some(track_paths) = &self.track_paths {
296 return (0..track_paths.len() as u32).collect();
297 }
298
299 if let Some(track_ids) = &self.track_ids {
300 return (0..track_ids.len() as u32).collect();
301 }
302
303 Vec::new()
304 }
305
306 pub fn get_ids(&self) -> Vec<String> {
308 if let Some(track_paths) = &self.track_paths {
309 return track_paths.clone();
310 }
311
312 if let Some(track_ids) = &self.track_ids {
313 return track_ids.into_iter().map(|id| format!("{}", id)).collect();
314 }
315
316 Vec::new()
317 }
318
319 pub fn enumerated_list(&self) -> Vec<(u16, String, Option<u32>)> {
321 let mut list: Vec<(u16, String, Option<u32>)> = Vec::new();
322 if let Some(track_paths) = &self.track_paths {
323 for (index, file_path) in track_paths.iter().enumerate() {
324 list.push((index as u16, String::from(file_path), None));
325 }
326
327 return list;
328 }
329
330 if let Some(track_ids) = &self.track_ids {
331 for (index, track_id) in track_ids.iter().enumerate() {
332 list.push((
333 index as u16,
334 String::from(self.file_path.as_ref().unwrap()),
335 Some(*track_id),
336 ));
337 }
338
339 return list;
340 }
341
342 list
343 }
344
345 pub fn container_track_entries(&self) -> Option<(String, Vec<(u16, u32)>)> {
347 let file_path = self.file_path.as_ref()?;
348 let track_ids = self.track_ids.as_ref()?;
349 let mut entries = Vec::new();
350 for (index, track_id) in track_ids.iter().enumerate() {
351 entries.push((index as u16, *track_id));
352 }
353 Some((file_path.clone(), entries))
354 }
355
356 pub fn get_duration(&self) -> &f64 {
358 &self.duration
359 }
360
361 pub fn get_track_mix_settings(&self) -> HashMap<u16, (f32, f32)> {
363 let mut settings = HashMap::new();
364
365 let tracks = match self.play_settings.as_ref() {
366 Some(PlaySettingsFile::V1(file)) => Some(&file.settings.inner().tracks),
367 Some(PlaySettingsFile::V2(file)) => Some(&file.settings.inner().tracks),
368 _ => None,
369 };
370
371 if let Some(tracks) = tracks {
372 for (index, track) in tracks.iter().enumerate() {
373 settings.insert(index as u16, (track.level, track.pan));
374 }
375 }
376
377 settings
378 }
379
380 pub fn get_length(&self) -> usize {
382 if let Some(track_paths) = &self.track_paths {
383 return track_paths.len();
384 }
385
386 if let Some(file_paths) = &self.file_paths {
387 return file_paths.len();
388 }
389
390 if let Some(track_ids) = &self.track_ids {
391 return track_ids.len();
392 }
393
394 0
395 }
396
397 pub fn count_possible_combinations(&self) -> Option<u128> {
399 if let Some(file_paths) = &self.file_paths {
400 return count_paths_track_combinations(file_paths);
401 }
402
403 let play_settings = self.play_settings.as_ref()?;
404 match play_settings {
405 PlaySettingsFile::Legacy(file) => {
406 count_legacy_track_combinations(file.settings.inner())
407 }
408 PlaySettingsFile::V1(file) => {
409 count_settings_track_combinations(&file.settings.inner().tracks)
410 }
411 PlaySettingsFile::V2(file) => {
412 count_settings_track_combinations(&file.settings.inner().tracks)
413 }
414 PlaySettingsFile::V3(file) => {
415 count_settings_track_combinations(&file.settings.inner().tracks)
416 }
417 PlaySettingsFile::Unknown { .. } => None,
418 }
419 }
420
421 pub fn get_file_paths_dictionary(&self) -> Vec<String> {
423 match &self.file_paths_dictionary {
424 Some(dictionary) => dictionary.to_vec(),
425 None => Vec::new(),
426 }
427 }
428}
429
430#[derive(Debug, Clone)]
432pub struct PathsTrack {
433 pub file_paths: Vec<String>,
435 pub level: f32,
437 pub pan: f32,
439 pub selections_count: u32,
441}
442
443fn count_settings_track_combinations(tracks: &[SettingsTrack]) -> Option<u128> {
444 let mut total: u128 = 1;
445 for track in tracks {
446 let choices = track.ids.len() as u128;
447 let selections = track.selections_count;
448 let count = checked_pow(choices, selections)?;
449 total = total.checked_mul(count)?;
450 }
451 Some(total)
452}
453
454fn count_paths_track_combinations(tracks: &[PathsTrack]) -> Option<u128> {
455 let mut total: u128 = 1;
456 for track in tracks {
457 let choices = track.file_paths.len() as u128;
458 let selections = track.selections_count;
459 let count = checked_pow(choices, selections)?;
460 total = total.checked_mul(count)?;
461 }
462 Some(total)
463}
464
465fn count_legacy_track_combinations(settings: &PlaySettingsLegacy) -> Option<u128> {
466 let mut total: u128 = 1;
467 for track in &settings.tracks {
468 let choices = track.length.unwrap_or(0) as u128;
469 let count = checked_pow(choices, 1)?;
470 total = total.checked_mul(count)?;
471 }
472 Some(total)
473}
474
475fn checked_pow(base: u128, exp: u32) -> Option<u128> {
476 if exp == 0 {
477 return Some(1);
478 }
479 if base == 0 {
480 return Some(1);
481 }
482 let mut result: u128 = 1;
483 for _ in 0..exp {
484 result = result.checked_mul(base)?;
485 }
486 Some(result)
487}
488
489impl PathsTrack {
490 pub fn new_from_file_paths(file_paths: Vec<String>) -> Self {
492 PathsTrack {
493 file_paths,
494 level: 1.0,
495 pan: 0.0,
496 selections_count: 1,
497 }
498 }
499}
500
501fn collect_tracks_from_ids(
502 tracks: &[SettingsTrack],
503 track_index_array: &mut Vec<u32>,
504 longest_duration: &mut f64,
505 info: &Info,
506 total_duration: &mut f64,
507) {
508 for track in tracks {
509 if track.ids.is_empty() {
510 continue;
511 }
512 let selections = track.selections_count as usize;
513 if selections == 0 {
514 continue;
515 }
516 for _ in 0..selections {
517 let random_number = rand::thread_rng().gen_range(0..track.ids.len());
518 let index = track.ids[random_number];
519 if let Some(track_duration) = info.get_duration(index) {
520 if track_duration > *longest_duration {
521 *longest_duration = track_duration;
522 *total_duration = *longest_duration;
523 }
524 }
525 track_index_array.push(index);
526 }
527 }
528}
529
530fn collect_legacy_tracks(
531 settings: &PlaySettingsLegacy,
532 track_index_array: &mut Vec<u32>,
533 longest_duration: &mut f64,
534 info: &Info,
535 total_duration: &mut f64,
536) {
537 for track in &settings.tracks {
538 let (Some(starting_index), Some(length)) = (track.starting_index, track.length) else {
539 continue;
540 };
541 let starting_index = starting_index + 1;
542 let index = rand::thread_rng().gen_range(starting_index..(starting_index + length));
543 if let Some(track_duration) = info.get_duration(index) {
544 if track_duration > *longest_duration {
545 *longest_duration = track_duration;
546 *total_duration = *longest_duration;
547 }
548 }
549 track_index_array.push(index);
550 }
551}