1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
use std::{
convert::TryFrom,
fmt::{self, Debug, Formatter},
fs::File,
io::Read,
path::Path,
time::Duration,
};
use anyhow::{Context, Error};
use hound::{WavReader, WavSpec};
use crate::{builtins::Arguments, Tensor};
pub fn sound(args: &Arguments, clip: &AudioClip) -> Result<Tensor, Error> {
let sample_rate: u32 = args.parse("hz")?;
let sample_duration_ms = args.parse("sample_duration_ms")?;
let duration = Duration::from_millis(sample_duration_ms);
let AudioClip { spec, samples } = clip;
transform_samples(sample_rate, duration, spec, samples)
}
fn transform_samples(
sample_rate: u32,
duration: Duration,
_spec: &WavSpec,
samples: &[i16],
) -> Result<Tensor, Error> {
let required_samples = usize::try_from(
(sample_rate as u128) * duration.as_micros() / 1_000_000,
)?;
if samples.len() < required_samples {
anyhow::bail!(
"At least {} samples are required to generate this input, but \
only {} were provided",
required_samples,
samples.len(),
);
}
let samples = &samples[..required_samples];
Ok(Tensor::new(samples, &[1, samples.len()]))
}
#[derive(Clone, PartialEq)]
pub struct AudioClip {
spec: WavSpec,
samples: Vec<i16>,
}
impl AudioClip {
pub fn from_wav_file(filename: impl AsRef<Path>) -> Result<Self, Error> {
let filename = filename.as_ref();
let f = File::open(filename).with_context(|| {
format!("Unable to open \"{}\" for reading", filename.display())
})?;
let wav = WavReader::new(f)?;
AudioClip::load(wav)
}
pub fn load(reader: WavReader<impl Read>) -> Result<Self, Error> {
let spec = reader.spec();
let samples = reader
.into_samples()
.collect::<Result<Vec<i16>, hound::Error>>()
.context("Unable to parse the WAV file")?;
Ok(AudioClip { spec, samples })
}
}
impl Debug for AudioClip {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let AudioClip { spec, samples } = self;
f.debug_struct("AudioClip")
.field("spec", spec)
.field("samples", &format_args!("({} samples)", samples.len()))
.finish()
}
}