Skip to main content

rustysynth_ext/
instrument_region.rs

1use crate::error::SoundFontError;
2use crate::generator::Generator;
3use crate::generator_type::GeneratorType;
4use crate::loop_mode::LoopMode;
5use crate::sample_header::SampleHeader;
6use crate::soundfont_math::SoundFontMath;
7use crate::zone::Zone;
8
9fn set_parameter(gs: &mut [i16; GeneratorType::COUNT], generator: &Generator) {
10    let index = generator.generator_type as usize;
11
12    // Unknown generators should be ignored.
13    if index < gs.len() {
14        gs[index] = generator.value as i16;
15    }
16}
17
18/// Represents an instrument region.
19/// An instrument region contains all the parameters necessary to synthesize a note.
20#[derive(Debug)]
21#[non_exhaustive]
22pub struct InstrumentRegion {
23    pub(crate) gs: [i16; GeneratorType::COUNT],
24    pub(crate) sample_start: i32,
25    pub(crate) sample_end: i32,
26    pub(crate) sample_start_loop: i32,
27    pub(crate) sample_end_loop: i32,
28    pub(crate) sample_sample_rate: i32,
29    pub(crate) sample_original_pitch: i32,
30    pub(crate) sample_pitch_correction: i32,
31}
32
33impl InstrumentRegion {
34    fn new(
35        instrument_id: usize,
36        global: &Zone,
37        local: &Zone,
38        samples: &[SampleHeader],
39    ) -> Result<Self, SoundFontError> {
40        let mut gs: [i16; GeneratorType::COUNT] = [0; GeneratorType::COUNT];
41        gs[GeneratorType::INITIAL_FILTER_CUTOFF_FREQUENCY as usize] = 13500;
42        gs[GeneratorType::DELAY_MODULATION_LFO as usize] = -12000;
43        gs[GeneratorType::DELAY_VIBRATO_LFO as usize] = -12000;
44        gs[GeneratorType::DELAY_MODULATION_ENVELOPE as usize] = -12000;
45        gs[GeneratorType::ATTACK_MODULATION_ENVELOPE as usize] = -12000;
46        gs[GeneratorType::HOLD_MODULATION_ENVELOPE as usize] = -12000;
47        gs[GeneratorType::DECAY_MODULATION_ENVELOPE as usize] = -12000;
48        gs[GeneratorType::RELEASE_MODULATION_ENVELOPE as usize] = -12000;
49        gs[GeneratorType::DELAY_VOLUME_ENVELOPE as usize] = -12000;
50        gs[GeneratorType::ATTACK_VOLUME_ENVELOPE as usize] = -12000;
51        gs[GeneratorType::HOLD_VOLUME_ENVELOPE as usize] = -12000;
52        gs[GeneratorType::DECAY_VOLUME_ENVELOPE as usize] = -12000;
53        gs[GeneratorType::RELEASE_VOLUME_ENVELOPE as usize] = -12000;
54        gs[GeneratorType::KEY_RANGE as usize] = 0x7F00;
55        gs[GeneratorType::VELOCITY_RANGE as usize] = 0x7F00;
56        gs[GeneratorType::KEY_NUMBER as usize] = -1;
57        gs[GeneratorType::VELOCITY as usize] = -1;
58        gs[GeneratorType::SCALE_TUNING as usize] = 100;
59        gs[GeneratorType::OVERRIDING_ROOT_KEY as usize] = -1;
60
61        for generator in global.generators.iter() {
62            set_parameter(&mut gs, generator);
63        }
64
65        for generator in local.generators.iter() {
66            set_parameter(&mut gs, generator);
67        }
68
69        let sample_id = gs[GeneratorType::SAMPLE_ID as usize] as usize;
70        if sample_id >= samples.len() {
71            return Err(SoundFontError::InvalidSampleId {
72                instrument_id,
73                sample_id,
74            });
75        }
76        let sample = &samples[sample_id];
77
78        Ok(Self {
79            gs,
80            sample_start: sample.start,
81            sample_end: sample.end,
82            sample_start_loop: sample.start_loop,
83            sample_end_loop: sample.end_loop,
84            sample_sample_rate: sample.sample_rate,
85            sample_original_pitch: sample.original_pitch as i32,
86            sample_pitch_correction: sample.pitch_correction as i32,
87        })
88    }
89
90    pub(crate) fn create(
91        instrument_id: usize,
92        zones: &[Zone],
93        samples: &[SampleHeader],
94    ) -> Result<Vec<InstrumentRegion>, SoundFontError> {
95        // Is the first one the global zone?
96        if zones[0].generators.is_empty()
97            || zones[0].generators.last().unwrap().generator_type != GeneratorType::SAMPLE_ID
98        {
99            // The first one is the global zone.
100            let global = &zones[0];
101
102            // The global zone is regarded as the base setting of subsequent zones.
103            let count = zones.len() - 1;
104            let mut regions: Vec<InstrumentRegion> = Vec::with_capacity(count);
105            for i in 0..count {
106                regions.push(InstrumentRegion::new(
107                    instrument_id,
108                    global,
109                    &zones[i + 1],
110                    samples,
111                )?);
112            }
113
114            Ok(regions)
115        } else {
116            // No global zone.
117            let count = zones.len();
118            let mut regions: Vec<InstrumentRegion> = Vec::with_capacity(count);
119            for zone in zones.iter().take(count) {
120                regions.push(InstrumentRegion::new(
121                    instrument_id,
122                    &Zone::empty(),
123                    zone,
124                    samples,
125                )?);
126            }
127
128            Ok(regions)
129        }
130    }
131
132    /// Checks if the region covers the given key and velocity.
133    /// Returns `true` if the region covers the given key and velocity.
134    ///
135    /// # Arguments
136    ///
137    /// * `key` - The key of a note.
138    /// * `velocity` - The velocity of a note.
139    pub fn contains(&self, key: i32, velocity: i32) -> bool {
140        let contains_key = self.get_key_range_start() <= key && key <= self.get_key_range_end();
141        let contains_velocity = self.get_velocity_range_start() <= velocity
142            && velocity <= self.get_velocity_range_end();
143        contains_key && contains_velocity
144    }
145
146    pub fn get_sample_start(&self) -> i32 {
147        self.sample_start + self.get_start_address_offset()
148    }
149
150    pub fn get_sample_end(&self) -> i32 {
151        self.sample_end + self.get_end_address_offset()
152    }
153
154    pub fn get_sample_start_loop(&self) -> i32 {
155        self.sample_start_loop + self.get_start_loop_address_offset()
156    }
157
158    pub fn get_sample_end_loop(&self) -> i32 {
159        self.sample_end_loop + self.get_end_loop_address_offset()
160    }
161
162    pub fn get_start_address_offset(&self) -> i32 {
163        32768 * self.gs[GeneratorType::START_ADDRESS_COARSE_OFFSET as usize] as i32
164            + self.gs[GeneratorType::START_ADDRESS_OFFSET as usize] as i32
165    }
166
167    pub fn get_end_address_offset(&self) -> i32 {
168        32768 * self.gs[GeneratorType::END_ADDRESS_COARSE_OFFSET as usize] as i32
169            + self.gs[GeneratorType::END_ADDRESS_OFFSET as usize] as i32
170    }
171
172    pub fn get_start_loop_address_offset(&self) -> i32 {
173        32768 * self.gs[GeneratorType::START_LOOP_ADDRESS_COARSE_OFFSET as usize] as i32
174            + self.gs[GeneratorType::START_LOOP_ADDRESS_OFFSET as usize] as i32
175    }
176
177    pub fn get_end_loop_address_offset(&self) -> i32 {
178        32768 * self.gs[GeneratorType::END_LOOP_ADDRESS_COARSE_OFFSET as usize] as i32
179            + self.gs[GeneratorType::END_LOOP_ADDRESS_OFFSET as usize] as i32
180    }
181
182    pub fn get_modulation_lfo_to_pitch(&self) -> i32 {
183        self.gs[GeneratorType::MODULATION_LFO_TO_PITCH as usize] as i32
184    }
185
186    pub fn get_vibrato_lfo_to_pitch(&self) -> i32 {
187        self.gs[GeneratorType::VIBRATO_LFO_TO_PITCH as usize] as i32
188    }
189
190    pub fn get_modulation_envelope_to_pitch(&self) -> i32 {
191        self.gs[GeneratorType::MODULATION_ENVELOPE_TO_PITCH as usize] as i32
192    }
193
194    pub fn get_initial_filter_cutoff_frequency(&self) -> f32 {
195        SoundFontMath::cents_to_hertz(
196            self.gs[GeneratorType::INITIAL_FILTER_CUTOFF_FREQUENCY as usize] as f32,
197        )
198    }
199
200    pub fn get_initial_filter_q(&self) -> f32 {
201        0.1_f32 * self.gs[GeneratorType::INITIAL_FILTER_Q as usize] as f32
202    }
203
204    pub fn get_modulation_lfo_to_filter_cutoff_frequency(&self) -> i32 {
205        self.gs[GeneratorType::MODULATION_LFO_TO_FILTER_CUTOFF_FREQUENCY as usize] as i32
206    }
207
208    pub fn get_modulation_envelope_to_filter_cutoff_frequency(&self) -> i32 {
209        self.gs[GeneratorType::MODULATION_ENVELOPE_TO_FILTER_CUTOFF_FREQUENCY as usize] as i32
210    }
211
212    pub fn get_modulation_lfo_to_volume(&self) -> f32 {
213        0.1_f32 * self.gs[GeneratorType::MODULATION_LFO_TO_VOLUME as usize] as f32
214    }
215
216    pub fn get_chorus_effects_send(&self) -> f32 {
217        0.1_f32 * self.gs[GeneratorType::CHORUS_EFFECTS_SEND as usize] as f32
218    }
219
220    pub fn get_reverb_effects_send(&self) -> f32 {
221        0.1_f32 * self.gs[GeneratorType::REVERB_EFFECTS_SEND as usize] as f32
222    }
223
224    pub fn get_pan(&self) -> f32 {
225        0.1_f32 * self.gs[GeneratorType::PAN as usize] as f32
226    }
227
228    pub fn get_delay_modulation_lfo(&self) -> f32 {
229        SoundFontMath::timecents_to_seconds(
230            self.gs[GeneratorType::DELAY_MODULATION_LFO as usize] as f32,
231        )
232    }
233
234    pub fn get_frequency_modulation_lfo(&self) -> f32 {
235        SoundFontMath::cents_to_hertz(
236            self.gs[GeneratorType::FREQUENCY_MODULATION_LFO as usize] as f32,
237        )
238    }
239
240    pub fn get_delay_vibrato_lfo(&self) -> f32 {
241        SoundFontMath::timecents_to_seconds(
242            self.gs[GeneratorType::DELAY_VIBRATO_LFO as usize] as f32,
243        )
244    }
245
246    pub fn get_frequency_vibrato_lfo(&self) -> f32 {
247        SoundFontMath::cents_to_hertz(self.gs[GeneratorType::FREQUENCY_VIBRATO_LFO as usize] as f32)
248    }
249
250    pub fn get_delay_modulation_envelope(&self) -> f32 {
251        SoundFontMath::timecents_to_seconds(
252            self.gs[GeneratorType::DELAY_MODULATION_ENVELOPE as usize] as f32,
253        )
254    }
255
256    pub fn get_attack_modulation_envelope(&self) -> f32 {
257        SoundFontMath::timecents_to_seconds(
258            self.gs[GeneratorType::ATTACK_MODULATION_ENVELOPE as usize] as f32,
259        )
260    }
261
262    pub fn get_hold_modulation_envelope(&self) -> f32 {
263        SoundFontMath::timecents_to_seconds(
264            self.gs[GeneratorType::HOLD_MODULATION_ENVELOPE as usize] as f32,
265        )
266    }
267
268    pub fn get_decay_modulation_envelope(&self) -> f32 {
269        SoundFontMath::timecents_to_seconds(
270            self.gs[GeneratorType::DECAY_MODULATION_ENVELOPE as usize] as f32,
271        )
272    }
273
274    pub fn get_sustain_modulation_envelope(&self) -> f32 {
275        0.1_f32 * self.gs[GeneratorType::SUSTAIN_MODULATION_ENVELOPE as usize] as f32
276    }
277
278    pub fn get_release_modulation_envelope(&self) -> f32 {
279        SoundFontMath::timecents_to_seconds(
280            self.gs[GeneratorType::RELEASE_MODULATION_ENVELOPE as usize] as f32,
281        )
282    }
283
284    pub fn get_key_number_to_modulation_envelope_hold(&self) -> i32 {
285        self.gs[GeneratorType::KEY_NUMBER_TO_MODULATION_ENVELOPE_HOLD as usize] as i32
286    }
287
288    pub fn get_key_number_to_modulation_envelope_decay(&self) -> i32 {
289        self.gs[GeneratorType::KEY_NUMBER_TO_MODULATION_ENVELOPE_DECAY as usize] as i32
290    }
291
292    pub fn get_delay_volume_envelope(&self) -> f32 {
293        SoundFontMath::timecents_to_seconds(
294            self.gs[GeneratorType::DELAY_VOLUME_ENVELOPE as usize] as f32,
295        )
296    }
297
298    pub fn get_attack_volume_envelope(&self) -> f32 {
299        SoundFontMath::timecents_to_seconds(
300            self.gs[GeneratorType::ATTACK_VOLUME_ENVELOPE as usize] as f32,
301        )
302    }
303
304    pub fn get_hold_volume_envelope(&self) -> f32 {
305        SoundFontMath::timecents_to_seconds(
306            self.gs[GeneratorType::HOLD_VOLUME_ENVELOPE as usize] as f32,
307        )
308    }
309
310    pub fn get_decay_volume_envelope(&self) -> f32 {
311        SoundFontMath::timecents_to_seconds(
312            self.gs[GeneratorType::DECAY_VOLUME_ENVELOPE as usize] as f32,
313        )
314    }
315
316    pub fn get_sustain_volume_envelope(&self) -> f32 {
317        0.1_f32 * self.gs[GeneratorType::SUSTAIN_VOLUME_ENVELOPE as usize] as f32
318    }
319
320    pub fn get_release_volume_envelope(&self) -> f32 {
321        SoundFontMath::timecents_to_seconds(
322            self.gs[GeneratorType::RELEASE_VOLUME_ENVELOPE as usize] as f32,
323        )
324    }
325
326    pub fn get_key_number_to_volume_envelope_hold(&self) -> i32 {
327        self.gs[GeneratorType::KEY_NUMBER_TO_VOLUME_ENVELOPE_HOLD as usize] as i32
328    }
329
330    pub fn get_key_number_to_volume_envelope_decay(&self) -> i32 {
331        self.gs[GeneratorType::KEY_NUMBER_TO_VOLUME_ENVELOPE_DECAY as usize] as i32
332    }
333
334    pub fn get_key_range_start(&self) -> i32 {
335        self.gs[GeneratorType::KEY_RANGE as usize] as i32 & 0xFF
336    }
337
338    pub fn get_key_range_end(&self) -> i32 {
339        (self.gs[GeneratorType::KEY_RANGE as usize] as i32 >> 8) & 0xFF
340    }
341
342    pub fn get_velocity_range_start(&self) -> i32 {
343        self.gs[GeneratorType::VELOCITY_RANGE as usize] as i32 & 0xFF
344    }
345
346    pub fn get_velocity_range_end(&self) -> i32 {
347        (self.gs[GeneratorType::VELOCITY_RANGE as usize] as i32 >> 8) & 0xFF
348    }
349
350    pub fn get_initial_attenuation(&self) -> f32 {
351        0.1_f32 * self.gs[GeneratorType::INITIAL_ATTENUATION as usize] as f32
352    }
353
354    pub fn get_coarse_tune(&self) -> i32 {
355        self.gs[GeneratorType::COARSE_TUNE as usize] as i32
356    }
357
358    pub fn get_fine_tune(&self) -> i32 {
359        self.gs[GeneratorType::FINE_TUNE as usize] as i32 + self.sample_pitch_correction
360    }
361
362    pub fn get_sample_modes(&self) -> LoopMode {
363        LoopMode::from_i16(self.gs[GeneratorType::SAMPLE_MODES as usize])
364    }
365
366    pub fn get_scale_tuning(&self) -> i32 {
367        self.gs[GeneratorType::SCALE_TUNING as usize] as i32
368    }
369
370    pub fn get_exclusive_class(&self) -> i32 {
371        self.gs[GeneratorType::EXCLUSIVE_CLASS as usize] as i32
372    }
373
374    pub fn get_root_key(&self) -> i32 {
375        if self.gs[GeneratorType::OVERRIDING_ROOT_KEY as usize] != -1 {
376            self.gs[GeneratorType::OVERRIDING_ROOT_KEY as usize] as i32
377        } else {
378            self.sample_original_pitch
379        }
380    }
381
382    pub fn get_sample_id(&self) -> usize {
383        self.gs[GeneratorType::SAMPLE_ID as usize] as usize
384    }
385}