initial commit
[rofl0r-KOL.git] / units / audiotoolslibrary / WAV.pas
blob1212fc5010c6671015ad2e345d547cc54ee9dbb8
1 { *************************************************************************** }
2 { }
3 { Audio Tools Library (Freeware) }
4 { Class TWAVfile - for extracting information from WAV file header }
5 { }
6 { Copyright (c) 2001,2002 by Jurgen Faul }
7 { E-mail: jfaul@gmx.de }
8 { http://jfaul.de/atl }
9 { }
10 { Version 1.2 (14 January 2002) }
11 { - Fixed bug with calculating of duration }
12 { - Some class properties added/changed }
13 { }
14 { Version 1.1 (9 October 2001) }
15 { - Fixed bug with WAV header detection }
16 { }
17 { Version 1.0 (31 July 2001) }
18 { - Info: channel mode, sample rate, bits per sample, file size, duration }
19 { }
20 { Ïîðòèðîâàíî â KOL - Ìàòâååâ äìèòðèé }
21 { }
22 { *************************************************************************** }
24 unit WAV;
26 interface
28 uses KOL;
30 const
31 { Format type names }
32 WAV_FORMAT_UNKNOWN = 'Unknown';
33 WAV_FORMAT_PCM = 'Windows PCM';
34 WAV_FORMAT_ADPCM = 'Microsoft ADPCM';
35 WAV_FORMAT_ALAW = 'A-LAW';
36 WAV_FORMAT_MULAW = 'MU-LAW';
37 WAV_FORMAT_DVI_IMA_ADPCM = 'DVI/IMA ADPCM';
38 WAV_FORMAT_MP3 = 'MPEG Layer III';
40 { Used with ChannelModeID property }
41 WAV_CM_MONO = 1; { Index for mono mode }
42 WAV_CM_STEREO = 2; { Index for stereo mode }
44 { Channel mode names }
45 WAV_MODE: array [0..2] of string = ('Unknown', 'Mono', 'Stereo');
47 type
48 PWAV = ^TWAV;
49 TWAV = object(TObj)
50 private
51 { Private declarations }
52 FValid: Boolean;
53 FFormatID: Word;
54 FChannelNumber: Byte;
55 FSampleRate: Cardinal;
56 FBytesPerSecond: Cardinal;
57 FBlockAlign: Word;
58 FBitsPerSample: Byte;
59 FSampleNumber: Integer;
60 FHeaderSize: Word;
61 FFileSize: Cardinal;
62 procedure FResetData;
63 function FGetFormat: string;
64 function FGetChannelMode: string;
65 function FGetDuration: Double;
66 procedure InitFields;
67 public
68 { Public declarations }
69 function ReadFromFile(const FileName: string): Boolean; { Load header }
70 property Valid: Boolean read FValid; { True if header valid }
71 property FormatID: Word read FFormatID; { Format type code }
72 property Format: string read FGetFormat; { Format type name }
73 property ChannelNumber: Byte read FChannelNumber; { Number of channels }
74 property ChannelMode: string read FGetChannelMode; { Channel mode name }
75 property SampleRate: Cardinal read FSampleRate; { Sample rate (hz) }
76 property BytesPerSecond: Cardinal read FBytesPerSecond; { Bytes/second }
77 property BlockAlign: Word read FBlockAlign; { Block alignment }
78 property BitsPerSample: Byte read FBitsPerSample; { Bits/sample }
79 property HeaderSize: Word read FHeaderSize; { Header size (bytes) }
80 property FileSize: Cardinal read FFileSize; { File size (bytes) }
81 property Duration: Double read FGetDuration; { Duration (seconds) }
82 end;
84 function NewWAV: PWAV;
86 implementation
88 const
89 DATA_CHUNK = 'data'; { Data chunk ID }
91 type
92 { WAV file header data }
93 WAVRecord = packed record
94 { RIFF file header }
95 RIFFHeader: array [1..4] of Char; { Must be "RIFF" }
96 FileSize: Integer; { Must be "RealFileSize - 8" }
97 WAVEHeader: array [1..4] of Char; { Must be "WAVE" }
98 { Format information }
99 FormatHeader: array [1..4] of Char; { Must be "fmt " }
100 FormatSize: Integer; { Format size }
101 FormatID: Word; { Format type code }
102 ChannelNumber: Word; { Number of channels }
103 SampleRate: Integer; { Sample rate (hz) }
104 BytesPerSecond: Integer; { Bytes/second }
105 BlockAlign: Word; { Block alignment }
106 BitsPerSample: Word; { Bits/sample }
107 DataHeader: array [1..4] of Char; { Can be "data" }
108 SampleNumber: Integer; { Number of samples (optional) }
109 end;
111 function NewWAV: PWAV;
112 begin
113 New(Result, Create);
114 Result.InitFields;
115 end;
117 { ********************* Auxiliary functions & procedures ******************** }
119 {$I-}
120 function ReadWAV(const FileName: string; var WAVData: WAVRecord): Boolean;
122 SourceFile: PStream;
123 begin
125 Result := true;
126 { Set read-access and open file }
127 SourceFile:= NewReadFileStream(FileName);
129 { Read header }
130 FillChar(WAVData, 40, 0);
131 SourceFile.Read(WAVData, 40);
132 { Read number of samples if exists }
133 if WAVData.DataHeader <> DATA_CHUNK then
134 begin
135 SourceFile.Seek(WAVData.FormatSize + 28, spBegin);
136 SourceFile.Read(WAVData.SampleNumber, 4);
137 end;
138 finally
139 SourceFile.Free;
140 end;
141 except
142 { Error }
143 Result := false;
144 end;
145 end;
146 {$I+}
147 { --------------------------------------------------------------------------- }
149 function HeaderIsValid(const WAVData: WAVRecord): Boolean;
150 begin
151 Result := true;
152 { Header validation }
153 if WAVData.RIFFHeader <> 'RIFF' then Result := false;
154 if WAVData.WAVEHeader <> 'WAVE' then Result := false;
155 if WAVData.FormatHeader <> 'fmt ' then Result := false;
156 if (WAVData.ChannelNumber <> WAV_CM_MONO) and
157 (WAVData.ChannelNumber <> WAV_CM_STEREO) then Result := false;
158 end;
160 { ********************** Private functions & procedures ********************* }
162 procedure TWAV.FResetData;
163 begin
164 { Reset all data }
165 FValid := false;
166 FFormatID := 0;
167 FChannelNumber := 0;
168 FSampleRate := 0;
169 FBytesPerSecond := 0;
170 FBlockAlign := 0;
171 FBitsPerSample := 0;
172 FSampleNumber := 0;
173 FHeaderSize := 0;
174 FFileSize := 0;
175 end;
177 { --------------------------------------------------------------------------- }
179 function TWAV.FGetFormat: string;
180 begin
181 { Get format type name }
182 case FFormatID of
183 1: Result := WAV_FORMAT_PCM;
184 2: Result := WAV_FORMAT_ADPCM;
185 6: Result := WAV_FORMAT_ALAW;
186 7: Result := WAV_FORMAT_MULAW;
187 17: Result := WAV_FORMAT_DVI_IMA_ADPCM;
188 85: Result := WAV_FORMAT_MP3;
189 else
190 Result := '';
191 end;
192 end;
194 { --------------------------------------------------------------------------- }
196 function TWAV.FGetChannelMode: string;
197 begin
198 { Get channel mode name }
199 Result := WAV_MODE[FChannelNumber];
200 end;
202 { --------------------------------------------------------------------------- }
204 function TWAV.FGetDuration: Double;
205 begin
206 { Get duration }
207 Result := 0;
208 if FValid then
209 begin
210 if (FSampleNumber = 0) and (FBytesPerSecond > 0) then
211 Result := (FFileSize - FHeaderSize) / FBytesPerSecond;
212 if (FSampleNumber > 0) and (FSampleRate > 0) then
213 Result := FSampleNumber / FSampleRate;
214 end;
215 end;
217 { ********************** Public functions & procedures ********************** }
219 procedure TWAV.InitFields;
220 begin
221 FResetData;
222 end;
224 { --------------------------------------------------------------------------- }
226 function TWAV.ReadFromFile(const FileName: string): Boolean;
228 WAVData: WAVRecord;
229 begin
230 { Reset and load header data from file to variable }
232 FResetData;
233 FillChar(WAVData, SizeOf(WAVData), 0);
234 Result := ReadWAV(FileName, WAVData);
235 { Process data if loaded and header valid }
236 if (Result) and (HeaderIsValid(WAVData)) then
237 begin
238 FValid := true;
239 { Fill properties with header data }
240 FFormatID := WAVData.FormatID;
241 FChannelNumber := WAVData.ChannelNumber;
242 FSampleRate := WAVData.SampleRate;
243 FBytesPerSecond := WAVData.BytesPerSecond;
244 FBlockAlign := WAVData.BlockAlign;
245 FBitsPerSample := WAVData.BitsPerSample;
246 FSampleNumber := WAVData.SampleNumber;
247 if WAVData.DataHeader = DATA_CHUNK then FHeaderSize := 44
248 else FHeaderSize := WAVData.FormatSize + 40;
249 FFileSize := WAVData.FileSize + 8;
250 if FHeaderSize > FFileSize then FHeaderSize := FFileSize;
251 end;
252 except
253 Result := False;
254 end;
255 end;
257 end.