Wave音频格式解析
来源:互联网 发布:广东网络干部培训学院 编辑:程序博客网 时间:2024/05/30 05:23
PCM脉码调制数字音频格式是70年代末发展起来的,记录媒体之一的CD,80年代初由飞利浦和索尼公司共同推出。PCM的音频格式也被DVD-A所采用,它支持立体声和5.1环绕声,1999年由DVD讨论会发布和推出的。
PCM的比特率,从14-bit发展到16-bit、18-bit、20-bit直到24-bit;采样频率从44.1kHz发展到192kHz。到目前 为止PCM这项技术可以改善和提高的方面则越来越来小。只是简单的增加PCM比特率和采样率,不能根本的改善它的根本问题。
PCM的主要问题在于:
1)任何PCM数字音频系统需要在其输入端设置急剧升降的滤波器,仅让20 Hz - 22.05 kHz的频率通过(高端22.05 kHz是由于CD 44.1 kHz的一半频率而确定),这是一项非常困难的任务。
2)在录音时采用多级或者串联抽选的数字滤波器(减低采样率),在重放时采用多级的内插的数字滤波器 (提高采样率),为了控制小信号在编码时的失真,两者又都需要加入重复定量噪声。这样就限制了PCM技术在音频还原时的保真度。
为了全面改善PCM 数字音频技术,获得更好的声音质量,就需要有新的技术来替换。近年来飞利浦和索尼公司再次联手,共同推出一种称为直接流数字编码技术DSD的格式, 其记录媒体为超级音频CD即SACD,支持立体声和5.1环绕声。
WAVE文件作为多媒体中使用的声波文件格式之一,它是以RIFF格式为标准的。 RIFF是英文Resource Interchange File Format的缩写,每个WAVE文件的头四个字节便是“RIFF”。WAVE文件由文件头和数据体两大部分组成。其中文件头又分为RIFF/WAV文件标识段和声音数据格式说明段两部分。WAVE文件各部分内容及格式见附表。
常见的声音文件主要有两种,分别对应于单声道(11.025KHz采样率、8Bit 的采样值)和双声道(44.1KHz采样率、16Bit的采样值)。采样率是指:声音信号在“模→数”转换过程中单位时间内采样的次数。采样值是指每一次采样周期内声音模拟信号的积分值。对于单声道声音文件,采样数据为八位的短整数(short int 00H-FFH); 而对于双声道立体声声音文件,每次采样数据为一个16位的整数(int),高八位和低八位分别代表左右两个声道。
WAVE文件数据块包含以脉冲编码调制(PCM)格式表示的样本。WAVE文件是由样本组织而成的。在单声道WAVE文件中,声道0代表左声道,声道1代表右声道。在多声道WAVE文件中,样本是交替出现的。
wave文件 = wave文件头部 + 音频数据(PCM格式)
//wave文件头部格式(共计44字节)
偏移地址
字节数
数据类型
内容
说明
0x00
4
unsigned long
“RIFF”
文件头标识,一般就是“RIFF”四个字母。
0x04
4
unsigned long
int
整个文件的大小。不包括0x00~0x07的空间大小。
0x08
4
unsigned long
“WAVE”
一般就是“WAVE”四个字母。
0x0c
4
unsigned long
“fmt”
格式说明块,一般就是“fmt”。
0x10
4
unsigned long
int
本数据块的大小。
0x14
2
unsigned short
格式类别
音频格式说明(1为PCM形式的声音数据)。
0x16
2
unsigned short
声道数
单声道为1,双声道为2。
0x18
4
unsigned long
采样率
每秒样本数,表示每个通道的播放速度。
0x1c
4
unsigned long
数据速率,以字节为单位计算
波形音频数据传送速率,其值为通道数×采样率×每样本的数据位数/8。
0x20
2
unsigned short
数据块的调整块
其值为通道数×每样本的数据位值/8。
0x22
2
unsigned short
每个样本的数据位数
表示每个声道中各个样本的数据位数。
0x24
4
char
“DATA”
一般就是“DATA”。
0x28
4
long
int
音频数据的长度。
PCM数据包格式
Sample1
Sample2
Sample3
Smaple4
Channel0
Channel0
Channel0
Channel0
8 bit单声道PCM数据包格式
Sample1
Sample2
Chanell0(left)
Channel1(right)
Channel0(left)
Channel0(right)
8bit立体音PCM数据包格式
Sample1
Sample2
Channel0
Low-order byte
Channel0
Hight-order byte
Channel0
Low-order byte
Channel0
Hight-order byte
16bit单声道PCM数据包格式
Smaple1
Channel0(left)
Low-order byte
Channel0(left)
High-order byte
Channel1(right)
Low-order byte
Channel1(right)
High-order byte
16bit立体音PCM数据包格式
#ifndef __By6000WaveFile_H__
#define __By6000WaveFile_H__
#include <windows.h>
#include <fstream>
#include <string>
#include <memory>
using namespace std;
struct WaveFile_Header
{
unsigned long ulChunkID; //equal to "RIFF"
unsigned long ulChunkSize; //size of chunk,not contain ulChunkID and ulChunkSize
unsigned long ulFormat; //equal to "WAVE"
unsigned long ulSubChunk01ID; //equal to "fmt"
unsigned long ulSubChunk01Size; //size of SubChunk01,equal to 16 when audio format is pcm
unsigned short usAudioFormat; //1,PCM; ...
unsigned short usChannelCount; //1,only one audio channel; 2,have two audio channels
unsigned long ulSampleRate; //sample count per second
unsigned long ulByteRate; //byte count per sample
unsigned short usBlockAlign; //
unsigned short usBitsPerSample; //bit count a sampe have
unsigned long ulSubChunk02ID; //equal to "DATA"
unsigned long ulSubChunk02Size; //length of valid data
};
class CBy6000WaveFile;
struct THREAD_PARAMS_By6000WaveFile
{
CBy6000WaveFile* lpRunClass;
bool (CBy6000WaveFile::*lpRunFun)(void* lpParam);
};
#define SINGLE_CONVERT_LENGTH_MAX 32*1024
class CBy6000WaveFile
{
public:
CBy6000WaveFile(void);
virtual ~CBy6000WaveFile(void);
bool parse_wave_file(WaveFile_Header& varWaveFileHeader, const wchar_t* lpszFilePath);
bool data_convert_wave16_to_by6000pcm128(const wchar_t* lpszBy6000pcm128_FilePath, const wchar_t* lpszWave16_FilePath);
private:
bool single_data_convert_wave16_to_by6000pcm128(BYTE* lpszBy6000pcm128_DataBuffer, const BYTE* lpszWave16_DataBuffer, long lConverLen);
bool start_thread_convert();
void end_thread_convert();
bool thread_fun_convert(void* lpParam);
static DWORD __stdcall thread_run(LPVOID lpParam);
private:
fstream m_fsReader;
fstream m_fsWriter;
wstring m_wstrBy6000pcm128_FilePath;
wstring m_wstrWave16_FilePath;
HANDLE m_hThread_Convert;
bool m_bThreadRunning_Convert;
THREAD_PARAMS_By6000WaveFile m_varThreadParams_By6000WaveFile;
bool m_bConverSucceed;
auto_ptr<BYTE> m_ptrWave16_DataBuffer;
auto_ptr<BYTE> m_ptrBy6000pcm128_DataBuffer;
};
#endif
//By6000WaveFile.cpp
#include "StdAfx.h"
#include "By6000WaveFile.h"
CBy6000WaveFile::CBy6000WaveFile(void)
{
m_bThreadRunning_Convert = false;
m_hThread_Convert = NULL;
m_bConverSucceed = false;
m_ptrWave16_DataBuffer = auto_ptr<BYTE>(new BYTE[SINGLE_CONVERT_LENGTH_MAX + 0x100]);
m_ptrBy6000pcm128_DataBuffer = auto_ptr<BYTE>(new BYTE[4*SINGLE_CONVERT_LENGTH_MAX + 0x100]);
}
CBy6000WaveFile::~CBy6000WaveFile(void)
{
}
bool CBy6000WaveFile::parse_wave_file(WaveFile_Header& varWaveFileHeader, const wchar_t* lpszFilePath)
{
m_fsReader.open(lpszFilePath, ios::in | ios::binary);
if(!m_fsReader.is_open() )
{
return false;
}
m_fsReader.read((char*)&varWaveFileHeader, sizeof(varWaveFileHeader) );
m_fsReader.close();
return true;
}
bool CBy6000WaveFile::data_convert_wave16_to_by6000pcm128(const wchar_t* lpszBy6000pcm128_FilePath, const wchar_t* lpszWave16_FilePath)
{
m_wstrBy6000pcm128_FilePath = lpszBy6000pcm128_FilePath;
m_wstrWave16_FilePath = lpszWave16_FilePath;
start_thread_convert();
if(WAIT_OBJECT_0 !=::WaitForSingleObject(m_hThread_Convert, 24*3600*1000) )
{
end_thread_convert();
return false;
}
end_thread_convert();
if(!m_bConverSucceed)
{
return false;
}
return true;
}
bool CBy6000WaveFile::single_data_convert_wave16_to_by6000pcm128(BYTE* lpszBy6000pcm128_DataBuffer, const BYTE* lpszWave16_DataBuffer, long lConverLen)
{
if(NULL == lpszBy6000pcm128_DataBuffer || NULL == lpszWave16_DataBuffer)
{
return false;
}
if(0 != lConverLen % 4)
{
return false;
}
for(int i = 0; i < lConverLen; i += 4)
{
/*
lpszBy6000pcm128_DataBuffer[4*i + 0] = lpszWave16_DataBuffer[i];
lpszBy6000pcm128_DataBuffer[4*i + 1] = lpszWave16_DataBuffer[i + 1];
lpszBy6000pcm128_DataBuffer[4*i + 4] = lpszWave16_DataBuffer[i + 2];
lpszBy6000pcm128_DataBuffer[4*i + 5] = lpszWave16_DataBuffer[i + 3];
*/
lpszBy6000pcm128_DataBuffer[4*i + 0] = lpszWave16_DataBuffer[i + 1];
lpszBy6000pcm128_DataBuffer[4*i + 1] = lpszWave16_DataBuffer[i + 0];
lpszBy6000pcm128_DataBuffer[4*i + 4] = lpszWave16_DataBuffer[i + 3];
lpszBy6000pcm128_DataBuffer[4*i + 5] = lpszWave16_DataBuffer[i + 2];
}
return true;
}
bool CBy6000WaveFile::start_thread_convert()
{
//if the thread is running, end it first
end_thread_convert();
memset(&m_varThreadParams_By6000WaveFile, 0, sizeof(m_varThreadParams_By6000WaveFile) );
m_varThreadParams_By6000WaveFile.lpRunClass = this;
m_varThreadParams_By6000WaveFile.lpRunFun = &CBy6000WaveFile::thread_fun_convert;
m_bThreadRunning_Convert = true;
m_bConverSucceed = false;
m_hThread_Convert = ::CreateThread(NULL, 0, &CBy6000WaveFile::thread_run, &m_varThreadParams_By6000WaveFile, FALSE, NULL);
if(NULL == m_hThread_Convert)
{
return false;
}
return true;
}
void CBy6000WaveFile::end_thread_convert()
{
if(m_bThreadRunning_Convert)
{
m_bThreadRunning_Convert = false;
::WaitForSingleObject(m_hThread_Convert, 200);
::CloseHandle(m_hThread_Convert);
m_hThread_Convert = NULL;
}
}
bool CBy6000WaveFile::thread_fun_convert(void* lpParam)
{
WaveFile_Header varWaveFile_Header = {0};
if(!parse_wave_file(varWaveFile_Header, m_wstrWave16_FilePath.c_str() ) )
{
return false;
}
m_fsReader.open(m_wstrWave16_FilePath.c_str(), ios::in|ios::binary);
if(!m_fsReader.is_open() )
{
return false;
}
m_fsWriter.open(m_wstrBy6000pcm128_FilePath.c_str(), ios::out|ios::binary);
if(!m_fsWriter.is_open() )
{
m_fsReader.close();
return false;
}
m_fsWriter.clear();
long lConvertTotalLength = varWaveFile_Header.ulSubChunk02Size - (varWaveFile_Header.ulSubChunk02Size % 4);
long lReadPos = sizeof(WaveFile_Header);
long lReadLen = (SINGLE_CONVERT_LENGTH_MAX < lConvertTotalLength) ? SINGLE_CONVERT_LENGTH_MAX : lConvertTotalLength;
while(true)
{
memset(m_ptrWave16_DataBuffer.get(), 0, SINGLE_CONVERT_LENGTH_MAX + 0x100);
memset(m_ptrBy6000pcm128_DataBuffer.get(), 0, 4*SINGLE_CONVERT_LENGTH_MAX + 0x100);
m_fsReader.seekg(lReadPos);
m_fsReader.read((char*)m_ptrWave16_DataBuffer.get(), lReadLen);
single_data_convert_wave16_to_by6000pcm128(m_ptrBy6000pcm128_DataBuffer.get(), m_ptrWave16_DataBuffer.get(), lReadLen);
m_fsWriter.write((char*)m_ptrBy6000pcm128_DataBuffer.get(), 4*lReadLen);
m_fsWriter.flush();
lReadPos += lReadLen;
//finish the convert
if(long(lReadPos - sizeof(WaveFile_Header) ) >= lConvertTotalLength)
{
break;
}
else
{
long lLengthRemain = lConvertTotalLength + sizeof(WaveFile_Header) - lReadPos;
lReadLen = (SINGLE_CONVERT_LENGTH_MAX < lLengthRemain) ? SINGLE_CONVERT_LENGTH_MAX : lLengthRemain;
}
}
m_fsReader.close();
m_fsWriter.close();
m_bConverSucceed = true;
return true;
}
DWORD CBy6000WaveFile::thread_run(LPVOID lpParam)
{
THREAD_PARAMS_By6000WaveFile* lpThreadParams = reinterpret_cast<THREAD_PARAMS_By6000WaveFile*>(lpParam);
CBy6000WaveFile* lpRunClass = lpThreadParams->lpRunClass;
bool (CBy6000WaveFile::*lpRunFun)(void*) = lpThreadParams->lpRunFun;
(lpRunClass->*lpRunFun)(NULL);
return 0;
}
//main.cpp
// Console.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <windows.h>
#include <iostream>
using namespace std;
// #define BOOST_ALL_NO_LIB
// #include <boost/thread.hpp>
// #pragma comment(lib, "boost_thread-vc90-mt-1_48.lib")
#include "By6000WaveFile.h"
int main(int argc, char* argv[])
{
CBy6000WaveFile varBy6000WaveFile;
WaveFile_Header varWaveFileHeader = {0};
varBy6000WaveFile.parse_wave_file(varWaveFileHeader, L"D:\\Wave.wav");
varBy6000WaveFile.data_convert_wave16_to_by6000pcm128(L"D:\\Wave.pcm", L"D:\\Wave.wav");
return 0;
}
- Wave音频格式解析
- 各类音频格式解析
- OGG音频格式解析
- WAVE 流媒体格式解析
- wave文件格式与解析
- 音频格式
- 音频格式
- 音频格式
- MP3技术白皮书-音频格式全解析
- C++ wave 音频文件解析程序
- WAVE文件头数据解析
- wave
- wave
- wave
- 多媒体音频格式解析WMA WAV OGG AAC APE FLAC[转载]
- 多媒体音频格式解析WMA WAV OGG AAC APE FLAC
- rtp的视频和音频格式初步分析(golang解析)
- C++ 解析WAVE格式文件信息,并取得播放时间
- Tasks and Back Stack
- 自己设计一个简单的的Java连接池(二)
- android:taskAffinity初识
- 关于一个工程中多个文件的相互调用的学习笔记(C语言)
- 将java文件开头的package路径进行规整,使包路径正确
- Wave音频格式解析
- ANDROID content provide 使用实例
- 10494 - If We Were a Child Again
- SoYoung的YII学习笔记2
- C++ 星号指针定义
- 成为高效程序员的7个重要习惯
- 凉鞋学 Parse Android Guide(六) 面向 Android 的Parse 云服务
- Guava学习之Immutable集合
- Linux启动流程一