波形格式 - 负数据大小

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

【讨论】:

以上是关于波形格式 - 负数据大小的主要内容,如果未能解决你的问题,请参考以下文章

NAudio WaveFileWriter 不会将文件大小写入波形文件

为啥波形图的加速度不一样

iOS 录音及播放 音波图波形

Rcpp R 向量大小限制(不允许负长度向量)

UIImageView 子类需要处理调整大小

使用负索引调整大小的列表切片分配[重复]