波形格式 - 负数据大小
Posted
技术标签:
【中文标题】波形格式 - 负数据大小【英文标题】:Wave Format - negative data size 【发布时间】:2018-09-24 14:31:11 【问题描述】:我正在处理 Wave 文件。我正在读取所有数据,但在某些文件中,数据大小(要读取的指定字节数)为负数,这破坏了读取机制。波形文件的字节偏移量是否恒定? x 偏移量总是相同的值吗?
【问题讨论】:
想展示您的代码吗?这可能是有符号/无符号整数问题。 RIFF/WAF 格式为thoroughly documented,因此只要您遵守规范,您就不会感到意外。 当时我的代码非常混乱,所以我不想展示它。我将其读取为一个小端整数,而对值的符号没有任何更改。 @GPlayer 我更新了我的答案以匹配新格式... 【参考方案1】:波形文件的字节偏移量是否恒定? x 是否总是偏移 相同的值?
不,至少数据部分并不总是在相同的偏移量处找到。一些简单的程序假定声音样本从固定偏移量 (44) 开始,但情况并非总是如此。 可靠读取波形文件的唯一方法是查找数据部分,一旦找到,数据大小字段将相对于数据部分偏移 +4。
【讨论】:
【参考方案2】:如果有帮助,这就是我用于 wav 解码/编码的方法(我几年前编码):
//---------------------------------------------------------------------------
//--- RIFF WAVE format: 1.01 ------------------------------------------------
//---------------------------------------------------------------------------
#ifndef _RIFF_h
#define _RIFF_h
//---------------------------------------------------------------------------
// 8bit PCM is unsigned
// 16bit PCM is signed 2'os complement little endian (big endian is RIFX)
//---------------------------------------------------------------------------
struct _wave_chunk
DWORD ids;
DWORD len;
_wave_chunk() ids=' '; len=0;
_wave_chunk(_wave_chunk& a) *this=a; ; ~_wave_chunk(); _wave_chunk* operator = (const _wave_chunk *a) *this=*a; return this; ; /*_wave_chunk* operator = (const _wave_chunk &a) ...copy... return this; ;*/
;
struct _wave_hdr
DWORD ids; // "RIFF"
DWORD len;
DWORD tps; // "WAVE"
_wave_hdr() ids='FFIR'; len=0; tps='EVAW';
_wave_hdr(_wave_hdr& a) *this=a; ; ~_wave_hdr(); _wave_hdr* operator = (const _wave_hdr *a) *this=*a; return this; ; /*_wave_hdr* operator = (const _wave_hdr &a) ...copy... return this; ;*/
;
struct _wave_fmt
DWORD ids; // "fmt "
DWORD len; // 16,18,40
WORD format; // 1 = PCM linear quantization
/* 0x0001 WAVE_FORMAT_PCM PCM
0x0003 WAVE_FORMAT_IEEE_FLOAT IEEE float
0x0006 WAVE_FORMAT_ALAW 8-bit ITU-T G.711 A-law
0x0007 WAVE_FORMAT_MULAW 8-bit ITU-T G.711 µ-law
0xFFFE WAVE_FORMAT_EXTENSIBLE Determined by SubFormat */
WORD chanels;
DWORD samplerate;
DWORD byterate;
WORD blockalign;
WORD bits;
WORD ext_len; // extension length 0,22
WORD ext_validbits;
DWORD ext_channelmask;
BYTE ext_subformat[16];
_wave_fmt() ids=' tmf'; len=16; format=1; chanels=1; samplerate=44100; bits=8; ext_len=0; ext_validbits=0; ext_channelmask=0; for (int i=0;i<16;i++) ext_subformat[i]=0; compute();
_wave_fmt(_wave_fmt& a) *this=a; ; ~_wave_fmt(); _wave_fmt* operator = (const _wave_fmt *a) *this=*a; return this; ; /*_wave_fmt* operator = (const _wave_fmt &a) ...copy... return this; ;*/
void compute()
byterate=(chanels*samplerate*bits)/8;
blockalign=(chanels*bits)/8;
;
struct _wave_dat
DWORD ids; // "data"
DWORD len;
_wave_dat() ids='atad'; len=0;
_wave_dat(_wave_dat& a) *this=a; ; ~_wave_dat(); _wave_dat* operator = (const _wave_dat *a) *this=*a; return this; ; /*_wave_dat* operator = (const _wave_dat &a) ...copy... return this; ;*/
;
//---------------------------------------------------------------------------
class wave
public:
AnsiString name;
int hnd;
bool readonly;
_wave_hdr hdr;
_wave_fmt fmt;
_wave_dat dat;
wave();
~wave();
void create(AnsiString _name);
void write(BYTE *data,DWORD size);
bool open(AnsiString _name);
DWORD read(BYTE *data,DWORD size);
void close();
;
//---------------------------------------------------------------------------
wave::wave()
name=0;
hnd=-1;
readonly=true;
//---------------------------------------------------------------------------
wave::~wave()
close();
//---------------------------------------------------------------------------
void wave::create(AnsiString _name)
close();
readonly=true;
// hdr=_wave_hdr();
// fmt=_wave_fmt();
// dat=_wave_dat();
hdr.len=sizeof(hdr)-8;
dat.len=0;
fmt.compute();
name=_name;
hnd=FileCreate(name);
if (hnd<0) return;
FileWrite(hnd,&hdr,sizeof(hdr));
FileWrite(hnd,&fmt,fmt.len+8);
FileWrite(hnd,&dat,sizeof(dat));
readonly=false;
//---------------------------------------------------------------------------
bool wave::open(AnsiString _name)
close();
readonly=true;
name=_name;
hnd=FileOpen(name,fmOpenRead);
if (hnd<0) return false;
if (FileRead(hnd,&hdr,sizeof(hdr))<sizeof(hdr)) close(); return false;
if (hdr.ids!='FFIR') return false;
if (hdr.tps!='EVAW') return false;
_wave_chunk chk;
DWORD sz=sizeof(chk),l;
for(;;)
if (FileRead(hnd,&chk,sz)<sz) close(); return false;
if (chk.ids==' tmf')
fmt.ids=chk.ids;
fmt.len=chk.len;
if (FileRead(hnd,((BYTE*)&fmt)+sz,chk.len)<chk.len) close(); return false;
else if (chk.ids=='atad')
dat.ids=chk.ids;
dat.len=chk.len;
return true;
else FileSeek(hnd,int(chk.len),1);
//---------------------------------------------------------------------------
void wave::write(BYTE *data,DWORD size)
if (hnd<0) return;
hdr.len+=size;
dat.len+=size;
if (!readonly) FileWrite(hnd,data,size);
//---------------------------------------------------------------------------
DWORD wave::read(BYTE *data,DWORD size)
if (hnd<0) return 0;
return FileRead(hnd,data,size);
//---------------------------------------------------------------------------
void wave::close()
name="";
if (hnd<0) return;
FileSeek(hnd,0,0);
if (!readonly) FileWrite(hnd,&hdr,sizeof(hdr));
FileClose(hnd);
hnd=-1;
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------
它不支持所有格式,但应该足以比较和修复您的代码。提取地址...代码基于C++/VCL,因此您需要将二进制文件访问和AnsiString
数据类型移植到您的环境...
但是负值表明您再次使用有符号整数(就像在您的其他 question 中一样)所以请改用无符号数据类型... RIFF Wave 中的偏移量文件永远不会是负面的!!!
[Edit1] 我更新了新格式的代码。
在向 Wave 格式添加一些扩展(参见第一个 xbug 下的注释中的 format info)到 Wave 格式之后,格式 fmt
块现在可以具有可变大小。他们还添加了一些其他块(与压缩相关),因此为了可靠地读取,您需要根据它们的块大小传递所有 RIFF 块,直到您点击您的数据样本应该遵循的 data
块...
我的原始代码是 1.0 格式的(正如提到它是几年前编码的),并且没有正确加载较新的波形文件(感谢 dsp_user 发现它)。我用新的格式更新了它,所以再次使用应该是安全的。
【讨论】:
您的 wave_header 结构假定声音样本从偏移量 44 开始,但波形格式规范并不要求这样做。事实上,许多音频编辑器对数据部分使用其他偏移量,因为它们通常有一些额外的部分(例如事实部分、列表部分)。因此,要正确解析波形文件,您需要搜索数据部分,而不是依赖固定的偏移量。 @dsp_user 你能分享一些带有偏移数据的 wav 文件吗? 如何在此处共享文件?无论如何,如果您有 Audacity,那么您可以创建自己的文件。最简单的方法是创建一个简单的正弦音(使用内置音调发生器)并将其导出为 wav 格式。 Audacity 创建的文件不是从偏移量 44 开始的(至少在我使用的版本中没有)。 这里是 (ulozto.net/!AJw7Ywpw8djU/80-aud-wav)。格式为22050Hz/32位浮点/1通道。 @dsp_user 感谢提供示例文件我更新了代码以匹配新格式,看起来它在我的应用程序和媒体播放器中都可以使用......【参考方案3】:由于 .wav 标头中的数据大小单位是无符号的,并且由于您获得的是有符号值,这表明您没有正确地从波形标头中读取值...
【讨论】:
以上是关于波形格式 - 负数据大小的主要内容,如果未能解决你的问题,请参考以下文章