最近做项目, 需要一个麦克风音量监听的功能:
找了好多这方面的资料, 不知道为什么 总之很少,
在此总结一下, 发贴一枚..
不啰嗦了, 直接上代码了:
#ifndef AUDIORECORDER_H #define AUDIORECORDER_H #include <QFile> #include <QWidget> #include <QPushButton> #include <QAudioInput> #include <QAudioOutput> #include <QAudioDeviceInfo> #include "ui_AudioRecorder.h" class AudioRecorder : public QWidget { Q_OBJECT public: AudioRecorder(QWidget *parent = 0); ~AudioRecorder(); private: int AddWavHeader(char *); int ApplyVolumeToSample(short iSample); void InitMonitor(); void CreateAudioInput(); void CreateAudioOutput(); private slots: void OnRecordStart(); void OnRecordStop(); void OnRecordPlay(); void OnRecordSave(); void OnStateChange(QAudio::State s); void OnReadMore(); void OnSliderValueChanged(int); void OnTimeOut(); private: Ui::Recorder ui; int miVolume; int miMaxValue; private: QAudioFormat mFormatFile; QFile *mpOutputFile; QAudioInput *mpAudioInputFile; // 负责读写文件 QAudioOutput *mpAudioOutputFile; QAudioFormat mFormatSound; QAudioInput *mpAudioInputSound; // 负责监听声音 QAudioOutput *mpAudioOutputSound; QIODevice *mpInputDevSound; QIODevice *mpOutputDevSound; }; #endif // AUDIORECORDER_H
#include "AudioRecorder.h" #include <QLayout> #include <QDebug> #include <QTimer> #include <QFileDialog> #include <QMessageBox> #define BufferSize 14096 struct HEADER { 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; }; AudioRecorder::AudioRecorder(QWidget *parent) : QWidget(parent) { ui.setupUi(this); miMaxValue = 0; miVolume = ui.horizontalSlider->value(); mpOutputFile = NULL; mpAudioInputFile = NULL; mpAudioOutputFile = NULL; mpAudioInputSound = NULL; mpAudioOutputSound = NULL; mpInputDevSound = NULL; mpInputDevSound = NULL; ui.btn_stop->setDisabled(true); ui.btn_play->setDisabled(true); ui.btn_save->setDisabled(true); mpOutputFile = new QFile(); mpOutputFile->setFileName(tr("record.raw")); //mFormatFile.setFrequency(8000); //mFormatFile.setChannels(1); mFormatFile.setSampleSize(16); mFormatFile.setSampleType(QAudioFormat::SignedInt); mFormatFile.setByteOrder(QAudioFormat::LittleEndian); mFormatFile.setCodec("audio/pcm"); QAudioDeviceInfo info(QAudioDeviceInfo::defaultInputDevice()); if (!info.isFormatSupported(mFormatFile)) { qWarning("input default mFormatFile not supported try to use nearest"); mFormatFile = info.nearestFormat(mFormatFile); } QAudioDeviceInfo info1(QAudioDeviceInfo::defaultOutputDevice()); if (!info1.isFormatSupported(mFormatFile)) { qWarning() << "output default mFormatFile not supported - trying to use nearest"; // mFormatFile = info.nearestFormat(mFormatSound); qWarning() << "output no support input mFormatFile."; return; } if(mFormatFile.sampleSize() != 16) { qWarning("audio device doesn't support 16 bit support %d bit samples, example cannot run", <span style="white-space:pre"> </span>mFormatFile.sampleSize()); mpAudioInputFile = 0; return; } mpAudioInputFile = NULL; mpAudioOutputFile = NULL; connect(ui.btn_start, SIGNAL(clicked()), this,SLOT(OnRecordStart())); connect(ui.btn_stop, SIGNAL(clicked()), this,SLOT(OnRecordStop())); connect(ui.btn_play, SIGNAL(clicked()), this,SLOT(OnRecordPlay())); connect(ui.btn_save, SIGNAL(clicked()), this,SLOT(OnRecordSave())); InitMonitor(); } AudioRecorder::~AudioRecorder() { } void AudioRecorder::OnRecordStart() { mpOutputFile->open(QIODevice::WriteOnly | QIODevice::Truncate); mpAudioInputFile = new QAudioInput(mFormatFile, this); mpAudioInputFile->start(mpOutputFile); ui.btn_start->setDisabled(true); ui.btn_stop->setDisabled(false); ui.btn_play->setDisabled(true); ui.btn_save->setDisabled(true); } void AudioRecorder::OnRecordPlay() { mpOutputFile->open(QIODevice::ReadOnly | QIODevice::Truncate); mpAudioOutputFile = new QAudioOutput(mFormatFile, this); connect(mpAudioOutputFile, SIGNAL(stateChanged(QAudio::State)), this,SLOT(OnStateChange(QAudio::State))); mpAudioOutputFile->start(mpOutputFile); ui.btn_start->setDisabled(true); ui.btn_stop->setDisabled(false); ui.btn_play->setDisabled(true); ui.btn_save->setDisabled(true); } void AudioRecorder::OnRecordStop() { if(mpAudioInputFile != NULL){ mpAudioInputFile->stop(); delete mpAudioInputFile; mpAudioInputFile = NULL; } if(mpAudioOutputFile != NULL){ mpAudioOutputFile->stop(); delete mpAudioOutputFile; mpAudioOutputFile = NULL; } mpOutputFile->close(); ui.btn_start->setDisabled(false); ui.btn_stop->setDisabled(true); ui.btn_play->setDisabled(false); ui.btn_save->setDisabled(false); } void AudioRecorder::OnRecordSave() { QString filename = QFileDialog::getSaveFileName( this, tr("choose a filename to save under"), QDir::currentPath(), "Wav(*.wav)"); if(filename.length() == 0) { QMessageBox::information(NULL, tr("filename"), tr("You didn't select any files.")); } else { if(AddWavHeader((filename+tr(".wav")).toLatin1().data())>0) QMessageBox::information(NULL, tr("Save"), tr("Success Save :") + filename); } } void AudioRecorder::OnStateChange(QAudio::State state) { if(state == QAudio::IdleState) OnRecordStop(); } int AudioRecorder::AddWavHeader(char *filename) { // 开始准备WAV的文件头 HEADER DestionFileHeader; DestionFileHeader.RIFFNAME[0] = 'R'; DestionFileHeader.RIFFNAME[1] = 'I'; DestionFileHeader.RIFFNAME[2] = 'F'; DestionFileHeader.RIFFNAME[3] = 'F'; DestionFileHeader.WAVNAME[0] = 'W'; DestionFileHeader.WAVNAME[1] = 'A'; DestionFileHeader.WAVNAME[2] = 'V'; DestionFileHeader.WAVNAME[3] = 'E'; DestionFileHeader.FMTNAME[0] = 'f'; DestionFileHeader.FMTNAME[1] = 'm'; DestionFileHeader.FMTNAME[2] = 't'; DestionFileHeader.FMTNAME[3] = 0x20; DestionFileHeader.nFMTLength = 16; // 表示 FMT 的长度 DestionFileHeader.nAudioFormat = 1; //这个表示a law PCM DestionFileHeader.DATANAME[0] = 'd'; DestionFileHeader.DATANAME[1] = 'a'; DestionFileHeader.DATANAME[2] = 't'; DestionFileHeader.DATANAME[3] = 'a'; DestionFileHeader.nBitsPerSample = 16; DestionFileHeader.nBytesPerSample = 2; // DestionFileHeader.nSampleRate = 8000; // DestionFileHeader.nBytesPerSecond = 16000; DestionFileHeader.nChannleNumber = 1; int nFileLen = 0; int nSize = sizeof(DestionFileHeader); FILE *fp_s = NULL; FILE *fp_d = NULL; fp_s = fopen("record.raw", "rb"); if (fp_s == NULL) return -1; fp_d = fopen(filename, "wb+"); if (fp_d == NULL) return -2; int nWrite = fwrite(&DestionFileHeader, 1, nSize, fp_d); if (nWrite != nSize) { fclose(fp_s); fclose(fp_d); return -3; } while( !feof(fp_s)) { char readBuf[4096]; int nRead = fread(readBuf, 1, 4096, fp_s); if (nRead > 0) { fwrite(readBuf, 1, nRead, fp_d); } nFileLen += nRead; } fseek(fp_d, 0L, SEEK_SET); DestionFileHeader.nRIFFLength = nFileLen - 8 + nSize; DestionFileHeader.nDataLength = nFileLen; nWrite = fwrite(&DestionFileHeader, 1, nSize, fp_d); if (nWrite != nSize) { fclose(fp_s); fclose(fp_d); return -4; } fclose(fp_s); fclose(fp_d); return nFileLen; } void AudioRecorder::InitMonitor() { mFormatSound.setSampleSize(16); //set sample sze to 16 bit mFormatSound.setSampleType(QAudioFormat::UnSignedInt ); //Sample type as usigned integer sample mFormatSound.setByteOrder(QAudioFormat::LittleEndian); //Byte order mFormatSound.setCodec("audio/pcm"); //set codec as simple audio/pcm QAudioDeviceInfo infoIn(QAudioDeviceInfo::defaultInputDevice()); if (!infoIn.isFormatSupported(mFormatSound)) { //Default format not supported - trying to use nearest mFormatSound = infoIn.nearestFormat(mFormatSound); } QAudioDeviceInfo infoOut(QAudioDeviceInfo::defaultOutputDevice()); if (!infoOut.isFormatSupported(mFormatSound)) { //Default format not supported - trying to use nearest mFormatSound = infoOut.nearestFormat(mFormatSound); } CreateAudioInput(); CreateAudioOutput(); mpOutputDevSound = mpAudioOutputSound->start(); mpInputDevSound = mpAudioInputSound->start(); connect(mpInputDevSound, SIGNAL(readyRead()), SLOT(OnReadMore())); connect(ui.horizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(OnSliderValueChanged(int))); } void AudioRecorder::CreateAudioInput() { if (mpInputDevSound != 0) { disconnect(mpInputDevSound, 0, this, 0); mpInputDevSound = 0; } QAudioDeviceInfo inputDevice(QAudioDeviceInfo::defaultInputDevice()); mpAudioInputSound = new QAudioInput(inputDevice, mFormatSound, this); } void AudioRecorder::CreateAudioOutput() { QAudioDeviceInfo outputDevice(QAudioDeviceInfo::defaultOutputDevice()); mpAudioOutputSound = new QAudioOutput(outputDevice, mFormatSound, this); } int AudioRecorder::ApplyVolumeToSample(short iSample) { //Calculate volume, Volume limited to max 30000 and min -30000 return std::max(std::min(((iSample * miVolume) / 50) ,20000), -20000); } void AudioRecorder::OnSliderValueChanged(int value) { miVolume = value; } void AudioRecorder::OnReadMore() { //Return if audio input is null if(!mpAudioInputSound) return; QByteArray _Buffer(BufferSize, 0); //Check the number of samples in input buffer qint64 len = mpAudioInputSound->bytesReady(); //Limit sample size if(len > 4096) len = 4096; //Read sound samples from input device to buffer qint64 l = mpInputDevSound->read(_Buffer.data(), len); if(l > 0) { //Assign sound samples to short array short* resultingData = (short*)_Buffer.data(); short *outdata=resultingData; outdata[ 0 ] = resultingData [ 0 ]; int iIndex; if(false) { //Remove noise using Low Pass filter algortm[Simple algorithm used to remove noise] for ( iIndex=1; iIndex < len; iIndex++ ) { outdata[ iIndex ] = 0.333 * resultingData[iIndex ] + ( 1.0 - 0.333 ) * outdata[ iIndex-1 ]; } } miMaxValue = 0; for ( iIndex=0; iIndex < len; iIndex++ ) { //Cange volume to each integer data in a sample int value = ApplyVolumeToSample( outdata[ iIndex ]); outdata[ iIndex ] = value; miMaxValue = miMaxValue>=value ? miMaxValue : value; } //write modified sond sample to outputdevice for playback audio mpOutputDevSound->write((char*)outdata, len); QTimer::singleShot(1000, this, SLOT(OnTimeOut())); } } void AudioRecorder::OnTimeOut() { ui.progress->setValue(miMaxValue); }