rust_raylib/
audio.rs

1use std::{
2    ffi::{CStr, CString},
3    time::Duration,
4};
5
6use crate::ffi;
7
8/// Audio file format
9#[derive(Clone, Copy, Debug, PartialEq, Eq)]
10pub enum AudioFormat {
11    /// Wave
12    Wav,
13    /// OGG
14    Ogg,
15    /// MP3
16    Mp3,
17    /// QOA
18    Qoa,
19    /// FLAC
20    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/// An object that handles audio playback
39#[derive(Debug)]
40pub struct AudioDevice(());
41
42impl AudioDevice {
43    /// Initialize audio device and context
44    #[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    /// Set master volume (listener)
58    #[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/// Wave, audio wave data
72#[derive(Debug)]
73#[repr(transparent)]
74pub struct Wave {
75    raw: ffi::Wave,
76}
77
78impl Wave {
79    /// Total number of frames (considering channels)
80    #[inline]
81    pub fn frame_count(&self) -> u32 {
82        self.raw.frameCount
83    }
84
85    /// Frequency (samples per second)
86    #[inline]
87    pub fn sample_rate(&self) -> u32 {
88        self.raw.sampleRate
89    }
90
91    /// Bit depth (bits per sample): 8, 16, 32 (24 not supported)
92    #[inline]
93    pub fn sample_size(&self) -> u32 {
94        self.raw.sampleSize
95    }
96
97    /// Number of channels (1-mono, 2-stereo, ...)
98    #[inline]
99    pub fn channels(&self) -> u32 {
100        self.raw.channels
101    }
102
103    /// Load wave data from file
104    #[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    /// Load wave from memory buffer
118    #[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    /// Export wave data to file, returns true on success
136    #[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    /// Export wave sample data to code (.h), returns true on success
144    #[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    /// Crop a wave to defined samples range
152    #[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    /// Convert wave data to desired format
158    #[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    /// Load samples data from wave as a 32bit float data array
171    #[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    /// Get the 'raw' ffi type
190    /// Take caution when cloning so it doesn't outlive the original
191    #[inline]
192    pub fn as_raw(&self) -> &ffi::Wave {
193        &self.raw
194    }
195
196    /// Get the 'raw' ffi type
197    /// Take caution when cloning so it doesn't outlive the original
198    #[inline]
199    pub fn as_raw_mut(&mut self) -> &mut ffi::Wave {
200        &mut self.raw
201    }
202
203    /// Convert a 'raw' ffi object to a safe wrapper
204    ///
205    /// # Safety
206    /// * The raw object must be correctly initialized
207    /// * The raw object should be unique. Otherwise, make sure its clones don't outlive the newly created object.
208    #[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/// AudioStream, custom audio stream
231#[derive(Debug)]
232#[repr(transparent)]
233pub struct AudioStream {
234    raw: ffi::AudioStream,
235}
236
237impl AudioStream {
238    /// Frequency (samples per second)
239    #[inline]
240    pub fn sample_rate(&self) -> u32 {
241        self.raw.sampleRate
242    }
243
244    /// Bit depth (bits per sample): 8, 16, 32 (24 not supported)
245    #[inline]
246    pub fn sample_size(&self) -> u32 {
247        self.raw.sampleSize
248    }
249
250    /// Number of channels (1-mono, 2-stereo, ...)
251    #[inline]
252    pub fn channels(&self) -> u32 {
253        self.raw.channels
254    }
255
256    /// Load audio stream (to stream raw audio pcm data)
257    #[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    /// Update audio stream buffers with data
269    #[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    /// Check if any audio stream buffers requires refill
281    #[inline]
282    pub fn is_processed(&self) -> bool {
283        unsafe { ffi::IsAudioStreamProcessed(self.raw.clone()) }
284    }
285
286    /// Play audio stream
287    #[inline]
288    pub fn play(&self, _device: &mut AudioDevice) {
289        unsafe { ffi::PlayAudioStream(self.raw.clone()) }
290    }
291
292    /// Pause audio stream
293    #[inline]
294    pub fn pause(&self, _device: &mut AudioDevice) {
295        unsafe { ffi::PauseAudioStream(self.raw.clone()) }
296    }
297
298    /// Resume audio stream
299    #[inline]
300    pub fn resume(&self, _device: &mut AudioDevice) {
301        unsafe { ffi::ResumeAudioStream(self.raw.clone()) }
302    }
303
304    /// Check if audio stream is playing
305    #[inline]
306    pub fn is_playing(&self, _device: &mut AudioDevice) -> bool {
307        unsafe { ffi::IsAudioStreamPlaying(self.raw.clone()) }
308    }
309
310    /// Stop audio stream
311    #[inline]
312    pub fn stop(&self, _device: &mut AudioDevice) {
313        unsafe { ffi::StopAudioStream(self.raw.clone()) }
314    }
315
316    /// Set volume for audio stream (1.0 is max level)
317    #[inline]
318    pub fn set_volume(&self, volume: f32, _device: &mut AudioDevice) {
319        unsafe { ffi::SetAudioStreamVolume(self.raw.clone(), volume) }
320    }
321
322    /// Set pitch for audio stream (1.0 is base level)
323    #[inline]
324    pub fn set_pitch(&self, pitch: f32, _device: &mut AudioDevice) {
325        unsafe { ffi::SetAudioStreamPitch(self.raw.clone(), pitch) }
326    }
327
328    /// Set pan for audio stream (0.5 is centered)
329    #[inline]
330    pub fn set_pan(&self, pan: f32, _device: &mut AudioDevice) {
331        unsafe { ffi::SetAudioStreamPan(self.raw.clone(), pan) }
332    }
333
334    /// Default size for new audio streams
335    #[inline]
336    pub fn set_default_buffer_size(size: usize) {
337        unsafe { ffi::SetAudioStreamBufferSizeDefault(size as _) }
338    }
339
340    /// Get the 'raw' ffi type
341    /// Take caution when cloning so it doesn't outlive the original
342    #[inline]
343    pub fn as_raw(&self) -> &ffi::AudioStream {
344        &self.raw
345    }
346
347    /// Get the 'raw' ffi type
348    /// Take caution when cloning so it doesn't outlive the original
349    #[inline]
350    pub fn as_raw_mut(&mut self) -> &mut ffi::AudioStream {
351        &mut self.raw
352    }
353
354    /// Convert a 'raw' ffi object to a safe wrapper
355    ///
356    /// # Safety
357    /// * The raw object must be correctly initialized
358    /// * The raw object should be unique. Otherwise, make sure its clones don't outlive the newly created object.
359    #[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/// Sound
373#[derive(Debug)]
374#[repr(transparent)]
375pub struct Sound {
376    raw: ffi::Sound,
377}
378
379impl Sound {
380    /// Total number of frames (considering channels)
381    #[inline]
382    pub fn frame_count(&self) -> u32 {
383        self.raw.frameCount
384    }
385
386    /// Load sound from file
387    #[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    /// Load sound from wave data
401    #[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    /// Update sound buffer with new data
413    #[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    /// Play a sound
425    #[inline]
426    pub fn play(&self, _device: &mut AudioDevice) {
427        unsafe { ffi::PlaySound(self.raw.clone()) }
428    }
429
430    /// Stop playing a sound
431    #[inline]
432    pub fn stop(&self, _device: &mut AudioDevice) {
433        unsafe { ffi::StopSound(self.raw.clone()) }
434    }
435
436    /// Pause a sound
437    #[inline]
438    pub fn pause(&self, _device: &mut AudioDevice) {
439        unsafe { ffi::PauseSound(self.raw.clone()) }
440    }
441
442    /// Resume a paused sound
443    #[inline]
444    pub fn resume(&self, _device: &mut AudioDevice) {
445        unsafe { ffi::ResumeSound(self.raw.clone()) }
446    }
447
448    /// Check if a sound is currently playing
449    #[inline]
450    pub fn is_playing(&self, _device: &mut AudioDevice) -> bool {
451        unsafe { ffi::IsSoundPlaying(self.raw.clone()) }
452    }
453
454    /// Set volume for a sound (1.0 is max level)
455    #[inline]
456    pub fn set_volume(&self, volume: f32, _device: &mut AudioDevice) {
457        unsafe { ffi::SetSoundVolume(self.raw.clone(), volume) }
458    }
459
460    /// Set pitch for a sound (1.0 is base level)
461    #[inline]
462    pub fn set_pitch(&self, pitch: f32, _device: &mut AudioDevice) {
463        unsafe { ffi::SetSoundPitch(self.raw.clone(), pitch) }
464    }
465
466    /// Set pan for a sound (0.5 is center)
467    #[inline]
468    pub fn set_pan(&self, pan: f32, _device: &mut AudioDevice) {
469        unsafe { ffi::SetSoundPan(self.raw.clone(), pan) }
470    }
471
472    /// Get the 'raw' ffi type
473    /// Take caution when cloning so it doesn't outlive the original
474    #[inline]
475    pub fn as_raw(&self) -> &ffi::Sound {
476        &self.raw
477    }
478
479    /// Get the 'raw' ffi type
480    /// Take caution when cloning so it doesn't outlive the original
481    #[inline]
482    pub fn as_raw_mut(&mut self) -> &mut ffi::Sound {
483        &mut self.raw
484    }
485
486    /// Convert a 'raw' ffi object to a safe wrapper
487    ///
488    /// # Safety
489    /// * The raw object must be correctly initialized
490    /// * The raw object should be unique. Otherwise, make sure its clones don't outlive the newly created object.
491    #[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/// Music, audio stream, anything longer than ~10 seconds should be streamed
505#[derive(Debug)]
506#[repr(transparent)]
507pub struct Music {
508    raw: ffi::Music,
509}
510
511impl Music {
512    /// Total number of frames (considering channels)
513    #[inline]
514    pub fn frame_count(&self) -> u32 {
515        self.raw.frameCount
516    }
517
518    /// Is music looping enabled
519    #[inline]
520    pub fn looping(&self) -> bool {
521        self.raw.looping
522    }
523
524    /// Enable/disable looping
525    #[inline]
526    pub fn set_looping(&mut self, looping: bool) {
527        self.raw.looping = looping;
528    }
529
530    /// Load music stream from file
531    #[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    /// Load music stream from data
544    #[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    /// Start music playing
562    #[inline]
563    pub fn play(&self, _device: &mut AudioDevice) {
564        unsafe { ffi::PlayMusicStream(self.raw.clone()) }
565    }
566
567    /// Check if music is playing
568    #[inline]
569    pub fn is_playing(&self, _device: &mut AudioDevice) -> bool {
570        unsafe { ffi::IsMusicStreamPlaying(self.raw.clone()) }
571    }
572
573    /// Updates buffers for music streaming
574    #[inline]
575    pub fn update(&self, _device: &mut AudioDevice) {
576        unsafe { ffi::UpdateMusicStream(self.raw.clone()) }
577    }
578
579    /// Stop music playing
580    #[inline]
581    pub fn stop(&self, _device: &mut AudioDevice) {
582        unsafe { ffi::StopMusicStream(self.raw.clone()) }
583    }
584
585    /// Pause music playing
586    #[inline]
587    pub fn pause(&self, _device: &mut AudioDevice) {
588        unsafe { ffi::PauseMusicStream(self.raw.clone()) }
589    }
590
591    /// Resume playing paused music
592    #[inline]
593    pub fn resume(&self, _device: &mut AudioDevice) {
594        unsafe { ffi::ResumeMusicStream(self.raw.clone()) }
595    }
596
597    /// Seek music to a position
598    #[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    /// Set volume for music (1.0 is max level)
604    #[inline]
605    pub fn set_volume(&self, volume: f32, _device: &mut AudioDevice) {
606        unsafe { ffi::SetMusicVolume(self.raw.clone(), volume) }
607    }
608
609    /// Set pitch for a music (1.0 is base level)
610    #[inline]
611    pub fn set_pitch(&self, pitch: f32, _device: &mut AudioDevice) {
612        unsafe { ffi::SetMusicPitch(self.raw.clone(), pitch) }
613    }
614
615    /// Set pan for a music (0.5 is center)
616    #[inline]
617    pub fn set_pan(&self, pan: f32, _device: &mut AudioDevice) {
618        unsafe { ffi::SetMusicPan(self.raw.clone(), pan) }
619    }
620
621    /// Get music time length
622    #[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    /// Get current music time played
628    #[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    /// Get the 'raw' ffi type
634    /// Take caution when cloning so it doesn't outlive the original
635    #[inline]
636    pub fn as_raw(&self) -> &ffi::Music {
637        &self.raw
638    }
639
640    /// Get the 'raw' ffi type
641    /// Take caution when cloning so it doesn't outlive the original
642    #[inline]
643    pub fn as_raw_mut(&mut self) -> &mut ffi::Music {
644        &mut self.raw
645    }
646
647    /// Convert a 'raw' ffi object to a safe wrapper
648    ///
649    /// # Safety
650    /// * The raw object must be correctly initialized
651    /// * The raw object should be unique. Otherwise, make sure its clones don't outlive the newly created object.
652    #[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//pub type AudioCallback = Option<unsafe extern "C" fn(bufferData: *mut core::ffi::c_void, frames: u32, )>;
666
667/*
668    /// Audio thread callback to request new data
669    #[inline]
670    pub fn SetAudioStreamCallback(stream: AudioStream, callback: AudioCallback);
671    /// Attach audio stream processor to stream
672    #[inline]
673    pub fn AttachAudioStreamProcessor(stream: AudioStream, processor: AudioCallback);
674    /// Detach audio stream processor from stream
675    #[inline]
676    pub fn DetachAudioStreamProcessor(stream: AudioStream, processor: AudioCallback);
677    /// Attach audio stream processor to the entire audio pipeline
678    #[inline]
679    pub fn AttachAudioMixedProcessor(processor: AudioCallback);
680    /// Detach audio stream processor from the entire audio pipeline
681    #[inline]
682    pub fn DetachAudioMixedProcessor(processor: AudioCallback);
683*/