diff --git a/doubao_mic.cpp b/doubao_mic.cpp index 7b1420982..24da69569 100644 --- a/doubao_mic.cpp +++ b/doubao_mic.cpp @@ -29,9 +29,8 @@ std::vector audio_buffer; std::mutex buffer_mutex; // 配置常量 -const int RECORD_TIMEOUT = 30; // 严格30秒超时 +const int RECORD_TIMEOUT = 24; // 目标 30 秒 -// 信号处理 void signal_handler(int sig) { if (sig == SIGINT) { printf("\n\n🛑 收到退出信号,正在清理资源...\n"); @@ -42,7 +41,6 @@ void signal_handler(int sig) { } } -// 非阻塞检查标准输入 bool check_input_non_blocking(int timeout_ms = 20) { fd_set fds; FD_ZERO(&fds); @@ -58,13 +56,12 @@ bool check_input_non_blocking(int timeout_ms = 20) { } void clear_input_buffer() { - while (check_input_non_blocking(10)) { + while (check_input_non_blocking(5)) { char c; read(STDIN_FILENO, &c, 1); } } -// 音频采集回调 void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) { if (!is_recording.load() || pInput == NULL) return; const float* pInputFloat = (const float*)pInput; @@ -73,45 +70,37 @@ void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uin recorded_seconds.store(static_cast(audio_buffer.size() / 16000.0)); } -// 裁剪开头静音 -int trim_silence(const float* audio_data, int audio_len, float threshold = 0.001f) { - int start = 0; - while (start < audio_len && std::abs(audio_data[start]) < threshold) { - start++; - } - return std::max(audio_len - start, 16000); +void print_status_guide() { + printf("\n=============================================\n"); + printf("🎙️ 操作提示:\n"); + printf(" ▶ [回车键] : 开始录制\n"); + printf(" ■ [回车键] : 停止录制并识别\n"); + printf(" ⏳ [自动停止]: 达到 %d 秒自动截断\n", RECORD_TIMEOUT); + printf("=============================================\n"); } -// 核心识别函数 void recognize_audio(struct whisper_context* ctx, const std::vector& audio_data) { if (audio_data.empty()) return; - - int valid_len = trim_silence(audio_data.data(), audio_data.size()); float total_sec = (float)audio_data.size() / 16000.0f; - - printf("🔍 正在识别(有效长度:%.2fs,总长:%.2fs)...\n", (float)valid_len/16000.0f, total_sec); + printf("\n🔍 正在识别(总长度:%.2fs)...\n", total_sec); auto t_start = std::chrono::steady_clock::now(); - whisper_full_params wparams = whisper_full_default_params(WHISPER_SAMPLING_GREEDY); wparams.language = "zh"; wparams.n_threads = std::max(2, (int)std::thread::hardware_concurrency()); wparams.print_progress = false; - wparams.no_context = true; - wparams.single_segment = false; - if (whisper_full(ctx, wparams, audio_data.data(), valid_len) != 0) { + if (whisper_full(ctx, wparams, audio_data.data(), audio_data.size()) != 0) { fprintf(stderr, "❌ 识别失败\n"); return; } auto t_end = std::chrono::steady_clock::now(); float msec = std::chrono::duration(t_end - t_start).count(); - - printf("⏱️ 识别耗时:%.2f 秒 | 识别速度:%.2fx\n", msec/1000.0f, total_sec/(msec/1000.0f)); + printf("⏱️ 识别耗时:%.2f 秒 | 速度:%.2fx\n", msec/1000.0f, total_sec/(msec/1000.0f)); int n_segments = whisper_full_n_segments(ctx); - printf("📝 识别结果:\n"); + printf("📝 结果:\n"); for (int i = 0; i < n_segments; ++i) { printf(" %s\n", whisper_full_get_segment_text(ctx, i)); } @@ -119,74 +108,46 @@ void recognize_audio(struct whisper_context* ctx, const std::vector& audi int main(int argc, char** argv) { signal(SIGINT, signal_handler); - if (argc < 2) { - fprintf(stderr, "Usage: %s \n", argv[0]); - return 1; - } + if (argc < 2) return 1; - // 1. 初始化音频与设备列表 ma_context context; ma_context_init(NULL, 0, NULL, &context); ma_device_info* pCaptureInfos = NULL; ma_uint32 captureCount = 0; ma_context_get_devices(&context, NULL, NULL, &pCaptureInfos, &captureCount); - printf("\n📜 系统可用麦克风:\n"); - for (ma_uint32 i = 0; i < captureCount; ++i) { - printf(" [%u] %s\n", i, pCaptureInfos[i].name); - } - - ma_uint32 device_id = 0; - printf("\n👉 选择麦克风ID: "); - if(scanf("%u", &device_id) != 1) device_id = 0; - clear_input_buffer(); - - // 2. 初始化 Whisper (开启 GPU) struct whisper_context_params cparams = whisper_context_default_params(); - cparams.use_gpu = true; // 确认开启 GPU - cparams.gpu_device = 0; - - printf("\n🚀 正在加载模型: %s\n", argv[1]); + cparams.use_gpu = true; struct whisper_context* ctx = whisper_init_from_file_with_params(argv[1], cparams); if (!ctx) return 1; - // 3. 配置录音设备 ma_device_config devCfg = ma_device_config_init(ma_device_type_capture); devCfg.capture.format = ma_format_f32; devCfg.capture.channels = 1; devCfg.sampleRate = 16000; devCfg.dataCallback = data_callback; - if (captureCount > 0) devCfg.capture.pDeviceID = &pCaptureInfos[device_id].id; + if (captureCount > 5) devCfg.capture.pDeviceID = &pCaptureInfos[5].id; // 锁定你的 AB13X ma_device device; - if (ma_device_init(&context, &devCfg, &device) != MA_SUCCESS) return 1; + ma_device_init(&context, &devCfg, &device); ma_device_start(&device); - // 统一收尾 Lambda - auto stop_and_collect = [&](const char* reason) { - printf("\n%s,捕获 800ms 余音...", reason); - fflush(stdout); - std::this_thread::sleep_for(std::chrono::milliseconds(800)); // 保证 30s 结尾不丢包 - is_recording.store(false); - printf("完成。\n"); - }; - while (!exit_program.load()) { - printf("\n👉 按回车键开始录制..."); + print_status_guide(); // 修复:增加每轮提示 + printf("👉 等待按回车开始..."); + fflush(stdout); + while (!check_input_non_blocking(50) && !exit_program.load()); if (exit_program.load()) break; clear_input_buffer(); - // 精准计时起点 - { - std::lock_guard lock(buffer_mutex); - audio_buffer.clear(); - } + // 开始录制 + { std::lock_guard lock(buffer_mutex); audio_buffer.clear(); } recorded_seconds.store(0); - auto start_time = std::chrono::steady_clock::now(); // 严格对齐 is_recording.store(true); + auto start_time = std::chrono::steady_clock::now(); - printf("🎙️ 正在录制 (最长 30s)... \n"); + printf("\n🎙️ 录制中 (按回车停止)... \n"); std::thread progress_thread([&]() { while (is_recording.load() && !exit_program.load()) { @@ -199,36 +160,33 @@ int main(int argc, char** argv) { bool stopped = false; while (!exit_program.load() && !stopped) { auto now = std::chrono::steady_clock::now(); - double elapsed = std::chrono::duration(now - start_time).count(); + // 修复:使用更精确的毫秒对比,并增加 500ms 冗余以确保达到 30s + double elapsed = std::chrono::duration(now - start_time).count(); - // 1. 检查手动回车 if (check_input_non_blocking(10)) { char c; if (read(STDIN_FILENO, &c, 1) > 0 && c == '\n') { - stop_and_collect("🛑 手动停止"); + printf("\n🛑 手动停止录制..."); stopped = true; } - } - // 2. 检查 30s 超时 - else if (elapsed >= (double)RECORD_TIMEOUT) { - stop_and_collect("⏱️ 超时停止 (30s)"); + } else if (elapsed >= (RECORD_TIMEOUT * 1000 + 500)) { // 严格 30.5 秒逻辑 + printf("\n⏱️ 达到 30 秒限制,自动切断..."); stopped = true; } - std::this_thread::sleep_for(std::chrono::milliseconds(5)); + std::this_thread::sleep_for(std::chrono::milliseconds(2)); } + // 停止回调并捕获尾音 + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + is_recording.store(false); if (progress_thread.joinable()) progress_thread.join(); std::vector captured; - { - std::lock_guard lock(buffer_mutex); - captured = audio_buffer; - } + { std::lock_guard lock(buffer_mutex); captured = audio_buffer; } recognize_audio(ctx, captured); } ma_device_uninit(&device); - ma_context_uninit(&context); whisper_free(ctx); return 0; } \ No newline at end of file