kson/
lib.rs

1pub mod camera;
2pub mod effects;
3mod graph;
4mod ksh;
5pub mod overlaps;
6pub mod parameter;
7pub mod score_ticks;
8mod vox;
9
10use camera::CameraInfo;
11use effects::AudioEffect;
12pub use graph::*;
13pub use ksh::*;
14use serde::de::Visitor;
15use serde::{Deserialize, Serialize};
16use std::collections::HashMap;
17use std::collections::HashSet;
18use std::marker::PhantomData;
19use std::slice::Windows;
20use std::str;
21pub use vox::*;
22
23type Dict<T> = HashMap<String, T>;
24
25#[inline]
26pub fn beat_in_ms(bpm: f64) -> f64 {
27    60_000.0 / bpm
28}
29
30#[inline]
31pub fn tick_in_ms(bpm: f64, ppqn: u32) -> f64 {
32    beat_in_ms(bpm) / ppqn as f64
33}
34
35#[inline]
36pub fn ticks_from_ms(ms: f64, bpm: f64, tpqn: u32) -> f64 {
37    ms / tick_in_ms(bpm, tpqn)
38}
39
40#[inline]
41pub fn ms_from_ticks(ticks: i64, bpm: f64, tpqn: u32) -> f64 {
42    tick_in_ms(bpm, tpqn) * ticks as f64
43}
44
45#[repr(usize)]
46#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
47pub enum Side {
48    Left = 0,
49    Right,
50}
51
52impl Side {
53    pub fn iter() -> std::array::IntoIter<Side, 2> {
54        [Self::Left, Self::Right].into_iter()
55    }
56    pub fn opposite(&self) -> Self {
57        match self {
58            Side::Left => Self::Right,
59            Side::Right => Self::Left,
60        }
61    }
62}
63
64#[repr(usize)]
65#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
66pub enum BtLane {
67    A = 0,
68    B,
69    C,
70    D,
71}
72
73impl TryFrom<usize> for BtLane {
74    type Error = usize;
75
76    fn try_from(value: usize) -> Result<Self, Self::Error> {
77        match value {
78            0 => Ok(BtLane::A),
79            1 => Ok(BtLane::B),
80            2 => Ok(BtLane::C),
81            3 => Ok(BtLane::D),
82            _ => Err(value),
83        }
84    }
85}
86
87#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
88pub enum Track {
89    BT(BtLane),
90    FX(Side),
91    Laser(Side),
92}
93
94#[derive(Serialize, Deserialize)]
95#[serde(untagged)]
96enum SingleOrPair<T> {
97    Single(T),
98    Pair(T, T),
99}
100
101#[derive(Copy, Clone, Default)]
102pub struct GraphPoint {
103    pub y: u32,
104    pub v: f64,
105    pub vf: Option<f64>,
106    pub a: f64,
107    pub b: f64,
108}
109impl<'de> Deserialize<'de> for GraphPoint {
110    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
111    where
112        D: serde::Deserializer<'de>,
113    {
114        struct GpVisitor;
115        impl<'de> Visitor<'de> for GpVisitor {
116            type Value = GraphPoint;
117
118            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
119                formatter.write_str("[u32, f64 | [f64, f64], none | [f64, f64]]")
120            }
121
122            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
123            where
124                A: serde::de::SeqAccess<'de>,
125            {
126                let y = seq
127                    .next_element()?
128                    .ok_or_else(|| serde::de::Error::custom("No element"))?;
129                let (v, vf) = match seq
130                    .next_element::<SingleOrPair<f64>>()?
131                    .ok_or_else(|| serde::de::Error::custom("Missing 2nd element"))?
132                {
133                    SingleOrPair::Single(v) => (v, None),
134                    SingleOrPair::Pair(v, vf) => (v, Some(vf)),
135                };
136                let (a, b) = if let Some((a, b)) = seq.next_element::<(f64, f64)>()? {
137                    (a, b)
138                } else {
139                    (0.5, 0.5)
140                };
141
142                Ok(GraphPoint { y, v, vf, a, b })
143            }
144        }
145
146        deserializer.deserialize_seq(GpVisitor)
147    }
148}
149
150impl Serialize for GraphPoint {
151    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
152    where
153        S: serde::Serializer,
154    {
155        use serde::ser::SerializeTuple;
156        let point_len = if (self.a - self.b).abs() > f64::EPSILON {
157            3
158        } else {
159            2
160        };
161
162        let mut top_tup = serializer.serialize_tuple(point_len)?;
163        top_tup.serialize_element(&self.y)?;
164        if let Some(vf) = self.vf {
165            top_tup.serialize_element(&(self.v, vf))?;
166        } else {
167            top_tup.serialize_element(&self.v)?;
168        }
169        if point_len == 3 {
170            top_tup.serialize_element(&(self.a, self.b))?;
171        }
172
173        top_tup.end()
174    }
175}
176
177#[derive(Copy, Clone)]
178pub struct GraphSectionPoint {
179    pub ry: u32,
180    pub v: f64,
181    pub vf: Option<f64>,
182    pub a: f64,
183    pub b: f64,
184}
185
186impl<'de> Deserialize<'de> for GraphSectionPoint {
187    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
188    where
189        D: serde::Deserializer<'de>,
190    {
191        struct GspVisitor;
192        impl<'de> Visitor<'de> for GspVisitor {
193            type Value = GraphSectionPoint;
194
195            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
196                formatter.write_str("[u32, f64 | [f64, f64], none | [f64, f64]]")
197            }
198
199            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
200            where
201                A: serde::de::SeqAccess<'de>,
202            {
203                let ry = seq
204                    .next_element()?
205                    .ok_or_else(|| serde::de::Error::custom("No element"))?;
206                let (v, vf) = match seq
207                    .next_element::<SingleOrPair<f64>>()?
208                    .ok_or_else(|| serde::de::Error::custom("Missing 2nd element"))?
209                {
210                    SingleOrPair::Single(v) => (v, None),
211                    SingleOrPair::Pair(v, vf) => (v, Some(vf)),
212                };
213                let (a, b) = if let Some((a, b)) = seq.next_element::<(f64, f64)>()? {
214                    (a, b)
215                } else {
216                    (0.5, 0.5)
217                };
218
219                Ok(GraphSectionPoint { ry, v, vf, a, b })
220            }
221        }
222
223        deserializer.deserialize_seq(GspVisitor)
224    }
225}
226
227impl Serialize for GraphSectionPoint {
228    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
229    where
230        S: serde::Serializer,
231    {
232        use serde::ser::SerializeTuple;
233        let point_len = if (self.a - self.b).abs() > f64::EPSILON {
234            3
235        } else {
236            2
237        };
238
239        let mut top_tup = serializer.serialize_tuple(point_len)?;
240        top_tup.serialize_element(&self.ry)?;
241        if let Some(vf) = self.vf {
242            top_tup.serialize_element(&(self.v, vf))?;
243        } else {
244            top_tup.serialize_element(&self.v)?;
245        }
246        if point_len == 3 {
247            top_tup.serialize_element(&(self.a, self.b))?;
248        }
249
250        top_tup.end()
251    }
252}
253
254pub type ByMeasureIdx<T> = Vec<(u32, T)>;
255
256impl GraphSectionPoint {
257    pub fn new(ry: u32, v: f64) -> Self {
258        GraphSectionPoint {
259            ry,
260            v,
261            vf: None,
262            a: 0.5,
263            b: 0.5,
264        }
265    }
266}
267
268#[derive(Copy, Clone, Debug)]
269pub struct Interval {
270    pub y: u32,
271    pub l: u32,
272}
273
274impl Serialize for Interval {
275    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
276    where
277        S: serde::Serializer,
278    {
279        use serde::ser::SerializeTuple;
280        if self.l == 0 {
281            serializer.serialize_u32(self.y)
282        } else {
283            let mut tup = serializer.serialize_tuple(2)?;
284            tup.serialize_element(&self.y)?;
285            tup.serialize_element(&self.l)?;
286            tup.end()
287        }
288    }
289}
290
291struct IntervalVisitor;
292
293impl<'de> Visitor<'de> for IntervalVisitor {
294    type Value = Interval;
295
296    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
297        formatter.write_str("integer or `y` integer pair [`y`, `l`]")
298    }
299
300    fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
301    where
302        E: serde::de::Error,
303    {
304        Ok(Interval { l: 0, y: v as u32 })
305    }
306
307    fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
308    where
309        E: serde::de::Error,
310    {
311        Ok(Interval { l: 0, y: v as u32 })
312    }
313
314    fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
315    where
316        E: serde::de::Error,
317    {
318        Ok(Interval { l: 0, y: v as u32 })
319    }
320
321    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
322    where
323        A: serde::de::SeqAccess<'de>,
324    {
325        let y = seq
326            .next_element()?
327            .ok_or_else(|| serde::de::Error::custom("Empty sequence"))?;
328        let l = seq.next_element()?.unwrap_or(0);
329        Ok(Interval { y, l })
330    }
331}
332
333impl<'de> Deserialize<'de> for Interval {
334    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
335    where
336        D: serde::Deserializer<'de>,
337    {
338        deserializer.deserialize_any(IntervalVisitor)
339    }
340}
341
342fn default_zero<T: From<u8>>() -> T {
343    T::from(0)
344}
345
346fn default_true<T: From<bool>>() -> T {
347    T::from(true)
348}
349
350fn serde_eq<T: Into<i64> + Copy, const N: i64>(v: &T) -> bool {
351    N == (*v).into()
352}
353
354#[allow(unused)]
355fn serde_def_n<T: From<u32> + Copy, const N: u32>() -> T {
356    N.into()
357}
358
359// fn default_false<T: From<bool>>() -> T {
360//     T::from(false)
361// }
362
363/// (tick, section points, wide)
364#[derive(Serialize, Deserialize, Clone)]
365pub struct LaserSection(
366    pub u32,
367    pub Vec<GraphSectionPoint>,
368    #[serde(
369        default = "default_one::<u8>",
370        skip_serializing_if = "serde_eq::<_, 1>"
371    )]
372    pub u8,
373);
374
375impl LaserSection {
376    pub fn tick(&self) -> u32 {
377        self.0
378    }
379    pub fn segments(&self) -> Windows<GraphSectionPoint> {
380        self.1.windows(2)
381    }
382
383    pub fn last(&self) -> Option<&GraphSectionPoint> {
384        self.1.last()
385    }
386
387    pub fn first(&self) -> Option<&GraphSectionPoint> {
388        self.1.first()
389    }
390
391    pub fn wide(&self) -> u8 {
392        self.2
393    }
394}
395
396//https://github.com/m4saka/ksh2kson/issues/4#issuecomment-573343229
397pub fn do_curve(x: f64, a: f64, b: f64) -> f64 {
398    let t = if x < f64::EPSILON || a < f64::EPSILON {
399        (a - (a * a + x - 2.0 * a * x).sqrt()) / (-1.0 + 2.0 * a)
400    } else {
401        x / (a + (a * a + (1.0 - 2.0 * a) * x).sqrt())
402    };
403    2.0 * (1.0 - t) * t * b + t * t
404}
405
406fn default_one<T: From<u8>>() -> T {
407    T::from(1)
408}
409
410#[derive(Serialize, Deserialize, Clone)]
411pub struct NoteInfo {
412    pub bt: [Vec<Interval>; 4],
413    pub fx: [Vec<Interval>; 2],
414    pub laser: [Vec<LaserSection>; 2],
415}
416
417impl NoteInfo {
418    fn new() -> NoteInfo {
419        NoteInfo {
420            bt: [Vec::new(), Vec::new(), Vec::new(), Vec::new()],
421            fx: [Vec::new(), Vec::new()],
422            laser: [Vec::new(), Vec::new()],
423        }
424    }
425}
426
427#[derive(Serialize, Deserialize, Clone)]
428pub struct DifficultyInfo {
429    pub name: Option<String>,
430    pub short_name: Option<String>,
431    pub idx: u8,
432}
433
434#[derive(Serialize, Deserialize, Clone)]
435pub struct MetaInfo {
436    pub title: String,
437    #[serde(skip_serializing_if = "Option::is_none")]
438    pub title_img_filename: Option<String>,
439    #[serde(skip_serializing_if = "Option::is_none")]
440    pub subtitle: Option<String>,
441    pub artist: String,
442    pub gauge: Option<GaugeInfo>,
443    #[serde(skip_serializing_if = "Option::is_none")]
444    pub artist_img_filename: Option<String>,
445    pub chart_author: String,
446    pub difficulty: u8,
447    pub level: u8,
448    pub disp_bpm: String,
449    #[serde(skip_serializing_if = "Option::is_none")]
450    pub std_bpm: Option<f64>,
451    pub jacket_filename: String,
452    pub jacket_author: String,
453    #[serde(skip_serializing_if = "Option::is_none")]
454    pub information: Option<String>,
455}
456
457#[derive(Serialize, Deserialize, Clone)]
458pub struct GaugeInfo {
459    pub total: u32,
460}
461
462impl MetaInfo {
463    fn new() -> MetaInfo {
464        MetaInfo {
465            title: String::new(),
466            title_img_filename: None,
467            subtitle: None,
468            gauge: None,
469            artist: String::new(),
470            artist_img_filename: None,
471            chart_author: String::new(),
472            difficulty: 0,
473            level: 1,
474            disp_bpm: String::new(),
475            std_bpm: None,
476            jacket_filename: String::new(),
477            jacket_author: String::new(),
478            information: None,
479        }
480    }
481}
482
483pub type ByPulse<T> = Vec<(u32, T)>;
484#[derive(Copy, Clone, Default, PartialEq)]
485pub struct ByPulseOption<T>(u32, Option<T>);
486
487impl<T> ByPulseOption<T> {
488    pub fn tick(&self) -> u32 {
489        self.0
490    }
491
492    pub fn value(&self) -> Option<&T> {
493        self.1.as_ref()
494    }
495
496    pub fn new(y: u32, v: Option<T>) -> Self {
497        Self(y, v)
498    }
499}
500
501impl<T: Serialize> Serialize for ByPulseOption<T> {
502    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
503    where
504        S: serde::Serializer,
505    {
506        use serde::ser::SerializeTuple;
507        if let Some(v) = &self.1 {
508            let mut tup = serializer.serialize_tuple(2)?;
509            tup.serialize_element(&self.0)?;
510            tup.serialize_element(v)?;
511            tup.end()
512        } else {
513            serializer.serialize_u32(self.0)
514        }
515    }
516}
517
518impl<'de, T: Deserialize<'de>> Deserialize<'de> for ByPulseOption<T> {
519    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
520    where
521        D: serde::Deserializer<'de>,
522    {
523        struct ByPulseOptionVisitor<T>(PhantomData<T>);
524        impl<'de, T: Deserialize<'de>> Visitor<'de> for ByPulseOptionVisitor<T> {
525            type Value = ByPulseOption<T>;
526
527            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
528                formatter.write_str("[`u32`, v] or `u32`")
529            }
530
531            fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
532            where
533                E: serde::de::Error,
534            {
535                Ok(ByPulseOption::<T>(v as u32, None))
536            }
537
538            fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
539            where
540                E: serde::de::Error,
541            {
542                Ok(ByPulseOption::<T>(v as u32, None))
543            }
544
545            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
546            where
547                A: serde::de::SeqAccess<'de>,
548            {
549                Ok(ByPulseOption::<T>(
550                    seq.next_element()?.unwrap_or_default(),
551                    seq.next_element()?,
552                ))
553            }
554        }
555
556        deserializer.deserialize_any(ByPulseOptionVisitor(PhantomData))
557    }
558}
559
560#[derive(Serialize, Deserialize, Copy, Clone)]
561pub struct ByNote<T> {
562    pub y: u32,
563    pub v: Option<T>,
564    #[serde(default = "default_true::<bool>")]
565    pub dom: bool,
566}
567
568#[derive(Serialize, Deserialize, Clone)]
569pub struct ByNotes<T> {
570    pub bt: Option<[Vec<ByNote<T>>; 4]>,
571    pub fx: Option<[Vec<ByNote<T>>; 2]>,
572    pub laser: Option<[Vec<ByNote<T>>; 2]>,
573}
574
575impl<'a, T> IntoIterator for &'a ByNotes<T> {
576    type Item = (&'a ByNote<T>, Track);
577    type IntoIter = ByNotesIter<'a, T>;
578
579    fn into_iter(self) -> Self::IntoIter {
580        ByNotesIter {
581            by_notes: self,
582            indexes: Default::default(),
583        }
584    }
585}
586
587pub struct ByNotesIter<'a, T> {
588    by_notes: &'a ByNotes<T>,
589    indexes: HashMap<Track, usize>,
590}
591
592impl<'a, T> Iterator for ByNotesIter<'a, T> {
593    type Item = (&'a ByNote<T>, Track);
594
595    fn next(&mut self) -> Option<Self::Item> {
596        let mut current_events = HashMap::new();
597
598        if let Some(bt) = &self.by_notes.bt {
599            for (lane, bt) in bt.iter().enumerate() {
600                let bt_lane = match lane {
601                    0 => BtLane::A,
602                    1 => BtLane::B,
603                    2 => BtLane::C,
604                    3 => BtLane::D,
605                    _ => unreachable!(),
606                };
607
608                let track = Track::BT(bt_lane);
609                let index = self.indexes.entry(track).or_insert(0);
610
611                if let Some(note) = bt.get(*index) {
612                    current_events.insert(track, note);
613                }
614            }
615        }
616
617        if let Some(fx) = &self.by_notes.fx {
618            for (lane, fx) in fx.iter().enumerate() {
619                let fx_lane = match lane {
620                    0 => Side::Left,
621                    1 => Side::Right,
622                    _ => unreachable!(),
623                };
624                let track = Track::FX(fx_lane);
625                let index = self.indexes.entry(track).or_insert(0);
626
627                if let Some(note) = fx.get(*index) {
628                    current_events.insert(track, note);
629                }
630            }
631        }
632
633        if let Some(laser) = &self.by_notes.laser {
634            for (lane, laser) in laser.iter().enumerate() {
635                let laser_lane = match lane {
636                    0 => Side::Left,
637                    1 => Side::Right,
638                    _ => unreachable!(),
639                };
640                let track = Track::Laser(laser_lane);
641                let index = self.indexes.entry(track).or_insert(0);
642
643                if let Some(note) = laser.get(*index) {
644                    current_events.insert(track, note);
645                }
646            }
647        }
648
649        if let Some((track, event)) = current_events.iter().min_by_key(|(_, evt)| evt.y) {
650            self.indexes.entry(*track).and_modify(|i| *i += 1);
651            Some((*event, *track))
652        } else {
653            None
654        }
655    }
656}
657
658/// (Numerator, Denominator)
659#[derive(Serialize, Deserialize, Copy, Clone)]
660pub struct TimeSignature(pub u32, pub u32);
661
662impl TimeSignature {
663    //Parse from "n/d" string
664    fn from_str(s: &str) -> Self {
665        let mut data = s.split('/');
666        let n: u32 = data.next().unwrap_or("4").parse().unwrap_or(4);
667        let d: u32 = data.next().unwrap_or("4").parse().unwrap_or(4);
668
669        TimeSignature(n, d)
670    }
671}
672
673#[derive(Serialize, Deserialize, Clone)]
674pub struct BeatInfo {
675    pub bpm: ByPulse<f64>,
676    pub time_sig: ByMeasureIdx<TimeSignature>,
677    pub scroll_speed: Vec<GraphPoint>,
678}
679
680pub const KSON_RESOLUTION: u32 = 240;
681
682impl BeatInfo {
683    fn new() -> Self {
684        BeatInfo {
685            bpm: Vec::new(),
686            time_sig: Vec::new(),
687            scroll_speed: Vec::new(),
688        }
689    }
690}
691
692#[derive(Serialize, Deserialize, Clone, Default)]
693pub struct BgmInfo {
694    #[serde(default, skip_serializing_if = "String::is_empty")]
695    pub filename: String,
696    #[serde(default = "default_one::<f64>")]
697    pub vol: f64,
698    #[serde(default = "default_zero::<i32>")]
699    pub offset: i32,
700    pub preview: PreviewInfo,
701    pub legacy: LegacyBgmInfo,
702}
703
704#[derive(Serialize, Deserialize, Clone, Default)]
705pub struct LegacyBgmInfo {
706    pub fp_filenames: Vec<String>,
707}
708
709#[derive(Serialize, Deserialize, Clone, Default)]
710pub struct PreviewInfo {
711    #[serde(default = "default_zero::<u32>")]
712    pub offset: u32,
713    #[serde(default = "default_zero::<u32>")]
714    pub duration: u32,
715    #[serde(skip_serializing_if = "Option::is_none")]
716    pub preview_filename: Option<String>,
717}
718
719impl BgmInfo {
720    fn new() -> Self {
721        BgmInfo {
722            filename: String::new(),
723            vol: 1.0,
724            offset: 0,
725            preview: PreviewInfo::default(),
726            legacy: LegacyBgmInfo::default(),
727        }
728    }
729}
730
731#[derive(Serialize, Deserialize, Clone, Default)]
732pub struct KeySoundInfo {
733    pub fx: KeySoundFXInfo,
734    pub laser: KeySoundLaserInfo,
735}
736
737#[derive(Serialize, Deserialize, Clone, Default)]
738pub struct KeySoundLaserInfo {
739    pub vol: ByPulse<f64>,
740}
741
742#[derive(Serialize, Deserialize, Clone, Default)]
743pub struct KeySoundFXInfo {
744    pub chip_event: HashMap<String, [Vec<ByPulse<KeySoundInvokeFX>>; 2]>,
745}
746
747#[derive(Serialize, Deserialize, Clone)]
748pub struct KeySoundInvokeFX {
749    pub vol: f64,
750}
751
752type NoteParamChange = ByPulseOption<Dict<String>>;
753
754#[derive(Serialize, Deserialize, Clone, Default, PartialEq)]
755pub struct AudioEffectFXInfo {
756    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
757    pub def: Dict<AudioEffect>,
758    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
759    pub param_change: Dict<Dict<ByPulse<String>>>,
760    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
761    pub long_event: Dict<[Vec<NoteParamChange>; 2]>,
762}
763
764#[derive(Serialize, Deserialize, Clone, Default, PartialEq)]
765pub struct AudioEffectLaserInfo {
766    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
767    def: Dict<AudioEffect>,
768    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
769    pub param_change: Dict<Dict<ByPulse<String>>>,
770    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
771    pub pulse_event: Dict<ByPulse<()>>,
772    #[serde(default = "default_zero::<i32>")]
773    pub peaking_filter_delay: i32,
774}
775
776#[derive(Serialize, Deserialize, Clone, Default, PartialEq)]
777pub struct AudioEffectInfo {
778    pub fx: AudioEffectFXInfo,
779    pub laser: AudioEffectLaserInfo,
780}
781
782#[derive(Serialize, Deserialize, Clone, Default)]
783#[serde(default)]
784pub struct AudioInfo {
785    pub bgm: BgmInfo,
786    #[serde(default, skip_serializing_if = "crate::IsDefault::is_default")]
787    pub audio_effect: AudioEffectInfo,
788    #[serde(skip_deserializing)]
789    pub key_sound: KeySoundInfo,
790}
791
792impl AudioInfo {
793    fn new() -> Self {
794        Self::default()
795    }
796}
797
798#[derive(Serialize, Deserialize, Clone)]
799pub struct Chart {
800    pub meta: MetaInfo,
801    pub note: NoteInfo,
802    pub beat: BeatInfo,
803    pub audio: AudioInfo,
804    #[serde(default)]
805    pub camera: camera::CameraInfo,
806    pub version: String,
807    pub bg: BgInfo,
808    #[serde(skip)]
809    pub file_hash: String,
810}
811
812#[derive(Serialize, Deserialize, Clone)]
813pub struct BgInfo {
814    pub filename: Option<String>,
815    #[serde(default)]
816    pub offset: i32,
817    pub legacy: Option<LegacyBgInfo>,
818}
819
820impl BgInfo {
821    pub fn new() -> Self {
822        Self {
823            filename: None,
824            offset: 0,
825            legacy: None,
826        }
827    }
828}
829
830impl Default for BgInfo {
831    fn default() -> Self {
832        Self::new()
833    }
834}
835
836#[derive(Serialize, Deserialize, Clone)]
837pub struct LegacyBgInfo {
838    pub bg: Option<Vec<KshBgInfo>>,
839    pub layer: Option<KshLayerInfo>,
840    pub movie: Option<KshMovieInfo>,
841}
842
843#[derive(Serialize, Deserialize, Clone)]
844pub struct KshLayerInfo {
845    pub filename: Option<String>, // self-explanatory (can be KSM default animation layer such as "arrow")
846    /// one-loop duration in milliseconds.
847    ///
848    /// If the value is negative, the animation is played backwards.
849    ///
850    /// If the value is zero, the play speed is tempo-synchronized and set to 1 frame per 0.035 measure (= 28.571... frames/measure).
851    #[serde(default)]
852    pub duration: i32,
853    pub rotation: Option<KshLayerRotationInfo>, // rotation conditions
854}
855
856#[derive(Serialize, Deserialize, Clone)]
857pub struct KshLayerRotationInfo {
858    pub tilt: bool, // whether lane tilts affect rotation of BG/layer
859    pub spin: bool, // whether lane spins affect rotation of BG/layer
860}
861#[derive(Serialize, Deserialize, Clone)]
862pub struct KshMovieInfo {
863    pub filename: Option<String>, // self-explanatory
864    pub offset: i32,              // movie offset in millisecond
865}
866
867#[derive(Serialize, Deserialize, Clone)]
868pub struct KshBgInfo {
869    pub filename: String,
870}
871
872type BeatLineFn = dyn Fn(u32) -> Option<(u32, bool)>;
873pub struct MeasureBeatLines {
874    tick: u32,
875    funcs: Vec<(u32, Box<BeatLineFn>)>,
876    func_index: usize,
877}
878
879impl Iterator for MeasureBeatLines {
880    type Item = (u32, bool);
881
882    fn next(&mut self) -> Option<(u32, bool)> {
883        if let Some(func) = self.funcs.get(self.func_index) {
884            if let Some((new_tick, is_measure)) = func.1(self.tick) {
885                let old_tick = self.tick;
886                self.tick = new_tick;
887                if let Some(next_func) = self.funcs.get(self.func_index + 1) {
888                    if self.tick >= next_func.0 {
889                        self.func_index += 1;
890                    }
891                }
892
893                return Some((old_tick, is_measure));
894            }
895        }
896
897        None
898    }
899}
900
901impl Default for Chart {
902    fn default() -> Self {
903        Self::new()
904    }
905}
906
907//TODO: Duration based API
908impl Chart {
909    pub fn new() -> Self {
910        Chart {
911            meta: MetaInfo::new(),
912            note: NoteInfo::new(),
913            beat: BeatInfo::new(),
914            audio: AudioInfo::new(),
915            camera: CameraInfo::default(),
916            version: "0.7.0".to_string(),
917            bg: BgInfo::new(),
918            file_hash: String::new(),
919        }
920    }
921
922    pub fn mode_bpm(&self) -> Option<f64> {
923        let mut last_bpm = *self.beat.bpm.first()?;
924
925        let mut durations: HashMap<u64, f64> = HashMap::new();
926
927        for ab in self.beat.bpm.windows(2) {
928            let a = ab[0];
929            let b = ab[1];
930            let l = durations.entry(a.1.to_bits()).or_default();
931            *l += self.tick_to_ms(b.0) - self.tick_to_ms(a.0);
932
933            last_bpm = b;
934        }
935
936        {
937            let x = durations.entry(last_bpm.1.to_bits()).or_default();
938            *x += self.tick_to_ms(self.get_last_tick()) - self.tick_to_ms(last_bpm.0);
939        }
940
941        durations
942            .iter()
943            .max_by(|a, b| a.1.total_cmp(b.1))
944            .map(|x| f64::from_bits(*x.0))
945    }
946
947    pub fn ms_to_tick(&self, ms: f64) -> u32 {
948        if ms <= 0.0 {
949            return 0;
950        }
951
952        let bpm = match self.beat.bpm.binary_search_by(|b| {
953            self.tick_to_ms(b.0)
954                .partial_cmp(&ms)
955                .unwrap_or(std::cmp::Ordering::Less)
956        }) {
957            Ok(i) => self.beat.bpm[i],
958            Err(i) => self.beat.bpm[i - 1],
959        };
960
961        let remaining = ms - self.tick_to_ms(bpm.0);
962        bpm.0 + ticks_from_ms(remaining, bpm.1, KSON_RESOLUTION) as u32
963    }
964
965    pub fn tick_to_ms(&self, tick: u32) -> f64 {
966        let mut ret: f64 = 0.0;
967        let mut prev = self.beat.bpm.first().unwrap_or(&(0, 120.0));
968
969        for b in &self.beat.bpm {
970            if b.0 > tick {
971                break;
972            }
973            ret += ms_from_ticks((b.0 - prev.0) as i64, prev.1, KSON_RESOLUTION);
974            prev = b;
975        }
976        ret + ms_from_ticks((tick - prev.0) as i64, prev.1, KSON_RESOLUTION)
977    }
978
979    pub fn tick_to_measure(&self, tick: u32) -> u32 {
980        let mut ret = 0;
981        let mut time_sig_iter = self.beat.time_sig.iter();
982        let mut remaining_ticks = tick;
983        if let Some(first_sig) = time_sig_iter.next() {
984            let mut prev_index = first_sig.0;
985            let mut prev_ticks_per_measure = KSON_RESOLUTION * 4 * first_sig.1 .0 / first_sig.1 .1;
986            if prev_ticks_per_measure == 0 {
987                return ret;
988            }
989            for current_sig in time_sig_iter {
990                let measure_count = current_sig.0 - prev_index;
991                let tick_count = measure_count * prev_ticks_per_measure;
992                if tick_count > remaining_ticks {
993                    break;
994                }
995                ret += measure_count;
996                remaining_ticks -= tick_count;
997                prev_index = current_sig.0;
998                prev_ticks_per_measure = KSON_RESOLUTION * 4 * current_sig.1 .0 / current_sig.1 .1;
999                if prev_ticks_per_measure == 0 {
1000                    return ret;
1001                }
1002            }
1003            ret += remaining_ticks / prev_ticks_per_measure;
1004        }
1005        ret
1006    }
1007
1008    pub fn measure_to_tick(&self, measure: u32) -> u32 {
1009        let mut ret = 0;
1010        let mut remaining_measures = measure;
1011        let mut time_sig_iter = self.beat.time_sig.iter();
1012
1013        if let Some(first_sig) = time_sig_iter.next() {
1014            let mut prev_index = first_sig.0;
1015            let mut prev_ticks_per_measure = KSON_RESOLUTION * 4 * first_sig.1 .0 / first_sig.1 .1;
1016            for current_sig in time_sig_iter {
1017                let measure_count = current_sig.0 - prev_index;
1018                if measure_count > remaining_measures {
1019                    break;
1020                }
1021                ret += measure_count * prev_ticks_per_measure;
1022                remaining_measures -= measure_count;
1023                prev_index = current_sig.0;
1024                prev_ticks_per_measure = KSON_RESOLUTION * 4 * current_sig.1 .0 / current_sig.1 .1;
1025            }
1026            ret += remaining_measures * prev_ticks_per_measure;
1027        }
1028        ret
1029    }
1030
1031    pub fn bpm_at_tick(&self, tick: u32) -> f64 {
1032        match self.beat.bpm.binary_search_by(|b| b.0.cmp(&tick)) {
1033            Ok(i) => self.beat.bpm[i].1,
1034            Err(i) => self.beat.bpm[i - 1].1,
1035        }
1036    }
1037
1038    pub fn tick_duration_ms_at(&self, tick: u32) -> f64 {
1039        let bpm = self.bpm_at_tick(tick);
1040        beat_in_ms(bpm) / KSON_RESOLUTION as f64
1041    }
1042
1043    pub fn beat_line_iter(&self) -> MeasureBeatLines {
1044        let mut funcs: Vec<(u32, Box<BeatLineFn>)> = Vec::new();
1045        let mut prev_start = 0;
1046        let mut prev_sig = match self.beat.time_sig.first() {
1047            Some(v) => v,
1048            None => &(0, TimeSignature(4, 4)),
1049        };
1050
1051        for time_sig in &self.beat.time_sig {
1052            let ticks_per_beat = KSON_RESOLUTION * 4 / time_sig.1 .1;
1053            let ticks_per_measure = KSON_RESOLUTION * 4 * time_sig.1 .0 / time_sig.1 .1;
1054            let prev_ticks_per_measure = KSON_RESOLUTION * 4 * prev_sig.1 .0 / prev_sig.1 .1;
1055
1056            let new_start = prev_start + (time_sig.0 - prev_sig.0) * prev_ticks_per_measure;
1057            if ticks_per_measure > 0 && ticks_per_beat > 0 {
1058                funcs.push((
1059                    new_start,
1060                    Box::new(move |y| {
1061                        let adjusted = y - new_start;
1062                        Some((y + ticks_per_beat, (adjusted % ticks_per_measure) == 0))
1063                    }),
1064                ));
1065            } else {
1066                funcs.push((new_start, Box::new(|_| None)));
1067            }
1068
1069            prev_start = new_start;
1070            prev_sig = time_sig;
1071        }
1072
1073        MeasureBeatLines {
1074            tick: 0,
1075            funcs,
1076            func_index: 0,
1077        }
1078    }
1079
1080    pub fn get_last_tick(&self) -> u32 {
1081        let mut last_tick = 0;
1082
1083        //bt
1084        for i in 0..4 {
1085            if let Some(last) = &self.note.bt[i].last() {
1086                last_tick = last_tick.max(last.y + last.l);
1087            }
1088        }
1089
1090        //fx
1091        for i in 0..2 {
1092            if let Some(last) = &self.note.fx[i].last() {
1093                last_tick = last_tick.max(last.y + last.l);
1094            }
1095        }
1096
1097        //laser
1098        for i in 0..2 {
1099            for section in &self.note.laser[i] {
1100                let base_y = section.0;
1101                if let Some(last) = &section.1.last() {
1102                    last_tick = last_tick.max(last.ry + base_y);
1103                }
1104            }
1105        }
1106        last_tick
1107    }
1108}
1109
1110pub trait IsDefault {
1111    fn is_default(&self) -> bool;
1112}
1113
1114impl<T> IsDefault for T
1115where
1116    T: Default + PartialEq,
1117{
1118    fn is_default(&self) -> bool {
1119        self.eq(&T::default())
1120    }
1121}
1122
1123#[cfg(test)]
1124mod tests {
1125    use serde_test::Token;
1126
1127    use crate::parameter::{self, EffectFloat, EffectFreq, EffectParameterValue};
1128
1129    #[test]
1130    fn effect_param() {
1131        let mut param = parameter::EffectParameter {
1132            on: Some(EffectParameterValue::Freq(
1133                EffectFreq::Khz(10.0)..=EffectFreq::Khz(20.0),
1134            )),
1135            off: EffectParameterValue::Freq(EffectFreq::Hz(500)..=EffectFreq::Hz(500)),
1136            v: 0.0_f32,
1137            ..Default::default()
1138        };
1139
1140        serde_test::assert_tokens(&param, &[Token::Str("500Hz>10kHz-20kHz")]);
1141
1142        param.on = None;
1143        param.off =
1144            EffectParameterValue::Filename("e9fda14b-d635-4cd8-8c7a-ca12f8d9b78a".to_string());
1145
1146        serde_test::assert_tokens(
1147            &param,
1148            &[Token::Str("e9fda14b-d635-4cd8-8c7a-ca12f8d9b78a")],
1149        );
1150
1151        param.off = EffectParameterValue::Sample(100..=100);
1152        serde_test::assert_tokens(&param, &[Token::Str("100samples")]);
1153        param.off = EffectParameterValue::Sample(100..=1000);
1154        serde_test::assert_tokens(&param, &[Token::Str("100samples-1000samples")]);
1155
1156        param.off = EffectParameterValue::Length(
1157            EffectFloat::Fraction(1, 2)..=EffectFloat::Fraction(1, 2),
1158            true,
1159        );
1160        serde_test::assert_tokens(&param, &[Token::Str("1/2")]);
1161
1162        param.off = EffectParameterValue::Switch(false..=false);
1163        param.on = Some(EffectParameterValue::Switch(false..=true));
1164        serde_test::assert_tokens(&param, &[Token::Str("off>off-on")]);
1165    }
1166}