1use std::fmt;
2
3use anyhow::{anyhow, Context, Result};
4use kira::manager::{backend::DefaultBackend, AudioManager, AudioManagerSettings};
5use kira::sound::static_sound::{StaticSoundData, StaticSoundHandle};
6use kira::track::{TrackBuilder, TrackHandle};
7use kira::tween::Tween;
8use kira::Volume;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum TrackKind {
12 Bgm,
13 Se,
14 Pcm,
15 Koe,
16 Mov,
17}
18
19pub struct AudioHub {
24 manager: Option<AudioManager<DefaultBackend>>,
25 bgm: Option<TrackHandle>,
26 se: Option<TrackHandle>,
27 pcm: Option<TrackHandle>,
28 koe: Option<TrackHandle>,
29 mov: Option<TrackHandle>,
30 bgm_base: u8,
31 se_base: u8,
32 pcm_base: u8,
33 koe_base: u8,
34 mov_base: u8,
35 bgm_master: u8,
36 se_master: u8,
37 pcm_master: u8,
38 koe_master: u8,
39 mov_master: u8,
40}
41
42impl fmt::Debug for AudioHub {
43 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44 f.debug_struct("AudioHub")
45 .field("enabled", &self.manager.is_some())
46 .finish()
47 }
48}
49
50impl AudioHub {
51 pub fn new() -> Self {
52 match AudioManager::<DefaultBackend>::new(AudioManagerSettings::default()) {
53 Ok(mut manager) => {
54 let bgm = manager.add_sub_track(TrackBuilder::default()).ok();
55 let se = manager.add_sub_track(TrackBuilder::default()).ok();
56 let pcm = manager.add_sub_track(TrackBuilder::default()).ok();
57 let koe = manager.add_sub_track(TrackBuilder::default()).ok();
58 let mov = manager.add_sub_track(TrackBuilder::default()).ok();
59 Self {
60 manager: Some(manager),
61 bgm,
62 se,
63 pcm,
64 koe,
65 mov,
66 bgm_base: 255,
67 se_base: 255,
68 pcm_base: 255,
69 koe_base: 255,
70 mov_base: 255,
71 bgm_master: 255,
72 se_master: 255,
73 pcm_master: 255,
74 koe_master: 255,
75 mov_master: 255,
76 }
77 }
78 Err(e) => {
79 eprintln!("kira init failed, audio disabled: {:#}", e);
80 Self {
81 manager: None,
82 bgm: None,
83 se: None,
84 pcm: None,
85 koe: None,
86 mov: None,
87 bgm_base: 255,
88 se_base: 255,
89 pcm_base: 255,
90 koe_base: 255,
91 mov_base: 255,
92 bgm_master: 255,
93 se_master: 255,
94 pcm_master: 255,
95 koe_master: 255,
96 mov_master: 255,
97 }
98 }
99 }
100 }
101
102 pub fn is_enabled(&self) -> bool {
103 self.manager.is_some()
104 }
105
106 fn track_ref(&self, kind: TrackKind) -> Option<&TrackHandle> {
107 match kind {
108 TrackKind::Bgm => self.bgm.as_ref(),
109 TrackKind::Se => self.se.as_ref(),
110 TrackKind::Pcm => self.pcm.as_ref(),
111 TrackKind::Koe => self.koe.as_ref(),
112 TrackKind::Mov => self.mov.as_ref(),
113 }
114 }
115
116 fn track_mut(&mut self, kind: TrackKind) -> Option<&mut TrackHandle> {
117 match kind {
118 TrackKind::Bgm => self.bgm.as_mut(),
119 TrackKind::Se => self.se.as_mut(),
120 TrackKind::Pcm => self.pcm.as_mut(),
121 TrackKind::Koe => self.koe.as_mut(),
122 TrackKind::Mov => self.mov.as_mut(),
123 }
124 }
125
126 fn track_base_mut(&mut self, kind: TrackKind) -> &mut u8 {
127 match kind {
128 TrackKind::Bgm => &mut self.bgm_base,
129 TrackKind::Se => &mut self.se_base,
130 TrackKind::Pcm => &mut self.pcm_base,
131 TrackKind::Koe => &mut self.koe_base,
132 TrackKind::Mov => &mut self.mov_base,
133 }
134 }
135
136 fn track_master_mut(&mut self, kind: TrackKind) -> &mut u8 {
137 match kind {
138 TrackKind::Bgm => &mut self.bgm_master,
139 TrackKind::Se => &mut self.se_master,
140 TrackKind::Pcm => &mut self.pcm_master,
141 TrackKind::Koe => &mut self.koe_master,
142 TrackKind::Mov => &mut self.mov_master,
143 }
144 }
145
146 fn track_base(&self, kind: TrackKind) -> u8 {
147 match kind {
148 TrackKind::Bgm => self.bgm_base,
149 TrackKind::Se => self.se_base,
150 TrackKind::Pcm => self.pcm_base,
151 TrackKind::Koe => self.koe_base,
152 TrackKind::Mov => self.mov_base,
153 }
154 }
155
156 fn track_master(&self, kind: TrackKind) -> u8 {
157 match kind {
158 TrackKind::Bgm => self.bgm_master,
159 TrackKind::Se => self.se_master,
160 TrackKind::Pcm => self.pcm_master,
161 TrackKind::Koe => self.koe_master,
162 TrackKind::Mov => self.mov_master,
163 }
164 }
165
166 fn apply_track_volume(&mut self, kind: TrackKind) {
167 let base = self.track_base(kind) as f64 / 255.0;
168 let master = self.track_master(kind) as f64 / 255.0;
169 let amp = base * master;
170 let Some(track) = self.track_mut(kind) else {
171 return;
172 };
173 track.set_volume(Volume::Amplitude(amp), Tween::default());
174 }
175
176 fn apply_track_volume_fade(&mut self, kind: TrackKind, fade_ms: i64) {
177 let base = self.track_base(kind) as f64 / 255.0;
178 let master = self.track_master(kind) as f64 / 255.0;
179 let amp = base * master;
180 let Some(track) = self.track_mut(kind) else {
181 return;
182 };
183 let tween = if fade_ms > 0 {
184 Tween {
185 duration: std::time::Duration::from_millis(fade_ms as u64),
186 ..Tween::default()
187 }
188 } else {
189 Tween::default()
190 };
191 track.set_volume(Volume::Amplitude(amp), tween);
192 }
193
194 pub fn play_static(
195 &mut self,
196 kind: TrackKind,
197 data: StaticSoundData,
198 ) -> Result<StaticSoundHandle> {
199 let data = if let Some(track) = self.track_ref(kind) {
201 data.output_destination(track)
202 } else {
203 data
204 };
205
206 let manager = self
207 .manager
208 .as_mut()
209 .ok_or_else(|| anyhow!("audio disabled"))?;
210
211 manager.play(data).context("kira: play static sound")
212 }
213
214 pub fn set_track_volume_raw(&mut self, kind: TrackKind, volume_raw: u8) {
215 *self.track_base_mut(kind) = volume_raw;
216 self.apply_track_volume(kind);
217 }
218
219 pub fn set_track_master_volume_raw(&mut self, kind: TrackKind, volume_raw: u8) {
220 *self.track_master_mut(kind) = volume_raw;
221 self.apply_track_volume(kind);
222 }
223
224 pub fn set_track_volume_raw_fade(&mut self, kind: TrackKind, volume_raw: u8, fade_ms: i64) {
225 *self.track_base_mut(kind) = volume_raw;
226 self.apply_track_volume_fade(kind, fade_ms);
227 }
228}