波形格式 - 负数据大小

Wave Format - negative data size

我正在处理 Wave 文件。我正在读取所有数据,但在某些文件中,数据大小(要读取的指定字节数)为负数,这会破坏读取机制。波形文件的字节偏移量是否恒定? x 偏移量总是相同的值吗?

如果有帮助,这就是我用于 wav decoding/encoding(我几年前编码)的方法:

//---------------------------------------------------------------------------
//--- 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中一样)所以请改用无符号数据类型... [=中的偏移量28=]RIFF 波形文件永远不会是负的!!!

[Edit1] 我更新了新格式的代码。

在向 Wave 格式添加一些扩展(参见 xbug 在 OP 下的评论中的 format info 之后,格式 fmt 块可以有变量现在的大小。他们还添加了一些其他块(与压缩相关),因此为了可靠地读取,您需要根据块大小传递所有 RIFF 块,直到您到达 data 块您的数据样本应遵循...

我的原始代码适用于格式 1.0(如前所述,它是几年前编写的)并且没有正确加载较新的 wave 文件(感谢 dsp_user 发现它).我用新的格式更新了它,所以再次使用它应该是安全的。

Are wave files constant in terms of byte offsets? Is x offset always the same value?

不,至少数据部分并不总是在相同的偏移量处找到。一些简单的程序假定声音样本从固定偏移量 (44) 开始,但情况并非总是如此。 可靠地读取 wave 文件的唯一方法是查找数据部分,一旦找到它,数据大小字段将位于相对于数据部分的偏移 +4 处。

由于 .wav header 中数据大小的单位是无符号的,并且由于您得到的是带符号的值,这表明您没有正确读取 wave header 中的值...