bms_rs/bms/model/
volume.rs

1//! This module introduces struct [`VolumeObjects`], which manages volume control and that events.
2
3use std::collections::{BTreeMap, btree_map::Entry};
4
5use crate::{
6    bms::{error::Result, prelude::*},
7    parse::prompt::ChannelDuplication,
8};
9
10#[derive(Debug, Default, Clone, PartialEq, Eq)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12/// This aggregate manages volume control and that events.
13pub struct VolumeObjects {
14    /// The volume of the score.
15    pub volume: Volume,
16    /// BGM volume change events, indexed by time. `#xxx97:`
17    pub bgm_volume_changes: BTreeMap<ObjTime, BgmVolumeObj>,
18    /// KEY volume change events, indexed by time. `#xxx98:`
19    pub key_volume_changes: BTreeMap<ObjTime, KeyVolumeObj>,
20}
21
22impl VolumeObjects {
23    /// Adds a new BGM volume change object to the notes.
24    pub fn push_bgm_volume_change(
25        &mut self,
26        volume_obj: BgmVolumeObj,
27        prompt_handler: &impl Prompter,
28    ) -> Result<()> {
29        match self.bgm_volume_changes.entry(volume_obj.time) {
30            Entry::Vacant(entry) => {
31                entry.insert(volume_obj);
32                Ok(())
33            }
34            Entry::Occupied(mut entry) => {
35                let existing = entry.get();
36
37                prompt_handler
38                    .handle_channel_duplication(ChannelDuplication::BgmVolumeChangeEvent {
39                        time: volume_obj.time,
40                        older: existing,
41                        newer: &volume_obj,
42                    })
43                    .apply_channel(
44                        entry.get_mut(),
45                        volume_obj.clone(),
46                        volume_obj.time,
47                        Channel::BgmVolume,
48                    )
49            }
50        }
51    }
52
53    /// Adds a new KEY volume change object to the notes.
54    pub fn push_key_volume_change(
55        &mut self,
56        volume_obj: KeyVolumeObj,
57        prompt_handler: &impl Prompter,
58    ) -> Result<()> {
59        match self.key_volume_changes.entry(volume_obj.time) {
60            Entry::Vacant(entry) => {
61                entry.insert(volume_obj);
62                Ok(())
63            }
64            Entry::Occupied(mut entry) => {
65                let existing = entry.get();
66
67                prompt_handler
68                    .handle_channel_duplication(ChannelDuplication::KeyVolumeChangeEvent {
69                        time: volume_obj.time,
70                        older: existing,
71                        newer: &volume_obj,
72                    })
73                    .apply_channel(
74                        entry.get_mut(),
75                        volume_obj.clone(),
76                        volume_obj.time,
77                        Channel::KeyVolume,
78                    )
79            }
80        }
81    }
82}