Encode PCM f32 samples as WAV bytes (16-bit PCM, mono).
(samples: &[f32], sample_rate: u32)
| 9 | |
| 10 | /// Encode PCM f32 samples as WAV bytes (16-bit PCM, mono). |
| 11 | pub fn encode_wav_bytes(samples: &[f32], sample_rate: u32) -> Vec<u8> { |
| 12 | let num_samples = samples.len() as u32; |
| 13 | let byte_rate = sample_rate * 2; // 16-bit mono = 2 bytes per sample |
| 14 | let data_size = num_samples * 2; |
| 15 | let file_size = 36 + data_size; |
| 16 | |
| 17 | let mut buf = Vec::with_capacity(file_size as usize + 8); |
| 18 | // RIFF header |
| 19 | buf.extend_from_slice(b"RIFF"); |
| 20 | buf.extend_from_slice(&file_size.to_le_bytes()); |
| 21 | buf.extend_from_slice(b"WAVE"); |
| 22 | // fmt chunk |
| 23 | buf.extend_from_slice(b"fmt "); |
| 24 | buf.extend_from_slice(&16u32.to_le_bytes()); // chunk size |
| 25 | buf.extend_from_slice(&1u16.to_le_bytes()); // PCM format |
| 26 | buf.extend_from_slice(&1u16.to_le_bytes()); // mono |
| 27 | buf.extend_from_slice(&sample_rate.to_le_bytes()); |
| 28 | buf.extend_from_slice(&byte_rate.to_le_bytes()); |
| 29 | buf.extend_from_slice(&2u16.to_le_bytes()); // block align |
| 30 | buf.extend_from_slice(&16u16.to_le_bytes()); // bits per sample |
| 31 | // data chunk |
| 32 | buf.extend_from_slice(b"data"); |
| 33 | buf.extend_from_slice(&data_size.to_le_bytes()); |
| 34 | // Convert all samples to i16 bytes in one pass — single extend_from_slice |
| 35 | let sample_bytes: Vec<u8> = samples |
| 36 | .iter() |
| 37 | .flat_map(|&s| ((s.clamp(-1.0, 1.0) * 32767.0) as i16).to_le_bytes()) |
| 38 | .collect(); |
| 39 | buf.extend_from_slice(&sample_bytes); |
| 40 | buf |
| 41 | } |
| 42 | |
| 43 | /// Save PCM f32 samples as a WAV file (16-bit PCM, mono). |
| 44 | pub fn save_wav(samples: &[f32], path: &Path, sample_rate: u32) -> Result<()> { |
no outgoing calls