如何用hound库实现声音叠加:将1.wav无延迟叠加10次至out.wav
解决方案
你的问题出在当前代码是依次写入10遍原音频,所以结果是连续播放而非叠加混合。要实现叠加,需要把10个原音频的对应位置样本相加,生成混合后的音频。
修改后的代码(完全叠加版)
use hound::{WavReader, WavWriter, SampleFormat}; fn main() { // 读取原音频文件 let mut reader = WavReader::open("1.wav").unwrap(); let spec = reader.spec(); // 确保原音频为16位整数格式(若格式不同需调整处理逻辑) assert_eq!(spec.sample_format, SampleFormat::Int); assert_eq!(spec.bits_per_sample, 16); // 将原音频所有样本读取到内存,避免反复IO操作 let original_samples: Vec<i16> = reader.samples::<i16>() .map(|s| s.unwrap()) .collect(); // 创建输出文件,保持与原音频一致的规格 let mut writer = WavWriter::create("output.wav", spec).unwrap(); // 计算叠加后的样本:每个位置的样本为10次原样本的和,处理溢出问题 for &sample in &original_samples { // 转换为i32避免i16直接相乘溢出 let mixed_sample = (sample as i32) * 10; // 将结果限制在i16的合法取值范围内(-32768 至 32767) let clamped_sample = mixed_sample.clamp(i16::MIN as i32, i16::MAX as i32) as i16; writer.write_sample(clamped_sample).unwrap(); } writer.finalize().unwrap(); }
关键说明
- 内存预读取:一次性将原音频样本读入内存,避免反复seek和磁盘读取,既提升效率也方便后续叠加计算。
- 溢出处理:直接用i16叠加10次极易超出其取值范围,导致音频失真,因此先转换为i32计算,再通过
clamp方法将结果限制回i16的合法区间。
偏移叠加版(按需选择)
如果你的需求是间隔叠加(比如每播放原音频1/10时长就启动新的叠加轨),可使用以下代码,最终输出的音频时长更长,全程有多层音频混合:
use hound::{WavReader, WavWriter, SampleFormat}; fn main() { let mut reader = WavReader::open("1.wav").unwrap(); let spec = reader.spec(); assert_eq!(spec.sample_format, SampleFormat::Int); assert_eq!(spec.bits_per_sample, 16); let original_samples: Vec<i16> = reader.samples::<i16>() .map(|s| s.unwrap()) .collect(); let original_len = original_samples.len(); // 设置叠加偏移量:每1/10原时长启动一次新轨 let offset = original_len / 10; // 输出总长度:原长度 + 9倍偏移量 let output_len = original_len + 9 * offset; let mut writer = WavWriter::create("output_offset.wav", spec).unwrap(); for n in 0..output_len { let mut sum = 0i32; // 计算当前时刻有多少个叠加轨在播放 for i in 0..10 { let sample_idx = n - i * offset; if sample_idx >= 0 && sample_idx < original_len { sum += original_samples[sample_idx as usize] as i32; } } let clamped_sample = sum.clamp(i16::MIN as i32, i16::MAX as i32) as i16; writer.write_sample(clamped_sample).unwrap(); } writer.finalize().unwrap(); }
内容的提问来源于stack exchange,提问作者Inears
相关产品推荐
相关产品推荐

