首页 > 解决方案 > Wave Format - negative data size

问题描述

I'm working with Wave files. I'm reading all the data but in some files data size (specified amount of bytes to be read) is negative, which breaks the reading mechanism. Are wave files constant in terms of byte offsets? Is x offset always the same value?

标签: formatwave

解决方案


如果它有帮助,这就是我用于 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数据类型移植到您的环境...

但是负值表明您再次使用有符号整数(就像在您的其他问题中一样)所以请改用无符号数据类型...... RIFF Wave 文件中的偏移量永远不会是负数!

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

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

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


推荐阅读