发布网友 发布时间:2024-10-01 16:25
共1个回答
热心网友 时间:2024-10-24 22:51
上次写了存储float类型的wav文件,其实存储PCM的相关数据相对操作更少,难度更小。首先,和存储flaot类型的数据类似,定义一个文件头结构体。
typewaveHeaderstruct{RIFFID[4]byte//内容为""RIFFDwSizeuint32//最后填写,WAVE格式音频的大小FccType[4]byte//内容为"WAVE""FmtID[4]byte//内容为"fmt"FmtDwSizeuint32//内容为WAVE_FMT占的字节数,为16WFormatTaguint16//如果为PCM,值为1WChannelsuint16//通道数,单通道=1,双通道=2DwSamplesPerSecuint32//采样率DwAvgBytesPerSecuint32/*==dwSamplesPerSec*wChannels*uiBitsPerSample/8*/WBlockAlignuint16//==wChannels*uiBitsPerSample/8UiBitsPerSampleuint16//每个采样点的bit数,8bits=8,16bits=16DataID[4]byte//内容为dataDataDwSizeuint32//data的大小}写入文件分两部分,分别是创建文件头和写入文件数据。下面是我们创建文件并将部分PCM数据写入文件的过程。
funccreateNewWave(urlstring,input[]byte,channelsint,bits_per_sampleint,sample_rateint){inputContext:=inputf,err:=os.Create(url)iferr!=nil{fmt.Println(err.Error())}deferf.Close()inputLen:=len(inputContext)header:=createNewHeader(channels,bits_per_sample,sample_rate)headerPointer:=&headerheaderPointer.DataDwSize+=uint32(inputLen)headerPointer.DwSize+=uint32(inputLen)headerBytes:=*(*[]byte)(unsafe.Pointer(&headerPointer))//headerBytes:=[]byte(&header)f.Write(headerBytes[0:44])fmt.Println(headerBytes[0:44])//f.Seek(0,2)f.Write(inputContext)}其中input为需要写入的PCM数据,url为存储路径。channels为声道数,bits_per_sample为采样点大小,sample_rate为采样率。
PCM尾添加至已存在的wav文件。
funcp2w(input[]byte,outputstring){inputContent:=inputinputSize:=len(inputContent)fout,err:=os.OpenFile(output,os.O_RDWR,os.ModePerm)iferr!=nil{log.Fatal(err.Error())}deferfout.Close()buff:=make([]byte,44)size,err:=fout.Read(buff)ifsize!=44{fmt.Println("文件损坏")}varheader*waveHeader=*(**waveHeader)(unsafe.Pointer(&buff))header.DataDwSize+=uint32(inputSize)header.DwSize+=uint32(inputSize)resHeader:=headerheaderBytes:=*(*[]byte)(unsafe.Pointer(&resHeader))fout.Seek(0,0)fout.Write(headerBytes[0:44])fout.Seek(0,2)fout.Write(inputContent)}里面涉及的知识点和上一篇文章大同小异。如果有感兴趣的同学可以留言一起讨论。