This commit is contained in:
2026-06-14 15:54:35 +08:00
commit 3caeb07e54
2804 changed files with 373231 additions and 0 deletions
+154
View File
@@ -0,0 +1,154 @@
//
// Created by Administrator on 2025/1/17.
//
#pragma once
#include <QAudioSource>
#include <QMediaDevices>
#include <QAudioDevice>
#include <QAudioFormat>
#include <QTimer>
#include <QDir>
#include <vector>
#include <QScopedPointer>
#include <QMutex>
/**
* @brief 录音模块
* @author Misaki
* @date 2025/1/17(first) 2025/11/30(update)
* 单例类
* 使用 QAudioSource 获取原始 PCM 数据,实现 RMS 计算和 WAV 保存
*/
class AudioInput : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(AudioInput) // 禁用拷贝
private:
/**
* @brief 构造函数
* @param parent
*/
explicit AudioInput(QObject *parent = nullptr);
static QScopedPointer<AudioInput> instance;
static QMutex mutex;
public:
/**
* @brief 获取实例
* @return AudioInput*
*/
static AudioInput* getInstance();
/**
* @brief 析构函数
*/
~AudioInput() override;
/**
* @brief 配置音频参数 (Qt6 中推荐使用 float 或 int16)
*/
void setAudioSettings(int rate = 44100, int channels = 2);
/**
* @brief 设置录音文件输出路径与文件名
* @param path 输出路径
* @param fileName 文件名
*/
void setAudioPath(const QString &path, const QString &fileName);
/**
* @brief 开始录音
*/
void startAudio();
/**
* @brief 停止录音
*/
void stopAudio();
/**
* @brief 设置录音时间并开始录音
* @param duration 录音时长,单位为秒
*/
void startAudioWithDuration(int duration);
/**
* @brief 开始自动录音,根据声音判断是否停止
* @param silenceThreshold 静音阈值,低于该值则认为没有声音
* @param silenceDuration 静音持续时间,单位为毫秒
*/
void startAutoStopAudio(qreal silenceThreshold = 1200, int silenceDuration = 1500);
/**
* @brief 开始最佳阈值计算
* @param Duration 持续时间,单位为毫秒
*/
void startAutoThresholdClu(int Duration = 5000);
/**
* @brief 获取当前系统所有的音频输入设备
* @return 音频输入设备名称列表
*/
static QList<QString> getAvailableAudioInputDevices();
/**
* @brief 设置当前录音设备
* @param deviceName 设备名称
*/
void setAudioInputDevice(const QString &deviceName);
/**
* @brief 设置静音阈值
* @param silenceThreshold 阈值
*/
void setSilenceThreshold(qreal silenceThreshold);
[[nodiscard]] qreal getSilenceThreshold() const;
private:
// WAV头生成工具函数
[[nodiscard]] QByteArray generateWavHeader(quint32 dataSize) const;
// 计算RMS值工具函数
static qreal calculateRMS(const QByteArray& buffer);
signals:
// 录音完成信号
void recordingFinished();
void recordingFinished_Byte(const QByteArray &wavData); // 携带音频数据
// 实时RMS值信号
void rmsRealValue(qreal value);
// 阈值计算完成信号
void thresholdCalculated(qreal bestThreshold);
private slots:
void onTimeout(); // 定时器超时槽函数
void thresholdTimeout(); // 阈值超时槽函数
// void processBuffer(const QAudioBuffer& buffer); // 处理缓冲区数据
void onReadyRead(); // 替代原先的 processBuffer,当有音频数据来时触发
private:
QAudioSource *m_audioSource = nullptr; /// Qt6 核心录音对象
QIODevice *m_ioDevice = nullptr; /// 用于读取数据的 IO 设备
QAudioFormat m_format; /// 音频格式
QAudioDevice m_currentDevice; /// 当前选中的输入设备
// 数据缓存
QByteArray m_rawPCMData; /// 存储原始PCM数据
QString m_outputFilePath;
// 逻辑控制变量
bool isAutoRecording = false; /// 是否自动录音状态
bool isAutoThreshold = false; /// 是否自动计算阈值
qreal m_rmsValue = 0.0; /// 实时RMS值
// 定时器
QTimer *m_timer; /// 总时长定时器
QTimer *m_silenceTimer; /// 静音检测定时器
QTimer *m_thresholdTimer; /// 阈值计算定时器
// 阈值算法相关
std::vector<qreal> m_rmsValues; /// RMS值vector
qreal m_silenceThreshold = 1200; /// 静音阈值
int m_silenceDuration = 1500; /// 静音持续时间
qreal m_smoothRms = 0.0; /// 平滑RMS值(用于防止低频杂波突然打断静音检测)
bool m_hasVoiceDetected = false; /// 是否已检测到人声
};
+121
View File
@@ -0,0 +1,121 @@
//
// Created by Administrator on 2025/1/17.
//
#pragma once
#include <QObject>
#include <QMediaPlayer> // 音频播放模块
#include <QAudioOutput> // QMediaPlayer 的音量控制组件
#include <QAudioSink> // 音频输出组件, 用于原始数据播放
#include <QThread>
#include <QMutex>
#include <QQueue>
#include <QUrl>
#include <QBuffer>
#include <QAudioFormat>
/**
* @brief 音频播放模块
* @author Misaki
* 单例类
* 本模块重新基于Qt6重构 2026.1.31第三次重构
* 实现的功能
* 1. 流式wav音频播放
* 2. 根据音频文件路径播放音频
*/
// Worker 类定义 (负责流式音频的底层处理) 注意:此类实例将完全运行在子线程中
class StreamAudioWorker : public QObject {
Q_OBJECT
public:
explicit StreamAudioWorker(QObject* parent = nullptr) : QObject(parent) {}
~StreamAudioWorker() override;
public slots:
// 初始化并启动音频设备
void start(int sampleRate, int channelCount, int bitDepth);
// 处理接收到的音频数据块
void processChunk(const QByteArray& chunk);
// 停止播放并清理资源
void stop();
signals:
void errorOccurred(const QString& msg);
void playbackFinished(); // 流播放结束(通常指队列空了)
private:
QScopedPointer<QAudioSink> m_sink;
QIODevice* m_ioDevice = nullptr; // 由 m_sink->start() 返回,不需要且不能手动 delete
bool m_firstChunk = true; // 标记是否是第一块数据(用于剥离WAV头)
};
// AudioOutput 主类 (单例,线程安全)
class AudioOutput : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(AudioOutput)
private:
explicit AudioOutput(QObject *parent = nullptr);
static QScopedPointer<AudioOutput> m_instance;
static QMutex m_mutex;
public:
static AudioOutput *getInstance();
static void destroy(); // 显式销毁
~AudioOutput() override;
// 通用控制接口
// 停止所有播放 (文件和流)
void stopPlayback();
// 设置音量 (0-100)
void setVolume(int volume);
// 获取当前状态
bool isPlaying() const;
// 文件/URL 播放接口 (基于 QMediaPlayer)
void playUrl(const QUrl& url);
void playData(const QByteArray& data); // 播放完整的内存文件
// 流式播放接口 (基于 QAudioSink + Worker Thread)
/**
* @brief 开启流式播放会话
* @param sampleRate 采样率 (默认 32000)
* @param channelCount 通道数 (默认 1)
* @param bitDepth 位深 (默认 16)
*/
void startStream(int sampleRate = 32000, int channelCount = 1, int bitDepth = 16);
/**
* @brief 写入流数据
* @param chunk 音频数据块
*/
void pushStreamData(const QByteArray& chunk);
/**
* @brief 结束流 (停止接收新数据,播放完当前缓冲后停止)
*/
void stopStream();
signals:
// 内部转发给 Worker 的信号
void sigOperateStreamStart(int sampleRate, int channelCount, int bitDepth);
void sigOperateStreamChunk(const QByteArray& chunk);
void sigOperateStreamStop();
// 对外通知信号
void playbackFinished();
void errorOccurred(const QString& error);
private:
// 文件播放组件
QMediaPlayer* m_player = nullptr;
QAudioOutput* m_audioOutput = nullptr;
// 流式播放组件
QThread* m_workerThread = nullptr;
StreamAudioWorker* m_streamWorker = nullptr;
// 状态管理
bool m_isStreaming = false;
};