use std::io::Write;
use std::path::Path;
pub fn generate_wav(
path: &Path,
sample_rate: u32,
channels: u16,
duration_secs: f32,
bit_depth: u16,
) {
let bytes_per_sample = bit_depth / 8;
let block_align = channels * bytes_per_sample;
let byte_rate = sample_rate * block_align as u32;
let num_samples = (sample_rate as f32 * duration_secs) as u32;
let data_size = num_samples * block_align as u32;
let file_size = 4 + 24 + 8 + data_size;
let mut file = std::fs::File::create(path).expect("failed to create WAV file");
file.write_all(b"RIFF").unwrap();
file.write_all(&file_size.to_le_bytes()).unwrap();
file.write_all(b"WAVE").unwrap();
file.write_all(b"fmt ").unwrap();
file.write_all(&16u32.to_le_bytes()).unwrap(); file.write_all(&1u16.to_le_bytes()).unwrap(); file.write_all(&channels.to_le_bytes()).unwrap();
file.write_all(&sample_rate.to_le_bytes()).unwrap();
file.write_all(&byte_rate.to_le_bytes()).unwrap();
file.write_all(&block_align.to_le_bytes()).unwrap();
file.write_all(&bit_depth.to_le_bytes()).unwrap();
file.write_all(b"data").unwrap();
file.write_all(&data_size.to_le_bytes()).unwrap();
let zeros = [0u8; 4096];
let mut remaining = data_size as usize;
while remaining > 0 {
let chunk = remaining.min(zeros.len());
file.write_all(&zeros[..chunk]).unwrap();
remaining -= chunk;
}
file.flush().unwrap();
}
pub fn generate_wav_tone(path: &Path, sample_rate: u32, frequency_hz: f32, duration_secs: f32) {
let channels: u16 = 1;
let bit_depth: u16 = 16;
let bytes_per_sample = bit_depth / 8;
let block_align = channels * bytes_per_sample;
let byte_rate = sample_rate * block_align as u32;
let num_samples = (sample_rate as f32 * duration_secs) as u32;
let data_size = num_samples * block_align as u32;
let file_size = 4 + 24 + 8 + data_size;
let mut file = std::fs::File::create(path).expect("failed to create WAV file");
file.write_all(b"RIFF").unwrap();
file.write_all(&file_size.to_le_bytes()).unwrap();
file.write_all(b"WAVE").unwrap();
file.write_all(b"fmt ").unwrap();
file.write_all(&16u32.to_le_bytes()).unwrap();
file.write_all(&1u16.to_le_bytes()).unwrap(); file.write_all(&channels.to_le_bytes()).unwrap();
file.write_all(&sample_rate.to_le_bytes()).unwrap();
file.write_all(&byte_rate.to_le_bytes()).unwrap();
file.write_all(&block_align.to_le_bytes()).unwrap();
file.write_all(&bit_depth.to_le_bytes()).unwrap();
file.write_all(b"data").unwrap();
file.write_all(&data_size.to_le_bytes()).unwrap();
for i in 0..num_samples {
let t = i as f32 / sample_rate as f32;
let sample = (2.0 * std::f32::consts::PI * frequency_hz * t).sin();
let sample_i16 = (sample * i16::MAX as f32) as i16;
file.write_all(&sample_i16.to_le_bytes()).unwrap();
}
file.flush().unwrap();
}
pub fn generate_mp3_with_both_tags(path: &Path, id3v2_title: &str, id3v1_title: &str) {
let mut out: Vec<u8> = Vec::new();
let mut frames: Vec<u8> = Vec::new();
frames.extend_from_slice(b"TIT2");
let body_len = id3v2_title.len() as u32 + 1; frames.extend_from_slice(&body_len.to_be_bytes());
frames.extend_from_slice(&[0, 0]); frames.push(0); frames.extend_from_slice(id3v2_title.as_bytes());
frames.extend_from_slice(b"TRCK");
frames.extend_from_slice(&2u32.to_be_bytes());
frames.extend_from_slice(&[0, 0]);
frames.push(0);
frames.push(b'7');
out.extend_from_slice(b"ID3");
out.extend_from_slice(&[3, 0, 0]); let n = frames.len() as u32;
out.extend_from_slice(&[
((n >> 21) & 0x7f) as u8,
((n >> 14) & 0x7f) as u8,
((n >> 7) & 0x7f) as u8,
(n & 0x7f) as u8,
]);
out.extend_from_slice(&frames);
for _ in 0..40 {
out.extend_from_slice(&[0xFF, 0xFB, 0x90, 0x00]);
out.extend_from_slice(&[0u8; 413]);
}
let mut v1 = [0u8; 128];
v1[..3].copy_from_slice(b"TAG");
let title = id3v1_title.as_bytes();
let take = title.len().min(30);
v1[3..3 + take].copy_from_slice(&title[..take]);
out.extend_from_slice(&v1);
std::fs::write(path, out).expect("failed to write MP3 file");
}