PCM跟ADPCM的一些笔记

1 篇文章 0 订阅
本文介绍了作者在尝试将PDM麦克风芯片的PCM数据压缩为ADPCM过程中遇到的问题和解决思路。文章简述了PCM和ADPCM的头部结构,并探讨了4bit ADPCM压缩算法,提到了压缩和解压缩过程中出现的噪声问题。同时,提供了相关代码和资源链接供读者参考。
摘要由CSDN通过智能技术生成

这两天调ST的一颗PDM MIC芯片,PDM转PCM是完成了,但是PCM数据量太大了不适合传输,所以在尝试ADPCM压缩。网上找了很久关于PCM压缩到ADPCM以及ADPCM解压缩到PCM的文章,很多都讲压缩的实现过程,关键是很多像我一样的喜欢拿来主义的并不感兴趣。经过几天的摸索,大概理清了一些东西,顺手记下来。

正文之前还是简单说一下PCM头跟ADPCM头。实际音频采样回来都是裸的PCM数据,加上一个头就是可以播放的wav格式文件。ADPCM有很多种,有5bit压缩的,更多的是4bit压缩,也有3bit压缩的,我只了解了其中的4bit压缩。废话不多说,还是上代码。因为测试代码是在Qt creator上面写的,有一些数据类型是Qt平台定义的,应该很好辨识。

struct PCMHeaderInfo
{
    char RIFF[4];
	quint32 filesize;
    char WAVE[4];
    char FMT[4];
    quint32 format;
    quint16 fmttag;
    quint16 channels;
    quint32 samplerate;
    quint32 byterate;
    quint16 blockalign;
	quint16 bitspersample;
    char DATA[4];
    quint32 datalength;
};
struct ADPCMHeaderInfo
{
    char     RIFF[4];
    quint32  filesize;
    char     WAVE[4];
    char     FMT[4];
    quint32  format;
    quint16  fmttag;
    quint16  channels;
    quint32  samplerate;
    quint32  byterate;
    quint16  blockalign;
    quint16  bitspersample;
    quint16  blockinfo[2];
    char     DATA[4];
    quint32  sampledatabytes;
};

可以看出pcm的头跟adpcm的头很相似。
RIFF[4]: 恒定的’R’,‘I’,‘F’,‘F’;
filesize: 文件大小,wav文件的总大小 - 8 ;
WAVE[4]: 恒定的’W’,‘A’,‘V’,‘E’;
FMT[4]: 恒定的’f’,‘m’,‘t’,’ ‘;最后一个空格不要忘了;
format: PCM文件是0x00000010,ADPCM文件是0x00000014(此处可能有其他情况,因为ADPCM有很多标准;);
fmttag: PCM文件是0x0001,ADPCM文件是0x0011(也有可能是其他的);
channels: 音频的通道数,单声道就是01,双声道就是02;
samplerate: 音频的采样率,常见的8k,16k,22.05k,32k,44.1k,48k等,就是对应的数值8000,16000…
byterate:应该可以叫码率吧,值是(采样率 * 通道数)* 采样位数 / 8;
blockalign: PCM文件是bitspersample / 2,ADPCM我使用的是256也就是0x0100;后面会说这256字节的具体含义;
bitspersample :每个采样点的位数。常见的16位,就是说前段采样AD的位数是16位,一次采样产生16bit的数据;
blockinfo[2] :ADPCM特有的, blockinfo[0]恒定的0x0002,blockinfo[1] = (blockalign - 4) * 2 + 1;
DATA[4] :恒定的’d’,‘a’,‘t’,‘a’;
sampledatabytes :总的采样字节数(文件总大小取出头信息),即wav文件的总大小 - 44(PCM)或者-48(ADPCM) ;
大概头的一些简要说明就先说这么多,因为我的测试音频都是单声道的,双声道的可能有些不一样,不能全部照搬

接下去说一下ADPCMde block信息。之前定了ADPCM一个block大小256字节,怎么定义这256字节?

struct ADPCMBlock
{
    qint16 sample0;
    quint8 index;
    quint8 RESERVED;
    quint8 sampledata[252];
};

前两个字节是该block第一个为压缩过的采样数据,其实是个short型,占两个字节,中间一个字节是上一个block的index,具体作用查看adpcm.c中的源码。下一个字节保留没用,之后的252字节就是该block剩余的采样数据。这样的话,因为采用的是4bit压缩,一个16bit的PCM数据就被压缩到4bit,这样252字节ADPCM数据就是504个PCM数据的压缩,再加上最开始没有被压缩的一个PCM数据,一个blcok就包含了505个PCM数据。
接下去就是压缩算法,找的gayhub上面的一个92年的,应该比较成熟。其实就一个adpcm.h跟adpcm.c文件,里面就两个api,一个编码的一个解码的,很简单。但是实际输出的音频文件就很大的噪声,问了一下别人说PCM直接转ADPCM是会有噪音,所以那些软件都做过其他处理,后来我用Au测试生成的文件也有一些噪音,3bit压缩噪音还是很明显,4bit压缩就要好一些。


/*
** Intel/DVI ADPCM coder/decoder.
**
** The algorithm for this coder was taken from the IMA Compatability Project
** proceedings, Vol 2, Number 2; May 1992.
**
** Version 1.2, 18-Dec-92.
**
** Change log:
** - Fixed a stupid bug, where the delta was computed as
**   stepsize*code/4 in stead of stepsize*(code+0.5)/4.
** - There was an off-by-one error causing it to pick
**   an incorrect delta once in a blue moon.
** - The NODIVMUL define has been removed. Computations are now always done
**   using shifts, adds and subtracts. It turned out that, because the standard
**   is defined using shift/add/subtract, you needed bits of fixup code
**   (because the div/mul simulation using shift/add/sub made some rounding
**   errors that real div/mul don't make) and all together the resultant code
**   ran slower than just using the shifts all the time.
** - Changed some of the variable names to be more meaningful.
*/

#include "adpcm.h"

/* Intel ADPCM step variation table */
static int indexTable[16] = {
	-1, -1, -1, -1, 2, 4, 6, 8,
	-1, -1, -1, -1, 2, 4, 6, 8,
};

static int stepsizeTable[89] = {
	7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
	19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
	50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
	130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
	337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
	876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
	2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
	5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
	15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
};

int adpcm_coder(short *indata, unsigned char *outdata, int len, struct adpcm_state *state)
{
	int val;   /* Current input sample value */
	unsigned int delta; /* Current adpcm output value */
	int diff;   /* Difference between val and valprev */
	int step;         /* Stepsize */
	int valpred;  /* Predicted output value */
	int vpdiff;         /* Current change to valpred */
	int index;   /* Current step change index */
	unsigned int outputbuffer = 0;/* place to keep previous 4-bit value */
	int count = 0;      /* the number of bytes encoded */

	valpred = state->valprev;
	index = (int)state->index;
	step = stepsizeTable[index];

	while (len > 0) {
		/* Step 1 - compute difference with previous value */
		val = *indata++;
		diff = val - valpred;
		if (diff < 0)
		{
			delta = 8;
			diff = (-diff);
		}
		else
		{
			delta = 0;
		}

		/* Step 2 - Divide and clamp */
		/* Note:
		** This code *approximately* computes:
		**    delta = diff*4/step;
		**    vpdiff = (delta+0.5)*step/4;
		** but in shift step bits are dropped. The net result of this is
		** that even if you have fast mul/div hardware you cannot put it to
		** good use since the fixup would be too expensive.
		*/
		vpdiff = (step >> 3);

		if (diff >= step) {
			delta |= 4;
			diff -= step;
			vpdiff += step;
		}
		step >>= 1;
		if (diff >= step) {
			delta |= 2;
			diff -= step;
			vpdiff += step;
		}
		step >>= 1;
		if (diff >= step) {
			delta |= 1;
			vpdiff += step;
		}

		/* Phil Frisbie combined steps 3 and 4 */
		/* Step 3 - Update previous value */
		/* Step 4 - Clamp previous value to 16 bits */
		if ((delta & 8) != 0)
		{
			valpred -= vpdiff;
			if (valpred < -32768)
				valpred = -32768;
		}
		else
		{
			valpred += vpdiff;
			if (valpred > 32767)
				valpred = 32767;
		}

		/* Step 5 - Assemble value, update index and step values */
		index += indexTable[delta];
		if (index < 0) index = 0;
		else if (index > 88) index = 88;
		step = stepsizeTable[index];

		/* Step 6 - Output value */
		outputbuffer = (delta << 4);

		/* Step 1 - compute difference with previous value */
		val = *indata++;
		diff = val - valpred;
		if (diff < 0)
		{
			delta = 8;
			diff = (-diff);
		}
		else
		{
			delta = 0;
		}

		/* Step 2 - Divide and clamp */
		/* Note:
		** This code *approximately* computes:
		**    delta = diff*4/step;
		**    vpdiff = (delta+0.5)*step/4;
		** but in shift step bits are dropped. The net result of this is
		** that even if you have fast mul/div hardware you cannot put it to
		** good use since the fixup would be too expensive.
		*/
		vpdiff = (step >> 3);

		if (diff >= step) {
			delta |= 4;
			diff -= step;
			vpdiff += step;
		}
		step >>= 1;
		if (diff >= step) {
			delta |= 2;
			diff -= step;
			vpdiff += step;
		}
		step >>= 1;
		if (diff >= step) {
			delta |= 1;
			vpdiff += step;
		}

		/* Phil Frisbie combined steps 3 and 4 */
		/* Step 3 - Update previous value */
		/* Step 4 - Clamp previous value to 16 bits */
		if ((delta & 8) != 0)
		{
			valpred -= vpdiff;
			if (valpred < -32768)
				valpred = -32768;
		}
		else
		{
			valpred += vpdiff;
			if (valpred > 32767)
				valpred = 32767;
		}

		/* Step 5 - Assemble value, update index and step values */
		index += indexTable[delta];
		if (index < 0) index = 0;
		else if (index > 88) index = 88;
		step = stepsizeTable[index];

		/* Step 6 - Output value */
		*outdata++ = (unsigned char)(delta | outputbuffer);
		count++;
		len -= 2;
	}

	state->valprev = (short)valpred;
	state->index = (char)index;

	return count;
}

// 解码
int adpcm_decoder(unsigned char *indata, short *outdata, int len, struct adpcm_state *state)
{
	unsigned int delta; /* Current adpcm output value */
	int step;         /* Stepsize */
	int valpred;  /* Predicted value */
	int vpdiff;         /* Current change to valpred */
	int index;   /* Current step change index */
	unsigned int inputbuffer = 0;/* place to keep next 4-bit value */
	int count = 0;

	valpred = state->valprev;
	index = (int)state->index;
	step = stepsizeTable[index];

	/* Loop unrolling by Phil Frisbie */
	/* This assumes there are ALWAYS an even number of samples */
	while (len-- > 0) {

		/* Step 1 - get the delta value */
		inputbuffer = (unsigned int)*indata++;
		delta = (inputbuffer >> 4);

		/* Step 2 - Find new index value (for later) */
		index += indexTable[delta];
		if (index < 0) index = 0;
		else if (index > 88) index = 88;


		/* Phil Frisbie combined steps 3, 4, and 5 */
		/* Step 3 - Separate sign and magnitude */
		/* Step 4 - Compute difference and new predicted value */
		/* Step 5 - clamp output value */
		/*
		** Computes 'vpdiff = (delta+0.5)*step/4', but see comment
		** in adpcm_coder.
		*/
		vpdiff = step >> 3;
		if ((delta & 4) != 0) vpdiff += step;
		if ((delta & 2) != 0) vpdiff += step >> 1;
		if ((delta & 1) != 0) vpdiff += step >> 2;

		if ((delta & 8) != 0)
		{
			valpred -= vpdiff;
			if (valpred < -32768)
				valpred = -32768;
		}
		else
		{
			valpred += vpdiff;
			if (valpred > 32767)
				valpred = 32767;
		}

		/* Step 6 - Update step value */
		step = stepsizeTable[index];

		/* Step 7 - Output value */
		*outdata++ = (short)valpred;

		/* Step 1 - get the delta value */
		delta = inputbuffer & 0xf;

		/* Step 2 - Find new index value (for later) */
		index += indexTable[delta];
		if (index < 0) index = 0;
		else if (index > 88) index = 88;


		/* Phil Frisbie combined steps 3, 4, and 5 */
		/* Step 3 - Separate sign and magnitude */
		/* Step 4 - Compute difference and new predicted value */
		/* Step 5 - clamp output value */
		/*
		** Computes 'vpdiff = (delta+0.5)*step/4', but see comment
		** in adpcm_coder.
		*/
		vpdiff = step >> 3;
		if ((delta & 4) != 0) vpdiff += step;
		if ((delta & 2) != 0) vpdiff += step >> 1;
		if ((delta & 1) != 0) vpdiff += step >> 2;

		if ((delta & 8) != 0)
		{
			valpred -= vpdiff;
			if (valpred < -32768)
				valpred = -32768;
		}
		else
		{
			valpred += vpdiff;
			if (valpred > 32767)
				valpred = 32767;
		}

		/* Step 6 - Update step value */
		step = stepsizeTable[index];

		/* Step 7 - Output value */
		*outdata++ = (short)valpred;
		count += 2;
	}

	state->valprev = (short)valpred;
	state->index = (char)index;

	return count;
}

其余的一些操作就是读写文件,添加头信息这些。

struct adpcm_state state =
{
    0,
    0
};

#pragma pack(1)
struct PCMHeaderInfo pcmheader_t;
#pragma pack()


#pragma pack(1)
struct ADPCMHeaderInfo adpcmheader_t;
#pragma pack()

#pragma pack(1)
struct ADPCMBlock block;
#pragma pack()

上面是一些数据的定义,那几个结构体记得1byte对齐,不然后面写文件的时候可能会有问题。还有一个state结构体,类型说明是在adpcm.h文件,其实就是记录的第一个没有被压缩的采样数据以及上一个block的index,文件里面的压缩跟解压缩的api里面需要这个结构体,正好我们在连续转换的时候可以直接将这个结构体做参数传进去,结构体成员的内容会自动刷新的。

void MainWindow::getFileName()
{
    fileDialog = new QFileDialog(this);
    fileDialog->setAcceptMode(QFileDialog::AcceptOpen);
    fileDialog->setFileMode(QFileDialog::AnyFile);
    filefull = fileDialog->getOpenFileName(this,"Open wav or dat file",".","*.wav *.dat");
    fileinfo = QFileInfo(filefull);
    ui->filenameLineEdit->setText(fileinfo.fileName());
}



void MainWindow::initHeaderInfo(struct PCMHeaderInfo *header,quint32 samplerate,quint16 databits)
{
    header->RIFF[0] = 'R';
    header->RIFF[1] = 'I';
    header->RIFF[2] = 'F';
    header->RIFF[3] = 'F';

	header->filesize = 0;

    header->WAVE[0] = 'W';
    header->WAVE[1] = 'A';
    header->WAVE[2] = 'V';
    header->WAVE[3] = 'E';

    header->FMT[0] = 'f';
    header->FMT[1] = 'm';
    header->FMT[2] = 't';
    header->FMT[3] = ' ';

    header->format = 0x00000010;
    header->fmttag = 0x01;
    header->channels = 0x01;
    header->samplerate = samplerate;
	header->byterate = (samplerate * header->channels * databits / 8);
    header->blockalign = databits / 8;
	header->bitspersample = databits;

    header->DATA[0] = 'd';
    header->DATA[1] = 'a';
    header->DATA[2] = 't';
    header->DATA[3] = 'a';
    header->datalength = 0;
}



void MainWindow::initHeaderInfo(struct ADPCMHeaderInfo *header,quint32 samplerate,quint16 databits)
{
    header->RIFF[0] = 'R';
    header->RIFF[1] = 'I';
    header->RIFF[2] = 'F';
    header->RIFF[3] = 'F';

    header->filesize = 0;

    header->WAVE[0] = 'W';
    header->WAVE[1] = 'A';
    header->WAVE[2] = 'V';
    header->WAVE[3] = 'E';

    header->FMT[0] = 'f';
    header->FMT[1] = 'm';
    header->FMT[2] = 't';
    header->FMT[3] = ' ';
    header->format = 0x00000014;
    header->fmttag = 0x0011;
    header->channels = 0x01;
    header->samplerate = samplerate;
	header->byterate = (samplerate * header->channels * databits / 8);
    header->blockalign = 256;
	header->bitspersample = databits;
	header->blockinfo[1] = (header->blockalign - 4) * 2 + 1;
	header->blockinfo[0] = 0x0002;
    header->DATA[0] = 'd';
    header->DATA[1] = 'a';
    header->DATA[2] = 't';
    header->DATA[3] = 'a';
    header->sampledatabytes = 0;
}

这边的三个函数分别是获取要操作的文件名以及路径这些,初始化PCM的头或者ADPCM的头。有一些内容目前未知,所以先写的0,到后来转换完成之后再填写。

void MainWindow::convertAdpcmToPcm(QFile *pcmfile,QFile* adpcmfile)
{
    qint16 pcmbuffer[505] = {0};
    quint8 filebuffer[256] = {0};
    quint32 adpcmfilesize = 0;
    quint32 totalreadsize = 0;
    quint32 readdatasize = 0;
    quint32 convertsize = 0;
    quint32 totalwritesize = 0;
    quint32 totalblocks = 0;
    quint32 blockcnt = 0;
    if(adpcmfile->open(QIODevice::ReadOnly) == false)
    {
        QMessageBox::warning(NULL,"Error","ADPCM File Open Failed!",QMessageBox::Yes);
        adpcmfile->close();
        return;
    }
    if(pcmfile->open(QIODevice::WriteOnly) == false)
    {
        QMessageBox::warning(NULL,"Error","PCM File Open Failed!",QMessageBox::Yes);
        pcmfile->close();
        return;
    }
    QDataStream in(adpcmfile);
    QDataStream out(pcmfile);
    in.readRawData(reinterpret_cast<char *>(filebuffer),48);
    memcpy(&adpcmheader_t,filebuffer,48);
    if(adpcmheader_t.fmttag != 0x0011)
    {
        QMessageBox::information(NULL,"Error","File is Not a ADPCM File!",QMessageBox::Yes,QMessageBox::Yes);
        pcmfile->close();
        adpcmfile->close();
        return;
    }
	if (adpcmheader_t.bitspersample != 4)
    {
        QMessageBox::information(NULL,"Error","Only Support 4bit ADPCM File!",QMessageBox::Yes,QMessageBox::Yes);
        pcmfile->close();
        adpcmfile->close();
        return;
    }
    if(adpcmheader_t.channels != 0x01)
    {
        QMessageBox::information(NULL,"Error","Only Support 1 Channel Audio File!",QMessageBox::Yes,QMessageBox::Yes);
        pcmfile->close();
        adpcmfile->close();
        return;
    }

    initHeaderInfo(&pcmheader_t,adpcmheader_t.samplerate,16);
    out.writeRawData(reinterpret_cast<char *>(&pcmheader_t),sizeof(pcmheader_t));
    totalwritesize += sizeof(pcmheader_t);
    adpcmfilesize = adpcmfile->size();
    if((adpcmfilesize - sizeof(adpcmheader_t)) % (adpcmheader_t.blockalign))
        totalblocks = (adpcmfilesize - sizeof(adpcmheader_t)) / (adpcmheader_t.blockalign) + 1;
    else
        totalblocks = (adpcmfilesize - sizeof(adpcmheader_t)) / (adpcmheader_t.blockalign);
    memset(&state,0,sizeof(state));
    while(blockcnt < totalblocks)
    {
        readdatasize = in.readRawData(reinterpret_cast<char *>(filebuffer),256);
        totalreadsize += readdatasize;
        pcmbuffer[0] = static_cast<short>(filebuffer[1]) << 8 | filebuffer[0];
        if(blockcnt == 0)
            state.index = 0;
        else
            state.index = filebuffer[2];
        convertsize = adpcm_decoder(&filebuffer[4],&pcmbuffer[1],readdatasize - 4,&state);
        out.writeRawData(reinterpret_cast<char *>(pcmbuffer),sizeof(pcmbuffer));
        totalwritesize += sizeof(pcmbuffer);
        ui->playerProgressBar->setValue((totalreadsize * 1.0f) / adpcmfilesize * 100);
        blockcnt++;
    }
    ui->playerProgressBar->setValue(100);
    pcmheader_t.filesize = totalwritesize - 8;
    pcmheader_t.datalength = totalwritesize - 44;
    pcmfile->seek(0);
    out.writeRawData(reinterpret_cast<char *>(&pcmheader_t),44);  //update file size and sample size before close file
    pcmfile->close();
    adpcmfile->close();
    QMessageBox::information(NULL,"Success!","Convert Success!!",QMessageBox::Yes,QMessageBox::Yes);
    ui->playerProgressBar->setValue(0);
}

这个函数就是将adpcm文件解压缩成pcm文件。

void MainWindow::convertPcmToAdpcm(QFile *pcmfile,QFile* adpcmfile)
{
	quint8 filebuffer[1010] = {0};
    quint32 pcmfilesize = 0;
    quint32 totalreadsize = 0;
    quint32 totalwritesize = 0;
    quint32 readdatasize = 0;
    quint32 convertsize = 0;
    quint32 totalblocks = 0;
    quint32 blockcnt = 0;
	quint32 tempcnt = 0;
    if(pcmfile->open(QIODevice::ReadOnly) == false)
    {
        QMessageBox::warning(NULL,"Error","PCM File Open Failed!",QMessageBox::Yes);
        pcmfile->close();
        return;
    }
    if(adpcmfile->open(QIODevice::WriteOnly) == false)
    {
        QMessageBox::warning(NULL,"Error","ADPCM File Open Failed!",QMessageBox::Yes);
        adpcmfile->close();
        return;
    }
    QDataStream in(pcmfile);
    QDataStream out(adpcmfile);
	tempcnt = in.readRawData(reinterpret_cast<char *>(filebuffer), sizeof(pcmheader_t));     //skip 44bytes header info
    memcpy(&pcmheader_t,filebuffer,44);
    if(pcmheader_t.format != 0x0010)
    {
        QMessageBox::information(NULL,"Error","File is Not a RAW PCM File!",QMessageBox::Yes,QMessageBox::Yes);
        pcmfile->close();
        adpcmfile->close();
        return;
    }
	if (pcmheader_t.bitspersample != 16)
    {
        QMessageBox::information(NULL,"Error","Only Support 16bit PCM File!",QMessageBox::Yes,QMessageBox::Yes);
        pcmfile->close();
        adpcmfile->close();
        return;
    }
    if(pcmheader_t.channels != 0x01)
    {
        QMessageBox::information(NULL,"Error","Only Support 1 Channel Audio File!",QMessageBox::Yes,QMessageBox::Yes);
        pcmfile->close();
        adpcmfile->close();
        return;
    }
    initHeaderInfo(&adpcmheader_t,pcmheader_t.samplerate,4);								//only support 4bit compress
	tempcnt = out.writeRawData(reinterpret_cast<char *>(&adpcmheader_t), sizeof(adpcmheader_t)); //write 48 bytes adpcm header
	totalwritesize += tempcnt;
    pcmfilesize = pcmfile->size();
    if((pcmfilesize - sizeof(pcmheader_t)) % 1010)
        totalblocks = (pcmfilesize - sizeof(pcmheader_t)) / 1010 + 1;						//get total adpcm blocks
    else
        totalblocks = (pcmfilesize - sizeof(pcmheader_t)) / 1010;
    while(blockcnt < totalblocks)
    {
		if (blockcnt == 0)
			block.index = 0;
		else
			block.index = state.index;													//get block index
        readdatasize = in.readRawData(reinterpret_cast<char *>(filebuffer),1010);		// read 1010 byte pcm data(505 sample points)
        totalreadsize += readdatasize;													//update total read size
        block.sample0 = (static_cast<short>(filebuffer[1]) << 8) | filebuffer[0];       //get first sample point of current block;
		block.RESERVED = 0;
		state.valprev = block.sample0;
        convertsize = adpcm_coder(reinterpret_cast<short *>(&filebuffer[2]),block.sampledata,(readdatasize - 2) / 2,&state);//convert the remain 504 sample points;
		tempcnt = out.writeRawData(reinterpret_cast<char *>(&block), sizeof(block));               //write 256 bytes block data
		totalwritesize += tempcnt;
        ui->playerProgressBar->setValue((totalreadsize * 1.0f) / pcmfilesize * 100);
        blockcnt++;
    }
    ui->playerProgressBar->setValue(100);
    adpcmheader_t.filesize = totalwritesize - 8;
    adpcmheader_t.sampledatabytes = totalwritesize - 48;
    adpcmfile->seek(0);
    out.writeRawData(reinterpret_cast<char *>(&adpcmheader_t),48);  //update file size and sample size before close file
    pcmfile->close();
    adpcmfile->close();
    QMessageBox::information(NULL,"Success!","Convert Success!!",QMessageBox::Yes,QMessageBox::Yes);
    ui->playerProgressBar->setValue(0);
}

跟上一个函数相反的操作。

完整的工程文件在下面这个链接,工程是用的Qt creator创建的。
http://download.csdn.net/download/u013910954/10042543

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值