rytm_rs/object/sound/page/
samp.rs

1// All casts in this file are intended or safe within the context of this library.
2//
3// One can change `allow` to `warn` to review them if necessary.
4#![allow(
5    clippy::cast_lossless,
6    clippy::cast_possible_truncation,
7    clippy::cast_sign_loss
8)]
9
10use crate::{
11    error::{ConversionError, ParameterError, RytmError},
12    util::{
13        from_s_u16_t, i8_to_u8_midpoint_of_u8_input_range, scale_f32_to_u16, scale_u16_to_f32,
14        to_s_u16_t_union_a, u8_to_i8_midpoint_of_u8_input_range,
15    },
16};
17use rytm_rs_macro::parameter_range;
18use rytm_sys::ar_sound_t;
19use serde::{Deserialize, Serialize};
20
21/// Represents parameters in the sample page of a sound.
22#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Serialize, Deserialize)]
23pub struct Sample {
24    tune: i8,
25    fine_tune: i8,
26    number: u8,
27    bit_reduction: u8,
28    start: f32,
29    end: f32,
30    loop_flag: bool,
31    volume: u8,
32}
33
34impl Default for Sample {
35    fn default() -> Self {
36        Self {
37            tune: 0,
38            fine_tune: 0,
39            number: 0,
40            bit_reduction: 0,
41            start: 0.0,
42            end: 120.0,
43            loop_flag: false,
44            volume: 100,
45        }
46    }
47}
48
49impl TryFrom<&ar_sound_t> for Sample {
50    type Error = ConversionError;
51    fn try_from(raw_sound: &ar_sound_t) -> Result<Self, Self::Error> {
52        let start = scale_u16_to_f32(
53            unsafe { from_s_u16_t(raw_sound.sample_start) },
54            0u16,
55            30720u16,
56            0f32,
57            120.0f32,
58        );
59
60        let end = scale_u16_to_f32(
61            unsafe { from_s_u16_t(raw_sound.sample_end) },
62            0u16,
63            30720u16,
64            0f32,
65            120.0f32,
66        );
67
68        Ok(Self {
69            tune: u8_to_i8_midpoint_of_u8_input_range(raw_sound.sample_tune, 127, 0),
70            fine_tune: u8_to_i8_midpoint_of_u8_input_range(raw_sound.sample_fine_tune, 127, 0),
71            number: raw_sound.sample_nr,
72            bit_reduction: raw_sound.sample_br,
73            start,
74            end,
75            loop_flag: raw_sound.sample_loop_flag != 0,
76            volume: raw_sound.sample_volume,
77        })
78    }
79}
80
81impl Sample {
82    pub(crate) fn apply_to_raw_sound(&self, raw_sound: &mut ar_sound_t) {
83        // // map range of 0.0..=120.0 to u16 0..=30720
84        let start = scale_f32_to_u16(self.start, 0f32, 120.0f32, 0u16, 30720u16);
85        let end = scale_f32_to_u16(self.end, 0f32, 120.0f32, 0u16, 30720u16);
86
87        raw_sound.sample_tune = i8_to_u8_midpoint_of_u8_input_range(self.tune, 127, 0);
88        raw_sound.sample_fine_tune = i8_to_u8_midpoint_of_u8_input_range(self.fine_tune, 127, 0);
89        raw_sound.sample_nr = self.number;
90        raw_sound.sample_br = self.bit_reduction;
91
92        raw_sound.sample_start = to_s_u16_t_union_a(start);
93        raw_sound.sample_end = to_s_u16_t_union_a(end);
94        raw_sound.sample_loop_flag = self.loop_flag as u8;
95        raw_sound.sample_volume = self.volume;
96    }
97
98    /// Sets the coarse tune of the sample.
99    ///
100    /// Range: `-24..=24`
101    #[parameter_range(range = "tune:-24..=24")]
102    pub fn set_tune(&mut self, tune: isize) -> Result<(), RytmError> {
103        self.tune = tune as i8;
104        Ok(())
105    }
106
107    /// Sets the fine tune of the sample.
108    ///
109    /// Range: `-64..=63`
110    #[parameter_range(range = "fine_tune:-64..=63")]
111    pub fn set_fine_tune(&mut self, fine_tune: isize) -> Result<(), RytmError> {
112        self.fine_tune = fine_tune as i8;
113        Ok(())
114    }
115
116    /// Sets the slice number of the sample.
117    ///
118    /// Range: `0..=127`
119    #[parameter_range(range = "number:0..=127")]
120    pub fn set_slice_number(&mut self, number: usize) -> Result<(), RytmError> {
121        self.number = number as u8;
122        Ok(())
123    }
124
125    /// Unsets the sample slice.
126    ///
127    /// Synonym with `SMP OFF`.
128    pub fn unset_slice(&mut self) {
129        // TODO: Double check
130        self.number = 0xFF;
131    }
132
133    /// Sets the bit reduction of the sample.
134    ///
135    /// Range: `0..=127`
136    #[parameter_range(range = "bit_reduction:0..=127")]
137    pub fn set_bit_reduction(&mut self, bit_reduction: usize) -> Result<(), RytmError> {
138        self.bit_reduction = bit_reduction as u8;
139        Ok(())
140    }
141
142    /// Sets the start of the sample.
143    ///
144    /// Range: `0.0..=120.0`
145    #[parameter_range(range = "start:0.0..=120.0")]
146    pub fn set_start(&mut self, start: f32) -> Result<(), RytmError> {
147        self.start = start;
148        Ok(())
149    }
150
151    /// Sets the end of the sample.
152    ///
153    /// Range: `0.0..=120.0`
154    #[parameter_range(range = "end:0.0..=120.0")]
155    pub fn set_end(&mut self, end: f32) -> Result<(), RytmError> {
156        self.end = end;
157        Ok(())
158    }
159
160    /// Sets the loop flag of the sample.
161    pub fn set_loop_flag(&mut self, loop_flag: bool) {
162        self.loop_flag = loop_flag;
163    }
164
165    /// Sets the volume of the sample.
166    ///
167    /// Range: `0..=127`
168    #[parameter_range(range = "volume:0..=127")]
169    pub fn set_volume(&mut self, volume: usize) -> Result<(), RytmError> {
170        self.volume = volume as u8;
171        Ok(())
172    }
173
174    /// Returns the coarse tune of the sample.
175    ///
176    /// Range: `-24..=24`
177    pub const fn tune(&self) -> isize {
178        self.tune as isize
179    }
180
181    /// Returns the fine tune of the sample.
182    ///
183    /// Range: `-64..=63`
184    pub const fn fine_tune(&self) -> isize {
185        self.fine_tune as isize
186    }
187
188    /// Returns the slice number of the sample.
189    ///
190    /// Range: `0..=127`
191    pub const fn slice_number(&self) -> usize {
192        self.number as usize
193    }
194
195    /// Returns the bit reduction of the sample.
196    ///
197    /// Range: `0..=127`
198    pub const fn bit_reduction(&self) -> usize {
199        self.bit_reduction as usize
200    }
201
202    /// Returns the start of the sample.
203    ///
204    /// Range: `0.0..=120.0`
205    pub const fn start(&self) -> f32 {
206        self.start
207    }
208
209    /// Returns the end of the sample.
210    ///
211    /// Range: `0.0..=120.0`
212    pub const fn end(&self) -> f32 {
213        self.end
214    }
215
216    /// Returns the loop flag of the sample.
217    pub const fn loop_flag(&self) -> bool {
218        self.loop_flag
219    }
220
221    /// Returns the volume of the sample.
222    ///
223    /// Range: `0..=127`
224    pub const fn volume(&self) -> usize {
225        self.volume as usize
226    }
227}