synthizer/
buffer.rs

1use std::io::{Read, Seek};
2use std::os::raw::{c_char, c_longlong, c_uint, c_ulonglong};
3use std::path::Path;
4
5use crate::internal_prelude::*;
6use crate::*;
7
8#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)]
9pub struct Buffer(pub(crate) Handle);
10
11impl Buffer {
12    pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Buffer> {
13        let path = path.as_ref();
14        let u_str = path
15            .to_str()
16            .ok_or_else(|| Error::rust_error("Path is not valid utf8"))?;
17        let c_str = std::ffi::CString::new(u_str)
18            .map_err(|_| Error::rust_error("Path contains a NULL byte"))?;
19
20        wrap_constructor(|ud, cb| {
21            let mut h = Default::default();
22            check_error(unsafe {
23                syz_createBufferFromFile(&mut h as *mut syz_Handle, c_str.as_ptr(), ud, Some(cb))
24            })?;
25            Ok(Buffer(Handle::new(h)))
26        })
27    }
28
29    pub fn from_encoded_data(data: &[u8]) -> Result<Buffer> {
30        let mut h = Default::default();
31        check_error(unsafe {
32            syz_createBufferFromEncodedData(
33                &mut h as *mut syz_Handle,
34                data.len() as c_ulonglong,
35                &data[0] as *const u8 as *const i8,
36                std::ptr::null_mut(),
37                None,
38            )
39        })?;
40        Ok(Buffer(Handle::new(h)))
41    }
42
43    pub fn from_float_array(sr: c_uint, channels: c_uint, data: &[f32]) -> Result<Buffer> {
44        if data.is_empty() {
45            return Err(Error::rust_error(
46                "Cannot create a buffer from an empty array",
47            ));
48        }
49        if channels == 0 {
50            return Err(Error::rust_error("channels may not be 0"));
51        }
52        if data.len() % channels as usize != 0 {
53            return Err(Error::rust_error(
54                "Length of data must be a multiple of the channel count",
55            ));
56        }
57
58        let mut h = Default::default();
59        check_error(unsafe {
60            syz_createBufferFromFloatArray(
61                &mut h as *mut syz_Handle,
62                sr,
63                channels,
64                data.len() as c_ulonglong / channels as c_ulonglong,
65                &data[0] as *const f32,
66                std::ptr::null_mut(),
67                None,
68            )
69        })?;
70        Ok(Buffer(Handle::new(h)))
71    }
72
73    pub fn from_stream_handle(&self, handle: StreamHandle) -> Result<Buffer> {
74        let mut h = Default::default();
75        check_error(unsafe {
76            syz_createBufferFromStreamHandle(
77                &mut h as *mut syz_Handle,
78                handle.get_handle(),
79                std::ptr::null_mut(),
80                None,
81            )
82        })?;
83        // No need to link: buffers consume the stream entirely in the calling thread.
84        Ok(Buffer(Handle::new(h)))
85    }
86
87    pub fn from_stream_params(protocol: &str, path: &str, param: usize) -> Result<Buffer> {
88        // The below transmute uses the fact that `usize` is the size of a
89        // pointer on all common platforms.
90        let mut h = Default::default();
91        let protocol_c = std::ffi::CString::new(protocol)
92            .map_err(|_| Error::rust_error("Unable to convert protocol to a C string"))?;
93        let path_c = std::ffi::CString::new(path)
94            .map_err(|_| Error::rust_error("Unable to convert path to a C string"))?;
95        let protocol_ptr = protocol_c.as_ptr();
96        let path_ptr = path_c.as_ptr();
97        check_error(unsafe {
98            syz_createBufferFromStreamParams(
99                &mut h as *mut syz_Handle,
100                protocol_ptr as *const c_char,
101                path_ptr as *const c_char,
102                std::mem::transmute(param),
103                std::ptr::null_mut(),
104                None,
105            )
106        })?;
107        Ok(Buffer(Handle::new(h)))
108    }
109
110    /// Decode a buffer from a `Read + Seek` implementation.
111    ///
112    /// This avoids the Sync and 'static requirements on going through a stream
113    /// handle.
114    ///
115    /// We require `Seek` as well because there are some formats that Synthizer
116    /// can't decode without it, most notably wav.
117    pub fn from_read_seek<R: Read + Seek>(mut reader: R) -> Result<Buffer> {
118        let size = reader
119            .seek(std::io::SeekFrom::End(0))
120            .and_then(|_| reader.stream_position())
121            .and_then(|_| reader.seek(std::io::SeekFrom::Start(0)))
122            .map_err(|x| Error::rust_error(&format!("{}", x)))?;
123
124        let cdata = CustomStreamData {
125            err_msg: Default::default(),
126            stream: reader,
127        };
128
129        let mut boxed = Box::new(cdata);
130
131        let mut sdef = syz_CustomStreamDef {
132            read_cb: Some(stream_read_cb::<R>),
133            seek_cb: Some(stream_seek_cb::<R>),
134            length: size as c_longlong,
135            userdata: &mut *boxed as *mut CustomStreamData<R> as *mut std::ffi::c_void,
136            ..Default::default()
137        };
138
139        let mut sh = 0;
140        check_error(unsafe {
141            syz_createStreamHandleFromCustomStream(
142                &mut sh as *mut syz_Handle,
143                &mut sdef as *mut syz_CustomStreamDef,
144                null_mut(),
145                None,
146            )
147        })?;
148        // Immediately put this behind a handle that doesn't escape this
149        // function, which ensures that we always drop it when we go out of
150        // scope.
151        let sh = Handle::new(sh);
152
153        wrap_constructor(|ud, cb| {
154            let mut h = Default::default();
155            check_error(unsafe {
156                syz_createBufferFromStreamHandle(
157                    &mut h as *mut syz_Handle,
158                    sh.to_syz_handle(),
159                    ud,
160                    Some(cb),
161                )
162            })?;
163            Ok(Buffer(Handle::new(h)))
164        })
165    }
166
167    pub fn get_length_in_samples(&self) -> Result<u32> {
168        let mut out = Default::default();
169        check_error(unsafe {
170            syz_bufferGetLengthInSamples(&mut out as *mut u32, self.to_syz_handle())
171        })?;
172        Ok(out)
173    }
174
175    pub fn get_length_in_seconds(&self) -> Result<f64> {
176        let mut out = Default::default();
177        check_error(unsafe {
178            syz_bufferGetLengthInSeconds(&mut out as *mut f64, self.to_syz_handle())
179        })?;
180        Ok(out)
181    }
182
183    pub fn get_channels(&self) -> Result<u32> {
184        let mut out = Default::default();
185        check_error(unsafe { syz_bufferGetChannels(&mut out as *mut u32, self.to_syz_handle()) })?;
186        Ok(out)
187    }
188
189    pub fn get_size_in_bytes(&self) -> Result<u64> {
190        let mut out = 0;
191        check_error(unsafe {
192            syz_bufferGetSizeInBytes(&mut out as *mut u64, self.to_syz_handle())
193        })?;
194        Ok(out)
195    }
196    object_common!();
197}
198
199handle_traits!(Buffer);