当前位置: 首页 > news >正文

Qt - 音频采集程序

我们将创建一个简单的Qt应用程序,用于采集麦克风的音频数据。我们将使用QAudioInput来捕获音频,并将捕获的原始PCM数据保存到文件中。同时,我们也会在界面上显示一些基本的控制按钮(开始、停止)和状态信息。

步骤:

  1. 创建Qt项目(例如使用Qt Widgets Application)。

  2. 在.pro文件中添加multimedia模块:QT += multimedia

  3. 设计一个简单的界面,包含两个按钮(开始和停止)和一个标签显示状态。

  4. 在后台代码中,设置音频输入设备,并当点击开始按钮时,开始捕获音频数据;点击停止按钮时,停止捕获。

注意:我们这里将捕获的原始PCM数据保存为文件,但请注意原始PCM数据没有文件头(如WAV头),所以不能直接播放。如果需要可播放的文件,可以添加WAV头或者使用其他格式。

但是,为了简单起见,我们只保存原始PCM数据。如果你需要播放,可以使用Audacity等工具导入原始数据(设置正确的采样率、样本大小和通道数)。

我们将使用以下音频格式:

  • 采样率:44100 Hz

  • 样本大小:16位

  • 通道数:2(立体声)

如果默认设备不支持这些参数,我们将使用最接近的设置。

代码结构:

  • 使用QAudioInput进行音频输入。

  • 使用QFile来存储捕获的音频数据。

界面设计:

  • 一个QPushButton用于开始捕获。

  • 一个QPushButton用于停止捕获(初始不可用)。

  • 一个QLabel用于显示状态。

逻辑:

  • 点击开始按钮后,初始化音频输入设备并开始捕获,同时将开始按钮禁用,停止按钮启用。

  • 点击停止按钮后,停止捕获,关闭文件,并将按钮状态重置。

我们将创建一个类,比如叫AudioCapture,来管理音频捕获。

由于Qt6中对多媒体模块有一些变化,请注意:如果你使用的是Qt6,需要确保包括正确的模块。在Qt6中,QAudioInput位于QtMultimedia模块中。

Qt 麦克风音频数据采集应用

下面是一个完整的 Qt 应用程序,用于采集麦克风音频数据并实时显示波形。

 

1. 项目文件(AudioCaptureApp.pro)

qmake
QT       += core gui multimedia widgetsCONFIG   += c++17TARGET = AudioCaptureApp
TEMPLATE = appSOURCES += \main.cpp \mainwindow.cpp \audiocapture.cppHEADERS += \mainwindow.h \audiocapture.hFORMS += \widget.ui

2. 主程序入口 (main.cpp)

cpp
#include <QApplication>
#include "mainwindow.h"int main(int argc, char *argv[])
{QApplication app(argc, argv);// 设置应用程序信息app.setApplicationName("音频采集应用");app.setApplicationVersion("1.0");app.setOrganizationName("MyCompany");MainWindow window;window.show();return app.exec();
}

3. 音频采集类头文件 (audiocapture.h)

cpp
#ifndef AUDIOCAPTURE_H
#define AUDIOCAPTURE_H#include <QObject>
#include <QAudioInput>
#include <QAudioDeviceInfo>
#include <QByteArray>
#include <QTimer>
#include <QDebug>class AudioCapture : public QObject
{Q_OBJECTpublic:explicit AudioCapture(QObject *parent = nullptr);~AudioCapture();// 音频设备操作bool initializeAudio();void startCapture();void stopCapture();void pauseCapture();void resumeCapture();// 设备信息QList<QAudioDeviceInfo> getAvailableDevices() const;QString getCurrentDeviceName() const;// 音频参数设置void setSampleRate(int rate);void setChannelCount(int channels);void setSampleSize(int size);// 状态查询bool isCapturing() const { return m_isCapturing; }qint64 getBytesCaptured() const { return m_bytesCaptured; }signals:// 音频数据可用信号void audioDataAvailable(const QByteArray &data);// 音频电平信号(用于显示波形)void audioLevelChanged(qreal level);// 状态变化信号void captureStateChanged(bool capturing);// 错误信号void errorOccurred(const QString &errorMessage);public slots:void setAudioDevice(const QAudioDeviceInfo &device);private slots:void handleAudioDataReady();void updateAudioLevel();private:void setupAudioFormat();void calculateAudioLevel(const QByteArray &data);private:QAudioInput *m_audioInput;QIODevice *m_audioDevice;QAudioFormat m_audioFormat;QAudioDeviceInfo m_currentDevice;QTimer *m_levelTimer;bool m_isCapturing;bool m_isPaused;qint64 m_bytesCaptured;qreal m_currentLevel;
};#endif // AUDIOCAPTURE_H

4. 音频采集类实现 (audiocapture.cpp)

cpp
#include "audiocapture.h"AudioCapture::AudioCapture(QObject *parent) : QObject(parent), m_audioInput(nullptr), m_audioDevice(nullptr), m_isCapturing(false), m_isPaused(false), m_bytesCaptured(0), m_currentLevel(0.0)
{m_levelTimer = new QTimer(this);connect(m_levelTimer, &QTimer::timeout, this, &AudioCapture::updateAudioLevel);
}AudioCapture::~AudioCapture()
{stopCapture();
}bool AudioCapture::initializeAudio()
{// 获取默认输入设备m_currentDevice = QAudioDeviceInfo::defaultInputDevice();if (m_currentDevice.isNull()) {emit errorOccurred("未找到可用的音频输入设备");return false;}// 设置音频格式setupAudioFormat();// 检查格式支持if (!m_currentDevice.isFormatSupported(m_audioFormat)) {m_audioFormat = m_currentDevice.nearestFormat(m_audioFormat);qDebug() << "使用最接近的音频格式:" << m_audioFormat.sampleRate() << "Hz," << m_audioFormat.channelCount() << "channels,"<< m_audioFormat.sampleSize() << "bits";}// 创建音频输入对象m_audioInput = new QAudioInput(m_currentDevice, m_audioFormat, this);// 设置缓冲区大小m_audioInput->setBufferSize(4096);return true;
}void AudioCapture::setupAudioFormat()
{m_audioFormat.setSampleRate(44100);      // 44.1 kHzm_audioFormat.setChannelCount(1);        // 单声道m_audioFormat.setSampleSize(16);         // 16位m_audioFormat.setCodec("audio/pcm");     // PCM编码m_audioFormat.setByteOrder(QAudioFormat::LittleEndian);m_audioFormat.setSampleType(QAudioFormat::SignedInt);
}void AudioCapture::startCapture()
{if (!m_audioInput) {if (!initializeAudio()) {return;}}if (m_isCapturing && !m_isPaused) {return;}if (m_isPaused) {resumeCapture();return;}// 开始音频采集m_audioDevice = m_audioInput->start();if (!m_audioDevice) {emit errorOccurred("无法启动音频设备");return;}// 连接数据可用信号connect(m_audioDevice, &QIODevice::readyRead, this, &AudioCapture::handleAudioDataReady);m_isCapturing = true;m_isPaused = false;m_bytesCaptured = 0;// 启动电平计时器(用于实时显示)m_levelTimer->start(50); // 每50ms更新一次电平emit captureStateChanged(true);qDebug() << "开始音频采集,设备:" << m_currentDevice.deviceName();
}void AudioCapture::stopCapture()
{if (m_audioInput) {m_audioInput->stop();if (m_audioDevice) {m_audioDevice->disconnect();m_audioDevice = nullptr;}}m_levelTimer->stop();m_isCapturing = false;m_isPaused = false;m_currentLevel = 0.0;emit captureStateChanged(false);emit audioLevelChanged(0.0);qDebug() << "停止音频采集,总采集数据:" << m_bytesCaptured << "字节";
}void AudioCapture::pauseCapture()
{if (m_isCapturing && !m_isPaused) {m_audioInput->suspend();m_isPaused = true;m_levelTimer->stop();emit audioLevelChanged(0.0);}
}void AudioCapture::resumeCapture()
{if (m_isCapturing && m_isPaused) {m_audioInput->resume();m_isPaused = false;m_levelTimer->start(50);}
}void AudioCapture::handleAudioDataReady()
{if (!m_audioDevice) return;// 读取音频数据QByteArray audioData = m_audioDevice->readAll();if (audioData.isEmpty()) return;m_bytesCaptured += audioData.size();// 计算音频电平(用于波形显示)calculateAudioLevel(audioData);// 发送数据可用信号emit audioDataAvailable(audioData);
}void AudioCapture::calculateAudioLevel(const QByteArray &data)
{const qint16 *samples = reinterpret_cast<const qint16*>(data.constData());int sampleCount = data.size() / 2; // 16位样本,每个样本2字节qreal maxValue = 0;for (int i = 0; i < sampleCount; ++i) {qreal value = qAbs(samples[i]) / 32768.0; // 16位有符号整数范围:-32768到32767if (value > maxValue) {maxValue = value;}}m_currentLevel = maxValue;
}void AudioCapture::updateAudioLevel()
{emit audioLevelChanged(m_currentLevel);m_currentLevel = 0.0; // 重置为下次计算
}QList<QAudioDeviceInfo> AudioCapture::getAvailableDevices() const
{return QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
}QString AudioCapture::getCurrentDeviceName() const
{return m_currentDevice.deviceName();
}void AudioCapture::setAudioDevice(const QAudioDeviceInfo &device)
{if (m_isCapturing) {stopCapture();}m_currentDevice = device;// 重新初始化音频输入if (m_audioInput) {delete m_audioInput;m_audioInput = nullptr;}initializeAudio();
}void AudioCapture::setSampleRate(int rate)
{m_audioFormat.setSampleRate(rate);if (m_isCapturing) {// 需要重新启动采集stopCapture();startCapture();}
}void AudioCapture::setChannelCount(int channels)
{m_audioFormat.setChannelCount(channels);if (m_isCapturing) {stopCapture();startCapture();}
}void AudioCapture::setSampleSize(int size)
{m_audioFormat.setSampleSize(size);if (m_isCapturing) {stopCapture();startCapture();}
}

5. 主窗口头文件 (mainwindow.h)

cpp
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QPushButton>
#include <QLabel>
#include <QComboBox>
#include <QProgressBar>
#include <QCheckBox>
#include <QSpinBox>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QGroupBox>
#include <QFileDialog>
#include <QMessageBox>
#include "audiocapture.h"class MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:void onStartStopClicked();void onPauseResumeClicked();void onSaveDataClicked();void onDeviceChanged(int index);void handleAudioDataAvailable(const QByteArray &data);void handleAudioLevelChanged(qreal level);void handleCaptureStateChanged(bool capturing);void handleErrorOccurred(const QString &errorMessage);private:void setupUI();void setupConnections();void updateDeviceList();void updateUIState();private:// UI 组件QWidget *m_centralWidget;QVBoxLayout *m_mainLayout;QGroupBox *m_deviceGroup;QComboBox *m_deviceCombo;QLabel *m_statusLabel;QProgressBar *m_levelBar;QGroupBox *m_controlGroup;QPushButton *m_startStopButton;QPushButton *m_pauseResumeButton;QPushButton *m_saveButton;QGroupBox *m_settingsGroup;QCheckBox *m_autoSaveCheck;QSpinBox *m_sampleRateSpin;QSpinBox *m_channelsSpin;QLabel *m_statsLabel;// 音频采集AudioCapture *m_audioCapture;// 数据存储QByteArray m_capturedData;bool m_isCapturing;bool m_isPaused;
};#endif // MAINWINDOW_H

6. 主窗口实现 (mainwindow.cpp)

cpp
#include "mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), m_audioCapture(new AudioCapture(this)), m_isCapturing(false), m_isPaused(false)
{setWindowTitle("Qt 音频采集应用");setMinimumSize(600, 400);setupUI();setupConnections();updateDeviceList();updateUIState();
}MainWindow::~MainWindow()
{if (m_isCapturing) {m_audioCapture->stopCapture();}
}void MainWindow::setupUI()
{m_centralWidget = new QWidget(this);setCentralWidget(m_centralWidget);m_mainLayout = new QVBoxLayout(m_centralWidget);// 设备选择组m_deviceGroup = new QGroupBox("音频设备", this);QVBoxLayout *deviceLayout = new QVBoxLayout(m_deviceGroup);m_deviceCombo = new QComboBox(this);deviceLayout->addWidget(m_deviceCombo);m_statusLabel = new QLabel("状态: 未启动", this);deviceLayout->addWidget(m_statusLabel);m_levelBar = new QProgressBar(this);m_levelBar->setRange(0, 100);m_levelBar->setValue(0);m_levelBar->setFormat("音频电平: %p%");deviceLayout->addWidget(m_levelBar);m_mainLayout->addWidget(m_deviceGroup);// 控制按钮组m_controlGroup = new QGroupBox("控制", this);QHBoxLayout *controlLayout = new QHBoxLayout(m_controlGroup);m_startStopButton = new QPushButton("开始采集", this);m_pauseResumeButton = new QPushButton("暂停", this);m_saveButton = new QPushButton("保存数据", this);m_pauseResumeButton->setEnabled(false);m_saveButton->setEnabled(false);controlLayout->addWidget(m_startStopButton);controlLayout->addWidget(m_pauseResumeButton);controlLayout->addWidget(m_saveButton);m_mainLayout->addWidget(m_controlGroup);// 设置组m_settingsGroup = new QGroupBox("设置", this);QHBoxLayout *settingsLayout = new QHBoxLayout(m_settingsGroup);m_autoSaveCheck = new QCheckBox("自动保存", this);m_sampleRateSpin = new QSpinBox(this);m_sampleRateSpin->setRange(8000, 192000);m_sampleRateSpin->setValue(44100);m_sampleRateSpin->setSuffix(" Hz");m_channelsSpin = new QSpinBox(this);m_channelsSpin->setRange(1, 2);m_channelsSpin->setValue(1);m_channelsSpin->setSuffix(" 声道");settingsLayout->addWidget(new QLabel("采样率:", this));settingsLayout->addWidget(m_sampleRateSpin);settingsLayout->addWidget(new QLabel("声道数:", this));settingsLayout->addWidget(m_channelsSpin);settingsLayout->addWidget(m_autoSaveCheck);settingsLayout->addStretch();m_mainLayout->addWidget(m_settingsGroup);// 统计信息m_statsLabel = new QLabel("采集数据: 0 字节", this);m_mainLayout->addWidget(m_statsLabel);m_mainLayout->addStretch();
}void MainWindow::setupConnections()
{connect(m_startStopButton, &QPushButton::clicked, this, &MainWindow::onStartStopClicked);connect(m_pauseResumeButton, &QPushButton::clicked, this, &MainWindow::onPauseResumeClicked);connect(m_saveButton, &QPushButton::clicked, this, &MainWindow::onSaveDataClicked);connect(m_deviceCombo, QOverload<int>::of(&QComboBox::currentIndexChanged),this, &MainWindow::onDeviceChanged);connect(m_audioCapture, &AudioCapture::audioDataAvailable,this, &MainWindow::handleAudioDataAvailable);connect(m_audioCapture, &AudioCapture::audioLevelChanged,this, &MainWindow::handleAudioLevelChanged);connect(m_audioCapture, &AudioCapture::captureStateChanged,this, &MainWindow::handleCaptureStateChanged);connect(m_audioCapture, &AudioCapture::errorOccurred,this, &MainWindow::handleErrorOccurred);
}void MainWindow::updateDeviceList()
{m_deviceCombo->clear();QList<QAudioDeviceInfo> devices = m_audioCapture->getAvailableDevices();for (const QAudioDeviceInfo &device : devices) {m_deviceCombo->addItem(device.deviceName(), QVariant::fromValue(device));}if (devices.isEmpty()) {m_deviceCombo->addItem("未找到音频设备");m_startStopButton->setEnabled(false);}
}void MainWindow::updateUIState()
{if (m_isCapturing) {m_startStopButton->setText("停止采集");m_pauseResumeButton->setEnabled(true);m_saveButton->setEnabled(false); // 采集时不能保存m_deviceCombo->setEnabled(false);m_sampleRateSpin->setEnabled(false);m_channelsSpin->setEnabled(false);if (m_isPaused) {m_pauseResumeButton->setText("继续");m_statusLabel->setText("状态: 已暂停");} else {m_pauseResumeButton->setText("暂停");m_statusLabel->setText("状态: 采集中...");}} else {m_startStopButton->setText("开始采集");m_pauseResumeButton->setEnabled(false);m_pauseResumeButton->setText("暂停");m_saveButton->setEnabled(!m_capturedData.isEmpty());m_deviceCombo->setEnabled(true);m_sampleRateSpin->setEnabled(true);m_channelsSpin->setEnabled(true);m_statusLabel->setText("状态: 未启动");}m_statsLabel->setText(QString("采集数据: %1 字节").arg(m_capturedData.size()));
}void MainWindow::onStartStopClicked()
{if (m_isCapturing) {m_audioCapture->stopCapture();} else {// 应用设置m_audioCapture->setSampleRate(m_sampleRateSpin->value());m_audioCapture->setChannelCount(m_channelsSpin->value());// 开始采集m_audioCapture->startCapture();m_capturedData.clear(); // 清空之前的数据}
}void MainWindow::onPauseResumeClicked()
{if (m_isPaused) {m_audioCapture->resumeCapture();m_isPaused = false;} else {m_audioCapture->pauseCapture();m_isPaused = true;}updateUIState();
}void MainWindow::onSaveDataClicked()
{if (m_capturedData.isEmpty()) {QMessageBox::information(this, "提示", "没有可保存的音频数据");return;}QString fileName = QFileDialog::getSaveFileName(this, "保存音频数据", "", "原始音频数据 (*.raw);;所有文件 (*)");if (!fileName.isEmpty()) {QFile file(fileName);if (file.open(QIODevice::WriteOnly)) {file.write(m_capturedData);file.close();QMessageBox::information(this, "成功", "音频数据已保存");} else {QMessageBox::warning(this, "错误", "无法保存文件");}}
}void MainWindow::onDeviceChanged(int index)
{if (index >= 0) {QAudioDeviceInfo device = m_deviceCombo->itemData(index).value<QAudioDeviceInfo>();m_audioCapture->setAudioDevice(device);}
}void MainWindow::handleAudioDataAvailable(const QByteArray &data)
{m_capturedData.append(data);updateUIState();// 如果启用了自动保存,可以在这里实现自动保存逻辑if (m_autoSaveCheck->isChecked()) {// 自动保存实现(可选)}
}void MainWindow::handleAudioLevelChanged(qreal level)
{int levelPercent = qMin(100, static_cast<int>(level * 100));m_levelBar->setValue(levelPercent);
}void MainWindow::handleCaptureStateChanged(bool capturing)
{m_isCapturing = capturing;m_isPaused = false;updateUIState();
}void MainWindow::handleErrorOccurred(const QString &errorMessage)
{QMessageBox::critical(this, "音频采集错误", errorMessage);m_isCapturing = false;m_isPaused = false;updateUIState();
}

功能特点

  1. 设备选择:自动检测并列出所有可用的音频输入设备

  2. 实时监控:显示音频电平,可视化音频输入强度

  3. 灵活控制:开始/停止、暂停/继续采集

  4. 参数设置:可调节采样率、声道数等音频参数

  5. 数据保存:将采集的原始PCM数据保存为文件

  6. 状态显示:实时显示采集状态和统计数据

编译和运行

  1. 使用 Qt Creator 打开项目文件 AudioCaptureApp.pro

  2. 配置正确的 Qt 版本(确保包含 multimedia 模块)

  3. 编译并运行项目

使用说明

  1. 启动应用程序后,选择要使用的音频输入设备

  2. 根据需要调整采样率和声道数设置

  3. 点击"开始采集"按钮开始录音

  4. 观察音频电平显示,确认设备正常工作

  5. 点击"暂停"可以临时停止采集

  6. 点击"停止采集"结束录音

  7. 点击"保存数据"将采集的音频保存为文件

 

 

http://www.hskmm.com/?act=detail&tid=14750

相关文章:

  • 923-
  • 基于 AI 网关提升大模型应用可用性的实践
  • 绝了!TaskMatrix Pro - 谷歌、火狐浏览器任务管理插件,四象限矩阵让拖延症瞬间消失 - 开源免费
  • 洛谷P10288 [GESP样题 八级] 区间
  • AI 时代下,开发流程的重塑:从“代码先行”到“文档驱动”
  • P13617 [ICPC 2025 APC] Bit Counting Sequenc
  • perl -MCPAN -e install GD;
  • P3959 [NOIP 2017 提高组] 宝藏 题解
  • C#与Access数据库操作简易指南:增删改查及类封装
  • 对之前部署hbase总结
  • 国产 CAD 新选择!NanoCAD 24.0:全功能 DWG 支持 + 3D 建模优化,多领域设计效率拉满
  • java 框架mybatis_01(
  • 扣子Coze智能体实战:自动采集1000条小红书爆款笔记 ,自动写入飞书多维表格
  • 公众号文章添加附件,公众号运营必学加分技巧-支持Word、Excel、PDF等文件
  • python脚本划分数据集
  • 用前端(HTML+Node.js)实现物品借用登记:完整代码示例
  • Google智能体Jules小试牛刀
  • 搞笑椅子机房语录
  • 在AI技术快速实现创意的时代,挖掘渗透测试框架新需求成为关键挑战
  • 基于区域的空间域图像融合MATLAB实现
  • Qt - 音视频采集
  • 梳理 | 脑神经科学原理学习资料整理
  • 如何做有效的Bug管理?
  • 2025年9月16日纸质证书 - 高同学PostgreSQL管理员(中级)认证
  • 智能体重电子秤解决方案:开发时注意事项
  • 一套开源、美观、高性能的跨平台 .NET MAUI 控件库,助力轻松构建美观且功能丰富的应用程序!
  • 2025年9月16日纸质证书 - 张同学PostgreSQL管理员(中级)认证
  • SQL统计:统计TEMP表空间的脚本
  • 读书笔记:Oracle索引必知必会:避开这些坑,让你的数据库飞起来
  • 三维CT图像重建算法