1use fmod::{self, ChannelControl};
4
5#[derive(Debug, Default, PartialEq)]
21pub struct Voice {
22 channel : Option <fmod::Channel>,
23 channel_group : Option <fmod::ChannelGroup>
24}
25
26pub type IndexType = u16;
27#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
28pub struct Id (pub IndexType);
29
30impl Voice {
31 pub fn new() -> Self {
32 Voice::default()
33 }
34
35 pub const fn channel (&self) -> Option <&fmod::Channel> {
36 self.channel.as_ref()
37 }
38
39 pub const fn channel_mut (&mut self) -> Option <&mut fmod::Channel> {
40 self.channel.as_mut()
41 }
42
43 pub const fn channel_group (&self) -> Option <&fmod::ChannelGroup> {
44 self.channel_group.as_ref()
45 }
46
47 pub const fn channel_group_mut (&mut self) -> Option <&mut fmod::ChannelGroup> {
48 self.channel_group.as_mut()
49 }
50
51 pub fn is_playing (&self) -> Option <bool> {
52 if let Some (channel) = self.channel.as_ref() {
53 let playing = match channel.is_playing() {
54 Ok (playing) => playing,
55 Err (fmod::Error::ChannelStolen | fmod::Error::InvalidHandle) => false,
56 Err (err) => unreachable!("err: {:?}", err)
57 };
58 Some (playing)
59 } else {
60 None
61 }
62 }
63 #[expect(clippy::missing_panics_doc)]
71 pub fn play (&mut self,
72 sound : &mut fmod::Sound,
73 mut channel_group : Option <fmod::ChannelGroup>
74 ) {
75 let _ = self.stop();
76 sound.set_mode (fmod::Mode::LOOP_OFF | fmod::Mode::_2D).unwrap();
77 self.channel = Some (sound.play (channel_group.as_mut(), false).unwrap());
78 self.channel_group = channel_group;
79 }
80
81 #[expect(clippy::missing_panics_doc)]
86 pub fn loop_ (&mut self,
87 sound : &mut fmod::Sound,
88 mut channel_group : Option <fmod::ChannelGroup>
89 ) {
90 let _ = self.stop();
91 sound.set_mode (fmod::Mode::LOOP_NORMAL | fmod::Mode::_2D).unwrap();
92 self.channel = Some (sound.play (channel_group.as_mut(), false).unwrap());
93 self.channel_group = channel_group;
94 }
95
96 #[expect(clippy::missing_panics_doc)]
101 pub fn play_from (&mut self,
102 sound : &mut fmod::Sound,
103 channel_group : Option <fmod::ChannelGroup>,
104 position : u32
105 ) {
106 let _ = self.stop();
107 self.cue (sound, channel_group);
108 assert!(!self.position (position, None).unwrap());
109 assert!(!self.resume().unwrap());
110 }
111
112 #[expect(clippy::missing_panics_doc)]
120 pub fn loop_from (&mut self,
121 sound : &mut fmod::Sound,
122 mut channel_group : Option <fmod::ChannelGroup>,
123 position : u32
124 ) {
125 let _ = self.stop();
126 sound.set_mode (fmod::Mode::LOOP_NORMAL | fmod::Mode::_2D).unwrap();
127 self.channel = Some (sound.play (channel_group.as_mut(), true).unwrap());
128 self.channel_group = channel_group;
129 assert!(!self.position (position, None).unwrap());
130 assert!(!self.resume().unwrap());
131 }
132
133 #[expect(clippy::missing_panics_doc)]
135 pub fn cue (&mut self,
136 sound : &mut fmod::Sound,
137 mut channel_group : Option <fmod::ChannelGroup>
138 ) {
139 let _ = self.stop();
140 sound.set_mode (fmod::Mode::LOOP_OFF | fmod::Mode::_2D).unwrap();
141 self.channel = Some (sound.play (channel_group.as_mut(), true).unwrap());
142 self.channel_group = channel_group;
143 }
144
145 #[expect(clippy::missing_panics_doc)]
154 pub fn trigger (&mut self) -> Option <bool> {
155 if let Some (mut channel) = self.channel.take() {
156 let playing = match channel.is_playing() {
157 Ok (playing) => {
158 channel.set_position (0, fmod::Timeunit::PCM).unwrap();
159 channel.set_paused (false).unwrap();
160 self.channel = Some (channel);
161 playing
162 }
163 Err (fmod::Error::ChannelStolen | fmod::Error::InvalidHandle) => {
164 let mut sound = channel.sound_ref();
165 self.play (&mut sound, self.channel_group.clone());
166 false
167 }
168 Err (err) => unreachable!("err: {:?}", err)
169 };
170 Some (playing)
171 } else {
172 None
173 }
174 }
175
176 #[expect(clippy::missing_panics_doc)]
181 pub fn pause (&mut self) -> Option <bool> {
182 if let Some (mut channel) = self.channel.take() {
183 let playing = match channel.is_playing() {
184 Ok (playing) => {
185 channel.set_paused (true).unwrap();
186 self.channel = Some (channel);
187 playing
188 }
189 Err (fmod::Error::ChannelStolen | fmod::Error::InvalidHandle) => {
190 let mut sound = channel.sound_ref();
191 self.cue (&mut sound, self.channel_group.clone());
192 false
193 }
194 Err (err) => unreachable!("err: {:?}", err)
195 };
196 Some (playing)
197 } else {
198 None
199 }
200 }
201
202 #[expect(clippy::missing_panics_doc)]
207 pub fn resume (&mut self) -> Option <bool> {
208 if let Some (mut channel) = self.channel.take() {
209 let playing = match channel.is_playing() {
210 Ok (playing) => {
211 channel.set_paused (false).unwrap();
212 self.channel = Some (channel);
213 playing
214 }
215 Err (fmod::Error::ChannelStolen | fmod::Error::InvalidHandle) => {
216 let mut sound = channel.sound_ref();
217 self.play (&mut sound, self.channel_group.clone());
218 false
219 }
220 Err (err) => unreachable!("err: {:?}", err)
221 };
222 Some (playing)
223 } else {
224 None
225 }
226 }
227
228 #[expect(clippy::missing_panics_doc)]
235 pub fn position (&mut self, position : u32, timeunit : Option <fmod::Timeunit>)
236 -> Option <bool>
237 {
238 if let Some (mut channel) = self.channel.take() {
239 let timeunit = timeunit.unwrap_or (fmod::Timeunit::PCM);
240 let playing = match channel.is_playing() {
241 Ok (playing) => {
242 channel.set_position (position, timeunit).unwrap();
243 self.channel = Some (channel);
244 playing
245 }
246 Err (fmod::Error::ChannelStolen | fmod::Error::InvalidHandle) => {
247 let mut sound = channel.sound_ref();
248 self.cue (&mut sound, self.channel_group.clone());
249 self.channel.as_mut().unwrap().set_position (position, timeunit)
250 .unwrap();
251 false
252 }
253 Err (err) => unreachable!("err: {:?}", err)
254 };
255 Some (playing)
256 } else {
257 None
258 }
259 }
260
261 #[expect(clippy::missing_panics_doc)]
268 pub fn stop (&mut self) -> Option <bool> {
269 self.channel_group = None;
271 if let Some (mut channel) = self.channel.take() {
272 let playing = match channel.is_playing() {
273 Ok (playing) => {
274 channel.stop().unwrap();
275 playing
276 }
277 Err (fmod::Error::ChannelStolen | fmod::Error::InvalidHandle) => false,
278 Err (err) => unreachable!("err: {:?}", err)
279 };
280 Some (playing)
281 } else {
282 None
283 }
284 }
285}
286
287impl Drop for Voice {
288 fn drop (&mut self) {
289 self.stop();
290 }
291}