11//! Contains code related to audio. [`RaylibAudio`] plays sounds and music.
22
3- use crate :: error:: { error, Error } ;
4- use crate :: ffi;
5- use std:: ffi:: CString ;
3+ use crate :: { ffi, error:: { AudioInitError , LoadSoundError } } ;
4+ use std:: ffi:: { CStr , CString } ;
65use std:: marker:: PhantomData ;
76use std:: path:: Path ;
87
8+ use super :: error:: ExportWaveError ;
9+
910make_thin_wrapper_lifetime ! (
1011 /// Wave, audio wave data
1112 Wave ,
@@ -57,21 +58,6 @@ impl AudioSample for u8 {}
5758impl AudioSample for i16 { }
5859impl AudioSample for f32 { }
5960
60- pub struct RaylibAudioInitError ;
61-
62- impl std:: fmt:: Debug for RaylibAudioInitError {
63- fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
64- f. write_str ( "RaylibAudio cannot be instantiated more then once at a time." )
65- }
66- }
67- impl std:: fmt:: Display for RaylibAudioInitError {
68- fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
69- f. write_str ( "RaylibAudio cannot be instantiated more then once at a time." )
70- }
71- }
72-
73- impl std:: error:: Error for RaylibAudioInitError { }
74-
7561/// This token is used to indicate audio is initialized. It's also used to create [`Wave`], [`Sound`], [`Music`], [`AudioStream`], and [`SoundAlias`].
7662/// 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.
7763#[ derive( Debug , Clone ) ]
@@ -80,12 +66,15 @@ pub struct RaylibAudio(PhantomData<()>);
8066impl RaylibAudio {
8167 /// Initializes audio device and context.
8268 #[ inline]
83- pub fn init_audio_device ( ) -> Result < RaylibAudio , RaylibAudioInitError > {
69+ pub fn init_audio_device ( ) -> Result < RaylibAudio , AudioInitError > {
8470 unsafe {
8571 if ffi:: IsAudioDeviceReady ( ) {
86- return Err ( RaylibAudioInitError ) ;
72+ return Err ( AudioInitError :: DoubleInit ) ;
8773 }
8874 ffi:: InitAudioDevice ( ) ;
75+ if !ffi:: IsAudioDeviceReady ( ) {
76+ return Err ( AudioInitError :: InitFailed ) ;
77+ }
8978 }
9079 Ok ( RaylibAudio ( PhantomData ) )
9180 }
@@ -118,32 +107,32 @@ impl RaylibAudio {
118107
119108 /// Loads a new sound from file.
120109 #[ inline]
121- pub fn new_sound < ' aud > ( & ' aud self , filename : & str ) -> Result < Sound < ' aud > , Error > {
110+ pub fn new_sound < ' aud > ( & ' aud self , filename : & str ) -> Result < Sound < ' aud > , LoadSoundError > {
122111 let c_filename = CString :: new ( filename) . unwrap ( ) ;
123112 let s = unsafe { ffi:: LoadSound ( c_filename. as_ptr ( ) ) } ;
124113 if s. stream . buffer . is_null ( ) {
125- return Err ( error ! ( "failed to load sound" , filename) ) ;
114+ return Err ( LoadSoundError :: LoadFailed { path : filename. into ( ) } ) ;
126115 }
127116
128117 Ok ( Sound ( s, self ) )
129118 }
130119
131120 /// Loads sound from wave data.
132121 #[ inline]
133- pub fn new_sound_from_wave < ' aud > ( & ' aud self , wave : & Wave ) -> Result < Sound < ' aud > , Error > {
122+ pub fn new_sound_from_wave < ' aud > ( & ' aud self , wave : & Wave ) -> Result < Sound < ' aud > , LoadSoundError > {
134123 let s = unsafe { ffi:: LoadSoundFromWave ( wave. 0 ) } ;
135124 if s. stream . buffer . is_null ( ) {
136- return Err ( error ! ( "failed to load sound from wave" ) ) ;
125+ return Err ( LoadSoundError :: LoadFromWaveFailed ) ;
137126 }
138127 Ok ( Sound ( s, self ) )
139128 }
140129 /// Loads wave data from file into RAM.
141130 #[ inline]
142- pub fn new_wave < ' aud > ( & ' aud self , filename : & str ) -> Result < Wave < ' aud > , Error > {
131+ pub fn new_wave < ' aud > ( & ' aud self , filename : & str ) -> Result < Wave < ' aud > , LoadSoundError > {
143132 let c_filename = CString :: new ( filename) . unwrap ( ) ;
144133 let w = unsafe { ffi:: LoadWave ( c_filename. as_ptr ( ) ) } ;
145134 if w. data . is_null ( ) {
146- return Err ( error ! ( "Cannot load wave {}" , filename) ) ;
135+ return Err ( LoadSoundError :: LoadWaveFromFileFailed { path : filename. into ( ) } ) ;
147136 }
148137 Ok ( Wave ( w, self ) )
149138 }
@@ -154,24 +143,24 @@ impl RaylibAudio {
154143 & ' aud self ,
155144 filetype : & str ,
156145 bytes : & [ u8 ] ,
157- ) -> Result < Wave < ' aud > , Error > {
146+ ) -> Result < Wave < ' aud > , LoadSoundError > {
158147 let c_filetype = CString :: new ( filetype) . unwrap ( ) ;
159148 let w = unsafe {
160149 ffi:: LoadWaveFromMemory ( c_filetype. as_ptr ( ) , bytes. as_ptr ( ) , bytes. len ( ) as i32 )
161150 } ;
162151 if w. data . is_null ( ) {
163- return Err ( error ! ( "Wave data is null. Check provided buffer data" ) ) ;
152+ return Err ( LoadSoundError :: Null ) ;
164153 } ;
165154 Ok ( Wave ( w, self ) )
166155 }
167156
168157 /// Loads music stream from file.
169158 #[ inline]
170- pub fn new_music < ' aud > ( & ' aud self , filename : & str ) -> Result < Music < ' aud > , Error > {
159+ pub fn new_music < ' aud > ( & ' aud self , filename : & str ) -> Result < Music < ' aud > , LoadSoundError > {
171160 let c_filename = CString :: new ( filename) . unwrap ( ) ;
172161 let m = unsafe { ffi:: LoadMusicStream ( c_filename. as_ptr ( ) ) } ;
173162 if m. stream . buffer . is_null ( ) {
174- return Err ( error ! ( "music could not be loaded from file" , filename) ) ;
163+ return Err ( LoadSoundError :: LoadMusicFromFileFailed { path : filename. into ( ) } ) ;
175164 }
176165 Ok ( Music ( m, self ) )
177166 }
@@ -182,15 +171,13 @@ impl RaylibAudio {
182171 & ' aud self ,
183172 filetype : & str ,
184173 bytes : & Vec < u8 > ,
185- ) -> Result < Music < ' aud > , Error > {
174+ ) -> Result < Music < ' aud > , LoadSoundError > {
186175 let c_filetype = CString :: new ( filetype) . unwrap ( ) ;
187176 let w = unsafe {
188177 ffi:: LoadMusicStreamFromMemory ( c_filetype. as_ptr ( ) , bytes. as_ptr ( ) , bytes. len ( ) as i32 )
189178 } ;
190179 if w. stream . buffer . is_null ( ) {
191- return Err ( error ! (
192- "Music's buffer data data is null. Check provided buffer data"
193- ) ) ;
180+ return Err ( LoadSoundError :: MusicNull ) ;
194181 } ;
195182 Ok ( Music ( w, self ) )
196183 }
@@ -253,9 +240,24 @@ impl<'aud> Wave<'aud> {
253240
254241 /// Export wave file. Extension must be .wav or .raw
255242 #[ inline]
256- pub fn export ( & self , filename : impl AsRef < Path > ) -> bool {
243+ pub fn export ( & self , filename : impl AsRef < Path > ) -> Result < ( ) , ExportWaveError > {
257244 let c_filename = CString :: new ( filename. as_ref ( ) . to_string_lossy ( ) . as_bytes ( ) ) . unwrap ( ) ;
258- unsafe { ffi:: ExportWave ( self . 0 , c_filename. as_ptr ( ) ) }
245+ let success = unsafe { ffi:: ExportWave ( self . 0 , c_filename. as_ptr ( ) ) } ;
246+ if success {
247+ Ok ( ( ) )
248+ } else {
249+ // const WAV: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b".wav\0") };
250+ const QOA : & CStr = unsafe { CStr :: from_bytes_with_nul_unchecked ( b".qoa\0 " ) } ;
251+ // const RAW: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b".raw\0") };
252+ let is_qoa = unsafe { ffi:: IsFileExtension ( c_filename. as_ptr ( ) , QOA . as_ptr ( ) ) } ;
253+ if is_qoa {
254+ let samples = self . 0 . sampleSize as i32 ;
255+ if samples != 16 {
256+ return Err ( ExportWaveError :: QoaBadSamples ( self . 0 . sampleSize as i32 ) ) ;
257+ }
258+ }
259+ Err ( ExportWaveError :: ExportFailed )
260+ }
259261 }
260262
261263 /*/// Export wave sample data to code (.h)
@@ -650,10 +652,12 @@ impl<'aud> AudioStream<'aud> {
650652}
651653
652654impl < ' bind > Sound < ' bind > {
653- pub fn alias < ' snd > ( & ' snd self ) -> Result < SoundAlias < ' snd , ' bind > , Error > {
655+ /// Clone sound from existing sound data, clone does not own wave data
656+ // NOTE: Wave data must be unallocated manually and will be shared across all clones
657+ pub fn alias < ' snd > ( & ' snd self ) -> Result < SoundAlias < ' snd , ' bind > , LoadSoundError > {
654658 let s = unsafe { ffi:: LoadSoundAlias ( self . 0 ) } ;
655659 if s. stream . buffer . is_null ( ) {
656- return Err ( error ! ( "failed to load sound from wave" ) ) ;
660+ return Err ( LoadSoundError :: LoadFromWaveFailed ) ;
657661 }
658662 Ok ( SoundAlias ( s, PhantomData ) )
659663 }
0 commit comments