raylib/core/
audio.rs

1//! Contains code related to audio. [`RaylibAudio`] plays sounds and music.
2
3use crate::error::{error, Error};
4use crate::ffi;
5use std::ffi::CString;
6use std::marker::PhantomData;
7use std::path::Path;
8
9make_thin_wrapper_lifetime!(Wave, ffi::Wave, RaylibAudio, ffi::UnloadWave);
10
11make_thin_wrapper_lifetime!(Sound, ffi::Sound, RaylibAudio, (ffi::UnloadSound), true);
12make_thin_wrapper_lifetime!(Music, ffi::Music, RaylibAudio, ffi::UnloadMusicStream);
13make_thin_wrapper_lifetime!(
14    AudioStream,
15    ffi::AudioStream,
16    RaylibAudio,
17    ffi::UnloadAudioStream
18);
19
20pub struct WaveSamples(*mut f32, usize);
21
22impl AsRef<[f32]> for WaveSamples {
23    fn as_ref(&self) -> &[f32] {
24        unsafe { std::slice::from_raw_parts(self.0, self.1) }
25    }
26}
27
28impl Drop for WaveSamples {
29    fn drop(&mut self) {
30        unsafe { ffi::UnloadWaveSamples(self.0) }
31    }
32}
33
34/// A marker trait specifying an audio sample (`u8`, `i16`, or `f32`).
35pub trait AudioSample {}
36impl AudioSample for u8 {}
37impl AudioSample for i16 {}
38impl AudioSample for f32 {}
39
40pub struct RaylibAudioInitError;
41
42impl std::fmt::Debug for RaylibAudioInitError {
43    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44        f.write_str("RaylibAudio cannot be instantiated more then once at a time.")
45    }
46}
47impl std::fmt::Display for RaylibAudioInitError {
48    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49        f.write_str("RaylibAudio cannot be instantiated more then once at a time.")
50    }
51}
52
53impl std::error::Error for RaylibAudioInitError {}
54
55/// This token is used to indicate audio is initialized. It's also used to create [`Wave`], [`Sound`], [`Music`], [`AudioStream`], and [`SoundAlias`].
56/// All of those have a lifetime that is bound to RaylibAudio. The compiler will disallow you from using them without ensuring that the [`RaylibAudio`] is present while doing so.
57#[derive(Debug, Clone)]
58pub struct RaylibAudio(PhantomData<()>);
59
60impl RaylibAudio {
61    /// Initializes audio device and context.
62    #[inline]
63    pub fn init_audio_device() -> Result<RaylibAudio, RaylibAudioInitError> {
64        unsafe {
65            if ffi::IsAudioDeviceReady() {
66                return Err(RaylibAudioInitError);
67            }
68            ffi::InitAudioDevice();
69        }
70        Ok(RaylibAudio(PhantomData))
71    }
72
73    /// Checks if audio device is ready.
74    #[inline]
75    pub fn is_audio_device_ready(&self) -> bool {
76        unsafe { ffi::IsAudioDeviceReady() }
77    }
78
79    /// Get master volume (listener)
80    #[inline]
81    pub fn get_master_volume(&self) -> f32 {
82        unsafe { ffi::GetMasterVolume() }
83    }
84
85    /// Sets master volume (listener).
86    #[inline]
87    pub fn set_master_volume(&self, volume: f32) {
88        unsafe { ffi::SetMasterVolume(volume) }
89    }
90    
91    /// Sets default audio buffer size for new audio streams.
92    #[inline]
93    pub fn set_audio_stream_buffer_size_default(&self, size: i32) {
94        unsafe {
95            ffi::SetAudioStreamBufferSizeDefault(size);
96        }
97    }    
98
99    /// Loads a new sound from file.
100    #[inline]
101    pub fn new_sound<'aud>(&'aud self, filename: &str) -> Result<Sound<'aud>, Error> {
102        let c_filename = CString::new(filename).unwrap();
103        let s = unsafe { ffi::LoadSound(c_filename.as_ptr()) };
104        if s.stream.buffer.is_null() {
105            return Err(error!("failed to load sound", filename));
106        }
107
108        Ok(Sound(s, self))
109    }
110
111    /// Loads sound from wave data.
112    #[inline]
113    pub fn new_sound_from_wave<'aud>(&'aud self, wave: &Wave) -> Result<Sound<'aud>, Error> {
114        let s = unsafe { ffi::LoadSoundFromWave(wave.0) };
115        if s.stream.buffer.is_null() {
116            return Err(error!("failed to load sound from wave"));
117        }
118        Ok(Sound(s, self))
119    }
120    /// Loads wave data from file into RAM.
121    #[inline]
122    pub fn new_wave<'aud>(&'aud self, filename: &str) -> Result<Wave<'aud>, Error> {
123        let c_filename = CString::new(filename).unwrap();
124        let w = unsafe { ffi::LoadWave(c_filename.as_ptr()) };
125        if w.data.is_null() {
126            return Err(error!("Cannot load wave {}", filename));
127        }
128        Ok(Wave(w, self))
129    }
130
131    /// Load wave from memory buffer, fileType refers to extension: i.e. '.wav'
132    #[inline]
133    pub fn new_wave_from_memory<'aud>(
134        &'aud self,
135        filetype: &str,
136        bytes: &[u8],
137    ) -> Result<Wave<'aud>, Error> {
138        let c_filetype = CString::new(filetype).unwrap();
139        let w = unsafe {
140            ffi::LoadWaveFromMemory(c_filetype.as_ptr(), bytes.as_ptr(), bytes.len() as i32)
141        };
142        if w.data.is_null() {
143            return Err(error!("Wave data is null. Check provided buffer data"));
144        };
145        Ok(Wave(w, self))
146    }
147
148    /// Loads music stream from file.
149    #[inline]
150    pub fn new_music<'aud>(&'aud self, filename: &str) -> Result<Music<'aud>, Error> {
151        let c_filename = CString::new(filename).unwrap();
152        let m = unsafe { ffi::LoadMusicStream(c_filename.as_ptr()) };
153        if m.stream.buffer.is_null() {
154            return Err(error!("music could not be loaded from file", filename));
155        }
156        Ok(Music(m, self))
157    }
158
159    /// Load music stream from data
160    #[inline]
161    pub fn new_music_from_memory<'aud>(
162        &'aud self,
163        filetype: &str,
164        bytes: &Vec<u8>,
165    ) -> Result<Music<'aud>, Error> {
166        let c_filetype = CString::new(filetype).unwrap();
167        let w = unsafe {
168            ffi::LoadMusicStreamFromMemory(c_filetype.as_ptr(), bytes.as_ptr(), bytes.len() as i32)
169        };
170        if w.stream.buffer.is_null() {
171            return Err(error!(
172                "Music's buffer data data is null. Check provided buffer data"
173            ));
174        };
175        Ok(Music(w, self))
176    }
177
178    /// Initializes audio stream (to stream raw PCM data).
179    #[inline]
180    pub fn new_audio_stream<'aud>(
181        &'aud self,
182        sample_rate: u32,
183        sample_size: u32,
184        channels: u32,
185    ) -> AudioStream<'aud> {
186        unsafe {
187            AudioStream(
188                ffi::LoadAudioStream(sample_rate, sample_size, channels),
189                self,
190            )
191        }
192    }
193}
194
195impl<'aud> Drop for RaylibAudio {
196    fn drop(&mut self) {
197        unsafe { ffi::CloseAudioDevice() }
198    }
199}
200
201impl<'aud> Wave<'aud> {
202    pub fn frame_count(&self) -> u32 {
203        self.0.frameCount
204    }
205    pub fn sample_rate(&self) -> u32 {
206        self.0.sampleRate
207    }
208    pub fn sample_size(&self) -> u32 {
209        self.0.sampleSize
210    }
211    pub fn channels(&self) -> u32 {
212        self.0.channels
213    }
214    pub unsafe fn inner(self) -> ffi::Wave {
215        let inner = self.0;
216        std::mem::forget(self);
217        inner
218    }
219
220    #[inline]
221    pub fn is_wave_valid(&self) -> bool {
222        unsafe { ffi::IsWaveValid(self.0) }
223    }
224
225    /// Export wave file. Extension must be .wav or .raw
226    #[inline]
227    pub fn export(&self, filename: impl AsRef<Path>) -> bool {
228        let c_filename = CString::new(filename.as_ref().to_string_lossy().as_bytes()).unwrap();
229        unsafe { ffi::ExportWave(self.0, c_filename.as_ptr()) }
230    }
231
232    /// Export wave sample data to code (.h)
233    /*#[inline]
234    pub fn export_wave_as_code(&self, filename: &str) -> bool {
235        let c_filename = CString::new(filename).unwrap();
236        unsafe { ffi::ExportWaveAsCode(self.0, c_filename.as_ptr()) }
237    }*/
238
239    /// Copies a wave to a new wave.
240    #[inline]
241    pub(crate) fn copy(&self) -> Wave {
242        unsafe { Wave(ffi::WaveCopy(self.0), self.1) }
243    }
244
245    /// Converts wave data to desired format.
246    #[inline]
247    pub fn format(&mut self, sample_rate: i32, sample_size: i32, channels: i32) {
248        unsafe { ffi::WaveFormat(&mut self.0, sample_rate, sample_size, channels) }
249    }
250
251    /// Crops a wave to defined sample range.
252    #[inline]
253    pub fn crop(&mut self, init_sample: i32, final_sample: i32) {
254        unsafe { ffi::WaveCrop(&mut self.0, init_sample, final_sample) }
255    }
256
257    /// Load samples data from wave as a floats array
258    /// NOTE 1: Returned sample values are normalized to range [-1..1]
259    /// NOTE 2: Sample data allocated should be freed with UnloadWaveSamples()
260    #[inline]
261    pub fn load_samples(&self) -> WaveSamples {
262        WaveSamples(
263            unsafe { ffi::LoadWaveSamples(self.0) },
264            self.frameCount as usize,
265        )
266    }
267}
268
269impl<'aud> AsRef<ffi::AudioStream> for Sound<'aud> {
270    fn as_ref(&self) -> &ffi::AudioStream {
271        &self.0.stream
272    }
273}
274
275impl<'aud> AsMut<ffi::AudioStream> for Sound<'aud> {
276    fn as_mut(&mut self) -> &mut ffi::AudioStream {
277        &mut self.0.stream
278    }
279}
280
281impl<'aud> Sound<'aud> {
282    pub fn is_sound_valid(&self) -> bool {
283        unsafe { ffi::IsSoundValid(self.0) }
284    }
285
286    pub fn frame_count(&self) -> u32 {
287        self.0.frameCount
288    }
289    pub unsafe fn inner(self) -> ffi::Sound {
290        let inner = self.0;
291        std::mem::forget(self);
292        inner
293    }
294
295    /// Plays a sound.
296    #[inline]
297    pub fn play(&self) {
298        unsafe { ffi::PlaySound(self.0) }
299    }
300
301    /// Pauses a sound.
302    #[inline]
303    pub fn pause(&self) {
304        unsafe { ffi::PauseSound(self.0) }
305    }
306
307    /// Resumes a paused sound.
308    #[inline]
309    pub fn resume(&self) {
310        unsafe { ffi::ResumeSound(self.0) }
311    }
312
313    /// Stops playing a sound.
314    #[inline]
315    pub fn stop(&self) {
316        unsafe { ffi::StopSound(self.0) }
317    }
318
319    /// Checks if a sound is currently playing.
320    #[inline]
321    pub fn is_playing(&self) -> bool {
322        unsafe { ffi::IsSoundPlaying(self.0) }
323    }
324
325    /// Sets volume for a sound (`1.0` is max level).
326    #[inline]
327    pub fn set_volume(&self, volume: f32) {
328        unsafe { ffi::SetSoundVolume(self.0, volume) }
329    }
330
331    /// Sets pitch for a sound (`1.0` is base level).
332    #[inline]
333    pub fn set_pitch(&self, pitch: f32) {
334        unsafe { ffi::SetSoundPitch(self.0, pitch) }
335    }
336
337    #[inline]
338    pub fn set_pan(&self, pan: f32) {
339        unsafe { ffi::SetSoundPan(self.0, pan) }
340    }
341
342    // Uncomment this when Raylib fulfills the todo comment within the original function to make the function safe.
343    // /// Updates sound buffer with new data.
344    // #[inline]
345    // pub fn update<T: AudioSample>(&mut self, data: &[T]) {
346    //     unsafe {
347    //         ffi::UpdateSound(
348    //             self.0,
349    //             data.as_ptr() as *const std::os::raw::c_void,
350    //             (data.len() * std::mem::size_of::<T>()) as i32,
351    //         );
352    //     }
353    // }}
354}
355
356impl<'aud, 'bind> SoundAlias<'aud, 'bind> {
357    pub fn is_sound_valid(&self) -> bool {
358        unsafe { ffi::IsSoundValid(self.0) }
359    }
360
361    pub fn frame_count(&self) -> u32 {
362        self.0.frameCount
363    }
364    pub unsafe fn inner(self) -> ffi::Sound {
365        let inner = self.0;
366        std::mem::forget(self);
367        inner
368    }
369
370    /// Plays a sound.
371    #[inline]
372    pub fn play(&self) {
373        unsafe { ffi::PlaySound(self.0) }
374    }
375
376    /// Pauses a sound.
377    #[inline]
378    pub fn pause(&self) {
379        unsafe { ffi::PauseSound(self.0) }
380    }
381
382    /// Resumes a paused sound.
383    #[inline]
384    pub fn resume(&self) {
385        unsafe { ffi::ResumeSound(self.0) }
386    }
387
388    /// Stops playing a sound.
389    #[inline]
390    pub fn stop(&self) {
391        unsafe { ffi::StopSound(self.0) }
392    }
393
394    /// Checks if a sound is currently playing.
395    #[inline]
396    pub fn is_playing(&self) -> bool {
397        unsafe { ffi::IsSoundPlaying(self.0) }
398    }
399
400    /// Sets volume for a sound (`1.0` is max level).
401    #[inline]
402    pub fn set_volume(&self, volume: f32) {
403        unsafe { ffi::SetSoundVolume(self.0, volume) }
404    }
405
406    /// Sets pitch for a sound (`1.0` is base level).
407    #[inline]
408    pub fn set_pitch(&self, pitch: f32) {
409        unsafe { ffi::SetSoundPitch(self.0, pitch) }
410    }
411
412    #[inline]
413    pub fn set_pan(&self, pan: f32) {
414        unsafe { ffi::SetSoundPan(self.0, pan) }
415    }
416}
417
418impl Drop for SoundAlias<'_, '_> {
419    fn drop(&mut self) {
420        unsafe { ffi::UnloadSoundAlias(self.0) }
421    }
422}
423
424impl<'aud> Music<'aud> {
425    /// Starts music playing.
426    #[inline]
427    pub fn play_stream(&self) {
428        unsafe { ffi::PlayMusicStream(self.0) }
429    }
430
431    /// Updates buffers for music streaming.
432    #[inline]
433    pub fn update_stream(&self) {
434        unsafe { ffi::UpdateMusicStream(self.0) }
435    }
436
437    /// Stops music playing.
438    #[inline]
439    pub fn stop_stream(&self) {
440        unsafe { ffi::StopMusicStream(self.0) }
441    }
442
443    /// Pauses music playing.
444    #[inline]
445    pub fn pause_stream(&self) {
446        unsafe { ffi::PauseMusicStream(self.0) }
447    }
448
449    /// Resumes playing paused music.
450    #[inline]
451    pub fn resume_stream(&self) {
452        unsafe { ffi::ResumeMusicStream(self.0) }
453    }
454
455    /// Checks if music is playing.
456    #[inline]
457    pub fn is_stream_playing(&self) -> bool {
458        unsafe { ffi::IsMusicStreamPlaying(self.0) }
459    }
460
461    /// Sets volume for music (`1.0` is max level).
462    #[inline]
463    pub fn set_volume(&self, volume: f32) {
464        unsafe { ffi::SetMusicVolume(self.0, volume) }
465    }
466
467    /// Sets pitch for music (`1.0` is base level).
468    #[inline]
469    pub fn set_pitch(&self, pitch: f32) {
470        unsafe { ffi::SetMusicPitch(self.0, pitch) }
471    }
472
473    /// Gets music time length in seconds.
474    #[inline]
475    pub fn get_time_length(&self) -> f32 {
476        unsafe { ffi::GetMusicTimeLength(self.0) }
477    }
478
479    /// Gets current music time played in seconds.
480    #[inline]
481    pub fn get_time_played(&self) -> f32 {
482        unsafe { ffi::GetMusicTimePlayed(self.0) }
483    }
484
485    #[inline]
486    pub fn seek_stream(&self, position: f32) {
487        unsafe { ffi::SeekMusicStream(self.0, position) }
488    }
489
490    #[inline]
491    pub fn set_pan(&self, pan: f32) {
492        unsafe { ffi::SetMusicPan(self.0, pan) }
493    }
494
495    #[inline]
496    pub fn is_music_valid(&self) -> bool {
497        unsafe { ffi::IsMusicValid(self.0) }
498    }
499}
500
501impl<'aud> AudioStream<'aud> {
502    pub fn is_audio_stream_valid(&self) -> bool {
503        unsafe { ffi::IsAudioStreamValid(self.0) }
504    }
505    pub fn sample_rate(&self) -> u32 {
506        self.0.sampleRate
507    }
508    pub fn sample_size(&self) -> u32 {
509        self.0.sampleSize
510    }
511    pub fn channels(&self) -> u32 {
512        self.0.channels
513    }
514
515    pub unsafe fn inner(self) -> ffi::AudioStream {
516        let inner = self.0;
517        std::mem::forget(self);
518        inner
519    }
520
521    /// Updates audio stream buffers with data.
522    #[inline]
523    pub fn update<T: AudioSample>(&mut self, data: &[T]) {
524        unsafe {
525            ffi::UpdateAudioStream(
526                self.0,
527                data.as_ptr() as *const std::os::raw::c_void,
528                (data.len() * std::mem::size_of::<T>()) as i32,
529            );
530        }
531    }
532
533    /// Plays audio stream.
534    #[inline]
535    pub fn play(&self) {
536        unsafe {
537            ffi::PlayAudioStream(self.0);
538        }
539    }
540
541    /// Pauses audio stream.
542    #[inline]
543    pub fn pause(&self) {
544        unsafe {
545            ffi::PauseAudioStream(self.0);
546        }
547    }
548
549    /// Resumes audio stream.
550    #[inline]
551    pub fn resume(&self) {
552        unsafe {
553            ffi::ResumeAudioStream(self.0);
554        }
555    }
556
557    /// Checks if audio stream is currently playing.
558    #[inline]
559    pub fn is_playing(&self) -> bool {
560        unsafe { ffi::IsAudioStreamPlaying(self.0) }
561    }
562
563    /// Stops audio stream.
564    #[inline]
565    pub fn stop(&self) {
566        unsafe {
567            ffi::StopAudioStream(self.0);
568        }
569    }
570
571    /// Sets volume for audio stream (`1.0` is max level).
572    #[inline]
573    pub fn set_volume(&self, volume: f32) {
574        unsafe {
575            ffi::SetAudioStreamVolume(self.0, volume);
576        }
577    }
578
579    /// Sets pitch for audio stream (`1.0` is base level).
580    #[inline]
581    pub fn set_pitch(&self, pitch: f32) {
582        unsafe {
583            ffi::SetAudioStreamPitch(self.0, pitch);
584        }
585    }
586
587    /// Sets pitch for audio stream (`1.0` is base level).
588    #[inline]
589    pub fn is_processed(&self) -> bool {
590        unsafe { ffi::IsAudioStreamProcessed(self.0) }
591    }
592
593    pub fn set_pan(&self, pan: f32) {
594        unsafe {
595            ffi::SetAudioStreamPan(self.0, pan);
596        }
597    }
598}
599
600impl<'bind> Sound<'_> {
601    pub fn alias<'snd>(&'snd self) -> Result<SoundAlias<'bind, 'snd>, Error> {
602        let s = unsafe { ffi::LoadSoundAlias(self.0) };
603        if s.stream.buffer.is_null() {
604            return Err(error!("failed to load sound from wave"));
605        }
606        Ok(SoundAlias(s, PhantomData))
607    }
608}
609
610pub struct SoundAlias<'snd, 'bind>(ffi::Sound, PhantomData<&'snd Sound<'bind>>);