1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
use super::utils::Reader;
use crate::error::MissingChunk;
use crate::riff::{Chunk, ScratchReader};
use crate::{error::Error, riff::ChunkId};
use std::io::{Read, Seek};
#[derive(Debug)]
pub struct Version {
pub major: u16,
pub minor: u16,
}
impl Version {
fn from_bytes(bytes: [u8; 32]) -> Self {
Version {
major: u16::from_le_bytes([bytes[0], bytes[1]]),
minor: u16::from_le_bytes([bytes[2], bytes[3]]),
}
}
}
/// Supplemental Information
#[derive(Debug)]
pub struct Info {
/// Refers to the version of the Sound Font RIFF file
pub version: Version,
/// Refers to the target Sound Engine
pub sound_engine: String,
/// Refers to the Sound Font Bank Name
pub bank_name: String,
/// Refers to the Sound ROM Name
pub rom_name: Option<String>,
/// Refers to the Sound ROM Version
pub rom_version: Option<Version>,
/// Refers to the Date of Creation of the Bank
pub creation_date: Option<String>,
/// Sound Designers and Engineers for the Bank
pub engineers: Option<String>,
/// Product for which the Bank was intended
pub product: Option<String>,
/// Contains any Copyright message
pub copyright: Option<String>,
/// Contains any Comments on the Bank
pub comments: Option<String>,
/// The SoundFont tools used to create and alter the bank
pub software: Option<String>,
}
impl Info {
pub(crate) fn read(
info: &Chunk,
file: &mut ScratchReader<impl Read + Seek>,
) -> Result<Self, Error> {
assert_eq!(info.id(), ChunkId::LIST);
assert_eq!(info.read_type(file)?, ChunkId::INFO);
let mut version = None;
let mut sound_engine = None;
let mut bank_name = None;
let mut rom_name = None;
let mut rom_version = None;
let mut creation_date = None;
let mut engineers = None;
let mut product = None;
let mut copyright = None;
let mut comments = None;
let mut software = None;
let mut iter = info.iter();
while let Some(ch) = iter.next(file) {
let ch = ch?;
let id = ch.id();
match id {
// Refers to the version of the Sound Font RIFF file
ChunkId::ifil => {
let mut bytes = [0u8; 32];
ch.read_to(file, &mut bytes)?;
version = Some(Version::from_bytes(bytes));
}
// Refers to the target Sound Engine
ChunkId::isng => {
let data = ch.read_contents(file)?;
let mut data = Reader::new(data);
sound_engine = Some(data.read_string(ch.len() as usize)?);
}
// Refers to the Sound Font Bank Name
ChunkId::INAM => {
let data = ch.read_contents(file)?;
let mut data = Reader::new(data);
bank_name = Some(data.read_string(ch.len() as usize)?);
}
// Refers to the Sound ROM Name
ChunkId::irom => {
let data = ch.read_contents(file)?;
let mut data = Reader::new(data);
rom_name = Some(data.read_string(ch.len() as usize)?);
}
// Refers to the Sound ROM Version
ChunkId::iver => {
let mut bytes = [0u8; 32];
ch.read_to(file, &mut bytes)?;
rom_version = Some(Version::from_bytes(bytes));
}
// Refers to the Date of Creation of the Bank
ChunkId::ICRD => {
let data = ch.read_contents(file)?;
let mut data = Reader::new(data);
creation_date = Some(data.read_string(ch.len() as usize)?);
}
// Sound Designers and Engineers for the Bank
ChunkId::IENG => {
let data = ch.read_contents(file)?;
let mut data = Reader::new(data);
engineers = Some(data.read_string(ch.len() as usize)?);
}
// Product for which the Bank was intended
ChunkId::IPRD => {
let data = ch.read_contents(file)?;
let mut data = Reader::new(data);
product = Some(data.read_string(ch.len() as usize)?);
}
// Contains any Copyright message
ChunkId::ICOP => {
let data = ch.read_contents(file)?;
let mut data = Reader::new(data);
copyright = Some(data.read_string(ch.len() as usize)?);
}
// Contains any Comments on the Bank
ChunkId::ICMT => {
let data = ch.read_contents(file)?;
let mut data = Reader::new(data);
comments = Some(data.read_string(ch.len() as usize)?);
}
// The SoundFont tools used to create and alter the bank
ChunkId::ISFT => {
let data = ch.read_contents(file)?;
let mut data = Reader::new(data);
software = Some(data.read_string(ch.len() as usize)?);
}
_ => {
return Err(Error::UnexpectedMemberOfInfo(ch));
}
}
}
Ok(Info {
version: version.ok_or(MissingChunk::Version)?,
// Those two are requited by the specs, but you can often find files without them
// so that's why `unwrap_or_default` is used.
sound_engine: sound_engine.unwrap_or_default(),
bank_name: bank_name.unwrap_or_default(),
rom_name,
rom_version,
creation_date,
engineers,
product,
copyright,
comments,
software,
})
}
}