Move parser code into parser.rs.

Create lib.
This commit is contained in:
Pedro de Oliveira 2023-04-30 00:00:10 +01:00
parent c9092a6e36
commit 5655b00adc
3 changed files with 332 additions and 330 deletions

1
src/lib.rs Normal file
View File

@ -0,0 +1 @@
pub mod parser;

View File

@ -1,335 +1,7 @@
use nom::bytes::streaming::tag;
use nom::number;
#[derive(Clone, Copy, Debug)]
pub enum Codec {
Pcm8BitUnsigned,
Adpcm4to8,
Adpcm3to8,
Adpcm2to8,
Pcm16BitSigned,
Alaw,
Ulaw,
Adpcm4to16,
}
#[derive(Debug)]
pub enum BlockType {
Terminator,
SoundData {
sample_rate: u32,
codec: Codec,
data: Vec<u8>,
},
SoundDataContinuation {
data: Vec<u8>,
},
Silence {
length: u16,
sample_rate: u32,
},
Marker {
value: u16,
},
Text {
data: Vec<u8>,
},
RepeatStart {
count: u16,
},
RepeatEnd,
ExtraInformation {
sample_rate: u32,
codec: Codec,
channels: u8,
},
SoundDataNew {
sample_rate: u32,
bits: u8,
channels: u8,
codec: Codec,
reserved: u32,
data: Vec<u8>,
},
}
impl BlockType {
pub fn info(&self) {
match self {
BlockType::Terminator => println!("Terminator"),
BlockType::SoundData {
sample_rate,
codec,
data,
} => {
println!(
"Sound data: sample rate = {}, codec = {:?}, size = {}",
sample_rate,
codec,
data.len()
)
}
BlockType::SoundDataContinuation { data } => {
println!("Sound data continuation: size = {}", data.len())
}
BlockType::Silence {
length,
sample_rate,
} => {
println!(
"Silence: length = {}, sample rate = {}",
length, sample_rate
)
}
BlockType::Marker { value } => {
println!("Marker: value = {}", value)
}
BlockType::Text { data } => {
println!("Text: size = {}", data.len())
}
BlockType::RepeatStart { count } => {
println!("Repeat: repetitions = {}", count)
}
BlockType::RepeatEnd => {
println!("End repeat")
}
BlockType::ExtraInformation {sample_rate, codec, channels} => println!(
"Extra information: sample rate = {}, channels = {}, codec = {:?}",
sample_rate,
channels,
codec,
),
BlockType::SoundDataNew {
sample_rate, bits, channels, codec, reserved, data
} => println!(
"Sound data (NEW): sample rate = {}, bits = {}, channels = {}, codec = {:?}, reserved: {}, size = {}",
sample_rate,
bits,
channels,
codec,
reserved,
data.len()
)
}
}
}
#[derive(Debug)]
pub struct Version {
major: u8,
minor: u8,
}
#[derive(Debug)]
pub struct Checksum {
value: u16,
valid: bool,
}
#[derive(Debug)]
pub struct Voc {
version: Version,
checksum: Checksum,
blocks: Vec<BlockType>,
}
fn parse_sound_data(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
let (input, block_size) = number::streaming::le_u24(input)?;
let (input, frequency_divisor) = number::streaming::le_u8(input)?;
let (input, codec_id) = number::streaming::le_u8(input)?;
let sample_rate: u32 = 1000000_u32 / (256_u32 - frequency_divisor as u32);
let codec = match codec_id {
0 => Codec::Pcm8BitUnsigned,
1 => Codec::Adpcm4to8,
2 => Codec::Adpcm3to8,
3 => Codec::Adpcm2to8,
4 => Codec::Pcm16BitSigned,
5 => Codec::Alaw,
6 => Codec::Ulaw,
_ => panic!("Invalid sound format"),
};
let (input, data) = nom::bytes::complete::take(block_size - 2)(input)?;
Ok((
input,
BlockType::SoundData {
sample_rate,
codec,
data: data.to_vec(),
},
))
}
fn parse_sound_data_continuation(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
let (input, block_size) = number::streaming::le_u24(input)?;
let (input, data) = nom::bytes::complete::take(block_size)(input)?;
Ok((
input,
BlockType::SoundDataContinuation {
data: data.to_vec(),
},
))
}
fn parse_silence(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
let (input, _) = number::streaming::le_u16(input)?;
let (input, length) = number::streaming::le_u16(input)?;
let (input, frequency_divisor) = number::streaming::le_u8(input)?;
let sample_rate: u32 = 1000000_u32 / (256_u32 - frequency_divisor as u32);
Ok((
input,
BlockType::Silence {
length: length - 1,
sample_rate,
},
))
}
fn parse_marker(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
let (input, _) = number::streaming::le_u16(input)?;
let (input, value) = number::streaming::le_u16(input)?;
Ok((input, BlockType::Marker { value }))
}
fn parse_text(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
let (input, block_size) = number::streaming::le_u24(input)?;
let (input, data) = nom::bytes::complete::take(block_size)(input)?;
Ok((
input,
BlockType::Text {
data: data.to_vec(),
},
))
}
fn parse_repeat_start(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
let (input, _) = number::streaming::le_u24(input)?;
let (input, count) = number::streaming::le_u16(input)?;
Ok((input, BlockType::RepeatStart { count }))
}
fn parse_extra_information(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
let (input, _) = number::streaming::le_u24(input)?;
let (input, frequency_divisor) = number::streaming::le_u16(input)?;
let (input, codec_id) = number::streaming::le_u8(input)?;
let (input, channels) = number::streaming::le_u8(input)?;
let codec = match codec_id {
0 => Codec::Pcm8BitUnsigned,
1 => Codec::Adpcm4to8,
2 => Codec::Adpcm3to8,
3 => Codec::Adpcm2to8,
4 => Codec::Pcm16BitSigned,
5 => Codec::Alaw,
6 => Codec::Ulaw,
_ => panic!("Invalid sound format"),
};
let sample_rate: u32 =
256000000_u32 / ((channels as u32 + 1) * (65536 - frequency_divisor as u32));
Ok((
input,
BlockType::ExtraInformation {
sample_rate,
codec,
channels,
},
))
}
fn parse_sound_data_new(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
let (input, block_size) = number::streaming::le_u24(input)?;
let (input, sample_rate) = number::streaming::le_u32(input)?;
let (input, bits) = number::streaming::le_u8(input)?;
let (input, channels) = number::streaming::le_u8(input)?;
let (input, codec_id) = number::streaming::le_u16(input)?;
let (input, reserved) = number::streaming::le_u32(input)?;
let (input, data) = nom::bytes::complete::take(block_size - 12)(input)?;
let codec = match codec_id {
0 => Codec::Pcm8BitUnsigned,
1 => Codec::Adpcm4to8,
2 => Codec::Adpcm3to8,
3 => Codec::Adpcm2to8,
4 => Codec::Pcm16BitSigned,
5 => Codec::Alaw,
6 => Codec::Ulaw,
0x0200 => Codec::Adpcm4to16,
_ => panic!("Invalid sound format"),
};
Ok((
input,
BlockType::SoundDataNew {
sample_rate,
bits,
channels,
codec,
reserved,
data: data.to_vec(),
},
))
}
pub fn parse_block(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
let (input, block_type) = number::streaming::le_u8(input)?;
match block_type {
0 => Ok((input, BlockType::Terminator)),
1 => parse_sound_data(input),
2 => parse_sound_data_continuation(input),
3 => parse_silence(input),
4 => parse_marker(input),
5 => parse_text(input),
6 => parse_repeat_start(input),
7 => Ok((input, BlockType::RepeatEnd)),
8 => parse_extra_information(input),
9 => parse_sound_data_new(input),
_ => panic!("Invalid block type - {}", block_type),
}
}
pub fn parse_voc(input: &[u8]) -> nom::IResult<&[u8], Voc> {
let (input, _) = tag("Creative Voice File")(input)?;
let (input, _) = tag(&[0x1a, 0x1a, 0])(input)?;
let (input, version_minor) = number::streaming::le_u8(input)?;
let (input, version_major) = number::streaming::le_u8(input)?;
let (input, checksum) = number::streaming::le_u16(input)?;
// Calculate checksum from version
let checksum2 = (!i16::from_le_bytes([version_minor, version_major]) + 0x1234) as u16;
let valid = checksum == checksum2;
let mut blocks = Vec::new();
let mut remaining_input = input;
loop {
match parse_block(remaining_input) {
Ok((input, block)) => {
blocks.push(block);
remaining_input = input;
}
Err(nom::Err::Incomplete(_)) => {
break;
}
Err(err) => {
return Err(err);
}
}
}
Ok((
input,
Voc {
version: Version {
major: version_major,
minor: version_minor,
},
checksum: Checksum {
value: checksum,
valid,
},
blocks,
},
))
}
use vocnom::parser::parse_voc;
fn main() {
//let f = include_bytes!("../EDEN.MUS");
let f = include_bytes!("../ADOOR2.VOC");
let f = include_bytes!("../assets/GUARDIAN.VOC");
match parse_voc(f) {
Ok((_, voc)) => {
println!("Version: {}.{}", voc.version.major, voc.version.minor);

329
src/parser.rs Normal file
View File

@ -0,0 +1,329 @@
use nom::bytes::streaming::tag;
use nom::number;
#[derive(Eq, Debug, PartialEq)]
pub enum Codec {
Pcm8BitUnsigned,
Adpcm4to8,
Adpcm3to8,
Adpcm2to8,
Pcm16BitSigned,
Alaw,
Ulaw,
Adpcm4to16,
}
#[derive(Eq, Debug, PartialEq)]
pub enum BlockType {
Terminator,
SoundData {
sample_rate: u32,
codec: Codec,
data: Vec<u8>,
},
SoundDataContinuation {
data: Vec<u8>,
},
Silence {
length: u16,
sample_rate: u32,
},
Marker {
value: u16,
},
Text {
data: Vec<u8>,
},
RepeatStart {
count: u16,
},
RepeatEnd,
ExtraInformation {
sample_rate: u32,
codec: Codec,
channels: u8,
},
SoundDataNew {
sample_rate: u32,
bits: u8,
channels: u8,
codec: Codec,
reserved: u32,
data: Vec<u8>,
},
}
impl BlockType {
pub fn info(&self) {
match self {
BlockType::Terminator => println!("Terminator"),
BlockType::SoundData {
sample_rate,
codec,
data,
} => {
println!(
"Sound data: sample rate = {}, codec = {:?}, size = {}",
sample_rate,
codec,
data.len()
)
}
BlockType::SoundDataContinuation { data } => {
println!("Sound data continuation: size = {}", data.len())
}
BlockType::Silence {
length,
sample_rate,
} => {
println!(
"Silence: length = {}, sample rate = {}",
length, sample_rate
)
}
BlockType::Marker { value } => {
println!("Marker: value = {}", value)
}
BlockType::Text { data } => {
println!("Text: size = {}", data.len())
}
BlockType::RepeatStart { count } => {
println!("Repeat: repetitions = {}", count)
}
BlockType::RepeatEnd => {
println!("End repeat")
}
BlockType::ExtraInformation { sample_rate, codec, channels } => println!(
"Extra information: sample rate = {}, channels = {}, codec = {:?}",
sample_rate,
channels,
codec,
),
BlockType::SoundDataNew {
sample_rate, bits, channels, codec, reserved, data
} => println!(
"Sound data (NEW): sample rate = {}, bits = {}, channels = {}, codec = {:?}, reserved: {}, size = {}",
sample_rate,
bits,
channels,
codec,
reserved,
data.len()
)
}
}
}
#[derive(Debug)]
pub struct Version {
pub major: u8,
pub minor: u8,
}
#[derive(Debug)]
pub struct Checksum {
pub value: u16,
pub valid: bool,
}
#[derive(Debug)]
pub struct Voc {
pub version: Version,
pub checksum: Checksum,
pub blocks: Vec<BlockType>,
}
fn parse_sound_data(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
let (input, block_size) = number::streaming::le_u24(input)?;
let (input, frequency_divisor) = number::streaming::le_u8(input)?;
let (input, codec_id) = number::streaming::le_u8(input)?;
let sample_rate: u32 = 1000000_u32 / (256_u32 - frequency_divisor as u32);
let codec = match codec_id {
0 => Codec::Pcm8BitUnsigned,
1 => Codec::Adpcm4to8,
2 => Codec::Adpcm3to8,
3 => Codec::Adpcm2to8,
4 => Codec::Pcm16BitSigned,
5 => Codec::Alaw,
6 => Codec::Ulaw,
_ => panic!("Invalid sound format"),
};
let (input, data) = nom::bytes::complete::take(block_size - 2)(input)?;
Ok((
input,
BlockType::SoundData {
sample_rate,
codec,
data: data.to_vec(),
},
))
}
fn parse_sound_data_continuation(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
let (input, block_size) = number::streaming::le_u24(input)?;
let (input, data) = nom::bytes::complete::take(block_size)(input)?;
Ok((
input,
BlockType::SoundDataContinuation {
data: data.to_vec(),
},
))
}
fn parse_silence(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
let (input, _) = number::streaming::le_u16(input)?;
let (input, length) = number::streaming::le_u16(input)?;
let (input, frequency_divisor) = number::streaming::le_u8(input)?;
let sample_rate: u32 = 1000000_u32 / (256_u32 - frequency_divisor as u32);
Ok((
input,
BlockType::Silence {
length: length - 1,
sample_rate,
},
))
}
fn parse_marker(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
let (input, _) = number::streaming::le_u16(input)?;
let (input, value) = number::streaming::le_u16(input)?;
Ok((input, BlockType::Marker { value }))
}
fn parse_text(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
let (input, block_size) = number::streaming::le_u24(input)?;
let (input, data) = nom::bytes::complete::take(block_size)(input)?;
Ok((
input,
BlockType::Text {
data: data.to_vec(),
},
))
}
fn parse_repeat_start(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
let (input, _) = number::streaming::le_u24(input)?;
let (input, count) = number::streaming::le_u16(input)?;
Ok((input, BlockType::RepeatStart { count }))
}
fn parse_extra_information(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
let (input, _) = number::streaming::le_u24(input)?;
let (input, frequency_divisor) = number::streaming::le_u16(input)?;
let (input, codec_id) = number::streaming::le_u8(input)?;
let (input, channels) = number::streaming::le_u8(input)?;
let codec = match codec_id {
0 => Codec::Pcm8BitUnsigned,
1 => Codec::Adpcm4to8,
2 => Codec::Adpcm3to8,
3 => Codec::Adpcm2to8,
4 => Codec::Pcm16BitSigned,
5 => Codec::Alaw,
6 => Codec::Ulaw,
_ => panic!("Invalid sound format"),
};
let sample_rate: u32 =
256000000_u32 / ((channels as u32 + 1) * (65536 - frequency_divisor as u32));
Ok((
input,
BlockType::ExtraInformation {
sample_rate,
codec,
channels,
},
))
}
fn parse_sound_data_new(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
let (input, block_size) = number::streaming::le_u24(input)?;
let (input, sample_rate) = number::streaming::le_u32(input)?;
let (input, bits) = number::streaming::le_u8(input)?;
let (input, channels) = number::streaming::le_u8(input)?;
let (input, codec_id) = number::streaming::le_u16(input)?;
let (input, reserved) = number::streaming::le_u32(input)?;
let (input, data) = nom::bytes::complete::take(block_size - 12)(input)?;
let codec = match codec_id {
0 => Codec::Pcm8BitUnsigned,
1 => Codec::Adpcm4to8,
2 => Codec::Adpcm3to8,
3 => Codec::Adpcm2to8,
4 => Codec::Pcm16BitSigned,
5 => Codec::Alaw,
6 => Codec::Ulaw,
0x0200 => Codec::Adpcm4to16,
_ => panic!("Invalid sound format"),
};
Ok((
input,
BlockType::SoundDataNew {
sample_rate,
bits,
channels,
codec,
reserved,
data: data.to_vec(),
},
))
}
pub fn parse_block(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
let (input, block_type) = number::streaming::le_u8(input)?;
match block_type {
0 => Ok((input, BlockType::Terminator)),
1 => parse_sound_data(input),
2 => parse_sound_data_continuation(input),
3 => parse_silence(input),
4 => parse_marker(input),
5 => parse_text(input),
6 => parse_repeat_start(input),
7 => Ok((input, BlockType::RepeatEnd)),
8 => parse_extra_information(input),
9 => parse_sound_data_new(input),
_ => panic!("Invalid block type - {}", block_type),
}
}
pub fn parse_voc(input: &[u8]) -> nom::IResult<&[u8], Voc> {
let (input, _) = tag("Creative Voice File")(input)?;
let (input, _) = tag(&[0x1a, 0x1a, 0])(input)?;
let (input, version_minor) = number::streaming::le_u8(input)?;
let (input, version_major) = number::streaming::le_u8(input)?;
let (input, checksum) = number::streaming::le_u16(input)?;
// Calculate checksum from version
let checksum2 = (!i16::from_le_bytes([version_minor, version_major]) + 0x1234) as u16;
let valid = checksum == checksum2;
let mut blocks = Vec::new();
let mut remaining_input = input;
loop {
match parse_block(remaining_input) {
Ok((input, block)) => {
blocks.push(block);
remaining_input = input;
}
Err(nom::Err::Incomplete(_)) => {
break;
}
Err(err) => {
return Err(err);
}
}
}
Ok((
input,
Voc {
version: Version {
major: version_major,
minor: version_minor,
},
checksum: Checksum {
value: checksum,
valid,
},
blocks,
},
))
}