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