Skip to main content

rustysynth_ext/
instrument.rs

1use crate::error::SoundFontError;
2use crate::instrument_info::InstrumentInfo;
3use crate::instrument_region::InstrumentRegion;
4use crate::sample_header::SampleHeader;
5use crate::zone::Zone;
6
7/// Represents an instrument in the SoundFont.
8#[derive(Debug)]
9#[non_exhaustive]
10pub struct Instrument {
11    pub(crate) name: String,
12    pub(crate) regions: Vec<InstrumentRegion>,
13}
14
15impl Instrument {
16    fn new(
17        info: &InstrumentInfo,
18        instrument_id: usize,
19        zones: &[Zone],
20        samples: &[SampleHeader],
21    ) -> Result<Self, SoundFontError> {
22        let name = info.name.clone();
23
24        let zone_count = info.zone_end_index - info.zone_start_index + 1;
25        if zone_count <= 0 {
26            return Err(SoundFontError::InvalidInstrument(instrument_id));
27        }
28
29        let span_start = info.zone_start_index as usize;
30        let Some(span_end) = span_start.checked_add(zone_count as usize) else {
31            return Err(SoundFontError::InvalidInstrument(instrument_id));
32        };
33        let Some(zone_span) = zones.get(span_start..span_end) else {
34            return Err(SoundFontError::InvalidInstrument(instrument_id));
35        };
36        let regions = InstrumentRegion::create(instrument_id, zone_span, samples)?;
37
38        Ok(Self { name, regions })
39    }
40
41    pub(crate) fn create(
42        infos: &[InstrumentInfo],
43        zones: &[Zone],
44        samples: &[SampleHeader],
45    ) -> Result<Vec<Instrument>, SoundFontError> {
46        if infos.len() <= 1 {
47            return Err(SoundFontError::InstrumentNotFound);
48        }
49
50        // The last one is the terminator.
51        let count = infos.len() - 1;
52
53        let mut instruments: Vec<Instrument> = Vec::with_capacity(count);
54        for (instrument_id, info) in infos.iter().take(count).enumerate() {
55            instruments.push(Instrument::new(info, instrument_id, zones, samples)?);
56        }
57
58        Ok(instruments)
59    }
60
61    /// Gets the name of the instrument.
62    pub fn get_name(&self) -> &str {
63        &self.name
64    }
65
66    /// Gets the regions of the instrument.
67    pub fn get_regions(&self) -> &[InstrumentRegion] {
68        &self.regions[..]
69    }
70}