summaryrefslogtreecommitdiff
path: root/plugins/Watrack/formats/fmt_wav.pas
blob: 98d8e18fb8a0568a643d20b2ca52cc8311a4c971 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
{WAV processing}
unit fmt_WAV;
{$include compilers.inc}

interface
uses wat_api;

function ReadWAV(var Info:tSongInfo):boolean; cdecl;

implementation
uses windows,common,io,tags,srv_format;

const
  wavRIFF = $46464952;
  wavWAVE = $45564157;
  wavfmt_ = $20746D66;
  wavfact = $74636166;
  wavdata = $61746164;
type
  tWAVChunk = packed record
    id  :dword;
    size:dword;
  end;
type
  tWAVFormatChunk = packed record
    Codec        :word;
    Channels     :word;
    SampleRate   :dword;
    AvgBPS       :dword;
    BlockAlign   :word;
    BitsPerSample:word;
  end;

const
  WavPackID = $6B707677;
type
//    ckID         :dword; // "wvpk"
//    ckSize       :dword; // size of entire frame (minus 8, of course)
  tWavPackHeader = packed record
    version      :word;  // 0x403 for now
    track_no     :byte;  // track number (0 if not used, like now)
    index_no     :byte;  // track sub-index (0 if not used, like now)
    total_samples:dword; // for entire file (-1 if unknown)
    block_index  :dword; // index of first sample in block (to file begin)
    block_samples:dword; // # samples in This block
    flags        :dword; // various flags for id and decoding
    crc          :dword; // crc for actual decoded data
  end;

function ReadWAV(var Info:tSongInfo):boolean; cdecl;
var
  f:THANDLE;
  chunk:tWAVChunk;
  fmtchunk:tWAVFormatChunk;
  tmp:dword;
  WPH:tWavPackHeader;
  fsize:dword;
begin
  result:=false;
  f:=Reset(Info.mfile);
  if f=THANDLE(INVALID_HANDLE_VALUE) then
    exit;
  BlockRead(f,chunk,SizeOf(chunk));
  if chunk.id=WavPackID then
  begin
    BlockRead(f,WPH,SizeOf(tWavPackHeader));
    BlockRead(f,tmp,2); //!! $1621 33,22
    BlockRead(f,chunk,SizeOf(chunk));
  end
  else
  begin
    WPH.version:=0;
    integer(WPH.total_samples):=-1;
  end;
  if chunk.id<>wavRIFF then
    exit;
  BlockRead(f,chunk,SizeOf(dword));
  if chunk.id<>wavWAVE then
    exit;
  BlockRead(f,chunk,SizeOf(chunk));
  if chunk.id<>wavfmt_ then
    exit;
  BlockRead(f,fmtchunk,SizeOf(tWAVFormatChunk));
  Info.channels:=fmtchunk.Channels;
  Info.khz     :=fmtchunk.SampleRate div 1000;
  if chunk.size>SizeOf(tWAVFormatChunk) then
    Skip(f,chunk.size-SizeOf(tWAVFormatChunk));
  fsize:=FileSize(f);
  while FilePos(f)<fsize do
  begin
    BlockRead(f,chunk,SizeOf(chunk));
    if chunk.id=wavfact then
    begin
      BlockRead(f,tmp,4);
      break;
    end;
    if chunk.id=wavdata then
    begin
      tmp:=chunk.size;
      break;
    end;
    Skip(f,chunk.size);
  end;
  if WPH.version<>0 then
  begin
    ReadAPEv2(f,Info);
    ReadID3v1(f,Info);
  end;
  if integer(WPH.total_samples)=-1 then
    if (fmtchunk.BitsPerSample<>0) and (fmtchunk.Channels<>0) then
      WPH.total_samples:=(tmp*8) div (fmtchunk.Channels*fmtchunk.BitsPerSample);
  if fmtchunk.SampleRate<>0 then
    Info.total:= WPH.total_samples div fmtchunk.SampleRate;
  if Info.total<>0 then
    Info.kbps:=tmp*8 div Info.total div 1000;

  CloseHandle(f);
  result:=true;
end;

var
  LocalFormatLinkWAV,
  LocalFormatLinkWV:twFormat;

procedure InitLink;
begin
  LocalFormatLinkWAV.Next:=FormatLink;

  LocalFormatLinkWAV.This.proc :=@ReadWAV;
  LocalFormatLinkWAV.This.ext  :='WAV';
  LocalFormatLinkWAV.This.flags:=0;

  FormatLink:=@LocalFormatLinkWAV;

  LocalFormatLinkWV.Next:=FormatLink;

  LocalFormatLinkWV.This.proc :=@ReadWAV;
  LocalFormatLinkWV.This.ext  :='WV';
  LocalFormatLinkWV.This.flags:=0;

  FormatLink:=@LocalFormatLinkWV;
end;

initialization
  InitLink;
end.