1use std::{
2 ffi::{CStr, CString},
3 time::Duration,
4};
5
6use crate::ffi;
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq)]
10pub enum AudioFormat {
11 Wav,
13 Ogg,
15 Mp3,
17 Qoa,
19 Flac,
21}
22
23impl AudioFormat {
24 fn as_cstr(&self) -> &'static CStr {
25 use AudioFormat::*;
26
27 CStr::from_bytes_with_nul(match self {
28 Wav => b".wav\0",
29 Ogg => b".ogg\0",
30 Mp3 => b".mp3\0",
31 Qoa => b".qoa\0",
32 Flac => b".flac\0",
33 })
34 .unwrap()
35 }
36}
37
38#[derive(Debug)]
40pub struct AudioDevice(());
41
42impl AudioDevice {
43 #[inline]
45 pub fn init() -> Option<Self> {
46 unsafe {
47 ffi::InitAudioDevice();
48 }
49
50 if unsafe { ffi::IsAudioDeviceReady() } {
51 Some(Self(()))
52 } else {
53 None
54 }
55 }
56
57 #[inline]
59 pub fn set_master_volume(&mut self, volume: f32) {
60 unsafe { ffi::SetMasterVolume(volume) }
61 }
62}
63
64impl Drop for AudioDevice {
65 #[inline]
66 fn drop(&mut self) {
67 unsafe { ffi::CloseAudioDevice() }
68 }
69}
70
71#[derive(Debug)]
73#[repr(transparent)]
74pub struct Wave {
75 raw: ffi::Wave,
76}
77
78impl Wave {
79 #[inline]
81 pub fn frame_count(&self) -> u32 {
82 self.raw.frameCount
83 }
84
85 #[inline]
87 pub fn sample_rate(&self) -> u32 {
88 self.raw.sampleRate
89 }
90
91 #[inline]
93 pub fn sample_size(&self) -> u32 {
94 self.raw.sampleSize
95 }
96
97 #[inline]
99 pub fn channels(&self) -> u32 {
100 self.raw.channels
101 }
102
103 #[inline]
105 pub fn from_file(file_name: &str) -> Option<Self> {
106 let file_name = CString::new(file_name).unwrap();
107
108 let raw = unsafe { ffi::LoadWave(file_name.as_ptr()) };
109
110 if unsafe { ffi::IsWaveReady(raw.clone()) } {
111 Some(Self { raw })
112 } else {
113 None
114 }
115 }
116
117 #[inline]
119 pub fn from_memory(file_data: &[u8], format: AudioFormat) -> Option<Self> {
120 let raw = unsafe {
121 ffi::LoadWaveFromMemory(
122 format.as_cstr().as_ptr(),
123 file_data.as_ptr(),
124 file_data.len() as _,
125 )
126 };
127
128 if unsafe { ffi::IsWaveReady(raw.clone()) } {
129 Some(Self { raw })
130 } else {
131 None
132 }
133 }
134
135 #[inline]
137 pub fn export(&self, file_name: &str) -> bool {
138 let file_name = CString::new(file_name).unwrap();
139
140 unsafe { ffi::ExportWave(self.raw.clone(), file_name.as_ptr()) }
141 }
142
143 #[inline]
145 pub fn export_as_code(&self, file_name: &str) -> bool {
146 let file_name = CString::new(file_name).unwrap();
147
148 unsafe { ffi::ExportWaveAsCode(self.raw.clone(), file_name.as_ptr()) }
149 }
150
151 #[inline]
153 pub fn crop(&mut self, init_sample: u32, final_sample: u32) {
154 unsafe { ffi::WaveCrop(&mut self.raw as *mut _, init_sample as _, final_sample as _) }
155 }
156
157 #[inline]
159 pub fn convert_to_format(&mut self, sample_rate: u32, sample_size: u32, channels: u32) {
160 unsafe {
161 ffi::WaveFormat(
162 &mut self.raw as *mut _,
163 sample_rate as _,
164 sample_size as _,
165 channels as _,
166 )
167 }
168 }
169
170 #[inline]
172 pub fn load_samples(&self) -> Vec<f32> {
173 let samples = unsafe { ffi::LoadWaveSamples(self.raw.clone()) };
174
175 let mut vec = Vec::new();
176 let len = (self.frame_count() * self.channels()) as usize;
177
178 for i in 0..len {
179 vec.push(unsafe { samples.add(i).read() });
180 }
181
182 unsafe {
183 ffi::UnloadWaveSamples(samples);
184 }
185
186 vec
187 }
188
189 #[inline]
192 pub fn as_raw(&self) -> &ffi::Wave {
193 &self.raw
194 }
195
196 #[inline]
199 pub fn as_raw_mut(&mut self) -> &mut ffi::Wave {
200 &mut self.raw
201 }
202
203 #[inline]
209 pub unsafe fn from_raw(raw: ffi::Wave) -> Self {
210 Self { raw }
211 }
212}
213
214impl Clone for Wave {
215 #[inline]
216 fn clone(&self) -> Self {
217 Self {
218 raw: unsafe { ffi::WaveCopy(self.raw.clone()) },
219 }
220 }
221}
222
223impl Drop for Wave {
224 #[inline]
225 fn drop(&mut self) {
226 unsafe { ffi::UnloadWave(self.raw.clone()) }
227 }
228}
229
230#[derive(Debug)]
232#[repr(transparent)]
233pub struct AudioStream {
234 raw: ffi::AudioStream,
235}
236
237impl AudioStream {
238 #[inline]
240 pub fn sample_rate(&self) -> u32 {
241 self.raw.sampleRate
242 }
243
244 #[inline]
246 pub fn sample_size(&self) -> u32 {
247 self.raw.sampleSize
248 }
249
250 #[inline]
252 pub fn channels(&self) -> u32 {
253 self.raw.channels
254 }
255
256 #[inline]
258 pub fn new(sample_rate: u32, sample_size: u32, channels: u32) -> Option<Self> {
259 let raw = unsafe { ffi::LoadAudioStream(sample_rate, sample_size, channels) };
260
261 if unsafe { ffi::IsAudioStreamReady(raw.clone()) } {
262 Some(Self { raw })
263 } else {
264 None
265 }
266 }
267
268 #[inline]
270 pub fn update(&mut self, data: &[u8], frame_count: u32) {
271 unsafe {
272 ffi::UpdateAudioStream(
273 self.raw.clone(),
274 data.as_ptr() as *const _,
275 frame_count as _,
276 )
277 }
278 }
279
280 #[inline]
282 pub fn is_processed(&self) -> bool {
283 unsafe { ffi::IsAudioStreamProcessed(self.raw.clone()) }
284 }
285
286 #[inline]
288 pub fn play(&self, _device: &mut AudioDevice) {
289 unsafe { ffi::PlayAudioStream(self.raw.clone()) }
290 }
291
292 #[inline]
294 pub fn pause(&self, _device: &mut AudioDevice) {
295 unsafe { ffi::PauseAudioStream(self.raw.clone()) }
296 }
297
298 #[inline]
300 pub fn resume(&self, _device: &mut AudioDevice) {
301 unsafe { ffi::ResumeAudioStream(self.raw.clone()) }
302 }
303
304 #[inline]
306 pub fn is_playing(&self, _device: &mut AudioDevice) -> bool {
307 unsafe { ffi::IsAudioStreamPlaying(self.raw.clone()) }
308 }
309
310 #[inline]
312 pub fn stop(&self, _device: &mut AudioDevice) {
313 unsafe { ffi::StopAudioStream(self.raw.clone()) }
314 }
315
316 #[inline]
318 pub fn set_volume(&self, volume: f32, _device: &mut AudioDevice) {
319 unsafe { ffi::SetAudioStreamVolume(self.raw.clone(), volume) }
320 }
321
322 #[inline]
324 pub fn set_pitch(&self, pitch: f32, _device: &mut AudioDevice) {
325 unsafe { ffi::SetAudioStreamPitch(self.raw.clone(), pitch) }
326 }
327
328 #[inline]
330 pub fn set_pan(&self, pan: f32, _device: &mut AudioDevice) {
331 unsafe { ffi::SetAudioStreamPan(self.raw.clone(), pan) }
332 }
333
334 #[inline]
336 pub fn set_default_buffer_size(size: usize) {
337 unsafe { ffi::SetAudioStreamBufferSizeDefault(size as _) }
338 }
339
340 #[inline]
343 pub fn as_raw(&self) -> &ffi::AudioStream {
344 &self.raw
345 }
346
347 #[inline]
350 pub fn as_raw_mut(&mut self) -> &mut ffi::AudioStream {
351 &mut self.raw
352 }
353
354 #[inline]
360 pub unsafe fn from_raw(raw: ffi::AudioStream) -> Self {
361 Self { raw }
362 }
363}
364
365impl Drop for AudioStream {
366 #[inline]
367 fn drop(&mut self) {
368 unsafe { ffi::UnloadAudioStream(self.raw.clone()) }
369 }
370}
371
372#[derive(Debug)]
374#[repr(transparent)]
375pub struct Sound {
376 raw: ffi::Sound,
377}
378
379impl Sound {
380 #[inline]
382 pub fn frame_count(&self) -> u32 {
383 self.raw.frameCount
384 }
385
386 #[inline]
388 pub fn from_file(filname: &str) -> Option<Self> {
389 let file_name = CString::new(filname).unwrap();
390
391 let raw = unsafe { ffi::LoadSound(file_name.as_ptr()) };
392
393 if unsafe { ffi::IsSoundReady(raw.clone()) } {
394 Some(Self { raw })
395 } else {
396 None
397 }
398 }
399
400 #[inline]
402 pub fn from_wave(wave: &Wave) -> Option<Self> {
403 let raw = unsafe { ffi::LoadSoundFromWave(wave.raw.clone()) };
404
405 if unsafe { ffi::IsSoundReady(raw.clone()) } {
406 Some(Self { raw })
407 } else {
408 None
409 }
410 }
411
412 #[inline]
414 pub fn update(&mut self, data: &[u8], sample_count: u32) {
415 unsafe {
416 ffi::UpdateSound(
417 self.raw.clone(),
418 data.as_ptr() as *const _,
419 sample_count as _,
420 )
421 }
422 }
423
424 #[inline]
426 pub fn play(&self, _device: &mut AudioDevice) {
427 unsafe { ffi::PlaySound(self.raw.clone()) }
428 }
429
430 #[inline]
432 pub fn stop(&self, _device: &mut AudioDevice) {
433 unsafe { ffi::StopSound(self.raw.clone()) }
434 }
435
436 #[inline]
438 pub fn pause(&self, _device: &mut AudioDevice) {
439 unsafe { ffi::PauseSound(self.raw.clone()) }
440 }
441
442 #[inline]
444 pub fn resume(&self, _device: &mut AudioDevice) {
445 unsafe { ffi::ResumeSound(self.raw.clone()) }
446 }
447
448 #[inline]
450 pub fn is_playing(&self, _device: &mut AudioDevice) -> bool {
451 unsafe { ffi::IsSoundPlaying(self.raw.clone()) }
452 }
453
454 #[inline]
456 pub fn set_volume(&self, volume: f32, _device: &mut AudioDevice) {
457 unsafe { ffi::SetSoundVolume(self.raw.clone(), volume) }
458 }
459
460 #[inline]
462 pub fn set_pitch(&self, pitch: f32, _device: &mut AudioDevice) {
463 unsafe { ffi::SetSoundPitch(self.raw.clone(), pitch) }
464 }
465
466 #[inline]
468 pub fn set_pan(&self, pan: f32, _device: &mut AudioDevice) {
469 unsafe { ffi::SetSoundPan(self.raw.clone(), pan) }
470 }
471
472 #[inline]
475 pub fn as_raw(&self) -> &ffi::Sound {
476 &self.raw
477 }
478
479 #[inline]
482 pub fn as_raw_mut(&mut self) -> &mut ffi::Sound {
483 &mut self.raw
484 }
485
486 #[inline]
492 pub unsafe fn from_raw(raw: ffi::Sound) -> Self {
493 Self { raw }
494 }
495}
496
497impl Drop for Sound {
498 #[inline]
499 fn drop(&mut self) {
500 unsafe { ffi::UnloadSound(self.raw.clone()) }
501 }
502}
503
504#[derive(Debug)]
506#[repr(transparent)]
507pub struct Music {
508 raw: ffi::Music,
509}
510
511impl Music {
512 #[inline]
514 pub fn frame_count(&self) -> u32 {
515 self.raw.frameCount
516 }
517
518 #[inline]
520 pub fn looping(&self) -> bool {
521 self.raw.looping
522 }
523
524 #[inline]
526 pub fn set_looping(&mut self, looping: bool) {
527 self.raw.looping = looping;
528 }
529
530 #[inline]
532 pub fn from_file(file_name: &str) -> Option<Self> {
533 let file_name = CString::new(file_name).unwrap();
534
535 let raw = unsafe { ffi::LoadMusicStream(file_name.as_ptr()) };
536
537 if unsafe { ffi::IsMusicReady(raw.clone()) } {
538 Some(Self { raw })
539 } else {
540 None
541 }
542 }
543 #[inline]
545 pub fn from_memory(data: &[u8], format: AudioFormat) -> Option<Self> {
546 let raw = unsafe {
547 ffi::LoadMusicStreamFromMemory(
548 format.as_cstr().as_ptr(),
549 data.as_ptr(),
550 data.len() as _,
551 )
552 };
553
554 if unsafe { ffi::IsMusicReady(raw.clone()) } {
555 Some(Self { raw })
556 } else {
557 None
558 }
559 }
560
561 #[inline]
563 pub fn play(&self, _device: &mut AudioDevice) {
564 unsafe { ffi::PlayMusicStream(self.raw.clone()) }
565 }
566
567 #[inline]
569 pub fn is_playing(&self, _device: &mut AudioDevice) -> bool {
570 unsafe { ffi::IsMusicStreamPlaying(self.raw.clone()) }
571 }
572
573 #[inline]
575 pub fn update(&self, _device: &mut AudioDevice) {
576 unsafe { ffi::UpdateMusicStream(self.raw.clone()) }
577 }
578
579 #[inline]
581 pub fn stop(&self, _device: &mut AudioDevice) {
582 unsafe { ffi::StopMusicStream(self.raw.clone()) }
583 }
584
585 #[inline]
587 pub fn pause(&self, _device: &mut AudioDevice) {
588 unsafe { ffi::PauseMusicStream(self.raw.clone()) }
589 }
590
591 #[inline]
593 pub fn resume(&self, _device: &mut AudioDevice) {
594 unsafe { ffi::ResumeMusicStream(self.raw.clone()) }
595 }
596
597 #[inline]
599 pub fn seek(&self, position: Duration, _device: &mut AudioDevice) {
600 unsafe { ffi::SeekMusicStream(self.raw.clone(), position.as_secs_f32()) }
601 }
602
603 #[inline]
605 pub fn set_volume(&self, volume: f32, _device: &mut AudioDevice) {
606 unsafe { ffi::SetMusicVolume(self.raw.clone(), volume) }
607 }
608
609 #[inline]
611 pub fn set_pitch(&self, pitch: f32, _device: &mut AudioDevice) {
612 unsafe { ffi::SetMusicPitch(self.raw.clone(), pitch) }
613 }
614
615 #[inline]
617 pub fn set_pan(&self, pan: f32, _device: &mut AudioDevice) {
618 unsafe { ffi::SetMusicPan(self.raw.clone(), pan) }
619 }
620
621 #[inline]
623 pub fn get_time_length(&self, _device: &mut AudioDevice) -> Duration {
624 Duration::from_secs_f32(unsafe { ffi::GetMusicTimeLength(self.raw.clone()) })
625 }
626
627 #[inline]
629 pub fn get_time_played(&self, _device: &mut AudioDevice) -> Duration {
630 Duration::from_secs_f32(unsafe { ffi::GetMusicTimePlayed(self.raw.clone()) })
631 }
632
633 #[inline]
636 pub fn as_raw(&self) -> &ffi::Music {
637 &self.raw
638 }
639
640 #[inline]
643 pub fn as_raw_mut(&mut self) -> &mut ffi::Music {
644 &mut self.raw
645 }
646
647 #[inline]
653 pub unsafe fn from_raw(raw: ffi::Music) -> Self {
654 Self { raw }
655 }
656}
657
658impl Drop for Music {
659 #[inline]
660 fn drop(&mut self) {
661 unsafe { ffi::UnloadMusicStream(self.raw.clone()) }
662 }
663}
664
665