Skip to content

Commit 9a9011e

Browse files
authored
Merge pull request #7 from TheAwiteb/create-the-header
Create the wave header, and append the data to it
2 parents 7e0782d + 5ef14a1 commit 9a9011e

File tree

6 files changed

+46
-45
lines changed

6 files changed

+46
-45
lines changed

Cargo.toml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "data2sound"
3-
description = "A library to convert data to sound, and vice versa"
3+
description = "A library to convert data to sound, and vice versa (dependency-free)"
44
version = "0.1.6"
55
rust-version = "1.56.1"
66
edition = "2021"
@@ -15,8 +15,6 @@ categories = ["multimedia::audio"]
1515
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
1616

1717
[dependencies]
18-
file-utils = "= 0.1.5"
19-
hound = "= 3.5.0"
2018

2119

2220
[profile.release]
@@ -25,4 +23,4 @@ lto = true # Link-time optimization.
2523
debug = false # Disable debug info.
2624
codegen-units = 1 # Use a single codegen unit.
2725
panic = "abort" # Use abort instead of unwind.
28-
strip = true # Strip symbols.
26+
strip = true # Strip symbols.

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
# Data to sound
22
A simple crate to convert data to sound, and sound to data. The sound file format is wave (.wav).
3-
You can use it as a library or as a command line tool.
3+
You can use it as a library or as a command line tool. (dependency-free)
44

55
## Minimum supported Rust version
6-
The minimum supported Rust version is 1.56.1.
6+
The minimum supported Rust version is 1.59.0.
77

88
## Note
99
The sound frequency is 202860Hz (202.86kHz), and the sound is mono. The sound is encoded in 16 bits.
@@ -51,13 +51,13 @@ The following benchmarks were made on a 4.600GHz 12th Gen Intel i7-12700H CPU wi
5151
### Encoding
5252
| File size | Audio file size | Audio length | Speed | Link |
5353
|-----------|-----------------|------|-------| ---- |
54-
| 2687.94MB | 2687.94MB | 01:28:13 | 6.27s | [Soundcloud-link](https://soundcloud.com/awiteb/pop-os-2204-amd64-intel-23iso) |
55-
| 35.3MB | 35.3MB | 00:01::27 | 113.47ms | [Soundcloud-link](https://soundcloud.com/awiteb/rust-1671zip) |
54+
| 2687.94MB | 2687.94MB | 01:28:13 | 2.67s | [Soundcloud-link](https://soundcloud.com/awiteb/pop-os-2204-amd64-intel-23iso) |
55+
| 35.3MB | 35.3MB | 00:01::27 | 51.34ms | [Soundcloud-link](https://soundcloud.com/awiteb/rust-1671zip) |
5656
## Decoding
5757
| File size | Audio file size | Audio length | Speed | Link |
5858
|-----------|-----------------|------|-------| ---- |
59-
| 2687.94MB | 2687.94MB | 01:28:13 | 5.14s | [Soundcloud-link](https://soundcloud.com/awiteb/pop-os-2204-amd64-intel-23iso) |
60-
| 35.3MB | 35.3MB | 00:01::27 | 117.58ms | [Soundcloud-link](https://soundcloud.com/awiteb/rust-1671zip) |
59+
| 2687.94MB | 2687.94MB | 01:28:13 | 2.79s | [Soundcloud-link](https://soundcloud.com/awiteb/pop-os-2204-amd64-intel-23iso) |
60+
| 35.3MB | 35.3MB | 00:01::27 | 68.21ms | [Soundcloud-link](https://soundcloud.com/awiteb/rust-1671zip) |
6161

6262
## Disclaimer
6363
This tool was designed for educational purposes as it explains how to save data in an audio file. It is not recommended to exploit this thing to use cloud audio storage services to store your data, as your account may be banned.

src/errors.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,13 @@ pub type Result<T> = std::result::Result<T, Error>;
66
/// Error enum, used to return errors from the library.
77
#[derive(Debug)]
88
pub enum Error {
9-
/// Error from the hound crate
10-
Hound(hound::Error),
119
/// IO error, such as file not found
1210
Io(std::io::Error),
1311
/// Larg file size error (maxnimum file size is 4 GB)
1412
LargeFileSize,
1513
/// Invalid wav file error
1614
InvalidWavFile(String),
1715
}
18-
19-
impl From<hound::Error> for Error {
20-
fn from(err: hound::Error) -> Self {
21-
Error::Hound(err)
22-
}
23-
}
24-
2516
impl From<std::io::Error> for Error {
2617
fn from(err: std::io::Error) -> Self {
2718
Error::Io(err)
@@ -31,7 +22,6 @@ impl From<std::io::Error> for Error {
3122
impl fmt::Display for Error {
3223
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3324
match self {
34-
Error::Hound(err) => write!(f, "Hound error: {}", err),
3525
Error::Io(err) => write!(f, "IO error: {}", err),
3626
Error::LargeFileSize => write!(f, "File size is too large, maximum file size is 4 GB"),
3727
Error::InvalidWavFile(msg) => write!(f, "Invalid wav file, {}", msg),

src/lib.rs

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
use file_utils::read::Read;
21
use std::{
32
fs,
4-
io::{self, BufReader, BufWriter, Seek},
3+
io::{self, BufReader, BufWriter, Seek, Write},
54
path,
65
};
76

@@ -19,31 +18,23 @@ pub const SAMPLE_RATE: u32 = 202860;
1918
/// # Example
2019
/// ```rust|no_run
2120
/// use data2sound::encode;
22-
/// use std::fs;
23-
/// let file = fs::File::open("test.txt").unwrap();
24-
/// encode(file, "test.wav").unwrap();
21+
/// encode("test.txt", "test.wav").unwrap();
2522
/// ```
26-
pub fn encode(file: fs::File, wav_output: impl AsRef<path::Path>) -> Result<()> {
23+
pub fn encode(file: impl AsRef<path::Path>, wav_output: impl AsRef<path::Path>) -> Result<()> {
24+
let file = fs::File::open(file)?;
2725
utils::check_file_size(&file)?;
28-
let spec = hound::WavSpec {
29-
channels: 1,
30-
sample_rate: SAMPLE_RATE,
31-
bits_per_sample: 16,
32-
sample_format: hound::SampleFormat::Int,
33-
};
3426
let str_path = wav_output.as_ref().display().to_string();
3527
let wav_output = if !str_path.ends_with(".wav") {
3628
format!("{}.wav", wav_output.as_ref().display())
3729
} else {
3830
str_path
3931
};
40-
let mut writer = hound::WavWriter::create(wav_output, spec)?;
41-
42-
let mut file = BufReader::new(file);
43-
44-
while let Ok(byte) = file.read_i16() {
45-
writer.write_sample(byte)?;
46-
}
32+
let mut reader = BufReader::new(&file);
33+
let mut writer = BufWriter::new(fs::File::create(wav_output)?);
34+
// Write the wav header to the wav file
35+
writer.write_all(&utils::create_wav_header(file.metadata()?.len() as u32))?;
36+
// Copy the file to the wav file
37+
io::copy(&mut reader, &mut writer)?;
4738
Ok(())
4839
}
4940

@@ -78,7 +69,7 @@ mod tests {
7869
#[test]
7970
fn test_encode_decode() {
8071
fs::write("test.txt", "Some context").unwrap();
81-
encode(fs::File::open("test.txt").unwrap(), "test.wav").unwrap();
72+
encode("test.txt", "test.wav").unwrap();
8273
decode("test.wav", "test2.txt").unwrap();
8374
let file = fs::File::open("test.txt").unwrap();
8475
let file2 = fs::File::open("test2.txt").unwrap();

src/main.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use std::{env, fs};
2-
31
const HELP_MESSAGE: &str = r#"Usage: data2sound <command> <input> <output>
42
Commands:
53
encode, e Encode a file to a wav file
@@ -22,7 +20,7 @@ fn help() {
2220
}
2321

2422
fn try_main() -> data2sound::Result<()> {
25-
let args: Vec<String> = env::args().collect();
23+
let args: Vec<String> = std::env::args().collect();
2624
if args.iter().any(|arg| arg == "--version" || arg == "-v") {
2725
version()
2826
} else if args.iter().any(|arg| arg == "--help" || arg == "-h") || args.len() < 4 {
@@ -35,7 +33,7 @@ fn try_main() -> data2sound::Result<()> {
3533
let input = args.next().unwrap();
3634
let output = args.next().unwrap();
3735
match command.as_str() {
38-
"encode" | "e" => data2sound::encode(fs::File::open(input)?, output)?,
36+
"encode" | "e" => data2sound::encode(input, output)?,
3937
"decode" | "d" => data2sound::decode(input, output)?,
4038
_ => eprintln!(
4139
"Unknown command '{}' Run 'data2sound --help' for more information",

src/utils.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{Error, Result};
1+
use crate::{Error, Result, SAMPLE_RATE};
22
use std::fs;
33

44
/// Check the file size. The maximum file size is 4 GB.
@@ -20,3 +20,27 @@ pub(crate) fn check_wav_file_size(file: &fs::File) -> Result<()> {
2020
})
2121
.unwrap_or(Ok(()))
2222
}
23+
24+
/// Create the wave file header, the header is 44 bytes.
25+
/// ### Note
26+
/// - The `file_size` is the size of the file that will be encoded.
27+
/// - The bits per sample is 16.
28+
/// - The sample rate is 202860 Hz (202.86 kHz).
29+
/// - The number of channels is 1.
30+
pub(crate) fn create_wav_header(file_size: u32) -> [u8; 44] {
31+
let mut header = [0; 44];
32+
header[0..4].copy_from_slice(b"RIFF");
33+
header[4..8].copy_from_slice(&(file_size + 36).to_le_bytes());
34+
header[8..12].copy_from_slice(b"WAVE");
35+
header[12..16].copy_from_slice(b"fmt ");
36+
header[16..20].copy_from_slice(&16u32.to_le_bytes());
37+
header[20..22].copy_from_slice(&1u16.to_le_bytes());
38+
header[22..24].copy_from_slice(&1u16.to_le_bytes());
39+
header[24..28].copy_from_slice(&SAMPLE_RATE.to_le_bytes());
40+
header[28..32].copy_from_slice(&(SAMPLE_RATE * 2).to_le_bytes());
41+
header[32..34].copy_from_slice(&2u16.to_le_bytes());
42+
header[34..36].copy_from_slice(&16u16.to_le_bytes());
43+
header[36..40].copy_from_slice(b"data");
44+
header[40..44].copy_from_slice(&file_size.to_le_bytes());
45+
header
46+
}

0 commit comments

Comments
 (0)