封装音频
This commit is contained in:
parent
78a7c87762
commit
49879e1c59
99
src/test.cc
99
src/test.cc
|
|
@ -1,53 +1,54 @@
|
|||
// #include "piper_tts_interface.h"
|
||||
// #include <string>
|
||||
// #include <iostream>
|
||||
|
||||
// int main() {
|
||||
// PiperTTSInterface tts_processor;
|
||||
// // 示例 1: 只提供文本和输出文件名
|
||||
// std::string text1 = "你好,世界。温度传感器出现故障。只需输入文本即可。";
|
||||
// std::string file1 = "hello_world.wav";
|
||||
// if (tts_processor.text_to_speech(text1, file1)) {
|
||||
// std::cout << "Audio for '" << text1 << "' generated successfully!" << std::endl;
|
||||
// } else {
|
||||
// std::cerr << "Failed to generate audio for '" << text1 << "'." << std::endl;
|
||||
// }
|
||||
// return 0;
|
||||
// }
|
||||
#include "tts/piper_tts_interface.h"
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include "systemMonitor/iio_sensor.h" // 包含我们刚刚创建的头文件
|
||||
|
||||
int main() {
|
||||
// --- 配置参数 ---
|
||||
// !!! 修改这里以匹配你的设备和通道 !!!
|
||||
const std::string iio_device_path = "/sys/bus/iio/devices/iio:device0";
|
||||
const std::string iio_channel_name = "in_voltage2_raw"; // 例如,连接到 IN2 通道
|
||||
|
||||
const double adc_reference_voltage = 1.8; // ADC参考电压
|
||||
const int64_t adc_resolution = 4096; // ADC分辨率 (e.g., 2^12 for 12-bit)
|
||||
const double signal_gain = 11.0; // 信号通路的增益
|
||||
std::cout << "--- Starting IIO Sensor Reader (Version 2) ---" << std::endl;
|
||||
std::cout << "Reading from device: " << iio_device_path << std::endl;
|
||||
std::cout << "Reading channel: " << iio_channel_name << std::endl;
|
||||
std::cout << "-----------------------------------------------" << std::endl;
|
||||
|
||||
// 注意:传感器对象在 try 块外创建,如果构造失败(找不到文件),会立即被捕获
|
||||
IioSensor sensor(iio_device_path, iio_channel_name);
|
||||
while (true) {
|
||||
try {
|
||||
// 封装后的调用方式非常简洁!
|
||||
// 每次调用 readVoltage,内部都会重新打开文件读取一次
|
||||
double actual_voltage = sensor.readVoltage(adc_reference_voltage, adc_resolution, signal_gain);
|
||||
// 输出结果
|
||||
std::cout << "Actual Voltage: " << actual_voltage << " V" << std::endl;
|
||||
} catch (const IioSensorError& e) {
|
||||
// 如果单次读取失败(例如文件内容格式错误、无权限等),打印错误但继续循环
|
||||
std::cerr << "[!] Read Error: " << e.what() << std::endl;
|
||||
}
|
||||
|
||||
// 每秒钟读取一次
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
// 使用默认配置 (piper 和 /app/piper_models/zh_CN-huayan-medium.onnx)
|
||||
PiperTTSInterface tts_speaker;
|
||||
// 如果你的piper可执行文件不在PATH中,或者模型路径不同,你可以这样指定:
|
||||
// PiperTTSInterface tts_speaker("/path/to/your/piper_executable", "/path/to/your/model.onnx");
|
||||
std::string text_to_say = "请执行上述调试步骤,特别是禁用文件删除后手动检查和播放 WAV 文件,这将提供更多线索";
|
||||
if (tts_speaker.say_text_and_play(text_to_say)) {
|
||||
std::cout << "语音播报完成。" << std::endl;
|
||||
} else {
|
||||
std::cerr << "语音播报失败,请检查日志。" << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// #include <iostream>
|
||||
// #include <chrono>
|
||||
// #include <thread>
|
||||
// #include "systemMonitor/iio_sensor.h" // 包含我们刚刚创建的头文件
|
||||
// int main() {
|
||||
// // --- 配置参数 ---
|
||||
// // !!! 修改这里以匹配你的设备和通道 !!!
|
||||
// const std::string iio_device_path = "/sys/bus/iio/devices/iio:device0";
|
||||
// const std::string iio_channel_name = "in_voltage2_raw"; // 例如,连接到 IN2 通道
|
||||
|
||||
// const double adc_reference_voltage = 1.8; // ADC参考电压
|
||||
// const int64_t adc_resolution = 4096; // ADC分辨率 (e.g., 2^12 for 12-bit)
|
||||
// const double signal_gain = 11.0; // 信号通路的增益
|
||||
// std::cout << "--- Starting IIO Sensor Reader (Version 2) ---" << std::endl;
|
||||
// std::cout << "Reading from device: " << iio_device_path << std::endl;
|
||||
// std::cout << "Reading channel: " << iio_channel_name << std::endl;
|
||||
// std::cout << "-----------------------------------------------" << std::endl;
|
||||
|
||||
// // 注意:传感器对象在 try 块外创建,如果构造失败(找不到文件),会立即被捕获
|
||||
// IioSensor sensor(iio_device_path, iio_channel_name);
|
||||
// while (true) {
|
||||
// try {
|
||||
// // 封装后的调用方式非常简洁!
|
||||
// // 每次调用 readVoltage,内部都会重新打开文件读取一次
|
||||
// double actual_voltage = sensor.readVoltage(adc_reference_voltage, adc_resolution, signal_gain);
|
||||
// // 输出结果
|
||||
// std::cout << "Actual Voltage: " << actual_voltage << " V" << std::endl;
|
||||
// } catch (const IioSensorError& e) {
|
||||
// // 如果单次读取失败(例如文件内容格式错误、无权限等),打印错误但继续循环
|
||||
// std::cerr << "[!] Read Error: " << e.what() << std::endl;
|
||||
// }
|
||||
|
||||
// // 每秒钟读取一次
|
||||
// std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
// }
|
||||
// return 0;
|
||||
// }
|
||||
|
|
@ -1,22 +1,39 @@
|
|||
#include "piper_tts_interface.h"
|
||||
#include <cstdlib> // For system()
|
||||
#include <cstdlib> // For system(), WEXITSTATUS
|
||||
#include <cstdio> // For remove()
|
||||
#include <chrono> // For std::chrono
|
||||
#include <thread> // For std::this_thread::sleep_for
|
||||
#include <cstring> // For strerror <--- **在这里添加这一行**
|
||||
#include <errno.h> // For errno <--- **也建议添加这一行,以防某些系统需要明确引入 errno**
|
||||
|
||||
// 构造函数实现
|
||||
PiperTTSInterface::PiperTTSInterface(const std::string& piper_exec_path,
|
||||
const std::string& model_path_fixed)
|
||||
: piper_executable(piper_exec_path), fixed_model_path(model_path_fixed) {
|
||||
|
||||
// 构造函数实现 (注意默认参数的设置仅在头文件中一次性完成)
|
||||
PiperTTSInterface::PiperTTSInterface(const std::string& piper_executable_path,
|
||||
const std::string& default_model_path)
|
||||
: piper_executable(piper_executable_path), fixed_model_path(default_model_path) {
|
||||
// 构造时直接初始化模型路径
|
||||
if (fixed_model_path.empty()) {
|
||||
std::cerr << "Warning: PiperTTSInterface created without a default model path. text_to_speech calls may fail." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// 注意:这里不再有 set_default_model_path 方法
|
||||
|
||||
// 辅助函数,封装 system() 调用,以便更好地控制和调试
|
||||
int PiperTTSInterface::execute_command(const std::string& command) {
|
||||
std::cout << "Executing command: " << command << std::endl;
|
||||
return std::system(command.c_str());
|
||||
// 使用WEXITSTATUS宏获取system()返回的实际退出码
|
||||
int result = std::system(command.c_str());
|
||||
if (result == -1) { // system() 失败
|
||||
std::cerr << "system() call failed: " << strerror(errno) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
// WEXITSTATUS 定义在 <sys/wait.h> 中,但通常 <cstdlib> 就足够了。
|
||||
// 如果编译仍然报错找不到 WEXITSTATUS,可能需要单独引入 <sys/wait.h>。
|
||||
if (WIFEXITED(result)) { // 检查子进程是否正常退出
|
||||
return WEXITSTATUS(result); // 获取子进程的退出状态码
|
||||
} else {
|
||||
std::cerr << "Command did not exit normally. System call result: " << result << std::endl;
|
||||
return -1; // 或者其他错误码表示非正常退出
|
||||
}
|
||||
}
|
||||
|
||||
bool PiperTTSInterface::text_to_speech(const std::string& text,
|
||||
|
|
@ -28,6 +45,8 @@ bool PiperTTSInterface::text_to_speech(const std::string& text,
|
|||
return false;
|
||||
}
|
||||
|
||||
// 注意:这里没有对 text 进行完整的 shell 转义,对于特殊字符可能需要更健壮的处理
|
||||
// 对于更安全的shell命令构建,可以考虑使用 popen 和管道,或者专业的库进行转义
|
||||
std::string escaped_text = text;
|
||||
|
||||
std::string command = "echo \"" + escaped_text + "\" | " +
|
||||
|
|
@ -36,7 +55,7 @@ bool PiperTTSInterface::text_to_speech(const std::string& text,
|
|||
|
||||
int result = execute_command(command);
|
||||
|
||||
if (result == 0) { // system() 返回 0 表明命令执行成功
|
||||
if (result == 0) { // execute_command() 返回 0 表明命令执行成功
|
||||
std::cout << "Successfully generated audio: " << output_filename << std::endl;
|
||||
return true;
|
||||
} else {
|
||||
|
|
@ -44,3 +63,38 @@ bool PiperTTSInterface::text_to_speech(const std::string& text,
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 新增函数:文本转语音,播放,然后删除文件
|
||||
bool PiperTTSInterface::say_text_and_play(const std::string& text) {
|
||||
// 1. 生成唯一的临时文件名
|
||||
auto now = std::chrono::high_resolution_clock::now();
|
||||
auto nanoseconds = std::chrono::duration_cast<std::chrono::nanoseconds>(now.time_since_epoch()).count();
|
||||
std::string temp_filename = "/tmp/piper_temp_" + std::to_string(nanoseconds) + ".wav";
|
||||
std::cout << "Generating temporary audio file: " << temp_filename << " for text: '" << text << "'" << std::endl;
|
||||
if (!text_to_speech(text, temp_filename)) {
|
||||
std::cerr << "Failed to generate audio for speech playback." << std::endl;
|
||||
return false;
|
||||
}
|
||||
// 3. 播放音频文件 - 改用 gst-launch-1.0
|
||||
// 使用 gst-launch-1.0 播放,它已经证明可以在你的系统上正常工作
|
||||
// 我们会直接使用你提供的成功播放的命令模板
|
||||
std::string play_command = "gst-launch-1.0 -v filesrc location=" + temp_filename +
|
||||
" ! decodebin ! audioconvert ! alsasink device=hw:2,0";
|
||||
std::cout << "Playing generated audio file using GStreamer: " << temp_filename << std::endl;
|
||||
int play_result = execute_command(play_command);
|
||||
if (play_result != 0) {
|
||||
std::cerr << "Failed to play audio file using GStreamer: " << temp_filename << ". Command exited with code: " << play_result << std::endl;
|
||||
} else {
|
||||
std::cout << "Audio playback finished using GStreamer for: " << temp_filename << std::endl;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
|
||||
// 4. 删除音频文件(调试完成后可以取消注释)
|
||||
std::cout << "Deleting temporary audio file: " << temp_filename << std::endl;
|
||||
if (std::remove(temp_filename.c_str()) != 0) {
|
||||
std::cerr << "Warning: Failed to delete temporary audio file: " << temp_filename << ". Error: " << strerror(errno) << std::endl;
|
||||
} else {
|
||||
std::cout << "Successfully deleted temporary audio file: " << temp_filename << std::endl;
|
||||
}
|
||||
return play_result == 0;
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
// piper_tts_interface.h
|
||||
#ifndef PIPER_TTS_INTERFACE_H
|
||||
#define PIPER_TTS_INTERFACE_H
|
||||
|
||||
|
|
@ -16,11 +17,17 @@ public:
|
|||
* @brief 将文本转换为语音并保存为WAV文件。
|
||||
* @param text 要转换的文本。
|
||||
* @param output_filename 生成的WAV文件名,例如 "output.wav"。
|
||||
* 如果model_path参数为空,则使用构造函数中指定的默认模型。
|
||||
* @return true 表示成功生成音频,false 表示失败。
|
||||
*/
|
||||
bool text_to_speech(const std::string& text,
|
||||
const std::string& output_filename); // 移除了 model_path 参数
|
||||
const std::string& output_filename);
|
||||
|
||||
/**
|
||||
* @brief 将文本转换为语音,使用 aplay 播放,然后删除生成的WAV文件。
|
||||
* @param text 要说出的文本。
|
||||
* @return true 表示成功生成并播放音频,false 表示失败。
|
||||
*/
|
||||
bool say_text_and_play(const std::string& text); // <--- 在这里添加新函数的声明
|
||||
|
||||
private:
|
||||
std::string piper_executable; // Piper 可执行文件的路径
|
||||
|
|
|
|||
Loading…
Reference in New Issue