0

我一直在使用代码在 delphi 中读取 .wav 数据,并将结果与​​从 matlab 函数 wavread 获得的值进行比较。从中我可以说matlab函数可以自动识别哪一个是样本数据值,但不能使用delphi(但matlab和delphi代码结果是相同的)。由于我的 delphi 代码无法识别示例数据值,因此我查看了数组,发现示例数据值开始的索引每个 .wav 文件都不同。例如,我测试了一些 .wav 文件并得到了这个:

  1. classic1.wav 从 wavedata[].Data[] 索引号 40 开始的样本数据值
  2. classic2.wav 从 wavedata[].Data[] 索引号 35 开始的样本数据值

我通过查看结果得到了上述结论 y,[y, Fs, nbits, opts]=wavread('classic1.wav','double'); 然后我去结果delphi返回一个数组检查它的值,并从索引40开始找到完全相同的值,对于classic1.wav和35对于classic2.wav。我想知道是否有一种方法可以知道每个 .wav 文件的样本数据值的起始索引?

编辑:我已经更正了类似于给定参考的记录,它与标题(从 ChunkID 到 Subchunk2size)完全正确,但我仍然对它后面的示例数据感到困惑,因为与之前的结果没有任何变化。

type
TWaveHeader = packed record

    Marker_RIFF: array [0..3] of char;
    ChunkSize: cardinal;
    Marker_WAVE: array [0..3] of char;


    Marker_fmt: array [0..3] of char;
    SubChunkSize: cardinal;
    FormatTag: word;
    NumChannels: word;
    SampleRate: longint;
    ByteRate: longint;
    BlockAlign:word; 
    BitsPerSample: word;


    Marker_data: array [0..3] of char;
    DataBytes: longint;
  end;

  TChannel = record
  Data : array of smallint;


end;
4

2 回答 2

4

您显然没有正确跳过所有标题字段。Wav 文件可以有一些可选的标头信息,因此尽管实际样本值通常从字节 44 开始,但并非总是如此。

例如,请参见此处:https ://ccrma.stanford.edu/courses/422/projects/WaveFormat/

直接跳到示例数据的一种方法(在读取您需要的标头的任何部分之后)是扫描文件(一次四个字节)以查找“数据”的 ascii 字符串(64 61 74 61 hex),然后读取紧随其后的 4 个字节,它(作为基数或长字)表示要读取的字节总数。实际样本紧随该红衣主教之后。

编辑:

正如预期的那样,在十六进制编辑器中查看文件 Classic1.wav 和 Classic2.wav 很明显它们都有一些元数据。在每个文件中的位置 36,而不是找到“数据”的 SubchunkID,而是找到“列表”。后面的四个字节给出了这个附加数据的大小。这是您必须跳过才能获取音乐样本数据的内容。

例如,Classic1.wav 有 148 字节的额外数据,从偏移量 44 开始。这将 Subchunk2ID 放置在偏移量 192 处,将 Subchunk2Size 放置在偏移量 196 处,这意味着第一个样本从文件中的偏移量 200 开始。

Classic2.wav 有 128 字节的额外数据,从偏移量 44 开始。这将 Subchunk2ID 放置在偏移量 172 处,将 Subchunk2Size 放置在偏移量 176 处,这意味着第一个样本从文件中的偏移量 180 开始。

这是一个非常基本的十六进制编辑器中的 Classic2.wav: 在此处输入图像描述

于 2013-04-26T18:05:15.677 回答
3

与其手动完成所有文件 I/O,不如使用 Win32 多媒体 API 函数 - mmioOpen()mmioDescend()mmioAscend()mmioRead()等。让他们为您完成所有艰苦的工作. 您的代码将更易于管理和阅读,因为您将能够更多地关注单个块的内容,同时让 API 为您处理查找每个块的低级细节。

于 2013-04-27T09:02:39.933 回答