Skip to main content

rustysynth_ext/
error.rs

1use std::error;
2use std::fmt;
3use std::io;
4
5use crate::four_cc::FourCC;
6
7/// Represents an error when initializing a synthesizer.
8#[derive(Debug)]
9#[non_exhaustive]
10pub enum SynthesizerError {
11    SampleRateOutOfRange(i32),
12    BlockSizeOutOfRange(usize),
13    MaximumPolyphonyOutOfRange(usize),
14}
15
16impl error::Error for SynthesizerError {}
17
18impl fmt::Display for SynthesizerError {
19    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
20        match self {
21            SynthesizerError::SampleRateOutOfRange(value) => write!(
22                f,
23                "the sample rate must be between 16000 and 192000, but was {}",
24                value
25            ),
26            SynthesizerError::BlockSizeOutOfRange(value) => write!(
27                f,
28                "the block size must be between 8 and 1024, but was {}",
29                value
30            ),
31            SynthesizerError::MaximumPolyphonyOutOfRange(value) => {
32                write!(
33                    f,
34                    "the maximum number of polyphony must be between 8 and 256, but was {}",
35                    value
36                )
37            }
38        }
39    }
40}
41
42/// Represents an error when loading a SoundFont.
43#[derive(Debug)]
44#[non_exhaustive]
45pub enum SoundFontError {
46    IoError(io::Error),
47    RiffChunkNotFound,
48    InvalidRiffChunkType {
49        expected: FourCC,
50        actual: FourCC,
51    },
52    ListChunkNotFound,
53    InvalidListChunkType {
54        expected: FourCC,
55        actual: FourCC,
56    },
57    ListContainsUnknownId(FourCC),
58    SampleDataNotFound,
59    UnsupportedSampleFormat,
60    SampleDecompressionFailed(String),
61    SubChunkNotFound(FourCC),
62    InvalidPresetList,
63    InvalidInstrumentId {
64        preset_id: usize,
65        instrument_id: usize,
66    },
67    InvalidPreset(usize),
68    PresetNotFound,
69    InvalidInstrumentList,
70    InvalidSampleId {
71        instrument_id: usize,
72        sample_id: usize,
73    },
74    InvalidInstrument(usize),
75    InstrumentNotFound,
76    InvalidSampleHeaderList,
77    InvalidZoneList,
78    ZoneNotFound,
79    InvalidGeneratorList,
80    SanityCheckFailed,
81}
82
83impl error::Error for SoundFontError {
84    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
85        match self {
86            SoundFontError::IoError(err) => Some(err),
87            _ => None,
88        }
89    }
90}
91
92impl fmt::Display for SoundFontError {
93    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
94        match self {
95            SoundFontError::IoError(err) => err.fmt(f),
96            SoundFontError::RiffChunkNotFound => write!(f, "the RIFF chunk was not found"),
97            SoundFontError::InvalidRiffChunkType { expected, actual } => write!(
98                f,
99                "the type of the RIFF chunk must be '{}', but was '{}'",
100                expected, actual
101            ),
102            SoundFontError::ListChunkNotFound => write!(f, "the LIST chunk was not found"),
103            SoundFontError::InvalidListChunkType { expected, actual } => write!(
104                f,
105                "the type of the LIST chunk must be '{}', but was '{}'",
106                expected, actual
107            ),
108            SoundFontError::ListContainsUnknownId(id) => {
109                write!(f, "the INFO list contains an unknown ID '{id}'")
110            }
111            SoundFontError::SampleDataNotFound => write!(f, "no valid sample data was found"),
112            SoundFontError::UnsupportedSampleFormat => write!(
113                f,
114                "SoundFont3 is not supported; rebuild rustysynth-ext with the 'sf3' feature enabled"
115            ),
116            SoundFontError::SampleDecompressionFailed(message) => {
117                write!(f, "failed to decompress the sample data: {message}")
118            }
119            SoundFontError::SubChunkNotFound(id) => {
120                write!(f, "the '{}' sub-chunk was not found", id)
121            }
122            SoundFontError::InvalidPresetList => write!(f, "the preset list is invalid"),
123            SoundFontError::InvalidInstrumentId {
124                preset_id,
125                instrument_id,
126            } => write!(
127                f,
128                "the preset with the ID '{preset_id}' contains an invalid instrument ID '{instrument_id}'"
129            ),
130            SoundFontError::InvalidPreset(preset_id) => {
131                write!(f, "the preset with the ID '{preset_id}' has no zone")
132            }
133            SoundFontError::PresetNotFound => write!(f, "no valid preset was found"),
134            SoundFontError::InvalidInstrumentList => write!(f, "the instrument list is invalid"),
135            SoundFontError::InvalidSampleId {
136                instrument_id,
137                sample_id,
138            } => write!(
139                f,
140                "the instrument with the ID '{instrument_id}' contains an invalid sample ID '{sample_id}'"
141            ),
142            SoundFontError::InvalidInstrument(instrument_id) => {
143                write!(
144                    f,
145                    "the instrument with the ID '{instrument_id}' has no zone"
146                )
147            }
148            SoundFontError::InstrumentNotFound => write!(f, "no valid instrument was found"),
149            SoundFontError::InvalidSampleHeaderList => {
150                write!(f, "the sample header list is invalid")
151            }
152            SoundFontError::InvalidZoneList => write!(f, "the zone list is invalid"),
153            SoundFontError::ZoneNotFound => write!(f, "no valid zone was found"),
154            SoundFontError::InvalidGeneratorList => write!(f, "the generator list is invalid"),
155            SoundFontError::SanityCheckFailed => write!(f, "sanity check failed"),
156        }
157    }
158}
159
160impl From<io::Error> for SoundFontError {
161    fn from(err: io::Error) -> Self {
162        SoundFontError::IoError(err)
163    }
164}
165
166/// Represents an error when loading a MIDI file.
167#[derive(Debug)]
168#[non_exhaustive]
169pub enum MidiFileError {
170    IoError(io::Error),
171    InvalidChunkType { expected: FourCC, actual: FourCC },
172    InvalidChunkData(FourCC),
173    UnsupportedFormat(i16),
174    InvalidTempoValue,
175}
176
177impl error::Error for MidiFileError {
178    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
179        match self {
180            MidiFileError::IoError(err) => Some(err),
181            _ => None,
182        }
183    }
184}
185
186impl fmt::Display for MidiFileError {
187    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
188        match self {
189            MidiFileError::IoError(err) => err.fmt(f),
190            MidiFileError::InvalidChunkType { expected, actual } => write!(
191                f,
192                "the chunk type must be '{}', but was '{}'",
193                expected, actual
194            ),
195            MidiFileError::InvalidChunkData(id) => write!(f, "the '{}' chunk has invalid data", id),
196            MidiFileError::UnsupportedFormat(format) => {
197                write!(f, "the format {} is not supported", format)
198            }
199            MidiFileError::InvalidTempoValue => write!(f, "failed to read the tempo value"),
200        }
201    }
202}
203
204impl From<io::Error> for MidiFileError {
205    fn from(err: io::Error) -> Self {
206        MidiFileError::IoError(err)
207    }
208}