style: cargo fmt sweep (reflow-only; verified rustfmt(HEAD) == worktree per file)
This commit is contained in:
1 parent
e8a6ddca71
commit
403d652c6d
8 files changed
+89
-49
No files matched your search
+31
-21
@@ -746,10 +746,9 @@ fn capture_loop(
|
||||
let rate = session.format.get_samplespersec() as usize;
|
||||
// Advance the timeline by the wall-clock gap (capped), but
|
||||
// never fewer frames than the mic we must write.
|
||||
let gap_frames = (elapsed.min(SILENCE_TICK_MAX).as_micros() as usize
|
||||
* rate
|
||||
/ 1_000_000)
|
||||
.max(mic.len());
|
||||
let gap_frames =
|
||||
(elapsed.min(SILENCE_TICK_MAX).as_micros() as usize * rate / 1_000_000)
|
||||
.max(mic.len());
|
||||
let bpf = session.format.get_nchannels() as usize
|
||||
* (session.format.get_bitspersample() as usize / 8);
|
||||
let silence = vec![0u8; gap_frames * bpf];
|
||||
@@ -939,22 +938,26 @@ fn write_wav_split(
|
||||
if channels == 0 {
|
||||
return Ok(0);
|
||||
}
|
||||
let (bytes_per_sample, decode): (usize, fn(&[u8]) -> f32) = match (sample_type, format.get_bitspersample()) {
|
||||
(SampleType::Float, 32) => (4, |c| f32::from_le_bytes(c.try_into().unwrap())),
|
||||
(SampleType::Int, 16) => (2, |c| {
|
||||
i16::from_le_bytes(c.try_into().unwrap()) as f32 / i16::MAX as f32
|
||||
}),
|
||||
(st, bits) => {
|
||||
return Err(AudioError::Device(format!(
|
||||
"unsupported capture format: {st} {bits}-bit"
|
||||
)))
|
||||
}
|
||||
};
|
||||
let (bytes_per_sample, decode): (usize, fn(&[u8]) -> f32) =
|
||||
match (sample_type, format.get_bitspersample()) {
|
||||
(SampleType::Float, 32) => (4, |c| f32::from_le_bytes(c.try_into().unwrap())),
|
||||
(SampleType::Int, 16) => (2, |c| {
|
||||
i16::from_le_bytes(c.try_into().unwrap()) as f32 / i16::MAX as f32
|
||||
}),
|
||||
(st, bits) => {
|
||||
return Err(AudioError::Device(format!(
|
||||
"unsupported capture format: {st} {bits}-bit"
|
||||
)))
|
||||
}
|
||||
};
|
||||
let mut frames = 0u64;
|
||||
for frame in loopback_bytes.chunks_exact(bytes_per_sample * channels) {
|
||||
// R = loopback downmixed to mono.
|
||||
let loop_mono =
|
||||
frame.chunks_exact(bytes_per_sample).map(decode).sum::<f32>() / channels as f32;
|
||||
let loop_mono = frame
|
||||
.chunks_exact(bytes_per_sample)
|
||||
.map(decode)
|
||||
.sum::<f32>()
|
||||
/ channels as f32;
|
||||
// L = mic for this frame (silent if the mic underran).
|
||||
let mic_s = mic.get(frames as usize).copied().unwrap_or(0.0);
|
||||
writer
|
||||
@@ -1120,7 +1123,11 @@ fn read_wav_16k(path: &Path, channel: Option<usize>) -> Result<Vec<f32>, AudioEr
|
||||
let mono: Vec<f32> = match (spec.sample_format, spec.bits_per_sample) {
|
||||
(SampleFormat::Float, 32) => bytes
|
||||
.chunks_exact(4 * channels)
|
||||
.map(|frame| reduce_frame(frame, 4, pick, channels, |c| f32::from_le_bytes(c.try_into().unwrap())))
|
||||
.map(|frame| {
|
||||
reduce_frame(frame, 4, pick, channels, |c| {
|
||||
f32::from_le_bytes(c.try_into().unwrap())
|
||||
})
|
||||
})
|
||||
.collect(),
|
||||
(SampleFormat::Int, 16) => bytes
|
||||
.chunks_exact(2 * channels)
|
||||
@@ -1201,8 +1208,8 @@ pub fn write_wav_mono_16k(path: &Path, samples: &[f32]) -> Result<(), AudioError
|
||||
bits_per_sample: 32,
|
||||
sample_format: SampleFormat::Float,
|
||||
};
|
||||
let mut writer =
|
||||
WavWriter::create(path, spec).map_err(|e| AudioError::Capture(format!("write wav: {e}")))?;
|
||||
let mut writer = WavWriter::create(path, spec)
|
||||
.map_err(|e| AudioError::Capture(format!("write wav: {e}")))?;
|
||||
for &s in samples {
|
||||
writer
|
||||
.write_sample(s)
|
||||
@@ -1338,7 +1345,10 @@ mod tests {
|
||||
fn voice_sample_skips_silence_and_keeps_speech() {
|
||||
let vs = VoiceSample::new(16_000);
|
||||
vs.push(&[0.0; 4_000]); // silence: below the energy floor
|
||||
assert!(vs.samples().is_empty(), "silence must not fill the voiceprint");
|
||||
assert!(
|
||||
vs.samples().is_empty(),
|
||||
"silence must not fill the voiceprint"
|
||||
);
|
||||
vs.push(&[0.2; 4_000]); // speech-level audio
|
||||
assert_eq!(vs.samples().len(), 4_000, "speech-level audio is collected");
|
||||
}
|
||||
|
||||
@@ -26,7 +26,11 @@ const AUTO_DOWNLOAD_KEY: &str = "auto_download_model";
|
||||
fn candidate_paths() -> Vec<PathBuf> {
|
||||
let mut paths = Vec::new();
|
||||
if let Ok(program_data) = std::env::var("ProgramData") {
|
||||
paths.push(PathBuf::from(program_data).join("WhispAssist").join("wa-defaults.ini"));
|
||||
paths.push(
|
||||
PathBuf::from(program_data)
|
||||
.join("WhispAssist")
|
||||
.join("wa-defaults.ini"),
|
||||
);
|
||||
}
|
||||
if let Ok(exe) = std::env::current_exe() {
|
||||
if let Some(dir) = exe.parent() {
|
||||
@@ -121,7 +125,8 @@ fn coerce(value: &str) -> Value {
|
||||
}
|
||||
|
||||
fn truthy(v: &Value) -> bool {
|
||||
matches!(v, Value::Bool(true)) || matches!(v, Value::String(s) if s.eq_ignore_ascii_case("true"))
|
||||
matches!(v, Value::Bool(true))
|
||||
|| matches!(v, Value::String(s) if s.eq_ignore_ascii_case("true"))
|
||||
}
|
||||
|
||||
/// Defense in depth: never seed anything that smells like a credential.
|
||||
|
||||
@@ -95,7 +95,12 @@ pub fn assign_split(
|
||||
seg.speaker = "You".to_string();
|
||||
} else if let Some(span) = far_spans
|
||||
.iter()
|
||||
.map(|sp| (overlap(seg.start_ms, seg.end_ms, sp.start_ms, sp.end_ms), sp))
|
||||
.map(|sp| {
|
||||
(
|
||||
overlap(seg.start_ms, seg.end_ms, sp.start_ms, sp.end_ms),
|
||||
sp,
|
||||
)
|
||||
})
|
||||
.filter(|(o, _)| *o > 0)
|
||||
.max_by_key(|(o, _)| *o)
|
||||
.map(|(_, sp)| sp)
|
||||
@@ -298,7 +303,12 @@ mod overlap_tests {
|
||||
fn split_keeps_the_prior_label_when_both_channels_are_silent() {
|
||||
let mut segments = vec![segment(5000, 6000)];
|
||||
segments[0].speaker = "S9".to_string();
|
||||
assign_split(&mut segments, &[(0, 1000)], &[(0, 1000)], &[span(0, 1000, "S1")]);
|
||||
assign_split(
|
||||
&mut segments,
|
||||
&[(0, 1000)],
|
||||
&[(0, 1000)],
|
||||
&[span(0, 1000, "S1")],
|
||||
);
|
||||
assert_eq!(segments[0].speaker, "S9");
|
||||
}
|
||||
|
||||
|
||||
+11
-3
@@ -117,7 +117,11 @@ fn fatal_startup_error(body: &str) -> ! {
|
||||
MessageBoxW, MB_ICONERROR, MB_OK, MB_SYSTEMMODAL,
|
||||
};
|
||||
// Null-terminated UTF-16 for the Win32 wide API.
|
||||
let to_wide = |s: &str| s.encode_utf16().chain(std::iter::once(0)).collect::<Vec<u16>>();
|
||||
let to_wide = |s: &str| {
|
||||
s.encode_utf16()
|
||||
.chain(std::iter::once(0))
|
||||
.collect::<Vec<u16>>()
|
||||
};
|
||||
let text = to_wide(body);
|
||||
let caption = to_wide("WhispAssist can't start");
|
||||
// SAFETY: both buffers are null-terminated and outlive the call.
|
||||
@@ -228,13 +232,17 @@ pub fn run() {
|
||||
)
|
||||
.await
|
||||
{
|
||||
tracing::warn!("deploy auto-download of model failed: {e:?}");
|
||||
tracing::warn!(
|
||||
"deploy auto-download of model failed: {e:?}"
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("first-run deploy seeding failed to write settings: {e:?}")
|
||||
tracing::error!(
|
||||
"first-run deploy seeding failed to write settings: {e:?}"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-11
@@ -21,10 +21,7 @@ pub enum MediaError {
|
||||
#[error("{0} isn't installed or on PATH — install it and try again")]
|
||||
ToolMissing(&'static str),
|
||||
#[error("{tool} failed: {message}")]
|
||||
Failed {
|
||||
tool: &'static str,
|
||||
message: String,
|
||||
},
|
||||
Failed { tool: &'static str, message: String },
|
||||
#[error("io error: {0}")]
|
||||
Io(#[from] std::io::Error),
|
||||
}
|
||||
@@ -60,7 +57,11 @@ fn run(program: &'static str, cmd: &mut Command) -> Result<(), MediaError> {
|
||||
if !output.status.success() {
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
let text = if stderr.trim().is_empty() { stdout } else { stderr };
|
||||
let text = if stderr.trim().is_empty() {
|
||||
stdout
|
||||
} else {
|
||||
stderr
|
||||
};
|
||||
let tail: Vec<&str> = text.lines().filter(|l| !l.trim().is_empty()).collect();
|
||||
let start = tail.len().saturating_sub(6);
|
||||
return Err(MediaError::Failed {
|
||||
@@ -145,12 +146,7 @@ mod tests {
|
||||
fn import_reports_a_missing_local_file_without_touching_a_tool() {
|
||||
let dir = std::env::temp_dir().join(format!("wa-media-{}", uuid::Uuid::new_v4()));
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
let err = import_to_wav(
|
||||
"no-such-file.mp4",
|
||||
&dir.join("out.wav"),
|
||||
&dir,
|
||||
)
|
||||
.unwrap_err();
|
||||
let err = import_to_wav("no-such-file.mp4", &dir.join("out.wav"), &dir).unwrap_err();
|
||||
assert!(matches!(err, MediaError::Failed { tool: "import", .. }));
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
@@ -1260,13 +1260,15 @@ impl Store for SqliteStore {
|
||||
started_at: i64,
|
||||
ended_at: Option<i64>,
|
||||
) -> Result<(), StoreError> {
|
||||
sqlx::query("UPDATE meetings SET started_at = ?, ended_at = ?, updated_at = ? WHERE id = ?")
|
||||
.bind(started_at)
|
||||
.bind(ended_at)
|
||||
.bind(now_unix())
|
||||
.bind(meeting_id)
|
||||
.execute(&self.pool)
|
||||
.await?;
|
||||
sqlx::query(
|
||||
"UPDATE meetings SET started_at = ?, ended_at = ?, updated_at = ? WHERE id = ?",
|
||||
)
|
||||
.bind(started_at)
|
||||
.bind(ended_at)
|
||||
.bind(now_unix())
|
||||
.bind(meeting_id)
|
||||
.execute(&self.pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -588,7 +588,10 @@ mod tests {
|
||||
feed_into(&mut s, &step, &d2, &mut out);
|
||||
assert!(out[3].interim && out[3].text == "next sentence");
|
||||
assert_ne!(out[3].id, out[2].id);
|
||||
assert!(out[3].start_ms >= 3000, "starts after the 3 committed steps");
|
||||
assert!(
|
||||
out[3].start_ms >= 3000,
|
||||
"starts after the 3 committed steps"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -612,7 +615,10 @@ mod tests {
|
||||
assert!(out.last().unwrap().interim, "still growing before flush");
|
||||
flush_into(&mut s, &decode, &mut out);
|
||||
let last = out.last().unwrap();
|
||||
assert!(!last.interim && last.text == "partial", "flush finalizes it");
|
||||
assert!(
|
||||
!last.interim && last.text == "partial",
|
||||
"flush finalizes it"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -24,7 +24,10 @@ pub const DEFAULT_ONNX_MODEL: &str = "base.en";
|
||||
/// disk, fetching only the merged decoder.
|
||||
const FILES: &[(&str, &str)] = &[
|
||||
("encoder_model.onnx", "onnx/encoder_model.onnx"),
|
||||
("decoder_model_merged.onnx", "onnx/decoder_model_merged.onnx"),
|
||||
(
|
||||
"decoder_model_merged.onnx",
|
||||
"onnx/decoder_model_merged.onnx",
|
||||
),
|
||||
("tokenizer.json", "tokenizer.json"),
|
||||
("generation_config.json", "generation_config.json"),
|
||||
];
|
||||
|
||||
Reference in new issue
Block a user