1mod clip;
9mod recording;
10mod stop;
11
12#[cfg(not(target_family = "wasm"))]
13mod capture;
14#[cfg(not(target_family = "wasm"))]
15mod resample;
16#[cfg(not(target_family = "wasm"))]
17mod spool;
18#[cfg(all(not(target_family = "wasm"), any(test, feature = "test-support")))]
19pub(crate) mod testing;
20#[cfg(not(target_family = "wasm"))]
21mod wav;
22
23use std::time::Duration;
24
25pub use clip::{Clip, ClipError};
26#[cfg(all(feature = "silero", not(target_family = "wasm")))]
27pub use recording::RecordingWaker;
28#[cfg(not(target_family = "wasm"))]
29pub use recording::SpooledRecordingWriter;
30pub use recording::{CaptureError, RecordedAudio, Recording, RecordingReader, RecordingWriter};
31#[cfg(not(target_family = "wasm"))]
32pub use resample::{ResampleError, Resampler};
33pub use stop::{StopSignal, Stopper};
34
35#[cfg(not(target_family = "wasm"))]
36pub use capture::{
37 AudioCapture, AutoStop, AutoStopError, MicrophoneError, RecordingMode, ReplayPace,
38 SilenceDuration, SilenceDurationError, WavReplayCapture, WavReplayError,
39};
40#[cfg(all(feature = "microphone", not(target_family = "wasm")))]
41pub use capture::{
42 Microphone, MicrophoneBuilder, PreparedMicrophone, WakeWordControl, WakeWordEvent,
43 WakeWordFailure, WakeWordMonitor, WakeWordSuspension, check_default_input_device,
44};
45#[cfg(not(target_family = "wasm"))]
46pub use spool::{SpoolError, remove_all_spools};
47#[cfg(all(not(target_family = "wasm"), any(test, feature = "test-support")))]
48pub use testing::{canonical_fixture, fixture_of};
49#[cfg(not(target_family = "wasm"))]
50pub use wav::{WavError, read_wav, write_wav};
51
52pub const CANONICAL_SAMPLE_RATE: u32 = 16_000;
53
54#[cfg(not(target_family = "wasm"))]
58pub(crate) const MAX_RECORDING_SAMPLES: u64 = (u32::MAX as u64 - 36) / 2;
59#[cfg(not(target_family = "wasm"))]
60pub(crate) const MAX_RECORDING_DURATION: Duration =
61 Duration::from_nanos(MAX_RECORDING_SAMPLES * (1_000_000_000 / CANONICAL_SAMPLE_RATE as u64));
62pub const CHANNELS: u16 = 1;
63
64pub(crate) const PCM_SCALE: f32 = 32_768.0;
66
67#[cfg(not(target_family = "wasm"))]
69pub fn pcm16_from_f32(sample: f32) -> i16 {
70 (sample * PCM_SCALE)
71 .round()
72 .clamp(-PCM_SCALE, PCM_SCALE - 1.0) as i16
73}
74
75pub fn f32_from_pcm16(sample: i16) -> f32 {
76 f32::from(sample) / PCM_SCALE
77}
78
79pub const fn canonical_samples(duration: Duration) -> u64 {
82 let samples = samples_at(duration, CANONICAL_SAMPLE_RATE);
83 if samples > u64::MAX as u128 {
84 u64::MAX
85 } else {
86 samples as u64
87 }
88}
89
90pub fn canonical_duration(samples: u64) -> Duration {
92 duration_at(samples, CANONICAL_SAMPLE_RATE)
93}
94
95pub(crate) const fn samples_at(duration: Duration, sample_rate: u32) -> u128 {
96 let rate = sample_rate as u128;
97 duration.as_secs() as u128 * rate + duration.subsec_nanos() as u128 * rate / 1_000_000_000
98}
99
100pub(crate) fn duration_at(samples: u64, sample_rate: u32) -> Duration {
101 let rate = u64::from(sample_rate);
102 Duration::from_secs(samples / rate)
103 + Duration::from_nanos(samples % rate * 1_000_000_000 / rate)
104}