我的编程空间,编程开发者的网络收藏夹
学习永远不晚

QT采集声卡PCM数据再保存为WAV格式,播放器可以直接播放(Android、ubuntu、windows运行OK)

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

QT采集声卡PCM数据再保存为WAV格式,播放器可以直接播放(Android、ubuntu、windows运行OK)

一、功能介绍

QT通过QAudioInput类读取声卡PCM数据,在封装WAV头,转为WAV格式的文件保存到本地。

代码里固定录制10S的声音,有进度条显示录制和播放的进度。

二、核心代码

mainwindow.h文件代码:


#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include 
#include 
#include      //这五个是QT处理音频的库
#include 
#include 
#include 
#include 
#include 
#include 
#include 
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    void SetStyle(const QString &qssFile);
    QFile sourceFile;   // class member.
    QFile destinationFile;   // Class member
    QAudioFormat auido_input_format;
    QTimer timer_progressBar;
    int progressBar_val;
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    QAudioInput *audio_in;
    QAudioOutput *audio_out;
    void Log_Display(QString text);
    qint64 CreateWavFile(QString catheFileName , QString wavFileName);
private slots:
    void update_progressBar();
    void on_pushButton_clicked();
    void stopRecording();
    void handleStateChanged_input(QAudio::State newState);
    void handleStateChanged_out(QAudio::State newState);
    void on_pushButton_2_clicked();
    void on_pushButton_3_clicked();
private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

mainwindow.cpp文件代码:


#include "mainwindow.h"
#include "ui_mainwindow.h"
//设置录音的时间--ms
#define AUDIO_INPUT_TIME 10000
//#define ANDROID_DEVICE
#ifdef ANDROID_DEVICE
//设置保存文件的路径
#define SAVE_FILE_PATH "/sdcard/DS_XIAOLONG/test.raw"
#else
//设置保存文件的路径
#define SAVE_FILE_PATH "test.pcm"
#define SAVE_WAV_FILE_PATH "test.wav"
#endif

void MainWindow::SetStyle(const QString &qssFile)
{
    QFile file(qssFile);
    if (file.open(QFile::ReadOnly)) {
        QString qss = QLatin1String(file.readAll());
        qApp->setStyleSheet(qss);
        QString PaletteColor = qss.mid(20,7);
        qApp->setPalette(QPalette(QColor(PaletteColor)));
        file.close();
    }
    else
    {
        qApp->setStyleSheet("");
    }
}
//日志信息显示
void MainWindow::Log_Display(QString text)
{
    ui->plainTextEdit->insertPlainText(text);
}
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    this->SetStyle(":/images/blue.css" );        //设置样式表
    this->setWindowIcon(QIcon(":/images/log.ico")); //设置图标
    this->setWindowTitle("录音机");
    //创建工作目录
#ifdef ANDROID_DEVICE
    QDir dir;
    if(!dir.exists("/sdcard/DS_XIAOLONG"))
    {
        if(dir.mkdir("/sdcard/DS_XIAOLONG"))
        {
            Log_Display("/sdcard/DS_XIAOLONG目录创建成功.\n");
        }
        else
        {
            Log_Display("/sdcard/DS_XIAOLONG目录创建失败.\n");
        }
    }
#endif
    //进度条更新
    progressBar_val=0;
    ui->progressBar->setRange(0,AUDIO_INPUT_TIME);
    ui->progressBar->setValue(0);
    connect(&timer_progressBar, SIGNAL(timeout()), this, SLOT(update_progressBar()));
}
void MainWindow::stopRecording()
{
  Log_Display("停止录音.\n");
  audio_in->stop();
  destinationFile.close();
}
MainWindow::~MainWindow()
{
    delete ui;
}
//录音状态
void MainWindow::handleStateChanged_input(QAudio::State newState)
{
 switch (newState) {
     case QAudio::StoppedState:
         if (audio_in->error() != QAudio::NoError) {
             // Error handling
             Log_Display("录音出现错误.\n");
         } else {
             // Finished recording
             Log_Display("完成录音\n");
             //将PCM文件转为WAV文件
             CreateWavFile(SAVE_FILE_PATH,SAVE_WAV_FILE_PATH);
         }
         break;
     case QAudio::ActiveState:
         // Started recording - read from IO device
         Log_Display("开始从IO设备读取PCM声音数据.\n");
         break;
     default:
         // ... other cases as appropriate
         break;
 }
}
//开始采集音频数据
void MainWindow::on_pushButton_clicked()
{
    static bool flag1=1;
    if(flag1) //只需要运行一次
    {
        flag1=0;
        //设置录音的格式
        auido_input_format.setSampleRate(16000); //设置采样率以对赫兹采样。
        auido_input_format.setChannelCount(1);   //将通道数设置为通道。
        auido_input_format.setSampleSize(16);   
        auido_input_format.setCodec("audio/pcm"); //设置编码格式
        auido_input_format.setByteOrder(QAudioFormat::LittleEndian); //样本是小端字节顺序
        auido_input_format.setSampleType(QAudioFormat::UnSignedInt); //样本是无符号整数
        //选择默认设备作为输入源
        QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
        Log_Display(tr("当前的录音设备的名字:%1\n").arg(info.deviceName()));
        //判断输入的格式是否支持,如果不支持就使用系统支持的默认格式
        if(!info.isFormatSupported(auido_input_format))
        {
          auido_input_format=info.nearestFormat(auido_input_format);
          
        }
        //当前设备支持的编码
        Log_Display("当前设备支持的编码格式:\n");
        QStringList list=info.supportedCodecs();
        for(int i=0;istate()==QAudio::StoppedState)
    {
       // qDebug()<start(&destinationFile);
        progressBar_val=0;
        ui->progressBar->setFormat("录音进度%p");
        timer_progressBar.start(1000); //开始定时器--显示进度条
    }
}
//更新进度条
void MainWindow::update_progressBar()
{
    progressBar_val+=1000; //1000ms
    if(progressBar_val>=AUDIO_INPUT_TIME)timer_progressBar.stop();
    ui->progressBar->setValue(progressBar_val);
}
//开始播放音频
void MainWindow::on_pushButton_2_clicked()
{
    static bool flag=1;
    if(flag)
    {
        flag=0;
        QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
        if(!info.isFormatSupported(auido_input_format))
        {
          Log_Display("后端不支持原始音频格式,无法播放音频.\n");
          return;
        }
        //当前设备支持的编码
        Log_Display("当前设备支持的编码格式:\n");
        QStringList list=info.supportedCodecs();
        for(int i=0;istart(&sourceFile);
    progressBar_val=0;
    ui->progressBar->setFormat("播放进度%p");
    timer_progressBar.start(1000); //开始定时器--显示进度条
}
//播放音频的反馈信息
void MainWindow::handleStateChanged_out(QAudio::State newState)
{
    switch (newState){
          case QAudio::IdleState:
              // Finished playing (no more data)
              audio_out->stop();
              sourceFile.close();
              Log_Display("音频播放完成.\n");
              break;
          case QAudio::StoppedState:
              // Stopped for other reasons
              if (audio_out->error() != QAudio::NoError) {
                 Log_Display("播放音频出现错误.\n");
              }
              break;
          default:
              // ... other cases as appropriate
              break;
      }
}
//查询可用的音频设备列表
void MainWindow::on_pushButton_3_clicked()
{
    foreach(const QAudioDeviceInfo &deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioOutput))
         Log_Display(tr("Device name:%1\n").arg(deviceInfo.deviceName()));
}
struct WAVFILEHEADER
{
    // RIFF 头
    char RiffName[4];
    unsigned long nRiffLength;
    // 数据类型标识符
    char WavName[4];
    // 格式块中的块头
    char FmtName[4];
    unsigned long nFmtLength;
    // 格式块中的块数据
    unsigned short nAudioFormat;
    unsigned short nChannleNumber;
    unsigned long nSampleRate;
    unsigned long nBytesPerSecond;
    unsigned short nBytesPerSample;
    unsigned short nBitsPerSample;
    // 数据块中的块头
    char    DATANAME[4];
    unsigned long   nDataLength;
};
// 将生成的.raw文件转成.wav格式文件;
qint64 MainWindow::CreateWavFile(QString PcmFileName,QString wavFileName)
{
    // 开始设置WAV的文件头
    WAVFILEHEADER WavFileHeader;
    qstrcpy(WavFileHeader.RiffName,"RIFF");
    qstrcpy(WavFileHeader.WavName, "WAVE");
    qstrcpy(WavFileHeader.FmtName, "fmt ");
    qstrcpy(WavFileHeader.DATANAME,"data");
    // 表示 FMT块 的长度
    WavFileHeader.nFmtLength = 16;
    // 表示 按照PCM 编码;
    WavFileHeader.nAudioFormat = 1;
    // 声道数目;
    WavFileHeader.nChannleNumber = 1;
    // 采样频率;
    WavFileHeader.nSampleRate = 16000;
    // nBytesPerSample 和 nBytesPerSecond这两个值通过设置的参数计算得到;
    // 数据块对齐单位(每个采样需要的字节数 = 通道数 × 每次采样得到的样本数据位数 / 8 )
    WavFileHeader.nBytesPerSample = 2;
    // 波形数据传输速率
    // (每秒平均字节数 = 采样频率 × 通道数 × 每次采样得到的样本数据位数 / 8  = 采样频率 × 每个采样需要的字节数 )
    WavFileHeader.nBytesPerSecond = 32000;
    // 每次采样得到的样本数据位数;
    WavFileHeader.nBitsPerSample = 16;
    QFile cacheFile(PcmFileName);
    QFile wavFile(wavFileName);
    if (!cacheFile.open(QIODevice::ReadWrite))
    {
        return -1;
    }
    if (!wavFile.open(QIODevice::WriteOnly))
    {
        return -2;
    }
    int nSize = sizeof(WavFileHeader);
    qint64 nFileLen = cacheFile.bytesAvailable();
    WavFileHeader.nRiffLength = static_cast(nFileLen - 8 + nSize);
    //static_cast(变量);  //新式的强制转换
    WavFileHeader.nDataLength = static_cast(nFileLen);
    // 先将wav文件头信息写入,再将音频数据写入;
    wavFile.write((const char *)&WavFileHeader,nSize);
    wavFile.write(cacheFile.readAll());
    cacheFile.close();
    wavFile.close();
    return nFileLen;
}

下面公众号提供了全套C、C++、单片机、QT基础教程:


作者:DS小龙哥


免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

QT采集声卡PCM数据再保存为WAV格式,播放器可以直接播放(Android、ubuntu、windows运行OK)

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

QT采集声卡PCM数据再保存为WAV格式,播放器可以直接播放(Android、ubuntu、windows运行OK)

一、功能介绍 QT通过QAudioInput类读取声卡PCM数据,在封装WAV头,转为WAV格式的文件保存到本地。 代码里固定录制10S的声音,有进度条显示录制和播放的进度。 二、核心代码 mainwindow.h文件代码:#ifndef
2022-06-06

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录