1#![allow(unused, non_snake_case, non_camel_case_types)]
2use std::ffi::{CString, OsStr};
3use std::os::raw::*;
4use std::time::{Duration, Instant};
5use std::{thread, path::Path};
6use std::marker::PhantomData;
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 {
81 IsWaveReady(self.clone())
82 }
83 }
84
85 pub fn export(&self, file_name: impl AsRef<Path>) {
86 let file = CString::new(file_name.as_ref().to_str().unwrap()).unwrap();
87 unsafe {
88 ExportWave(self.clone(), file.as_ptr());
89 }
90 }
91
92 pub fn crop(&mut self, init_sample: i32, final_sample: i32) {
93 unsafe {
94 WaveCrop(self as *mut Wave, init_sample as c_int, final_sample as c_int);
95 }
96 }
97
98 pub fn format(&mut self, sample_rate: i32, sample_size: i32, channels: i32) {
99 unsafe {
100 WaveFormat(self as *mut Wave, sample_rate as c_int, sample_size as c_int, channels as c_int);
101 }
102 }
103}
104
105impl Drop for Wave {
106 fn drop(&mut self) {
107 unsafe {
108 UnloadWave(self.clone());
109 }
110 }
111}
112
113impl Default for AudioDevice {
114 fn default() -> Self {
115 Self::new()
116 }
117}
118
119impl AudioDevice {
120 const FPS: u64 = 60;
121 const FRAME_DURATION: Duration = Duration::from_millis(1000 / Self::FPS);
122
123 pub fn new() -> Self {
124 unsafe {
125 InitAudioDevice();
126 }
127 AudioDevice {last_frame_time: Instant::now()}
128 }
129
130 pub fn is_ready(&self) -> bool {
131 unsafe {
132 IsAudioDeviceReady()
133 }
134 }
135
136 pub fn sync(&mut self) {
137 let now = Instant::now();
138 let elapsed = now.duration_since(self.last_frame_time);
139
140 if elapsed < Self::FRAME_DURATION {
141 thread::sleep(Self::FRAME_DURATION - elapsed);
142 }
143
144 self.last_frame_time = Instant::now();
145 }
146
147 pub fn set_master_volume(&self, volume: f32) {
148 unsafe {
149 SetMasterVolume(volume as c_float);
150 }
151 }
152
153 pub fn get_master_volume(&self) -> f32 {
154 let volume = unsafe {
155 GetMasterVolume()
156 };
157 volume as f32
158 }
159}
160
161impl Drop for AudioDevice {
162 fn drop(&mut self) {
163 unsafe {
164 CloseAudioDevice();
165 }
166 }
167}
168
169impl Sound {
170 pub fn load(path: impl AsRef<Path>) -> Self {
171 let path = path.as_ref();
172 if !path.exists() {
173 panic!("File doesn't exist.");
174 }
175
176 match path.extension().and_then(OsStr::to_str).unwrap() {
177 "wav" | "qoa" | "ogg" | "mp3" | "flac" => {
178 let file = CString::new(path.to_str().unwrap()).unwrap();
179 unsafe { LoadSound(file.as_ptr()) }
180 },
181 _ => panic!("Unsupported file format")
182 }
183 }
184
185 pub fn load_from_wave(wave: &Wave) -> Self {
186 unsafe {
187 LoadSoundFromWave(wave.clone())
188 }
189 }
190
191 pub fn is_ready(&self) -> bool {
192 unsafe {
193 IsSoundReady(self.clone())
194 }
195 }
196
197 pub fn play(&self) {
198 unsafe { PlaySound(self.clone()); }
199 }
200
201 pub fn stop(&self) {
202 unsafe { StopSound(self.clone()); }
203 }
204
205 pub fn pause(&self) {
206 unsafe { PauseSound(self.clone()); }
207 }
208
209 pub fn resume(&self) {
210 unsafe { ResumeSound(self.clone()); }
211 }
212
213 pub fn is_playing(&self) -> bool {
214 unsafe { IsSoundPlaying(self.clone()) }
215 }
216
217 pub fn set_voume(&self, volume: f32) {
218 unsafe { SetSoundVolume(self.clone(), volume as c_float); }
219 }
220
221 pub fn set_pitch(&self, pitch: f32) {
222 unsafe { SetSoundPitch(self.clone(), pitch as c_float); }
223 }
224
225 pub fn set_pan(&self, pan: f32) {
226 unsafe { SetSoundPan(self.clone(), pan as c_float); }
227 }
228}
229
230impl Drop for Sound {
231 fn drop(&mut self) {
232 unsafe {
233 UnloadSound(self.clone());
234 }
235 }
236}
237
238impl Music {
239 pub fn load(path: impl AsRef<Path>) -> Self {
240 let path = path.as_ref();
241 if !path.exists() {
242 panic!("File doesn't exist.");
243 }
244
245 match path.extension().and_then(OsStr::to_str).unwrap() {
246 "wav" | "qoa" | "ogg" | "mp3" | "flac" | "xm" => {
247 let file = CString::new(path.to_str().unwrap()).unwrap();
248 unsafe { LoadMusicStream(file.as_ptr()) }
249 },
250 _ => panic!("Unsupported file format")
251 }
252 }
253
254 pub fn is_ready(&self) -> bool {
255 unsafe {
256 IsMusicReady(self.clone())
257 }
258 }
259
260 pub fn play(&self) {
261 unsafe { PlayMusicStream(self.clone()); }
262 }
263
264 pub fn is_playing(&self) -> bool {
265 unsafe {IsMusicStreamPlaying(self.clone())}
266 }
267
268 pub fn update(&self) {
269 unsafe {UpdateMusicStream(self.clone());}
270 }
271
272 pub fn stop(&self) {
273 unsafe {StopMusicStream(self.clone());}
274 }
275
276 pub fn pause(&self) {
277 unsafe {PauseMusicStream(self.clone());}
278 }
279
280 pub fn resume(&self) {
281 unsafe {ResumeMusicStream(self.clone());}
282 }
283
284 pub fn seek(&self, position: f32) {
285 unsafe {SeekMusicStream(self.clone(), position as c_float);}
286 }
287
288 pub fn set_volume(&self, volume: f32) {
289 unsafe {SetMusicVolume(self.clone(), volume as c_float);}
290 }
291
292 pub fn set_pitch(&self, pitch: f32) {
293 unsafe { SetMusicPitch(self.clone(), pitch as c_float); }
294 }
295
296 pub fn set_pan(&self, pan: f32) {
297 unsafe { SetMusicPan(self.clone(), pan as c_float); }
298 }
299
300 pub fn duration(&self) -> Duration {
301 let dur = unsafe {
302 GetMusicTimeLength(self.clone())
303 };
304 Duration::from_secs_f32(dur as f32)
305 }
306
307 pub fn time_played(&self) -> Duration {
308 let dur = unsafe {
309 GetMusicTimePlayed(self.clone())
310 };
311 Duration::from_secs_f32(dur as f32)
312 }
313}
314
315impl Drop for Music {
316 fn drop(&mut self) {
317 unsafe {
318 UnloadMusicStream(self.clone());
319 }
320 }
321}
322
323#[no_mangle]
324#[link(name = "audio")]
325extern "C" {
326 fn InitAudioDevice();
327 fn CloseAudioDevice();
328 fn IsAudioDeviceReady() -> bool;
329 fn SetMasterVolume(volume: c_float);
330 fn GetMasterVolume() -> c_float;
331
332 fn LoadWave(fileName: *const c_char) -> Wave;
333 fn IsWaveReady(wave: Wave) -> bool;
334 fn LoadSound(fileName: *const c_char) -> Sound;
335 fn LoadSoundFromWave(wave: Wave) -> Sound;
336 fn IsSoundReady(sound: Sound) -> bool;
337 fn UnloadWave(wave: Wave);
338 fn UnloadSound(sound: Sound);
339 fn ExportWave(wave: Wave, fileName: *const c_char) -> bool;
340
341 fn PlaySound(sound: Sound);
342 fn StopSound(sound: Sound);
343 fn PauseSound(sound: Sound);
344 fn ResumeSound(sound: Sound);
345 fn IsSoundPlaying(sound: Sound) -> bool;
346 fn SetSoundVolume(sound: Sound, volume: c_float);
347 fn SetSoundPitch(sound: Sound, pitch: c_float);
348 fn SetSoundPan(sound: Sound, pan: c_float);
349 fn WaveCrop(wave: *mut Wave, initSample: c_int, finalSample: c_int);
350 fn WaveFormat(wave: *mut Wave, sampleRate: c_int, sampleSize: c_int, channels: c_int);
351
352 fn LoadMusicStream(fileName: *const c_char) -> Music;
353 fn IsMusicReady(music: Music) -> bool;
354 fn UnloadMusicStream(music: Music);
355 fn PlayMusicStream(music: Music);
356 fn IsMusicStreamPlaying(music: Music) -> bool;
357 fn UpdateMusicStream(music: Music);
358 fn StopMusicStream(music: Music);
359 fn PauseMusicStream(music: Music);
360 fn ResumeMusicStream(music: Music);
361 fn SeekMusicStream(music: Music, position: c_float);
362 fn SetMusicVolume(music: Music, volume: c_float);
363 fn SetMusicPitch(music: Music, pitch: c_float);
364 fn SetMusicPan(music: Music, pan: c_float);
365 fn GetMusicTimeLength(music: Music) -> c_float;
366 fn GetMusicTimePlayed(music: Music) -> c_float;
367}