1use alloc::boxed::Box;
4use core::ffi::c_char;
5use core::ffi::c_float;
6use core::ffi::c_int;
7use core::ops::Deref;
8use sys::ffi::CString;
9use sys::ffi::AudioSample;
10use fs::Path;
11use sys::ffi::SoundFormat;
12
13use crate::error::ApiError;
14use crate::error::Error;
15
16
17#[cfg_attr(feature = "bindings-derive-debug", derive(Debug))]
18pub struct Sample<Api: api::Api = api::Default>(pub(super) *mut AudioSample, Api);
19
20
21impl<Api: api::Api> Drop for Sample<Api> {
22 fn drop(&mut self) {
23 if !self.0.is_null() {
24 let f = self.1.free_sample();
25 unsafe { f(self.0) };
26 self.0 = core::ptr::null_mut();
27 }
28 }
29}
30
31
32impl<Api: Default + api::Api> Sample<Api> {
33 #[doc(alias = "sys::ffi::playdate_sound_sample::newSampleBuffer")]
37 #[inline(always)]
38 pub fn new_with_size(bytes: c_int) -> Result<Self, Error> {
39 let api: Api = Default::default();
40 Self::new_with_size_with(api, bytes)
41 }
42
43 #[inline(always)]
49 pub fn new_for_file<P: AsRef<Path>>(path: P) -> Result<Self, ApiError> {
50 let api: Api = Default::default();
51 Self::new_for_file_with(api, path).map_err(Into::into)
52 }
53
54 #[doc(alias = "sys::ffi::playdate_sound_sample::load")]
58 #[inline(always)]
59 pub fn new_from_file<P: AsRef<Path>>(path: P) -> Result<Self, ApiError> {
60 let api: Api = Default::default();
61 Self::new_from_file_with(api, path)
62 }
63
64
65 #[doc(alias = "sys::ffi::playdate_sound_sample::newSampleFromData")]
72 pub fn new_from_data<'t>(data: &'t mut [u8],
73 format: SoundFormat,
74 sample_rate: u32)
75 -> Result<SampleWithData<'t, Api>, Error> {
76 let api: Api = Default::default();
77 Self::new_from_data_with(api, data, format, sample_rate)
78 }
79}
80
81
82impl<Api: api::Api> Sample<Api> {
83 #[doc(alias = "sys::ffi::playdate_sound_sample::newSampleBuffer")]
87 pub fn new_with_size_with(api: Api, bytes: c_int) -> Result<Self, Error> {
88 let f = api.new_sample_buffer();
89 let ptr = unsafe { f(bytes) };
90 if ptr.is_null() {
91 Err(Error::Alloc)
92 } else {
93 Ok(Self(ptr, api))
94 }
95 }
96
97 pub fn new_for_file_with<P: AsRef<Path>>(api: Api, path: P) -> Result<Self, ApiError> {
103 let size = match fs::metadata(path) {
104 Ok(stats) => stats.size,
105 Err(err) => return Err(ApiError::from_err(err)),
106 };
107
108 Self::new_with_size_with(api, size as _).map_err(Into::into)
109 }
110
111 #[doc(alias = "sys::ffi::playdate_sound_sample::load")]
115 pub fn new_from_file_with<P: AsRef<Path>>(api: Api, path: P) -> Result<Self, ApiError> {
116 let path_cs = CString::new(path.as_ref())?;
117 let path_ptr = path_cs.as_ptr() as *mut c_char;
118
119 let f = api.load();
120
121 let ptr = unsafe { f(path_ptr) };
122 if ptr.is_null() {
123 Err(crate::error::Error::Alloc.into())
124 } else {
125 Ok(Self(ptr, api))
126 }
127 }
128
129
130 #[doc(alias = "sys::ffi::playdate_sound_sample::newSampleFromData")]
137 pub fn new_from_data_with<'t>(api: Api,
138 data: &'t mut [u8],
139 format: SoundFormat,
140 sample_rate: u32)
141 -> Result<SampleWithData<'t, Api>, Error> {
142 let f = api.new_sample_from_data();
143 let ptr = unsafe { f(data.as_mut_ptr(), format, sample_rate, data.len() as _, 0) };
144
145 if ptr.is_null() {
146 Err(Error::Alloc)
147 } else {
148 Ok(SampleWithData(Self(ptr, api), data))
149 }
150 }
151}
152
153
154impl<Api: api::Api> Sample<Api> {
155 #[doc(alias = "sys::ffi::playdate_sound_sample::getLength")]
159 pub fn length(&self) -> c_float {
160 if self.0.is_null() {
161 0.0
162 } else {
163 let f = self.1.get_length();
164 unsafe { f(self.0) }
165 }
166 }
167
168 #[doc(alias = "sys::ffi::playdate_sound_sample::getData")]
170 pub fn get_data<'t>(&'t self) -> SampleData<'t> {
171 let mut format: SoundFormat = SoundFormat::kSound8bitMono;
172 let mut sample_rate: u32 = 0;
173 let mut byte_length: u32 = 0;
174
175 let mut boxed_data = Box::new(core::ptr::null_mut());
176 let data = Box::into_raw(boxed_data);
177
178 let f = self.1.get_data();
179 unsafe { f(self.0, data, &mut format, &mut sample_rate, &mut byte_length) };
180
181 boxed_data = unsafe { Box::from_raw(data) };
182 let data = unsafe { core::slice::from_raw_parts_mut::<u8>(*boxed_data, byte_length as usize) };
183
184 SampleData { data, sample_rate }
185 }
186}
187
188
189#[cfg_attr(feature = "bindings-derive-debug", derive(Debug))]
191pub struct SampleWithData<'t, Api: api::Api>(Sample<Api>, #[allow(dead_code)] &'t mut [u8]);
192
193impl<Api: api::Api> Deref for SampleWithData<'_, Api> {
194 type Target = Sample<Api>;
195 fn deref(&self) -> &Self::Target { &self.0 }
196}
197
198impl<Api: api::Api> AsRef<Sample<Api>> for SampleWithData<'_, Api> {
199 fn as_ref(&self) -> &Sample<Api> { &self.0 }
200}
201
202
203pub struct SampleData<'t> {
204 pub sample_rate: u32,
205 pub data: &'t mut [u8],
206}
207
208
209pub mod api {
210 use core::ffi::c_int;
211 use core::ffi::c_char;
212 use core::ffi::c_float;
213 use core::ptr::NonNull;
214 use sys::ffi::AudioSample;
215 use sys::ffi::SoundFormat;
216 use sys::ffi::playdate_sound_sample;
217
218
219 #[derive(Debug, Clone, Copy, core::default::Default)]
223 pub struct Default;
224 impl Api for Default {}
225
226
227 #[derive(Clone, Copy)]
233 #[cfg_attr(feature = "bindings-derive-debug", derive(Debug))]
234 pub struct Cache(&'static playdate_sound_sample);
235
236 impl core::default::Default for Cache {
237 fn default() -> Self { Self(sys::api!(sound.sample)) }
238 }
239
240 impl From<*const playdate_sound_sample> for Cache {
241 #[inline(always)]
242 fn from(ptr: *const playdate_sound_sample) -> Self { Self(unsafe { ptr.as_ref() }.expect("sample")) }
243 }
244
245 impl From<&'static playdate_sound_sample> for Cache {
246 #[inline(always)]
247 fn from(r: &'static playdate_sound_sample) -> Self { Self(r) }
248 }
249
250 impl From<NonNull<playdate_sound_sample>> for Cache {
251 #[inline(always)]
252 fn from(ptr: NonNull<playdate_sound_sample>) -> Self { Self(unsafe { ptr.as_ref() }) }
253 }
254
255 impl From<&'_ NonNull<playdate_sound_sample>> for Cache {
256 #[inline(always)]
257 fn from(ptr: &NonNull<playdate_sound_sample>) -> Self { Self(unsafe { ptr.as_ref() }) }
258 }
259
260
261 impl Api for Cache {
262 fn new_sample_buffer(&self) -> unsafe extern "C" fn(byteCount: c_int) -> *mut AudioSample {
263 self.0.newSampleBuffer.expect("newSampleBuffer")
264 }
265
266 fn load_into_sample(&self) -> unsafe extern "C" fn(sample: *mut AudioSample, path: *const c_char) -> c_int {
267 self.0.loadIntoSample.expect("loadIntoSample")
268 }
269
270 fn load(&self) -> unsafe extern "C" fn(path: *const c_char) -> *mut AudioSample {
271 self.0.load.expect("load")
272 }
273
274 fn new_sample_from_data(
275 &self)
276 -> unsafe extern "C" fn(data: *mut u8,
277 format: SoundFormat,
278 sampleRate: u32,
279 byteCount: c_int,
280 shouldFreeData: c_int) -> *mut AudioSample {
281 self.0.newSampleFromData.expect("newSampleFromData")
282 }
283
284 fn get_data(
285 &self)
286 -> unsafe extern "C" fn(sample: *mut AudioSample,
287 data: *mut *mut u8,
288 format: *mut SoundFormat,
289 sampleRate: *mut u32,
290 bytelength: *mut u32) {
291 self.0.getData.expect("getData")
292 }
293
294 fn free_sample(&self) -> unsafe extern "C" fn(sample: *mut AudioSample) {
295 self.0.freeSample.expect("freeSample")
296 }
297
298 fn get_length(&self) -> unsafe extern "C" fn(sample: *mut AudioSample) -> c_float {
299 self.0.getLength.expect("getLength")
300 }
301 }
302
303
304 pub trait Api {
305 #[doc(alias = "sys::ffi::playdate_sound_sample::newSampleBuffer")]
307 fn new_sample_buffer(&self) -> unsafe extern "C" fn(byteCount: c_int) -> *mut AudioSample {
308 *sys::api!(sound.sample.newSampleBuffer)
309 }
310
311
312 #[doc(alias = "sys::ffi::playdate_sound_sample::loadIntoSample")]
314 fn load_into_sample(&self) -> unsafe extern "C" fn(sample: *mut AudioSample, path: *const c_char) -> c_int {
315 *sys::api!(sound.sample.loadIntoSample)
316 }
317
318
319 #[doc(alias = "sys::ffi::playdate_sound_sample::load")]
321 fn load(&self) -> unsafe extern "C" fn(path: *const c_char) -> *mut AudioSample {
322 *sys::api!(sound.sample.load)
323 }
324
325
326 #[doc(alias = "sys::ffi::playdate_sound_sample::newSampleFromData")]
328 fn new_sample_from_data(
329 &self)
330 -> unsafe extern "C" fn(data: *mut u8,
331 format: SoundFormat,
332 sampleRate: u32,
333 byteCount: c_int,
334 shouldFreeData: c_int) -> *mut AudioSample {
335 *sys::api!(sound.sample.newSampleFromData)
336 }
337
338 #[doc(alias = "sys::ffi::playdate_sound_sample::getData")]
340 fn get_data(
341 &self)
342 -> unsafe extern "C" fn(sample: *mut AudioSample,
343 data: *mut *mut u8,
344 format: *mut SoundFormat,
345 sampleRate: *mut u32,
346 bytelength: *mut u32) {
347 *sys::api!(sound.sample.getData)
348 }
349
350 #[doc(alias = "sys::ffi::playdate_sound_sample::freeSample")]
352 fn free_sample(&self) -> unsafe extern "C" fn(sample: *mut AudioSample) {
353 *sys::api!(sound.sample.freeSample)
354 }
355
356 #[doc(alias = "sys::ffi::playdate_sound_sample::getLength")]
358 fn get_length(&self) -> unsafe extern "C" fn(sample: *mut AudioSample) -> c_float {
359 *sys::api!(sound.sample.getLength)
360 }
361 }
362}