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 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
use crate::error::WadError;
/// .MUS format magic bytes
pub const MUS_MAGIC: [u8; 4] = [0x4d, 0x55, 0x53, 0x1a];
/// Represents the Music header
///
/// Every `u16` are in little-endianess
#[derive(Clone, Debug)]
pub struct MusHeader {
/// .MUS file identifier "MUS" 0x1A
pub magic: [u8; 4],
/// Score length in bytes
pub song_len: u16,
/// Absolute file position of the score
pub song_start: u16,
/// Count of primary channels
pub channels: u16,
/// Count of secondary channels
pub sec_channels: u16,
/// Instrument count
pub instr_count: u16,
/// Reserved bytes
pub dummy: u16,
/// Variable-length part starts here
pub instruments: Vec<u16>
}
impl Default for MusHeader {
fn default() -> Self {
Self {
magic: [0, 0, 0, 0],
song_len: 0,
song_start: 0,
channels: 0,
sec_channels: 0,
instr_count: 0,
dummy: 0,
instruments: Vec::new()
}
}
}
impl From<&[u8]> for MusHeader {
fn from(value: &[u8]) -> Self {
Self {
magic: value[0..4]
.try_into()
.unwrap_or_default(),
song_len: u16::from_le_bytes(
value[4..6]
.try_into()
.unwrap_or_default()
),
song_start: u16::from_le_bytes(
value[6..8]
.try_into()
.unwrap_or_default()
),
channels: u16::from_le_bytes(
value[8..10]
.try_into()
.unwrap_or_default()
),
sec_channels: u16::from_le_bytes(
value[10..12]
.try_into()
.unwrap_or_default()
),
instr_count: u16::from_le_bytes(
value[12..14]
.try_into()
.unwrap_or_default()
),
dummy: u16::from_le_bytes(
value[14..16]
.try_into()
.unwrap_or_default()
),
instruments: Vec::new(),
}
}
}
/// Provides informations about the event to perform
pub struct MetaEvent(pub u8);
impl MetaEvent {
/// It is set when the event is followed by a delay
pub fn last (&self) -> bool {
self.0 & 0x80 != 0
}
/// Indicates the event type
pub fn event_type(&self) -> u8 {
(self.0 & 0x70) >> 4
}
/// The channel the event is played on
pub fn channel(&self) -> u8 {
self.0 & 0xf
}
}
/// Event 0
///
/// This event stops the given note playing on the channel
/// specified by the event
///
/// Other notes on the channel are left playing.
pub struct MusReleaseNote(pub u8);
impl MusReleaseNote {
/// Note number
pub fn note(&self) -> u8 {
self.0 & 0x7f
}
}
/// Event 1
///
/// Play the note
pub struct MusPlayNote(pub u8, pub u8);
impl MusPlayNote {
/// Note number
pub fn note(&self) -> u8 {
self.0 & 0x7f
}
/// If the volume flag is set, it will use the
/// volume stored in the next byte
///
/// Otherwise, it will use the volume of the previous note
/// on the channel
pub fn is_volume(&self) -> bool {
self.0 & 0x80 != 0
}
/// Get the volume
pub fn volume(&self) -> u8 {
self.1 & 0x7f
}
}
/// Event 3
///
/// A system event is a controller with no associated value
/// The following values are valid, with their corresponding MIDI controller numbers:
///
/// See here for more details: https://moddingwiki.shikadi.net/wiki/MUS_Format
pub struct MusSystemEvent(pub u8);
impl MusSystemEvent {
/// Returns the controller ID
pub fn controller(&self) -> u8 {
self.0 & 0x7f
}
}
/// Event 4
///
/// A controller assigned to a value
///
/// See here for more details: https://moddingwiki.shikadi.net/wiki/MUS_Format
///
pub struct MusController(pub u8, pub u8);
impl MusController {
/// Returns the controller ID
pub fn controller(&self) -> u8 {
self.0 & 0x7f
}
/// Returns the controller value
pub fn value(&self) -> u8 {
self.1 & 0x7f
}
}
/// Represents a MUS file with tis metadata
#[derive(Clone)]
pub struct Mus {
/// Header
header: MusHeader,
/// Raw events content
event_buffer: Vec<u8>
}
impl Default for Mus {
fn default() -> Self {
Self {
header: MusHeader::default(),
event_buffer: Vec::new()
}
}
}
impl Mus {
pub fn new() -> Self {
Self::default()
}
/// Borrows the header
pub fn header(&self) -> &MusHeader {
&self.header
}
/// Borrows a event_buffer copy
pub fn event_buffer(&self) -> &Vec<u8> {
&self.event_buffer
}
/// Borrows a event_buffer copy
pub fn event_buffer_mut(&mut self) -> &mut Vec<u8> {
&mut self.event_buffer
}
}
impl From<&[u8]> for Mus {
fn from(value: &[u8]) -> Self {
let header = MusHeader::from(value);
let offset = (16 + (header.instr_count * 2)) as usize;
let event_buffer = value[offset..].to_vec();
Self {
header,
event_buffer
}
}
}
/// Take a value `value` that represents the MUS controller value
/// then convert it as a MIDI one
pub fn controller_as_midi(
value: u8
) -> Result<u8, WadError> {
let ret = match value {
0 | 1 => 0,
2 => 1,
3 => 7,
4 => 10,
5 => 11,
6 => 91,
7 => 93,
8 => 64,
9 => 67,
10 => 120,
11 => 123,
12 => 126,
13 => 127,
14 => 121,
_ => return Err(WadError::InvalidLump)
};
Ok(ret)
}