1#![allow(unused, non_snake_case, non_camel_case_types)]
2use std::ffi::{CString, OsStr};
3use std::marker::PhantomData;
4use std::os::raw::*;
5use std::time::{Duration, Instant};
6use std::{path::Path, thread};
7
8#[repr(C)]
9#[derive(Clone, Debug)]
10pub struct Wave {
11 pub frame_count: c_uint,
12 pub sample_rate: c_uint,
13 pub sample_size: c_uint,
14 pub channels: c_uint,
15 data: *mut c_void,
16}
17
18#[derive(Debug)]
19pub struct AudioDevice {
20 last_frame_time: Instant,
21}
22
23#[repr(C)]
25pub struct rAudioBuffer {
26 _data: [u8; 0],
27 _marker: PhantomData<(*mut u8, core::marker::PhantomPinned)>,
28}
29
30#[repr(C)]
31struct rAudioProcessor {
32 _data: [u8; 0],
33 _marker: PhantomData<(*mut u8, core::marker::PhantomPinned)>,
34}
35
36#[repr(C)]
37#[derive(Clone, Debug)]
38pub struct AudioStream {
39 buffer: *mut rAudioBuffer,
40 processor: *mut rAudioProcessor,
41 pub sample_rate: c_uint,
42 pub sample_size: c_uint,
43 pub channels: c_uint,
44}
45
46#[repr(C)]
47#[derive(Clone, Debug)]
48pub struct Sound {
49 pub stream: AudioStream,
50 pub frame_count: c_uint,
51}
52
53#[repr(C)]
54#[derive(Clone, Debug)]
55pub struct Music {
56 pub stream: AudioStream,
57 pub frame_count: c_uint,
58 looping: bool,
59 ctx_type: c_int,
60 ctx_data: *mut c_void,
61}
62
63impl Wave {
64 pub fn load(path: impl AsRef<Path>) -> Self {
65 let path = path.as_ref();
66 if !path.exists() {
67 panic!("File doesn't exist.");
68 }
69
70 match path.extension().and_then(OsStr::to_str).unwrap() {
71 "wav" => {
72 let file = CString::new(path.to_str().unwrap()).unwrap();
73 unsafe { LoadWave(file.as_ptr()) }
74 }
75 _ => panic!("Unsupported file format"),
76 }
77 }
78
79 pub fn is_ready(&self) -> bool {
80 unsafe { IsWaveReady(self.clone()) }
81 }
82
83 pub fn export(&self, file_name: impl AsRef<Path>) {
84 let file = CString::new(file_name.as_ref().to_str().unwrap()).unwrap();
85 unsafe {
86 ExportWave(self.clone(), file.as_ptr());
87 }
88 }
89
90 pub fn crop(&mut self, init_sample: i32, final_sample: i32) {
91 unsafe {
92 WaveCrop(
93 self as *mut Wave,
94 init_sample as c_int,
95 final_sample as c_int,
96 );
97 }
98 }
99
100 pub fn format(&mut self, sample_rate: i32, sample_size: i32, channels: i32) {
101 unsafe {
102 WaveFormat(
103 self as *mut Wave,
104 sample_rate as c_int,
105 sample_size as c_int,
106 channels as c_int,
107 );
108 }
109 }
110}
111
112impl Drop for Wave {
113 fn drop(&mut self) {
114 unsafe {
115 UnloadWave(self.clone());
116 }
117 }
118}
119
120impl Default for AudioDevice {
121 fn default() -> Self {
122 Self::new()
123 }
124}
125
126impl AudioDevice {
127 const FPS: u64 = 60;
128 const FRAME_DURATION: Duration = Duration::from_millis(1000 / Self::FPS);
129
130 pub fn new() -> Self {
131 unsafe {
132 InitAudioDevice();
133 }
134 AudioDevice {
135 last_frame_time: Instant::now(),
136 }
137 }
138
139 pub fn is_ready(&self) -> bool {
140 unsafe { IsAudioDeviceReady() }
141 }
142
143 pub fn sync(&mut self) {
144 let now = Instant::now();
145 let elapsed = now.duration_since(self.last_frame_time);
146
147 if elapsed < Self::FRAME_DURATION {
148 thread::sleep(Self::FRAME_DURATION - elapsed);
149 }
150
151 self.last_frame_time = Instant::now();
152 }
153
154 pub fn set_master_volume(&self, volume: f32) {
155 unsafe {
156 SetMasterVolume(volume as c_float);
157 }
158 }
159
160 pub fn get_master_volume(&self) -> f32 {
161 let volume = unsafe { GetMasterVolume() };
162 volume as f32
163 }
164}
165
166impl Drop for AudioDevice {
167 fn drop(&mut self) {
168 unsafe {
169 CloseAudioDevice();
170 }
171 }
172}
173
174impl Sound {
175 pub fn load(path: impl AsRef<Path>) -> Self {
176 let path = path.as_ref();
177 if !path.exists() {
178 panic!("File doesn't exist.");
179 }
180
181 match path.extension().and_then(OsStr::to_str).unwrap() {
182 "wav" | "qoa" | "ogg" | "mp3" | "flac" => {
183 let file = CString::new(path.to_str().unwrap()).unwrap();
184 unsafe { LoadSound(file.as_ptr()) }
185 }
186 _ => panic!("Unsupported file format"),
187 }
188 }
189
190 pub fn load_from_wave(wave: &Wave) -> Self {
191 unsafe { LoadSoundFromWave(wave.clone()) }
192 }
193
194 pub fn is_ready(&self) -> bool {
195 unsafe { IsSoundReady(self.clone()) }
196 }
197
198 pub fn play(&self) {
199 unsafe {
200 PlaySound(self.clone());
201 }
202 }
203
204 pub fn stop(&self) {
205 unsafe {
206 StopSound(self.clone());
207 }
208 }
209
210 pub fn pause(&self) {
211 unsafe {
212 PauseSound(self.clone());
213 }
214 }
215
216 pub fn resume(&self) {
217 unsafe {
218 ResumeSound(self.clone());
219 }
220 }
221
222 pub fn is_playing(&self) -> bool {
223 unsafe { IsSoundPlaying(self.clone()) }
224 }
225
226 pub fn set_volume(&self, volume: f32) {
227 unsafe {
228 SetSoundVolume(self.clone(), volume as c_float);
229 }
230 }
231
232 pub fn set_pitch(&self, pitch: f32) {
233 unsafe {
234 SetSoundPitch(self.clone(), pitch as c_float);
235 }
236 }
237
238 pub fn set_pan(&self, pan: f32) {
239 unsafe {
240 SetSoundPan(self.clone(), pan as c_float);
241 }
242 }
243}
244
245impl Drop for Sound {
246 fn drop(&mut self) {
247 unsafe {
248 UnloadSound(self.clone());
249 }
250 }
251}
252
253impl Music {
254 pub fn load(path: impl AsRef<Path>) -> Self {
255 let path = path.as_ref();
256 if !path.exists() {
257 panic!("File doesn't exist.");
258 }
259
260 match path.extension().and_then(OsStr::to_str).unwrap() {
261 "wav" | "qoa" | "ogg" | "mp3" | "flac" | "xm" => {
262 let file = CString::new(path.to_str().unwrap()).unwrap();
263 unsafe { LoadMusicStream(file.as_ptr()) }
264 }
265 _ => panic!("Unsupported file format"),
266 }
267 }
268
269 pub fn is_ready(&self) -> bool {
270 unsafe { IsMusicReady(self.clone()) }
271 }
272
273 pub fn play(&self) {
274 unsafe {
275 PlayMusicStream(self.clone());
276 }
277 }
278
279 pub fn is_playing(&self) -> bool {
280 unsafe { IsMusicStreamPlaying(self.clone()) }
281 }
282
283 pub fn update(&self) {
284 unsafe {
285 UpdateMusicStream(self.clone());
286 }
287 }
288
289 pub fn stop(&self) {
290 unsafe {
291 StopMusicStream(self.clone());
292 }
293 }
294
295 pub fn pause(&self) {
296 unsafe {
297 PauseMusicStream(self.clone());
298 }
299 }
300
301 pub fn resume(&self) {
302 unsafe {
303 ResumeMusicStream(self.clone());
304 }
305 }
306
307 pub fn seek(&self, position: f32) {
308 unsafe {
309 SeekMusicStream(self.clone(), position as c_float);
310 }
311 }
312
313 pub fn set_volume(&self, volume: f32) {
314 unsafe {
315 SetMusicVolume(self.clone(), volume as c_float);
316 }
317 }
318
319 pub fn set_pitch(&self, pitch: f32) {
320 unsafe {
321 SetMusicPitch(self.clone(), pitch as c_float);
322 }
323 }
324
325 pub fn set_pan(&self, pan: f32) {
326 unsafe {
327 SetMusicPan(self.clone(), pan as c_float);
328 }
329 }
330
331 pub fn duration(&self) -> Duration {
332 let dur = unsafe { GetMusicTimeLength(self.clone()) };
333 Duration::from_secs_f32(dur as f32)
334 }
335
336 pub fn time_played(&self) -> Duration {
337 let dur = unsafe { GetMusicTimePlayed(self.clone()) };
338 Duration::from_secs_f32(dur as f32)
339 }
340}
341
342impl Drop for Music {
343 fn drop(&mut self) {
344 unsafe {
345 UnloadMusicStream(self.clone());
346 }
347 }
348}
349
350unsafe extern "C" {
351 fn InitAudioDevice();
352 fn CloseAudioDevice();
353 fn IsAudioDeviceReady() -> bool;
354 fn SetMasterVolume(volume: c_float);
355 fn GetMasterVolume() -> c_float;
356
357 fn LoadWave(fileName: *const c_char) -> Wave;
358 fn IsWaveReady(wave: Wave) -> bool;
359 fn LoadSound(fileName: *const c_char) -> Sound;
360 fn LoadSoundFromWave(wave: Wave) -> Sound;
361 fn IsSoundReady(sound: Sound) -> bool;
362 fn UnloadWave(wave: Wave);
363 fn UnloadSound(sound: Sound);
364 fn ExportWave(wave: Wave, fileName: *const c_char) -> bool;
365
366 fn PlaySound(sound: Sound);
367 fn StopSound(sound: Sound);
368 fn PauseSound(sound: Sound);
369 fn ResumeSound(sound: Sound);
370 fn IsSoundPlaying(sound: Sound) -> bool;
371 fn SetSoundVolume(sound: Sound, volume: c_float);
372 fn SetSoundPitch(sound: Sound, pitch: c_float);
373 fn SetSoundPan(sound: Sound, pan: c_float);
374 fn WaveCrop(wave: *mut Wave, initSample: c_int, finalSample: c_int);
375 fn WaveFormat(wave: *mut Wave, sampleRate: c_int, sampleSize: c_int, channels: c_int);
376
377 fn LoadMusicStream(fileName: *const c_char) -> Music;
378 fn IsMusicReady(music: Music) -> bool;
379 fn UnloadMusicStream(music: Music);
380 fn PlayMusicStream(music: Music);
381 fn IsMusicStreamPlaying(music: Music) -> bool;
382 fn UpdateMusicStream(music: Music);
383 fn StopMusicStream(music: Music);
384 fn PauseMusicStream(music: Music);
385 fn ResumeMusicStream(music: Music);
386 fn SeekMusicStream(music: Music, position: c_float);
387 fn SetMusicVolume(music: Music, volume: c_float);
388 fn SetMusicPitch(music: Music, pitch: c_float);
389 fn SetMusicPan(music: Music, pan: c_float);
390 fn GetMusicTimeLength(music: Music) -> c_float;
391 fn GetMusicTimePlayed(music: Music) -> c_float;
392}