1pub mod raw;
2
3#[doc(hidden)]
4#[deprecated = "use `raw` instead"]
5pub use raw as data;
6
7pub mod error;
8pub use error::Error;
9
10mod riff;
11
12use raw::{
13 Bag, Generator, GeneratorAmountRange, GeneratorType, Info, InstrumentHeader, Modulator,
14 PresetHeader, RawSoundFontData, SampleData, SampleHeader,
15};
16
17use std::io::{Read, Seek};
18
19#[derive(Debug)]
20pub struct Preset {
21 pub header: PresetHeader,
22 pub zones: Vec<Zone>,
23}
24
25#[derive(Debug)]
26pub struct Instrument {
27 pub header: InstrumentHeader,
28 pub zones: Vec<Zone>,
29}
30
31#[derive(Debug)]
32pub struct SoundFont2 {
33 pub info: Info,
34 pub presets: Vec<Preset>,
35 pub instruments: Vec<Instrument>,
36 pub sample_headers: Vec<SampleHeader>,
37 pub sample_data: SampleData,
38}
39
40impl SoundFont2 {
41 pub fn load<F: Read + Seek>(file: &mut F) -> Result<Self, Error> {
42 RawSoundFontData::load(file).map(Self::from_raw)
43 }
44
45 pub fn from_raw(data: RawSoundFontData) -> Self {
46 fn get_zones(
47 zones: &[Bag],
48 modulators: &[Modulator],
49 generators: &[Generator],
50 start: usize,
51 end: usize,
52 ) -> Vec<Zone> {
53 let mut zone_items = Vec::new();
54 for j in start..end {
55 let curr = zones.get(j).unwrap();
56 let next = zones.get(j + 1);
57
58 let mod_list = {
59 let start = curr.modulator_id as usize;
60 let end = if let Some(next) = next {
61 next.modulator_id as usize
62 } else {
63 zones.len()
64 };
65
66 let mut list = Vec::new();
67
68 for i in start..end {
69 let item = modulators.get(i);
70 if let Some(item) = item {
71 list.push(item.to_owned());
72 }
73 }
74 list
75 };
76
77 let gen_list = {
78 let start = curr.generator_id as usize;
79 let end = if let Some(next) = next {
80 next.generator_id as usize
81 } else {
82 zones.len()
83 };
84
85 let mut list = Vec::new();
86
87 for i in start..end {
88 let item = generators.get(i);
89 if let Some(item) = item {
90 list.push(item.to_owned());
91 }
92 }
93 list
94 };
95
96 zone_items.push(Zone { mod_list, gen_list });
97 }
98 zone_items
99 }
100
101 let instruments = {
102 let headers = &data.hydra.instrument_headers;
103 let zones = &data.hydra.instrument_bags;
104 let modulators = &data.hydra.instrument_modulators;
105 let generators = &data.hydra.instrument_generators;
106
107 let iter = headers.iter();
108 let mut iter_peek = headers.iter();
109 iter_peek.next();
111
112 let mut list = Vec::new();
113
114 for header in iter {
115 let curr = header;
116 let next = iter_peek.next();
117
118 let start = curr.bag_id as usize;
119
120 let end = if let Some(next) = next {
121 next.bag_id as usize
122 } else {
123 zones.len()
124 };
125
126 let zone_items = get_zones(zones, modulators, generators, start, end);
127
128 if header.name != "EOS" {
130 list.push(Instrument {
131 header: header.clone(),
132 zones: zone_items,
133 })
134 }
135 }
136 list
137 };
138
139 let presets = {
140 let headers = &data.hydra.preset_headers;
141 let zones = &data.hydra.preset_bags;
142 let modulators = &data.hydra.preset_modulators;
143 let generators = &data.hydra.preset_generators;
144
145 let iter = headers.iter();
146 let mut iter_peek = headers.iter();
147 iter_peek.next();
149
150 let mut list = Vec::new();
151 for header in iter {
152 let curr = header;
153 let next = iter_peek.next();
154
155 let start = curr.bag_id as usize;
156
157 let end = if let Some(next) = next {
158 next.bag_id as usize
159 } else {
160 zones.len()
161 };
162
163 let zone_items = get_zones(zones, modulators, generators, start, end);
164
165 if header.name != "EOP" {
167 list.push(Preset {
168 header: header.clone(),
169 zones: zone_items,
170 })
171 }
172 }
173
174 list
175 };
176
177 Self {
178 info: data.info,
179 presets,
180 instruments,
181 sample_headers: data
182 .hydra
183 .sample_headers
184 .into_iter()
185 .filter(|h| h.name != "EOS")
187 .collect(),
188 sample_data: data.sample_data,
189 }
190 }
191
192 pub fn sort_presets(mut self) -> Self {
193 self.presets.sort_by(|a, b| {
194 let aval = (a.header.bank as i32) << 16 | a.header.preset as i32;
195 let bbal = (b.header.bank as i32) << 16 | b.header.preset as i32;
196 let cmp = aval - bbal;
197
198 cmp.cmp(&0)
199 });
200 self
201 }
202}
203
204#[derive(Debug, Clone)]
205pub struct Zone {
206 pub mod_list: Vec<Modulator>,
207 pub gen_list: Vec<Generator>,
208}
209
210impl Zone {
211 pub fn key_range(&self) -> Option<&i16> {
212 self.gen_list
213 .iter()
214 .find(|g| g.ty == GeneratorType::KeyRange)
215 .map(|g| g.amount.as_i16().unwrap())
216 }
217 pub fn vel_range(&self) -> Option<&GeneratorAmountRange> {
218 self.gen_list
219 .iter()
220 .find(|g| g.ty == GeneratorType::VelRange)
221 .map(|g| g.amount.as_range().unwrap())
222 }
223 pub fn instrument(&self) -> Option<&u16> {
224 self.gen_list
225 .iter()
226 .find(|g| g.ty == GeneratorType::Instrument)
227 .map(|g| g.amount.as_u16().unwrap())
228 }
229 pub fn sample(&self) -> Option<&u16> {
230 self.gen_list
231 .iter()
232 .find(|g| g.ty == GeneratorType::SampleID)
233 .map(|g| g.amount.as_u16().unwrap())
234 }
235}
236
237#[derive(Debug, PartialEq, Eq, Copy, Clone)]
244pub enum SfEnum<T, RAW> {
245 Value(T),
246 Unknown(RAW),
247}
248
249impl<T: PartialEq, RAW> PartialEq<T> for SfEnum<T, RAW> {
250 #[inline]
251 fn eq(&self, other: &T) -> bool {
252 if let Self::Value(ty) = self {
253 ty == other
254 } else {
255 false
256 }
257 }
258}