【问题标题】:Wave Format - negative data size波形格式 - 负数据大小
【发布时间】:2018-09-24 14:31:11
【问题描述】:

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

【问题讨论】:

  • 想展示您的代码吗?这可能是有符号/无符号整数问题。 RIFF/WAF 格式为thoroughly documented,因此只要您遵守规范,您就不会感到意外。
  • 当时我的代码非常混乱,所以我不想展示它。我将其读取为一个小端整数,而对值的符号没有任何更改。
  • @GPlayer 我更新了我的答案以匹配新格式...

标签: format wave


【解决方案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 标头中的数据大小单位是无符号的,并且由于您获得的是有符号值,这表明您没有正确地从波形标头中读取值...

    【讨论】:

      猜你喜欢
      • 2019-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-05
      • 1970-01-01
      • 1970-01-01
      • 2013-08-11
      • 2012-04-01
      相关资源
      最近更新 更多