近段时间了解了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
#include
#include
#include
#include
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
#include
#include
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了。如果要存到内存中去掉编译参数就可以了,项目可到此下载祝大家工作愉快。