var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www."); document.write(("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E")); var pageTracker = _gat._getTracker("UA-1571243-2"); pageTracker._trackPageview();

    2008-09-10

    呼呼,恢复音频文件 - [声音]

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://www.blogbus.com/seeit-logs/28711744.html

          研究了一共三天,终于将一段音频文件的尸体弄出了声。兹将过程详述与此,留待日后自己参考,嗯

          事情是这样的,一朋友拿audition录了近一个小时的广播节目,结果电脑死机,只留下了一个临时文件的尸体。本着团结互助、分发进取的精神,我决定把这个尸体拷回来,看看有没有什么办法恢复。按说,audition的“编辑”模式只生成一个临时文件,而且大小和相应时长的wav文件大小差不多,应该在这个临时文件中还保存着音频信息,但我不是程序员,也不太清楚audition是怎么组织临时文件的,所以,只能是试试看了……

          同所有徒劳的失败案例一样,普通的音频编辑程序是无法强制打开这个音频文件的。于是我干脆用ultra edit打开,看看究竟有什么玩意儿。比较了普通的wav格式音频文件之后,看出一点问题,原来audition的临时文件没有wav文件的文件头部,自然音频软件也就无法识别了。研究了两天,还在自己的电脑上也装了个audition,终于搞明白怎么重写文件头了(不过最后还是无法百分之百恢复,见后文)。

           我从网上找了一些资料,摘录一篇如下,非程序员的我看了好半天才终于看懂-_-b

    ===========================

    WAVE文件作为多媒体中使用的声波文件格式之一,它是以RIFF格式为标准的。RIFF是英文Resource  Interchange  File  Format的缩写,每个WAVE文件的头四个字节便是“RIFF”。WAVE文件由文件头和数据体两大部分组成。其中文件头又分为RIFF/WAV文件标识段和声音数据格式说明段两部分。WAVE文件各部分内容及格式见附表。
     
      常见的声音文件主要有两种,分别对应于单声道(11.025KHz采样率、8Bit的采样值)和双声道(44.1KHz采样率、16Bit的采样值)。采样率是指:声音信号在“模→数”转换过程中单位时间内采样的次数。采样值是指每一次采样周期内声音模拟信号的积分值。
     
      对于单声道声音文件,采样数据为八位的短整数(short  int  00H-FFH);而对于双声道立体声声音文件,每次采样数据为一个16位的整数(int),高八位和低八位分别代表左右两个声道。
     
            WAVE文件数据块包含以脉冲编码调制(PCM)格式表示的样本。WAVE文件是由样本组织而成的。在单声道WAVE文件中,声道0代表左声道,声道1代表右声道。在多声道WAVE文件中,样本是交替出现的。  
    WAV文件头:

    偏移地址     字节数     数据类型     内   容
      00H          4        char        "RIFF"标志
      04H          4        long int      文件长度
      08H          4        char         "WAVE"标志
      0CH          4        char         "fmt"标志
      10H          4        过渡字节(不定)
      14H          2        int      格式类别(10H为PCM形式的声音数据)
      16H          2        int        通道数,单声道为1,双声道为2
      18H          2        int 采样率(每秒样本数),表示每个通道的播放速度,
      1CH          4       long int  波形音频数据传送速率,其值为通道数×每秒数据位数×每样本的数据位数/8。播放软件利用此值可以估计缓冲区的大小。
      20H          2        int  数据块的调整数(按字节算的),其值为通道数×每样本的数据位值/8。播放软件需要一次处理多个该值大小的字节数据,以便将其值用于缓冲区的调整。
      22H          2       每样本的数据位数,表示每个声道中各个样本的数据位数。如果有多个声道,对每个声道而言,样本大小都一样。
      24H          4        char        数据标记符"data"
      28H          4        long int    语音数据的长度

    1)标准Wave PCM格式的音频文件头格式为一个44字节长的结构,该结构的声明及说明如下:

    typedef struct
    {
        char    riff[4];    //="RIFF";
        DWORD   size_8;     // = 音频文件 - 8 ( =音频数据长度+该结构体长度 - 8)
        char    wave[4];    //="WAVE";
        char    fmt[4];        //="fmt ";
        DWORD   fmtSize;    //下一个结构体的大小 = 16;

        //struct WAVEFORMAT defined in "mmreg.h"
        WORD    wFormatTag;        //WAVE_FORMAT_PCM ( = 1);
        WORD    wChannels;        //通道数 = 1
        DWORD   dwSamplesPerSec;    //采样率 (8000 或 16000)
        DWORD   dwAvgBytesPerSec;        //每秒字节数 ( = 采样率 × 量化比特数 ÷ 8 (nSamplesPerSec * wBitsPerSample / 8 ))
        WORD    wBlockAlign;        //每采样点字节数 (量化比特数÷8 (wBitsPerSample / 8))
        WORD    wBitsPerSample;        //量化比特数((当采样率为8000时=8,当采样率为16000时=16))

        char    data[4];        //="data";
        DWORD   datasize;        //纯数据长度
    }TWaveHeadPCM, *PTWaveHeadPCM;

    =============================

           如这段文字所示,加上用audition录音的实验,发现audition是在临时文件的头部另加了44字节的文件头(而不是改写文件头) 。如果知道临时文件在录音时的精度和采样率设置,是可以手工编写文件头部的。以下这段文字帮助我搞清楚了如何编写wav格式文件头:

    =============================

    以下是一个波形文件样本的头部:
    00000000h: 52 49 46 46 E6 E4 05 00 57 41 56 45 66 6D 74 20 ; RIFF驿..WAVEfmt
    00000010h: 12 00 00 00 01 00 01 00 40 1F 00 00 80 3E 00 00 ; ........@...€>..
    00000020h: 02 00 10 00 00 00 64 61 74 61 C0 E4 05 00      ; ......data冷..
    从该样本可以看出:
    该波形文件波形块的大小为386278(0x0005E4E6),波形文件大小为:386278+8 =386286字节;
    格式块的大小(WAVEFORMATEX结构体)为18字节;
    波形数据的大小为386240字节(0x0005E4C0);

    ===================================

         这样就可以估计出文件头中的几个关键数字了。如第一段引用的文字所述,在wav格式文件头中,只要知道声道数、采样率和采样精度,就可以确定44个字节中的大部分字节,而需要手工计算的有两个,一是文件长度,即04H处开始的四个字节;二是音频数据长度,也就是data标记后面的四个字节。第一个比较好算,整个文件大小的字节数减8即可,第二个比较困难,因为不知道临时文件中是否还保存了非音频数据信息。经过几次试验,我决定索性将所有的剩余长度全算成了音频数据长度。要注意的一件事就是,写入文件头的时候是在原文件头部另加了44字节,因此计算大小的时候也得把这44个字节算进去。

          这样我就得到了全部的文件头信息,写入之后,终于能让这个文件出声了!不过还伴随着另一个问题:audition的临时文件中,音频数据似乎不是完全按照时间顺序排列的,而是每隔一段就插入一小点不知道从哪来的音频数据——可能是为了缓存或其它什么原因,将最新录制的一小段声音数据插入到之前已经录制的音频数据中的某个位置吧,我猜测——结果,恢复出来的音频就跟神经错乱一样,每放几十秒就出一个怪声儿(其实就是小于一秒的后面某个位置的声音),不过总算能大致听出意思了……T_T

          至此恢复工作算是告一段落,不过还有许多问题,比如wav格式的存储方式,计算方式,音频软件究竟是如何对音频进行处理——比如混合,反相或者加效果等等——之类的,当然,这些如果研究明白,我就可以编写工作站程序去了……呵呵,还是留待日后慢慢研究吧

    分享到:
    引用地址: