reading of wav files is ready

This commit is contained in:
Данила Горнушко 2024-05-27 18:55:07 +03:00
parent c9f1c0968e
commit ced5884733
3 changed files with 40 additions and 6 deletions

1
.gitignore vendored
View file

@ -1 +1,2 @@
/target /target
/out/

View file

@ -3,6 +3,7 @@
<component name="NewModuleRootManager"> <component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$"> <content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/out" />
<excludeFolder url="file://$MODULE_DIR$/target" /> <excludeFolder url="file://$MODULE_DIR$/target" />
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />

View file

@ -1,15 +1,15 @@
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use clap::Parser; use clap::Parser;
use crc::{Crc, CRC_16_IBM_3740}; use crc::{Crc, CRC_16_IBM_3740};
use hound::{SampleFormat, WavSpec, WavWriter};
use log::{debug, error, info, LevelFilter}; use log::{debug, error, info, LevelFilter};
use serialport::SerialPort; use serialport::SerialPort;
use std::collections::HashMap; use std::collections::HashMap;
use std::io::{BufRead, BufReader, Read, Write}; use std::io::{BufRead, BufReader, Read, Write};
use std::slice;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use hound::{WavSpec, SampleFormat, WavWriter};
use std::fs::File;
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
const MAX_DATA_LEN: usize = 1024 * 2 + 4 + 2; const MAX_DATA_LEN: usize = 1024 * 2 + 4 + 2;
@ -70,7 +70,7 @@ fn main() {
channels: 1, channels: 1,
sample_rate: get_sample_rate(&mut port, args.device_id), sample_rate: get_sample_rate(&mut port, args.device_id),
bits_per_sample: 16, bits_per_sample: 16,
sample_format: hound::SampleFormat::Int, sample_format: SampleFormat::Int,
}; };
info!("Starting main loop..."); info!("Starting main loop...");
@ -106,6 +106,22 @@ fn main() {
match get_chunk(&mut port, args.device_id, args.baud_rate, winsize) { match get_chunk(&mut port, args.device_id, args.baud_rate, winsize) {
Some(data) => { Some(data) => {
info!("Received new data with len: {}", data.len()); info!("Received new data with len: {}", data.len());
let timestamp_ms = current_timestamp_ms();
let filename = format!("./out/wave_{}.wav", timestamp_ms);
// Create a new WAV file
let mut writer = WavWriter::create(&filename, spec)
.expect("Can't create new WAV file!");
let mut i16_writer = writer.get_i16_writer(data.len() as u32);
for sample in data {
unsafe {
i16_writer.write_sample_unchecked(sample);
}
}
i16_writer.flush().expect("Something went wrong while writing WAV file");
info!("WAV file {} has been written.", filename);
err_counter = err_counter.saturating_sub(1); err_counter = err_counter.saturating_sub(1);
last_chunk_id = cur_chunk_id; last_chunk_id = cur_chunk_id;
} }
@ -286,7 +302,7 @@ fn get_chunk(
id: u32, id: u32,
baud_rate: u32, baud_rate: u32,
win_size: usize, win_size: usize,
) -> Option<Vec<u8>> { ) -> Option<Vec<i16>> {
let command = format!("@{} convbuf\n", id); let command = format!("@{} convbuf\n", id);
debug!("Writing convbuf to the serial port"); debug!("Writing convbuf to the serial port");
port.write_all(command.as_bytes()) port.write_all(command.as_bytes())
@ -335,7 +351,9 @@ fn get_chunk(
None None
} else { } else {
debug!("CRC is correct!"); debug!("CRC is correct!");
Some(data_buf.to_vec()) // converting raw bytes to correct format
Some(convert_to_i16(data_buf))
} }
} }
_ => { _ => {
@ -345,6 +363,19 @@ fn get_chunk(
} }
} }
fn convert_to_i16(buffer: &[u8]) -> Vec<i16> {
assert_eq!(buffer.len() % 2, 0, "Buffer length must be a multiple of 2.");
let len = buffer.len() / 2; // Number of i16 elements
let ptr = buffer.as_ptr() as *const i16;
// Safety: We are transmuting the buffer from u8 to i16, ensuring that the types have the same size
// and alignment requirements. We also ensure that the buffer length is valid for transmuting.
unsafe {
let i16_slice = slice::from_raw_parts(ptr, len);
i16_slice.to_vec() // Convert the slice to a Vec<i16>
}
}
fn header_is_ok(vec: &[u8]) -> bool { fn header_is_ok(vec: &[u8]) -> bool {
vec.get(0..4) vec.get(0..4)
.map(|bytes| u32::from_be_bytes(bytes.try_into().unwrap())) .map(|bytes| u32::from_be_bytes(bytes.try_into().unwrap()))
@ -358,7 +389,8 @@ fn exp_buf_size(win_size: usize) -> usize {
fn current_timestamp_ms() -> u128 { fn current_timestamp_ms() -> u128 {
let start = SystemTime::now(); let start = SystemTime::now();
let since_the_epoch = start.duration_since(UNIX_EPOCH) let since_the_epoch = start
.duration_since(UNIX_EPOCH)
.expect("Time went backwards"); .expect("Time went backwards");
since_the_epoch.as_millis() since_the_epoch.as_millis()
} }