一、環境介紹
操作系統: windows10 64位
QT版本:5.12.6
二、功能介紹
封裝了一個播放WAV文件的類,可以播放指定的WAV文件、並且可以指定放聲音的揚聲器設備,在有多個聲卡的系統上非常實用。
代碼裏主要注意的地方:在其他系統上運行,需要注意結構體的字節對齊問題,WAV頭結構體正常字節大小是44字節。如果在Linux系統下運行如果無法播放WAV,要注意打印下WAV頭結構體大小是否是44字節。
(不同位數的系統下, unsigned long 類型佔用的字節不一樣,WAV頭結構體裏存在 unsigned long類型,在其他系統運行需要注意下,爲了兼容可以修改成 unsigned int)
三、核心代碼
3.1 widget.cpp文件代碼
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QSound>
#include <QMediaPlayer>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
foreach (const QAudioDeviceInfo &deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioOutput))
qDebug() << "當前系統可用的聲卡設備: " << deviceInfo.deviceName();
}
Widget::~Widget()
{
delete ui;
}
void Widget::wav_file_play(QString file)
{
WAV_PLAY *wav_play;
//這裏可使用指定的聲卡進行播放這裏默認使用系統的默認聲卡
//要使用指定聲卡,替換第一個參數即可,可看構造函數裏打印的可用設備
wav_play=new WAV_PLAY(QAudioDeviceInfo::defaultOutputDevice(),file);
wav_play->play();
}
void Widget::on_pushButton_clicked()
{
wav_file_play("D:/linux-share-dir/12804.wav");
}
3.2 widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include "wav_play.h"
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
void wav_file_play(QString file);
private slots:
void on_pushButton_clicked();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
3.3 wav_play.cpp文件代碼
#include "wav_play.h"
WAV_PLAY::WAV_PLAY(QAudioDeviceInfo info,QString wav_file)
{
audio=nullptr;
inputFile=nullptr;
thread=nullptr;
inputFile=new QFile;
inputFile->setFileName(wav_file);
if(inputFile->open(QIODevice::ReadOnly)==false)
{
qDebug()<<"文件打開失敗.";
QObject::deleteLater(); //釋放資源
return;
}
// 開始讀取WAV的文件頭
WAVFILEHEADER WavFileHeader;
if(inputFile->read((char*)&WavFileHeader,sizeof (WavFileHeader))!=sizeof (WavFileHeader))
{
qDebug()<<"讀取WAV文件頭失敗.";
QObject::deleteLater(); //釋放資源
return;
}
//打印讀取到的信息
qDebug()<<"RiffName:"<<WavFileHeader.RiffName;
qDebug()<<"WavName:"<<WavFileHeader.WavName;
qDebug()<<"FmtName:"<<WavFileHeader.FmtName;
qDebug()<<"DATANAME:"<<WavFileHeader.DATANAME;
qDebug()<<"FMT塊 的長度:"<<WavFileHeader.nFmtLength;
qDebug()<<"按照PCM 編碼:"<<WavFileHeader.nAudioFormat;
qDebug()<<"聲道數目:"<<WavFileHeader.nChannleNumber;
qDebug()<<"採樣頻率:"<<WavFileHeader.nSampleRate;
qDebug()<<"數據塊對齊單位:"<<WavFileHeader.nBytesPerSample;
qDebug()<<"每秒平均字節數:"<<WavFileHeader.nBytesPerSecond;
qDebug()<<"每次採樣得到的樣本數據位數:"<<WavFileHeader.nBitsPerSample;
QAudioFormat format;
//設置錄音的格式
format.setSampleRate(WavFileHeader.nSampleRate); //設置採樣率以對赫茲採樣。 以秒爲單位,每秒採集多少聲音數據的頻率.
format.setChannelCount(WavFileHeader.nChannleNumber); //將通道數設置爲通道。
format.setSampleSize(WavFileHeader.nBitsPerSample); /*將樣本大小設置爲指定的sampleSize(以位爲單位)通常爲8或16,但是某些系統可能支持更大的樣本量。*/
format.setCodec("audio/pcm"); //設置編碼格式
format.setByteOrder(QAudioFormat::LittleEndian); //樣本是小端字節順序
format.setSampleType(QAudioFormat::SignedInt); //樣本類型
audio = new QAudioOutput(info,format);
thread=new QThread;
//銷燬線程
QObject::connect(thread, &QThread::finished, thread, &QObject::deleteLater);
this->moveToThread(thread); //移動到子線程運行
//播放狀態
connect(audio,SIGNAL(stateChanged(QAudio::State)), this, SLOT(handleStateChanged_input(QAudio::State)),Qt::QueuedConnection);
thread->start();
}
WAV_PLAY::~WAV_PLAY()
{
qDebug()<<"開始資源釋放";
if(audio)
{
audio->stop();
delete audio;
}
if(inputFile)
{
inputFile->close();
delete inputFile;
}
qDebug()<<"資源釋放成功";
}
void WAV_PLAY::play()
{
if(audio)audio->start(inputFile);
}
//播放狀態
void WAV_PLAY::handleStateChanged_input(QAudio::State newState)
{
//開始
if(newState==QAudio::ActiveState)
{
}
//播放完成
/*
傳入的QIODevice沒有數據,並且音頻系統的緩衝區爲空,
此狀態在調用start()之後並且沒有音頻數據可用於處理時設置。
*/
if(newState==QAudio::IdleState)
{
QObject::deleteLater();
thread->exit();
}
}
3.4 wav_play.h代碼
#ifndef WAV_PLAY_H
#define WAV_PLAY_H
#include <QSound>
#include <QThread>
#include <QAudioOutput>
#include <QFile>
#include <QAudioFormat>
#include <QDebug>
//WAV文件結構體信息
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;
};
class WAV_PLAY:public QObject
{
Q_OBJECT
public:
WAV_PLAY(QAudioDeviceInfo info, QString wav_file);
~WAV_PLAY();
QFile *inputFile;
QAudioOutput *audio;
QThread *thread;
void play();
public slots:
void handleStateChanged_input(QAudio::State newState);
};
#endif // WAV_PLAY_H
四、運行效果
界面比較簡陋,只是爲了測試代碼。
下面公衆號裏有全套的QT\C++\C\單片機教程,歡迎關注: