Qt各种采样率录音 录音到内存

2023-10-27

近段时间了解了Qt的录音模块,Qt的录音模块分为QAudioInput输入,QAudioOutput输出。输入用来录音,输出用于播放。当然还用其它的QMediaPlayer、QAudioRecorder,这类控件封装的比较上层了;QAudioRecorder只能将数据录入到文件,QMediaPlayer是用于根据文件格式播放,一般用于音乐播放器中。

由于项目需要的是16k采样率的wav音频文件,首先使用QAudioRecorder进行录音,该类接口确实很方便,直接设置输出路径,但是通过Qt官方示例可以看出,

虽然可以设置采样率,但是录音出来的文件采样率并不是设置的参数,采样出来的文件只与setQuality设置的参数有关。



上图桌面的文件便是通过官方示例录制的采样率为16k的wav文件,当我有coolEdit打开时,可以看到采样率并不是16k


截图中红框部分便是实际采样率,于是最终我使用的QAudioInput来录音。

先介绍一下几个重要的类和函数,QAudioDeviceInfo检测本地可用设备;QAudioFormat,设置录音或播放参数;QAudioInput录音。

QAudioInput录音之后的数据是音频原始数据,要想转成wav文件,必需加入44字节的wav文件头。wav文件头的相关知识就请大家网上搜了

,开始录音时要传入一个QIODevice设备,如果想把数据录入到文件还是内存就要在这里入手了,如果是文件就是QFile,是内存就是QBufferr。

以下为一个固定采样率的小程序

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QFile>
#include <QPushButton>
#include <QAudioInput>
#include <QBuffer>

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);
    ~Widget();

private:
    QPushButton *_startBtn,*_endBtn;//开始和结束按钮
    QAudioInput *_audioInput; //录音对象
    QFile outFile;
    QByteArray voiceData;
    QBuffer bufDevice;
};

#endif // WIDGET_H

cpp文件如下

#include "widget.h"
#include <QApplication>
#include <QHBoxLayout>
#include <QDebug>
 
struct WAVHEADER
{
    // 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;
};
 
Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    _startBtn = new QPushButton(QStringLiteral("开始录音"),this);
    _endBtn = new QPushButton(QStringLiteral("结束录音"),this);
 
    QHBoxLayout *_hBoxLayout = new QHBoxLayout(this);
    _hBoxLayout->addWidget(_startBtn);
    _hBoxLayout->addWidget(_endBtn);
    //设置格式
 
 
    QAudioFormat audioFormat;
    audioFormat.setByteOrder(QAudioFormat::LittleEndian);
    audioFormat.setChannelCount(1);
    audioFormat.setCodec("audio/pcm");
    audioFormat.setSampleRate(16000);
    audioFormat.setSampleSize(16);
    audioFormat.setSampleType(QAudioFormat::SignedInt);
    //判断设备,查看是否存在
 
    QAudioDeviceInfo devInfo = QAudioDeviceInfo::defaultInputDevice();
    if(devInfo.isNull()){
        qDebug() << "未找到录音设备";
    }
    //不支持格式,使用最接近格式
    if(!devInfo.isFormatSupported(audioFormat)){ //当前使用设备是否支持
        audioFormat = devInfo.nearestFormat(audioFormat); //转换为最接近格式
    }
    _audioInput = new QAudioInput(devInfo,audioFormat,this);
    //内存的IO对象
 
    bufDevice.setBuffer(&voiceData);
    connect(_startBtn,&QPushButton::clicked,[&]()->void{
             #ifdef TOFILE //存到文件
                outFile.setFileName(qApp->applicationDirPath() + "/test.wav"); //语音原始文件
                outFile.open(QIODevice::WriteOnly | QIODevice::Truncate);
                _audioInput->start(&outFile);
            #else //存到内存
                bufDevice.open(QIODevice::WriteOnly | QIODevice::Truncate);
                _audioInput->start(&bufDevice);
            #endif
    });
 
    connect(_endBtn,&QPushButton::clicked,[&]()->void{
                QIODevice *device{nullptr};
                #ifdef TOFILE //存到文件
                    device = &outFile;
                #else //存到内存
                    device = &bufDevice;
                #endif
		//添加wav文件头
                static WAVHEADER wavHeader;
                qstrcpy(wavHeader.RiffName,"RIFF");
                qstrcpy(wavHeader.WavName,"WAVE");
                qstrcpy(wavHeader.FmtName,"fmt ");
                qstrcpy(wavHeader.DATANAME,"data");
 
                wavHeader.nFmtLength = 16;
                int nAudioFormat = 1;
                wavHeader.nAudioFormat = nAudioFormat;
                wavHeader.nBitsPerSample = 16;
                wavHeader.nChannleNumber = 1;
                wavHeader.nSampleRate = 16000;
                wavHeader.nBytesPerSample = wavHeader.nChannleNumber * wavHeader.nBitsPerSample / 8;
                wavHeader.nBytesPerSecond = wavHeader.nSampleRate * wavHeader.nChannleNumber *  wavHeader.nBitsPerSample / 8;
                wavHeader.nRiffLength = device->size() - 8 + sizeof(WAVHEADER);
                wavHeader.nDataLength = device->size();
		//写到IO设备头
 
                device->seek(0);
                device->write(reinterpret_cast<char*>(&wavHeader),sizeof WAVHEADER);
            });
}
 
Widget::~Widget()
{
#ifdef TOFILE
     outFile.close();
#else
     bufDevice.close();
#endif
 
}
以上程序定义了一个宏,通过宏来决定存到哪里。在QtCreator中加入编译参数即可输出到文件


看清楚添加参数的格式了哦,没有空格。



可以看到文件的采样率已经变到16000k了。如果要存到内存中去掉编译参数就可以了,项目可到此下载祝大家工作愉快。





本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Qt各种采样率录音 录音到内存 的相关文章

随机推荐

  • mysql组内排序

    比如说要获取班级的前3名 oracle 可以用 over partition by 来做 mysql就可以用GROUP CONCAT GROUP BY substring index实现 考试表 DROP TABLE IF EXISTS t
  • NLP:nltk+stanfordNLP

    1 NLTK import nltk form nltk book import 2 NLTK中使用stanfordNLP http www zmonster me 2016 06 08 use stanford nlp package i
  • SpringCloud Alibaba史上最强详解与史上最系统框架搭建

    框架实现代码资源地址 springCloud dataservice bus zip springcloudalibaba搭建 Java文档类资源 CSDN下载 目录 一 官网集合 Springboot官网 中文文档 Mybatis官网 S
  • TCP与UDP(非常详细)

    笔记记录 目录 前言 TCP UDP TCP UDP 区别 总结 前言 TCP IP模型是一些列协议的总称 TCP UDP IP FTP HTTP ICMP SMTP 这些协议可以划分为四层 链路层 网络层 传输层 应用层 TCP和UDP都
  • Oracle 11g客户端连接Oracle 12c服务器错误 ORA-28040

    问题描述 oracle服务器端版本 oracle 12 2 0 1 0 oracle客户端版本 oracle 11 2 0 1 0 在客户端访问oracle 12c提示如下错误 sqlplus scott scott 192 168 100
  • JSON是什么?如何正确理解?

    1 背景介绍 什么是JSON JSON JavaScript Object Notation JS 对象标记 是一种轻量级的数据交换格式 它基于 ECMAScript w3c制定的js规范 的一个子集 采用完全独立于编程语言的文本格式来存储
  • 遗传算法解释

    遗传算法是一种基于自然遗传和进化规律的人工智能算法 它通过模拟生物进化的过程 来解决各种复杂问题 遗传算法的基本流程如下 初始化 随机生成一些解作为初始种群 评估 评估每个解的适应度 根据适应度的高低决定哪些解具有更好的进化前景 交叉 选择
  • 最大连续区间和C++

    在求连续区间的最大和是一种动态规划的常见例题 那么如何能快速求算得一个长度为n的数组的最大连续区间和 第一反应当然是 通过暴力计算每一个区间的和进而求其最大值 但时间复杂度到达了不可接受的O n 2 而比较好的算法如下 include
  • 软件质量属性:可测试性

    测试的目的 尽可能多地发现软件中存在的BUG 不符合需求的部分或者是未实现的需求 测试的意义 尽可能确保软件正式上线运行后不出现问题 减少潜在的风险和损失 可测试性定义 指软件测试的难易度和效率 如果测试结果越直观 测试效率越高 可测试性就
  • 【100天精通Python】Day55:Python 数据分析_Pandas数据选取和常用操作

    目录 Pandas数据选择和操作 1 选择列和行 2 过滤数据 3 添加 删除和修改数据 4 数据排序 Pandas数据选择和操作 Pandas是一个Python库 用于数据分析和操作 提供了丰富的功能来选择 过滤 添加 删除和修改数据 1
  • VUE element-ui之table表格内容样式(颜色)修改

    要求将表格中的负数显示为红色 实现步骤 定义样式方法
  • Motion Partition

    Object Boundary Based motion partition scheme e is the best approximate of foreground picture but wastes coding d is a t
  • qt打包生成exe_Qt-Installer-Framework使用(一)

    Qt Installer Framework 以下简称QIFW 是 Qt 官方出品的一款功能强大的打包工具 可以满足我们日常使用中大部分需求 环境说明 OS Qt MinGW QIFW Windows7 64 Qt 5 7 1 5 3 3
  • impala与hive的比较以及impala的优缺点

    Impala相对于Hive所使用的优化技术 没有使用MapReduce进行并行计算 虽然MapReduce是非常好的并行计算框架 但它更多的面向批处理模式 而不是面向交互式的SQL执行 与MapReduce相比 Impala把整个查询分成一
  • 解决Idea按Alt+Enter键无效

    首先 去Settings gt keymap查看快捷键是否正确 默认情况是对的 关键来了 如果还不行 打开idea gt setting gt intention 有一个选项勾一下 搞定
  • Unity3d接入googleplay内购详细说明(四)

    因为本文内容比较多 整理花费时间比较长 故分几篇完成 以下为本文目录结构 方便查阅 Unity3d接入googleplay内购详细说明 一 引言 一 准备条件 二 谷歌开发者后台应用创建说明 Unity3d接入googleplay内购详细说
  • 会画画有什么用?

    盛夏的风 安江泽 小白菜 等 13332 人赞同 原问题是 会画画有什么用 现在这样一改感觉离题太远了 特此澄清 80后大叔在当年初中时家里不给买游戏机的时候可以自己画游戏棋和小伙伴玩 自己玩的比较久的是这个超任的超悟空传 游戏本来就是棋类
  • 出现了一个意外,不能完你在设置中所要求的更改-修改IPV4地址出错(更新)

    文章目录 一 更改IPV4的设置改不了 二 解决办法 1 通过管理员身份打开cmd窗口 2 输入两条指令 二 plus 解决方法后续 一 更改IPV4的设置改不了 本来我里面是有公司设置的IP地址和DNS服务器地址来着 现在要更改成自动获取
  • 解决PHP startup: Unable to load dynamic library的错误

    在 Windows 下安装完 PHP 和 web 服务器之后 可能想要安装一些扩展库来获得更多功能 可以通过修改 php ini 来选择当 PHP 启动时加载哪些扩展库 也可以在脚本中通过使用 dl 来动态加载 PHP 扩展库的 DLL 文
  • Qt各种采样率录音 录音到内存

    近段时间了解了Qt的录音模块 Qt的录音模块分为QAudioInput输入 QAudioOutput输出 输入用来录音 输出用于播放 当然还用其它的QMediaPlayer QAudioRecorder 这类控件封装的比较上层了 QAudi