1use 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
34pub 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#[derive(Debug, Clone)]
58pub struct RaylibAudio(PhantomData<()>);
59
60impl RaylibAudio {
61 #[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 #[inline]
75 pub fn is_audio_device_ready(&self) -> bool {
76 unsafe { ffi::IsAudioDeviceReady() }
77 }
78
79 #[inline]
81 pub fn get_master_volume(&self) -> f32 {
82 unsafe { ffi::GetMasterVolume() }
83 }
84
85 #[inline]
87 pub fn set_master_volume(&self, volume: f32) {
88 unsafe { ffi::SetMasterVolume(volume) }
89 }
90
91 #[inline]
93 pub fn set_audio_stream_buffer_size_default(&self, size: i32) {
94 unsafe {
95 ffi::SetAudioStreamBufferSizeDefault(size);
96 }
97 }
98
99 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[inline]
241 pub(crate) fn copy(&self) -> Wave {
242 unsafe { Wave(ffi::WaveCopy(self.0), self.1) }
243 }
244
245 #[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 #[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 #[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 #[inline]
297 pub fn play(&self) {
298 unsafe { ffi::PlaySound(self.0) }
299 }
300
301 #[inline]
303 pub fn pause(&self) {
304 unsafe { ffi::PauseSound(self.0) }
305 }
306
307 #[inline]
309 pub fn resume(&self) {
310 unsafe { ffi::ResumeSound(self.0) }
311 }
312
313 #[inline]
315 pub fn stop(&self) {
316 unsafe { ffi::StopSound(self.0) }
317 }
318
319 #[inline]
321 pub fn is_playing(&self) -> bool {
322 unsafe { ffi::IsSoundPlaying(self.0) }
323 }
324
325 #[inline]
327 pub fn set_volume(&self, volume: f32) {
328 unsafe { ffi::SetSoundVolume(self.0, volume) }
329 }
330
331 #[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 }
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 #[inline]
372 pub fn play(&self) {
373 unsafe { ffi::PlaySound(self.0) }
374 }
375
376 #[inline]
378 pub fn pause(&self) {
379 unsafe { ffi::PauseSound(self.0) }
380 }
381
382 #[inline]
384 pub fn resume(&self) {
385 unsafe { ffi::ResumeSound(self.0) }
386 }
387
388 #[inline]
390 pub fn stop(&self) {
391 unsafe { ffi::StopSound(self.0) }
392 }
393
394 #[inline]
396 pub fn is_playing(&self) -> bool {
397 unsafe { ffi::IsSoundPlaying(self.0) }
398 }
399
400 #[inline]
402 pub fn set_volume(&self, volume: f32) {
403 unsafe { ffi::SetSoundVolume(self.0, volume) }
404 }
405
406 #[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 #[inline]
427 pub fn play_stream(&self) {
428 unsafe { ffi::PlayMusicStream(self.0) }
429 }
430
431 #[inline]
433 pub fn update_stream(&self) {
434 unsafe { ffi::UpdateMusicStream(self.0) }
435 }
436
437 #[inline]
439 pub fn stop_stream(&self) {
440 unsafe { ffi::StopMusicStream(self.0) }
441 }
442
443 #[inline]
445 pub fn pause_stream(&self) {
446 unsafe { ffi::PauseMusicStream(self.0) }
447 }
448
449 #[inline]
451 pub fn resume_stream(&self) {
452 unsafe { ffi::ResumeMusicStream(self.0) }
453 }
454
455 #[inline]
457 pub fn is_stream_playing(&self) -> bool {
458 unsafe { ffi::IsMusicStreamPlaying(self.0) }
459 }
460
461 #[inline]
463 pub fn set_volume(&self, volume: f32) {
464 unsafe { ffi::SetMusicVolume(self.0, volume) }
465 }
466
467 #[inline]
469 pub fn set_pitch(&self, pitch: f32) {
470 unsafe { ffi::SetMusicPitch(self.0, pitch) }
471 }
472
473 #[inline]
475 pub fn get_time_length(&self) -> f32 {
476 unsafe { ffi::GetMusicTimeLength(self.0) }
477 }
478
479 #[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 #[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 #[inline]
535 pub fn play(&self) {
536 unsafe {
537 ffi::PlayAudioStream(self.0);
538 }
539 }
540
541 #[inline]
543 pub fn pause(&self) {
544 unsafe {
545 ffi::PauseAudioStream(self.0);
546 }
547 }
548
549 #[inline]
551 pub fn resume(&self) {
552 unsafe {
553 ffi::ResumeAudioStream(self.0);
554 }
555 }
556
557 #[inline]
559 pub fn is_playing(&self) -> bool {
560 unsafe { ffi::IsAudioStreamPlaying(self.0) }
561 }
562
563 #[inline]
565 pub fn stop(&self) {
566 unsafe {
567 ffi::StopAudioStream(self.0);
568 }
569 }
570
571 #[inline]
573 pub fn set_volume(&self, volume: f32) {
574 unsafe {
575 ffi::SetAudioStreamVolume(self.0, volume);
576 }
577 }
578
579 #[inline]
581 pub fn set_pitch(&self, pitch: f32) {
582 unsafe {
583 ffi::SetAudioStreamPitch(self.0, pitch);
584 }
585 }
586
587 #[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>>);