First commit

This commit is contained in:
Pedro de Oliveira 2022-11-09 00:47:32 +00:00
commit 735cd11a16
4 changed files with 224 additions and 0 deletions

7
Cargo.lock generated Normal file
View File

@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "voctool"
version = "0.1.0"

8
Cargo.toml Normal file
View File

@ -0,0 +1,8 @@
[package]
name = "voctool"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

36
README.md Normal file
View File

@ -0,0 +1,36 @@
# Original Lost Eden VOC file
```
Voc { type: ASCII, size: 536 }
Voc { type: SoundData, size: 234941, sample_rate: 11111, audio_format: Pcm8BitUnsigned }
Voc { type: Terminator, size: 0 }
```
# VOC file created with sox
`sox pestaninhas.mp3 -r 11111 -b 8 pest.voc`
```
Voc { type: SoundData, size: 153252, sample_rate: 11111, audio_format: Pcm8BitUnsigned }
Voc { type: Terminator, size: 0 }
```
# VOC file created with ffmpeg
`ffmpeg -i untitled.wav -ar 11111 -f s8 aids.voc`
```
Voc { type: SoundData, size: 487, sample_rate: 11111, audio_format: Pcm8BitUnsigned }
Voc { type: SoundContinue, size: 500 }
Voc { type: SoundContinue, size: 501 }
Voc { type: SoundContinue, size: 500 }
Voc { type: SoundContinue, size: 501 }
Voc { type: SoundContinue, size: 501 }
...
...
Voc { type: SoundContinue, size: 500 }
Voc { type: SoundContinue, size: 160 }
Voc { type: SoundContinue, size: 17 }
Voc { type: Terminator, size: 0 }
Found block type 0. Exiting
```

173
src/main.rs Normal file
View File

@ -0,0 +1,173 @@
use std::fmt;
use std::fs::File;
use std::io::{Read, Seek, SeekFrom};
#[derive(Debug)]
enum Compression {
Pcm8BitUnsigned,
Adpcm4to8,
Adpcm3to8,
Adpcm2to8,
Pcm16BitSigned,
Alaw1,
Alaw2,
Adpcm4to16
}
#[derive(Debug, PartialEq)]
enum BlockType {
Terminator,
SoundData,
SoundContinue,
Silence,
Marker,
ASCII,
Repeat,
EndRepeat
}
struct DataBlock {
block_type: BlockType,
block_size: i32,
sample_rate: Option<i32>,
audio_format: Option<Compression>,
data: Vec<u8>,
}
impl fmt::Debug for DataBlock {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.block_type == BlockType::SoundData {
f.debug_struct("Voc")
.field("type", &self.block_type)
.field("size", &self.block_size)
.field("sample_rate", &self.sample_rate.unwrap())
.field("audio_format", &self.audio_format.as_ref().unwrap())
.finish()
} else {
f.debug_struct("Voc")
.field("type", &self.block_type)
.field("size", &self.block_size)
.finish()
}
}
}
fn parse_voc(file_name: &str) {
println!("Parsing {} ...", file_name);
let mut fp = File::open(file_name).unwrap();
// Signature - Creative Voice File
let mut signature1_buffer: [u8; 19] = [0; 19];
std::mem::drop(fp.read(&mut signature1_buffer));
let signature1_expected = "Creative Voice File";
let signature1 = std::str::from_utf8(&signature1_buffer).unwrap();
if signature1 != signature1_expected {
panic!("Bad file. Expected \"{}\" got \"{}\"", signature1_expected, signature1);
}
// Signature - 1A 1A 00
let mut signature2_buffer: [u8; 3] = [0; 3];
std::mem::drop(fp.read(&mut signature2_buffer));
let signature2_expected: [u8; 3] = [0x1A, 0x1A, 0x0];
if signature2_buffer != signature2_expected {
panic!("Bad file. Expected {:02X?} got {:02X?}", signature2_expected, signature2_buffer);
}
// Version
let mut version_buffer: [u8; 2] = [0; 2];
std::mem::drop(fp.read(&mut version_buffer));
let version_int = i16::from_le_bytes(version_buffer);
let version = (version_buffer[1], version_buffer[0]);
// Version checksum
let mut checksum_buffer: [u8; 2] = [0; 2];
std::mem::drop(fp.read(&mut checksum_buffer));
let checksum = (!version_int + 0x1234).to_le_bytes();
if checksum_buffer != checksum {
panic!("Bad file. Expected {:02X?} got {:02X?}", checksum, checksum_buffer);
}
loop {
let mut block_type_buffer: [u8; 1] = [0];
std::mem::drop(fp.read(&mut block_type_buffer));
let block_type = match block_type_buffer[0] {
0 => BlockType::Terminator,
1 => BlockType::SoundData,
2 => BlockType::SoundContinue,
3 => BlockType::Silence,
4 => BlockType::Marker,
5 => BlockType::ASCII,
6 => BlockType::Repeat,
7 => BlockType::EndRepeat,
_ => panic!("Bad block type. Got {}", block_type_buffer[0])
};
if block_type == BlockType::Terminator {
let data_block = DataBlock { block_type, block_size: 0, sample_rate: None, audio_format: None, data: Vec::new() };
println!("{:?}", data_block);
println!("Found block type 0. Exiting");
break;
}
let mut block_size_buffer: [u8; 3] = [0; 3];
std::mem::drop(fp.read(&mut block_size_buffer));
let block_size = i32::from_le_bytes(
[block_size_buffer[0], block_size_buffer[1], block_size_buffer[2], 0]
);
let mut address = fp.seek(SeekFrom::Current(0)).unwrap() as i32;
let next = address + block_size;
let mut data_block: DataBlock;
match block_type {
BlockType::SoundData => {
let mut sample_rate_buffer: [u8; 1] = [0];
std::mem::drop(fp.read(&mut sample_rate_buffer));
let sample_rate: i32 = 1000000i32 / (256i32 - sample_rate_buffer[0] as i32);
let mut audio_format_buffer: [u8; 1] = [0];
std::mem::drop(fp.read(&mut audio_format_buffer));
let audio_format = match audio_format_buffer[0] {
0 => Compression::Pcm8BitUnsigned,
1 => Compression::Adpcm4to8,
2 => Compression::Adpcm3to8,
3 => Compression::Adpcm2to8,
4 => Compression::Pcm16BitSigned,
5 => Compression::Alaw1,
6 => Compression::Alaw2,
7 => Compression::Adpcm4to16,
_ => panic!("Bad Sound format. Got {}", audio_format_buffer[0])
};
address = fp.seek(SeekFrom::Current(0)).unwrap() as i32;
let mut data: Vec<u8> = vec![0; (next - address) as usize];
std::mem::drop(fp.read(&mut data));
data_block = DataBlock { block_type, block_size, sample_rate: Some(sample_rate), audio_format: Some(audio_format), data };
},
BlockType::SoundContinue => {
let mut data: Vec<u8> = vec![0; (next - address) as usize];
std::mem::drop(fp.read(&mut data));
data_block = DataBlock { block_type, block_size, sample_rate: None, audio_format: None, data };
},
BlockType::ASCII => {
let mut data: Vec<u8> = vec![0; (next - address) as usize];
std::mem::drop(fp.read(&mut data));
data_block = DataBlock { block_type, block_size, sample_rate: None, audio_format: None, data };
},
_ => panic!("block Type {:?} not implemented", block_type),
}
println!("{:?}", data_block);
}
}
fn main() {
parse_voc("_C24FF78A.voc");
parse_voc("pest.voc");
parse_voc("C24FF78A.voc");
parse_voc("pest2.voc");
}