使用delphi读取.wav文件

时间:2013-04-26 02:18:19

标签: delphi matlab delphi-7 wav

我现在尝试使用delphi读取.wav文件,这是我的代码:

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;
    BytesPerSecond: longint;
    BytesPerSample: word;
    BitsPerSample: word;


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

  TChannel = record
  Data : array of double;
end;
一些私人移民

private
    wavehdr:TWaveHeader;
    wavedata:array[0..3]of TChannel;
    numsamples:integer;

功能

  FillChar(wavehdr, sizeof(wavehdr), 0);
  Stream.Read(wavehdr, sizeof(wavehdr));

  { Log Header data }
  with memo1.Lines do begin
    Add('Filename : '+od.FileName);
    Add('Header size : '+inttostr(sizeof(wavehdr)));
    tmpstr := wavehdr.Marker_RIFF;
    Add('RIFF ID : '+tmpstr+'');
    Add('Chunk size : '+inttostr(wavehdr.ChunkSize));
    tmpstr := wavehdr.Marker_WAVE;
    Add('WAVE ID : '+tmpstr+'');
    tmpstr := wavehdr.Marker_fmt;
    Add('''fmt '' ID : '+tmpstr+''' ');
    Add('SubChunk size : '+inttostr(wavehdr.SubChunkSize));
    Add('Format : '+inttostr(wavehdr.FormatTag));
    Add('Num Channels : '+inttostr(wavehdr.NumChannels));
    Add('Sample rate : '+inttostr(wavehdr.SampleRate));
    Add('Bytes per second : '+inttostr(wavehdr.BytesPerSecond));
    Add('Bits per sample : '+inttostr(wavehdr.BitsPerSample));
    Add('Block Align : '+inttostr((wavehdr.NumChannels*wavehdr.BitsPerSample)div 8));
  end;

  numsamples := (file.size div (wavehdr.NumChannels*wavehdr.BitsPerSample)div 8) div wavehdr.BytesPerSample;
  case wavehdr.NumChannels of
      1:begin
        SetLength(wavedata[0].Data, numsamples);
        Stream.Read(wavedata[0].Data[0], numsamples);
      end;

      2:begin
        SetLength(wavedata[0].Data, numsamples);
        SetLength(wavedata[1].Data, numsamples);
        for i := 0 to high(wavedata[0].Data) do begin
          Stream.Read(wavedata[0].Data[i], 2);
          Stream.Read(wavedata[1].Data[i], 2);
        end;
      end;
  end;

上面的代码给出了与.wav标题完全相同的信息和细节(与MATLAB DOES相同),它是:

  • 文件名:E:\ dephi \ classic3.wav
  • RIFF ID:RIFF
  • 块大小:18312354
  • WAVE ID:WAVE
  • 'fmt'ID:fmt'
  • SubChunk size:16
  • 格式:1(PCM)
  • Num频道:2(立体声)
  • 采样率:44100
  • 每秒字节数:176400
  • 每个样本的位数:16
  • Block Align:4

除了我计算的总样本数据(波数据的大小/波数据的块对齐)-44,44是wav的标题。它不准确,有时会错过5,1,10。我只测试了5个样本。这里有一个例子:

  • classic1.wav matlab:3420288,delphi(我的计算):( 13681352/4)-44 = 3420294
  • classic2.wav matlab:2912256,delphi(我的计算):( 11649204/4)-44 = 2912257

而且来自matlab和delphi的样本数据值与

不同

classic1.wav MATLAB :(前10个值为leftchannel和rightchannel)

  1. -3.05175781250000e-05 [] 6.10351562500000e-05
  2. -6.10351562500000e-05 [] 6.10351562500000e-05
  3. -6.10351562500000e-05 [] 3.05175781250000e-05
  4. 0 [] -3.05175781250000e-05
  5. 6.10351562500000e-05 [] -6.10351562500000e-05
  6. 6.10351562500000e-05 [] -6.10351562500000e-05
  7. 3.05175781250000e-05 [] -3.05175781250000e-05
  8. 6.10351562500000e-05 [] -6.10351562500000e-05
  9. 3.05175781250000e-05 [] 0
  10. -3.05175781250000e-05 [] 6.10351562500000e-05
  11. DELPHI :(前10个值为leftchannel和rightchannel)

    1. 9.90156960830442E-320 [] 1.00265682167023E-319
    2. 9.90156960830442E-320 [] 9.77113627780233E-320
    3. 3.26083326255223E-322 [] 0
    4. 1.39677298735779E-319 [] 1.37088394751571E-319
    5. 1.45932169812129E-319 [] 1.33373021094845E-319
    6. 1.23175506164681E-319 [] 1.206903559661E-319
    7. 1.28239679034554E-319 [] 1.40932225476216E-319
    8. 1.37068632125737E-319 [] 1.33382902407761E-319
    9. 1.33373021094845E-319 [] 1.25685359645555E-319
    10. 1.40907522193924E-319 [] 1.33358199125469E-319
    11. 我的问题是:

      1. 查找wav文件的总样本时,如何正确执行?
      2. 是matlab和delphi读取wav文件(数据块)的方式 不同的方式?或者我的代码可能是错误的?
      3. 有没有办法像MATLAB一样得到相同的值?
      4. 编辑:我跟着mBo建议并将其改为mbo advise

        Data : array of SmallInt;
        numsamples := wavehdr.DataBytes div (wavehdr.NumChannels * wavehdr.BitsPerSample div 8);
        Stream.Read(wavedata[0].Data[i], SizeOf(SmallInt));
        
        解释部分我不确定,但我将其改为

        floattostr(wavedata[0].Data[i]/32768.0)
        floattostr(wavedata[1].Data[i]/32768.0)
        

        我得到的结果:

        1. 0.611602783203125 [] 0.61932373046875
        2. 0.611602783203125 [] 0.603546142578125
        3. 0.0023193359375 [] 0
        4. 0.862762451171875 [] 0.846771240234375
        5. 0.901397705078125 [] 0.823822021484375
        6. 0.760833740234375 [] 0.7454833984375
        7. 0.7921142578125 [] 0.870513916015625
        8. 0.799774169921875 [] 0.761016845703125
        9. 0.8238525390625 [] 0.782623291015625
        10. 0.354766845703125 [] 0.76123046875

1 个答案:

答案 0 :(得分:6)

Wav文件(每个样本位数:16)包含带符号的16位整数数据(SmallInt类型),但是您以float 8字节类型的Double数组读取数据。

您可以声明

Data : array of SmallInt;

计算

numsamples := wavehdr.DataBytes div (wavehdr.NumChannels * wavehdr.BitsPerSample div 8);

将其视为

Stream.Read(wavedata[0].Data[0], numsamples * SizeOf(SmallInt))
or multichannel case:
Stream.Read(wavedata[0].Data[i], SizeOf(SmallInt));

然后将数据值解释为浮点数Data [i] / 32768.0

请注意,matlab值3.05175781250000e-05 = 1 / 32768.0是16位信号的最小量程