Skip to main content

proteus_lib/container/play_settings/
mod.rs

1//! Serde models for `play_settings.json` with versioned decoding.
2
3use log::{info, warn};
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5
6use crate::dsp::effects::AudioEffect;
7#[deprecated(note = "Use DelayReverbSettings instead.")]
8pub use crate::dsp::effects::BasicReverbSettings;
9pub use crate::dsp::effects::{
10    CompressorSettings, ConvolutionReverbSettings, DelayReverbSettings, DistortionSettings,
11    HighPassFilterSettings, LimiterSettings, LowPassFilterSettings,
12};
13
14pub mod legacy;
15pub mod v1;
16pub mod v2;
17
18pub use legacy::{PlaySettingsLegacy, PlaySettingsLegacyFile, PlaySettingsTrackLegacy};
19pub use v1::{PlaySettingsV1, PlaySettingsV1File};
20pub use v2::{PlaySettingsV2, PlaySettingsV2File};
21
22/// Effect settings variants that can appear in the settings file.
23pub type EffectSettings = AudioEffect;
24
25/// Track-level configuration shared by newer settings versions.
26#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct SettingsTrack {
28    pub level: f32,
29    pub pan: f32,
30    pub ids: Vec<u32>,
31    pub name: String,
32    pub safe_name: String,
33}
34
35/// Wrapper allowing `play_settings` to be nested or flat.
36#[derive(Debug, Clone, Serialize, Deserialize)]
37#[serde(untagged)]
38pub enum PlaySettingsContainer<T> {
39    Nested { play_settings: T },
40    Flat(T),
41}
42
43impl<T> PlaySettingsContainer<T> {
44    /// Return the inner settings payload, regardless of nesting.
45    pub fn inner(&self) -> &T {
46        match self {
47            PlaySettingsContainer::Nested { play_settings } => play_settings,
48            PlaySettingsContainer::Flat(inner) => inner,
49        }
50    }
51}
52
53/// Versioned settings file representation.
54#[derive(Debug, Clone)]
55pub enum PlaySettingsFile {
56    Legacy(PlaySettingsLegacyFile),
57    V1(PlaySettingsV1File),
58    V2(PlaySettingsV2File),
59    Unknown {
60        encoder_version: Option<String>,
61        raw: serde_json::Value,
62    },
63}
64
65impl PlaySettingsFile {
66    /// Get the encoder version string, if known.
67    pub fn encoder_version(&self) -> Option<&str> {
68        match self {
69            PlaySettingsFile::Legacy(_) => None,
70            PlaySettingsFile::V1(_) => Some("1"),
71            PlaySettingsFile::V2(_) => Some("2"),
72            PlaySettingsFile::Unknown {
73                encoder_version, ..
74            } => encoder_version.as_deref(),
75        }
76    }
77}
78
79impl<'de> Deserialize<'de> for PlaySettingsFile {
80    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
81    where
82        D: Deserializer<'de>,
83    {
84        let value = serde_json::Value::deserialize(deserializer)?;
85        let encoder_version = value.get("encoder_version").and_then(|raw| match raw {
86            serde_json::Value::String(version) => Some(version.clone()),
87            serde_json::Value::Number(number) => number
88                .as_f64()
89                .map(|val| {
90                    if (val - 1.0).abs() < f64::EPSILON {
91                        "1".to_string()
92                    } else if (val - 2.0).abs() < f64::EPSILON {
93                        "2".to_string()
94                    } else {
95                        number.to_string()
96                    }
97                })
98                .or_else(|| Some(number.to_string())),
99            _ => None,
100        });
101
102        info!("Encoder version: {:?}", encoder_version);
103
104        let parsed = match encoder_version.as_deref() {
105            None => serde_json::from_value::<PlaySettingsLegacyFile>(value.clone())
106                .map(PlaySettingsFile::Legacy),
107            Some("1") => serde_json::from_value::<PlaySettingsV1File>(value.clone())
108                .map(PlaySettingsFile::V1),
109            Some("2") => serde_json::from_value::<PlaySettingsV2File>(value.clone())
110                .map(PlaySettingsFile::V2),
111            Some(version) => {
112                warn!("Unknown encoder version: {:?}", version);
113                return Ok(PlaySettingsFile::Unknown {
114                    encoder_version,
115                    raw: value,
116                });
117            }
118        };
119
120        parsed.or_else(|_| {
121            Ok(PlaySettingsFile::Unknown {
122                encoder_version,
123                raw: value,
124            })
125        })
126    }
127}
128
129impl Serialize for PlaySettingsFile {
130    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
131    where
132        S: Serializer,
133    {
134        fn with_version<T, S>(payload: &T, version: &str, serializer: S) -> Result<S::Ok, S::Error>
135        where
136            T: Serialize,
137            S: Serializer,
138        {
139            let mut value = serde_json::to_value(payload).map_err(serde::ser::Error::custom)?;
140            match value {
141                serde_json::Value::Object(ref mut map) => {
142                    map.insert(
143                        "encoder_version".to_string(),
144                        serde_json::Value::String(version.to_string()),
145                    );
146                }
147                other => {
148                    let mut map = serde_json::Map::new();
149                    map.insert(
150                        "encoder_version".to_string(),
151                        serde_json::Value::String(version.to_string()),
152                    );
153                    map.insert("play_settings".to_string(), other);
154                    value = serde_json::Value::Object(map);
155                }
156            }
157            value.serialize(serializer)
158        }
159
160        match self {
161            PlaySettingsFile::Legacy(file) => file.serialize(serializer),
162            PlaySettingsFile::V1(file) => with_version(file, "1", serializer),
163            PlaySettingsFile::V2(file) => with_version(file, "2", serializer),
164            PlaySettingsFile::Unknown { raw, .. } => raw.serialize(serializer),
165        }
166    }
167}