1use std::mem::MaybeUninit;
54
55use array_init;
56use byteorder::{ByteOrder, LittleEndian};
57use korg_syro_sys as syro;
58use thiserror::Error;
59
60#[macro_use]
61mod macros;
62use macros::*;
63
64pub mod pattern;
65
66#[derive(Error, Debug, PartialEq)]
67pub enum SyroError {
68 #[error("invalid value {val} for '{name}', expected at least {} and at most {}", .lo, .hi)]
69 OutOfBounds {
70 val: u32,
71 name: &'static str,
72 lo: usize,
73 hi: usize,
74 },
75
76 #[error("empty stream, provide at least one sample or pattern")]
77 EmptyStream,
78
79 #[error("unhandled SyroStatus {status:?}")]
80 SyroStatus { status: syro::SyroStatus },
81}
82
83fn check_syro_status(status: syro::SyroStatus) -> Result<(), SyroError> {
84 match status {
85 syro::SyroStatus::Status_Success => Ok(()),
86 _ => Err(SyroError::SyroStatus { status }),
96 }
97}
98
99max_check!(sample_index, 99);
100bounds_check!(bit_depth, 8, 16);
101
102struct SyroDataBundle {
104 #[allow(dead_code)]
105 data: Vec<u8>,
106 syro_data: syro::SyroData,
107}
108
109impl SyroDataBundle {
110 fn sample(
111 index: u32,
112 data_type: syro::SyroDataType,
113 mut data: Vec<u8>,
114 sample_rate: u32,
115 bit_depth: u32,
116 ) -> Self {
117 let syro_data = syro::SyroData {
118 DataType: data_type,
119 pData: data.as_mut_ptr(),
120 Number: index,
122 Size: data.len() as u32,
124 Quality: bit_depth,
126 Fs: sample_rate,
127 SampleEndian: korg_syro_sys::Endian::LittleEndian,
128 };
129
130 Self { data, syro_data }
131 }
132
133 fn erase(index: u32) -> Self {
134 let syro_data = syro::SyroData {
135 DataType: syro::SyroDataType::DataType_Sample_Erase,
136 pData: 0 as *mut u8,
137 Number: index,
138 Size: 0,
139 Quality: 0,
140 Fs: 0,
141 SampleEndian: korg_syro_sys::Endian::LittleEndian,
142 };
143
144 Self {
145 data: vec![],
146 syro_data,
147 }
148 }
149
150 fn reset(mut data: Vec<u8>) -> Self {
151 let syro_data = syro::SyroData {
152 DataType: syro::SyroDataType::DataType_Sample_All,
153 pData: data.as_mut_ptr(),
154 Size: data.len() as u32,
155 Number: 0,
156 Quality: 0,
157 Fs: 44100,
158 SampleEndian: korg_syro_sys::Endian::LittleEndian,
159 };
160
161 Self { data, syro_data }
162 }
163
164 fn reset_compressed(mut data: Vec<u8>, bit_depth: u32) -> Self {
165 let syro_data = syro::SyroData {
166 DataType: syro::SyroDataType::DataType_Sample_AllCompress,
167 pData: data.as_mut_ptr(),
168 Size: data.len() as u32,
169 Number: 0,
170 Quality: bit_depth,
171 Fs: 44100,
172 SampleEndian: korg_syro_sys::Endian::LittleEndian,
173 };
174
175 Self { data, syro_data }
176 }
177
178 fn pattern(index: u32, mut data: Vec<u8>) -> Self {
179 let syro_data = syro::SyroData {
180 DataType: syro::SyroDataType::DataType_Pattern,
181 pData: data.as_mut_ptr(),
182 Number: index,
183 Size: data.len() as u32,
184 Quality: 0,
185 Fs: 0,
186 SampleEndian: korg_syro_sys::Endian::LittleEndian,
187 };
188
189 Self { data, syro_data }
190 }
191
192 fn data(&self) -> syro::SyroData {
193 self.syro_data
194 }
195}
196
197pub struct SyroStream {
203 samples: [Option<SyroDataBundle>; 100],
204 patterns: [Option<SyroDataBundle>; 10],
205}
206
207impl Default for SyroStream {
208 fn default() -> Self {
209 Self {
210 samples: array_init::array_init(|_| None),
211 patterns: array_init::array_init(|_| None),
212 }
213 }
214}
215
216fn convert_data(data: Vec<i16>) -> Vec<u8> {
217 let mut new_data: Vec<u8> = vec![0; data.len() * 2];
218 LittleEndian::write_i16_into(data.as_slice(), new_data.as_mut_slice());
219 new_data
220}
221
222impl SyroStream {
223 pub fn reset(data: Vec<u8>, compression: Option<u32>) -> Result<Vec<i16>, SyroError> {
225 let mut syro_stream = Self::default();
226 let syro_data_bundle = match compression {
227 Some(bit_depth) => {
228 check_bit_depth(bit_depth as u8)?;
229 SyroDataBundle::reset_compressed(data, bit_depth)
230 }
231 None => SyroDataBundle::reset(data),
232 };
233 match syro_stream.samples.get_mut(0) {
234 Some(elem) => {
235 *elem = Some(syro_data_bundle);
236 }
237 None => unreachable!(),
238 }
239 syro_stream.generate()
240 }
241
242 pub fn add_sample(
249 &mut self,
250 index: u32,
251 data: Vec<i16>,
252 sample_rate: u32,
253 compression: Option<u32>,
254 ) -> Result<&mut Self, SyroError> {
255 check_sample_index(index as u8)?;
256 let data = convert_data(data);
257 let bundle = match compression {
258 Some(bit_depth) => {
259 check_bit_depth(bit_depth as u8)?;
260 SyroDataBundle::sample(
261 index,
262 syro::SyroDataType::DataType_Sample_Compress,
263 data,
264 sample_rate,
265 bit_depth,
266 )
267 }
268 None => SyroDataBundle::sample(
269 index,
270 syro::SyroDataType::DataType_Sample_Liner,
271 data,
272 sample_rate,
273 0,
274 ),
275 };
276 match self.samples.get_mut(index as usize) {
277 Some(elem) => *elem = Some(bundle),
278 None => panic!("Index out of bounds, checking must have failed"),
279 }
280 Ok(self)
281 }
282
283 pub fn erase_sample(&mut self, index: u32) -> Result<&mut Self, SyroError> {
287 check_sample_index(index as u8)?;
288 match self.samples.get_mut(index as usize) {
290 Some(elem) => *elem = Some(SyroDataBundle::erase(index)),
291 None => panic!("Index out of bounds, checking must have failed"),
292 }
293 Ok(self)
294 }
295
296 pub fn add_pattern(
300 &mut self,
301 index: usize,
302 pattern: pattern::Pattern,
303 ) -> Result<&mut Self, SyroError> {
304 pattern::check_pattern_index(index as u8)?;
305 let data = SyroDataBundle::pattern(index as u32, pattern.to_bytes());
306 if let Some(elem) = self.patterns.get_mut(index) {
307 *elem = Some(data);
308 }
309 Ok(self)
310 }
311
312 pub fn generate(self) -> Result<Vec<i16>, SyroError> {
316 let mut data: Vec<syro::SyroData> = Vec::with_capacity(110);
317
318 for sample in self.samples.iter() {
319 if let Some(bundle) = sample {
320 data.push(bundle.data());
321 }
322 }
323
324 for pattern in self.patterns.iter() {
325 if let Some(bundle) = pattern {
326 data.push(bundle.data());
327 }
328 }
329
330 if data.len() == 0 {
331 return Err(SyroError::EmptyStream);
332 }
333
334 let syro_stream = {
336 let (handle, num_frames) = init_syro_handle(data)?;
337 let result = generate_syro_stream(handle, num_frames);
338 free_syro_handle(handle)?;
339 result
340 }?;
341 Ok(syro_stream)
342 }
343}
344
345fn init_syro_handle(mut data: Vec<syro::SyroData>) -> Result<(syro::SyroHandle, u32), SyroError> {
346 let mut num_frames = 0;
347
348 let handle: syro::SyroHandle = unsafe {
349 let mut handle: MaybeUninit<syro::SyroHandle> = MaybeUninit::uninit();
350
351 let status = syro::SyroVolcaSample_Start(
352 handle.as_mut_ptr(),
353 data.as_mut_ptr(),
354 data.len() as i32,
355 0,
356 &mut num_frames,
357 );
358 check_syro_status(status)?;
359
360 handle.assume_init()
361 };
362
363 Ok((handle, num_frames))
364}
365
366fn free_syro_handle(handle: syro::SyroHandle) -> Result<(), SyroError> {
367 unsafe {
368 let status = korg_syro_sys::SyroVolcaSample_End(handle);
369 check_syro_status(status)
370 }
371}
372
373fn generate_syro_stream(handle: syro::SyroHandle, num_frames: u32) -> Result<Vec<i16>, SyroError> {
374 let mut left: i16 = 0;
375 let mut right: i16 = 0;
376 let mut buffer = Vec::with_capacity(num_frames as usize * 2);
377 for _ in 0..num_frames {
378 unsafe {
379 let status = syro::SyroVolcaSample_GetSample(handle, &mut left, &mut right);
380 if status == syro::SyroStatus::Status_NoData {
381 } else {
383 check_syro_status(status)?;
384 }
385 }
386 buffer.push(left);
387 buffer.push(right);
388 }
389
390 Ok(buffer)
391}
392
393#[cfg(test)]
394mod tests {
395 use super::*;
396 use pattern::*;
397 use waver;
398
399 fn sine_wave() -> Vec<i16> {
401 let mut wf = waver::Waveform::<i16>::new(44100.0);
402 wf.superpose(waver::Wave {
403 frequency: 440.0,
404 ..Default::default()
405 })
406 .normalize_amplitudes();
407 wf.iter().take(22050).collect()
408 }
409
410 #[test]
411 fn out_of_bounds() {
412 let mut syro_stream = SyroStream::default();
413 let result = syro_stream.add_sample(100, vec![], 44100, None);
414 assert!(result.is_err());
415 assert_eq!(
416 result.err().unwrap(),
417 SyroError::OutOfBounds {
418 val: 100,
419 name: "sample_index".into(),
420 lo: 0,
421 hi: 99
422 }
423 );
424 }
425
426 #[test]
427 fn empty_syrostream() {
428 let result = SyroStream::default().generate();
429 assert!(result.is_err());
430 assert_eq!(result.err().unwrap(), SyroError::EmptyStream);
431 }
432
433 #[test]
434 fn basic() -> anyhow::Result<()> {
435 let input_data: Vec<i16> = sine_wave();
436
437 let mut syro_stream = SyroStream::default();
438
439 syro_stream.add_sample(0, input_data, 44100, None)?;
440 syro_stream.erase_sample(1)?;
441 syro_stream.add_pattern(0, Pattern::default())?;
442
443 let _output = syro_stream.generate()?;
444 Ok(())
445 }
446}