zoukankan      html  css  js  c++  java
  • Qt录音机

    近期做项目, 须要一个麦克风音量监听的功能:

    找了好多这方面的资料, 不知道为什么 总之非常少, 

    在此总结一下, 发贴一枚..

    不啰嗦了, 直接上代码了: 

    #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);
    }


    
    
    代码已上传: http://download.csdn.net/detail/robertkun/7421767

  • 相关阅读:
    自定义TextInput中displayAsPassword的字符
    C#序列化与反序列化代码记录
    解决Discuz!NT"Code: 100, Message: 指定..."问题
    如何在asp.net项目开发的验证码图片和打印中区别0和O(零和字母O)
    "淘宝开放平台"可以成为程序员的摇钱树吗?
    Discuz!NT与asp.net整合集成实例教程
    最震撼的大片《2012》世界末日 电影 高画质 超DVD版清晰效果 在线视频播
    划时代的感人大片!《机器人总动员》(WALL.E) 在线播放
    从数据库某表转换并导入数据到另一表
    界面原型设计工具选择报告
  • 原文地址:https://www.cnblogs.com/claireyuancy/p/6768299.html
Copyright © 2011-2022 走看看