1use std::error;
2use std::fmt;
3use std::io;
4
5use crate::four_cc::FourCC;
6
7#[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#[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 InvalidSampleData,
60 UnsupportedSampleFormat,
61 SampleDecompressionFailed(String),
62 SubChunkNotFound(FourCC),
63 InvalidPresetList,
64 InvalidInstrumentId {
65 preset_id: usize,
66 instrument_id: usize,
67 },
68 InvalidPreset(usize),
69 PresetNotFound,
70 InvalidInstrumentList,
71 InvalidSampleId {
72 instrument_id: usize,
73 sample_id: usize,
74 },
75 InvalidInstrument(usize),
76 InstrumentNotFound,
77 InvalidSampleHeaderList,
78 InvalidZoneList,
79 ZoneNotFound,
80 InvalidGeneratorList,
81 SanityCheckFailed,
82}
83
84impl error::Error for SoundFontError {
85 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
86 match self {
87 SoundFontError::IoError(err) => Some(err),
88 _ => None,
89 }
90 }
91}
92
93impl fmt::Display for SoundFontError {
94 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
95 match self {
96 SoundFontError::IoError(err) => err.fmt(f),
97 SoundFontError::RiffChunkNotFound => write!(f, "the RIFF chunk was not found"),
98 SoundFontError::InvalidRiffChunkType { expected, actual } => write!(
99 f,
100 "the type of the RIFF chunk must be '{}', but was '{}'",
101 expected, actual
102 ),
103 SoundFontError::ListChunkNotFound => write!(f, "the LIST chunk was not found"),
104 SoundFontError::InvalidListChunkType { expected, actual } => write!(
105 f,
106 "the type of the LIST chunk must be '{}', but was '{}'",
107 expected, actual
108 ),
109 SoundFontError::ListContainsUnknownId(id) => {
110 write!(f, "the INFO list contains an unknown ID '{id}'")
111 }
112 SoundFontError::SampleDataNotFound => write!(f, "no valid sample data was found"),
113 SoundFontError::InvalidSampleData => write!(f, "the sample data chunk is invalid"),
114 SoundFontError::UnsupportedSampleFormat => write!(
115 f,
116 "SoundFont3 is not supported; rebuild rustysynth-ext with the 'sf3' feature enabled"
117 ),
118 SoundFontError::SampleDecompressionFailed(message) => {
119 write!(f, "failed to decompress the sample data: {message}")
120 }
121 SoundFontError::SubChunkNotFound(id) => {
122 write!(f, "the '{}' sub-chunk was not found", id)
123 }
124 SoundFontError::InvalidPresetList => write!(f, "the preset list is invalid"),
125 SoundFontError::InvalidInstrumentId {
126 preset_id,
127 instrument_id,
128 } => write!(
129 f,
130 "the preset with the ID '{preset_id}' contains an invalid instrument ID '{instrument_id}'"
131 ),
132 SoundFontError::InvalidPreset(preset_id) => {
133 write!(f, "the preset with the ID '{preset_id}' has no zone")
134 }
135 SoundFontError::PresetNotFound => write!(f, "no valid preset was found"),
136 SoundFontError::InvalidInstrumentList => write!(f, "the instrument list is invalid"),
137 SoundFontError::InvalidSampleId {
138 instrument_id,
139 sample_id,
140 } => write!(
141 f,
142 "the instrument with the ID '{instrument_id}' contains an invalid sample ID '{sample_id}'"
143 ),
144 SoundFontError::InvalidInstrument(instrument_id) => {
145 write!(
146 f,
147 "the instrument with the ID '{instrument_id}' has no zone"
148 )
149 }
150 SoundFontError::InstrumentNotFound => write!(f, "no valid instrument was found"),
151 SoundFontError::InvalidSampleHeaderList => {
152 write!(f, "the sample header list is invalid")
153 }
154 SoundFontError::InvalidZoneList => write!(f, "the zone list is invalid"),
155 SoundFontError::ZoneNotFound => write!(f, "no valid zone was found"),
156 SoundFontError::InvalidGeneratorList => write!(f, "the generator list is invalid"),
157 SoundFontError::SanityCheckFailed => write!(f, "sanity check failed"),
158 }
159 }
160}
161
162impl From<io::Error> for SoundFontError {
163 fn from(err: io::Error) -> Self {
164 SoundFontError::IoError(err)
165 }
166}
167
168#[derive(Debug)]
170#[non_exhaustive]
171pub enum MidiFileError {
172 IoError(io::Error),
173 InvalidChunkType { expected: FourCC, actual: FourCC },
174 InvalidChunkData(FourCC),
175 UnsupportedFormat(i16),
176 InvalidTimeDivision(i16),
177 InvalidTempoValue,
178 InvalidEventList,
179}
180
181impl error::Error for MidiFileError {
182 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
183 match self {
184 MidiFileError::IoError(err) => Some(err),
185 _ => None,
186 }
187 }
188}
189
190impl fmt::Display for MidiFileError {
191 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
192 match self {
193 MidiFileError::IoError(err) => err.fmt(f),
194 MidiFileError::InvalidChunkType { expected, actual } => write!(
195 f,
196 "the chunk type must be '{}', but was '{}'",
197 expected, actual
198 ),
199 MidiFileError::InvalidChunkData(id) => write!(f, "the '{}' chunk has invalid data", id),
200 MidiFileError::UnsupportedFormat(format) => {
201 write!(f, "the format {} is not supported", format)
202 }
203 MidiFileError::InvalidTimeDivision(division) => write!(
204 f,
205 "the time division must be a positive number of ticks per quarter note, but was {} (SMPTE timecode divisions are not supported)",
206 division
207 ),
208 MidiFileError::InvalidTempoValue => write!(f, "failed to read the tempo value"),
209 MidiFileError::InvalidEventList => write!(
210 f,
211 "the event list is invalid: the times must be in non-decreasing order"
212 ),
213 }
214 }
215}
216
217impl From<io::Error> for MidiFileError {
218 fn from(err: io::Error) -> Self {
219 MidiFileError::IoError(err)
220 }
221}