Add level measurement to gauge background noise
This commit is contained in:
parent
362be00d07
commit
07308a548a
2 changed files with 81 additions and 5 deletions
78
src/main.zig
78
src/main.zig
|
|
@ -286,6 +286,70 @@ fn signalHandler(sig: i32) callconv(.c) void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn runMeasureLevels(allocator: std.mem.Allocator) !void {
|
||||||
|
const stdout = std.fs.File.stdout();
|
||||||
|
const is_tty = stdout.isTty();
|
||||||
|
|
||||||
|
var capture = try stt.AlsaCapture.init(allocator, "default", 16000, 1024);
|
||||||
|
defer capture.deinit();
|
||||||
|
try capture.open();
|
||||||
|
|
||||||
|
_ = try stdout.writeAll("Measuring audio levels... Press Ctrl+C to exit\n");
|
||||||
|
if (is_tty) {
|
||||||
|
_ = try stdout.writeAll("Histogram (0-10000):\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
var buffer: [4096]i16 = undefined;
|
||||||
|
var write_buffer: [256]u8 = undefined;
|
||||||
|
var second_max: u16 = 0;
|
||||||
|
var last_print = std.time.milliTimestamp();
|
||||||
|
|
||||||
|
while (!should_exit.load(.acquire)) {
|
||||||
|
_ = try capture.readAudio();
|
||||||
|
const samples_read = capture.getAudioSamples(&buffer);
|
||||||
|
if (samples_read == 0) {
|
||||||
|
std.Thread.sleep(10 * std.time.ns_per_ms);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var max_amp: u16 = 0;
|
||||||
|
for (buffer[0..samples_read]) |sample| {
|
||||||
|
const abs_sample = @abs(sample);
|
||||||
|
if (abs_sample > max_amp) max_amp = abs_sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_amp > second_max) second_max = max_amp;
|
||||||
|
|
||||||
|
const now = std.time.milliTimestamp();
|
||||||
|
if (now - last_print >= 1000) {
|
||||||
|
if (is_tty) {
|
||||||
|
const bar_width = (@as(u32, second_max) * 60) / 10000;
|
||||||
|
var writer = stdout.writer(&write_buffer);
|
||||||
|
const w = &writer.interface;
|
||||||
|
try w.print("{d:5} |", .{second_max});
|
||||||
|
try w.flush();
|
||||||
|
for (0..bar_width) |_| {
|
||||||
|
_ = try stdout.writeAll("█");
|
||||||
|
}
|
||||||
|
_ = try stdout.writeAll("\n");
|
||||||
|
} else {
|
||||||
|
var writer = stdout.writer(&write_buffer);
|
||||||
|
const w = &writer.interface;
|
||||||
|
try w.print("{d}\n", .{second_max});
|
||||||
|
try w.flush();
|
||||||
|
}
|
||||||
|
second_max = 0;
|
||||||
|
last_print = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
std.Thread.sleep(50 * std.time.ns_per_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_tty) {
|
||||||
|
_ = try stdout.writeAll("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn signalAction(sig: i32, info: *const std.posix.siginfo_t, _: ?*anyopaque) callconv(.c) void {
|
fn signalAction(sig: i32, info: *const std.posix.siginfo_t, _: ?*anyopaque) callconv(.c) void {
|
||||||
// NOTE: info only works correctly if std.posix.SA.SIGINFO is in the flags
|
// NOTE: info only works correctly if std.posix.SA.SIGINFO is in the flags
|
||||||
// std.log.debug("signal action. sig {d}", .{sig});
|
// std.log.debug("signal action. sig {d}", .{sig});
|
||||||
|
|
@ -353,6 +417,7 @@ pub fn main() !void {
|
||||||
|
|
||||||
var model_path: ?[]const u8 = null;
|
var model_path: ?[]const u8 = null;
|
||||||
var exec_program: ?[]const u8 = null;
|
var exec_program: ?[]const u8 = null;
|
||||||
|
var measure_levels = false;
|
||||||
|
|
||||||
// Parse arguments
|
// Parse arguments
|
||||||
for (args[1..]) |arg| {
|
for (args[1..]) |arg| {
|
||||||
|
|
@ -363,11 +428,13 @@ pub fn main() !void {
|
||||||
_ = try stdout.writeAll("OPTIONS:\n");
|
_ = try stdout.writeAll("OPTIONS:\n");
|
||||||
_ = try stdout.writeAll(" --model=<path> Path to Vosk model directory\n");
|
_ = try stdout.writeAll(" --model=<path> Path to Vosk model directory\n");
|
||||||
_ = try stdout.writeAll(" --exec=<program> Program to execute with recognized text\n");
|
_ = try stdout.writeAll(" --exec=<program> Program to execute with recognized text\n");
|
||||||
|
_ = try stdout.writeAll(" --measure-levels Display real-time audio level histogram\n");
|
||||||
_ = try stdout.writeAll(" --help, -h Show this help message\n\n");
|
_ = try stdout.writeAll(" --help, -h Show this help message\n\n");
|
||||||
_ = try stdout.writeAll("EXAMPLES:\n");
|
_ = try stdout.writeAll("EXAMPLES:\n");
|
||||||
_ = try stdout.writeAll(" stt\n");
|
_ = try stdout.writeAll(" stt\n");
|
||||||
_ = try stdout.writeAll(" stt --model=../share/vosk/models/vosk-model-small-en-us-0.15\n");
|
_ = try stdout.writeAll(" stt --model=../share/vosk/models/vosk-model-small-en-us-0.15\n");
|
||||||
_ = try stdout.writeAll(" stt --exec=echo\n\n");
|
_ = try stdout.writeAll(" stt --exec=echo\n");
|
||||||
|
_ = try stdout.writeAll(" stt --measure-levels\n\n");
|
||||||
_ = try stdout.writeAll("The application will search for models in these locations:\n");
|
_ = try stdout.writeAll("The application will search for models in these locations:\n");
|
||||||
_ = try stdout.writeAll(" vosk-model-small-en-us-0.15\n");
|
_ = try stdout.writeAll(" vosk-model-small-en-us-0.15\n");
|
||||||
_ = try stdout.writeAll(" <binary_dir>/../share/vosk/models/vosk-model-small-en-us-0.15\n");
|
_ = try stdout.writeAll(" <binary_dir>/../share/vosk/models/vosk-model-small-en-us-0.15\n");
|
||||||
|
|
@ -376,6 +443,8 @@ pub fn main() !void {
|
||||||
model_path = arg[8..]; // Skip "--model="
|
model_path = arg[8..]; // Skip "--model="
|
||||||
} else if (std.mem.startsWith(u8, arg, "--exec=")) {
|
} else if (std.mem.startsWith(u8, arg, "--exec=")) {
|
||||||
exec_program = arg[7..]; // Skip "--exec="
|
exec_program = arg[7..]; // Skip "--exec="
|
||||||
|
} else if (std.mem.eql(u8, arg, "--measure-levels")) {
|
||||||
|
measure_levels = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -385,6 +454,13 @@ pub fn main() !void {
|
||||||
.exec_program = exec_program,
|
.exec_program = exec_program,
|
||||||
};
|
};
|
||||||
defer handler.deinit();
|
defer handler.deinit();
|
||||||
|
|
||||||
|
// If measure-levels mode, run that instead of normal STT
|
||||||
|
if (measure_levels) {
|
||||||
|
try runMeasureLevels(allocator);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const speech_handler = stt.SpeechEventHandler{
|
const speech_handler = stt.SpeechEventHandler{
|
||||||
.onSpeechFn = SpeechHandler.onSpeech,
|
.onSpeechFn = SpeechHandler.onSpeech,
|
||||||
.onErrorFn = SpeechHandler.onError,
|
.onErrorFn = SpeechHandler.onError,
|
||||||
|
|
|
||||||
|
|
@ -531,7 +531,7 @@ pub const AlsaCapture = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read audio data from ALSA device and process it
|
/// Read audio data from ALSA device and process it
|
||||||
fn readAudio(self: *Self) !usize {
|
pub fn readAudio(self: *Self) !usize {
|
||||||
if (self.pcm_handle == null)
|
if (self.pcm_handle == null)
|
||||||
return Error.AudioDeviceError;
|
return Error.AudioDeviceError;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue