#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)
, mBuffer(BufferSize, 0)
{
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", 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);
}