initial commit
[rofl0r-KOL.git] / units / mp3 / KolHeader.pas
blobfd5f0706f2867054933c9697bbdf4b50f130fff8
1 (*
2 * File: $RCSfile: Header.pas,v $
3 * Revision: $Revision: 1.1.1.1 $
4 * Version : $Id: Header.pas,v 1.1.1.1 2002/04/21 12:57:16 fobmagog Exp $
5 * Author: $Author: fobmagog $
6 * Homepage: http://delphimpeg.sourceforge.net/
7 * Kol translation by Thaddy de Koning
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 {$DEFINE SEEK_STOP}
25 unit KolHeader;
27 interface
29 uses
30 Windows, Kol, KolCRC, KolBitStream, KolBitReserve;
32 type
33 TVersion = (MPEG2_LSF, MPEG1);
34 TMode = (Stereo, JointStereo, DualChannel, SingleChannel);
35 TSampleFrequency = (FourtyFourPointOne, FourtyEight, ThirtyTwo, Unknown);
37 const
38 FREQUENCIES: array[TVersion, TSampleFrequency] of cardinal = ((22050, 24000, 16000, 1),
39 (44100, 48000, 32000, 1));
41 type
42 // Class for extraction information from a frame header:
43 PHeader = ^THeader;
44 THeader = object(Tobj)
45 private
46 FLayer: cardinal;
47 FProtectionBit: cardinal;
48 FBitrateIndex: cardinal;
49 FPaddingBit: cardinal;
50 FModeExtension: cardinal;
51 FVersion: TVersion;
52 FMode: TMode;
53 FSampleFrequency: TSampleFrequency;
54 FNumberOfSubbands: cardinal;
55 FIntensityStereoBound: cardinal;
56 FCopyright: boolean;
57 FOriginal: boolean;
58 FInitialSync: boolean;
59 FCRC: PCRC16;
60 FOffset: PCardinalArray;
61 FChecksum: cardinal;
62 FFrameSize: cardinal;
63 FNumSlots: cardinal;
65 function GetFrequency: cardinal;
66 function GetChecksums: boolean;
67 function GetChecksumOK: boolean;
68 function GetPadding: boolean;
70 public
71 property Version: TVersion read FVersion;
72 property Layer: cardinal read FLayer;
73 property BitrateIndex: cardinal read FBitrateIndex;
74 property SampleFrequency: TSampleFrequency read FSampleFrequency;
75 property Frequency: cardinal read GetFrequency;
76 property Mode: TMode read FMode;
77 property Checksums: boolean read GetChecksums;
78 property Copyright: boolean read FCopyright;
79 property Original: boolean read FOriginal;
80 property ChecksumOK: boolean read GetChecksumOK;
81 // compares computed checksum with stream checksum
82 property Padding: boolean read GetPadding;
83 property Slots: cardinal read FNumSlots;
84 property ModeExtension: cardinal read FModeExtension;
85 property NumberOfSubbands: cardinal read FNumberOfSubbands;
86 // returns the number of subbands in the current frame
87 property IntensityStereoBound: cardinal read FIntensityStereoBound;
88 // (Layer II joint stereo only)
89 // returns the number of subbands which are in stereo mode,
90 // subbands above that limit are in intensity stereo mode
92 //constructor Create;
93 destructor Destroy; virtual;
95 function ReadHeader(Stream: PBitStream; var CRC: PCRC16): boolean;
96 // read a 32-bit header from the bitstream
98 function Bitrate: cardinal;
100 function CalculateFrameSize: cardinal;
102 // Scrolling stuff
103 function StreamSeek(Stream: PBitStream; SeekPos: cardinal): boolean;
104 function MaxNumberOfFrames(Stream: PBitStream): integer;
105 function MinNumberOfFrames(Stream: PBitStream): integer;
107 function MSPerFrame: single; // milliseconds per frame, for time display
108 function TotalMS(Stream: PBitStream): single;
109 end;
111 function Newheader: PHeader;
113 implementation
115 { THeader }
117 const
118 BITRATES: array[TVersion, 0..2, 0..15] of
119 cardinal = (((0 {free format}, 32000, 48000, 56000, 64000, 80000, 96000,
120 112000, 128000, 144000, 160000, 176000, 192000, 224000, 256000, 0),
121 (0 {free format}, 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000,
122 80000, 96000, 112000, 128000, 144000, 160000, 0),
123 (0 {free format}, 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000,
124 80000, 96000, 112000, 128000, 144000, 160000, 0)),
125 ((0 {free format}, 32000, 64000, 96000, 128000, 160000, 192000, 224000,
126 256000, 288000, 320000, 352000, 384000, 416000, 448000, 0),
127 (0 {free format}, 32000, 48000, 56000, 64000, 80000, 96000, 112000,
128 128000, 160000, 192000, 224000, 256000, 320000, 384000, 0),
129 (0 {free format}, 32000, 40000, 48000, 56000, 64000, 80000, 96000,
130 112000, 128000, 160000, 192000, 224000, 256000, 320000, 0))
133 function THeader.Bitrate: cardinal;
134 begin
135 Result := BITRATES[FVersion, FLayer - 1, FBitrateIndex];
136 end;
138 // calculates framesize in bytes excluding header size
139 function THeader.CalculateFrameSize: cardinal;
140 var
141 Val1, Val2: cardinal;
142 begin
143 if (FLayer = 1) then
144 begin
145 FFramesize := (12 * BITRATES[FVersion, 0, FBitrateIndex]) div FREQUENCIES[FVersion,
146 FSampleFrequency];
148 if (FPaddingBit <> 0) then
149 inc(FFrameSize);
151 FFrameSize := FFrameSize shl 2; // one slot is 4 bytes long
153 FNumSlots := 0;
154 end
155 else
156 begin
157 FFrameSize := (144 * BITRATES[FVersion, FLayer - 1, FBitrateIndex]) div
158 FREQUENCIES[FVersion, FSampleFrequency];
160 if (FVersion = MPEG2_LSF) then
161 FFrameSize := FFrameSize shr 1;
163 if (FPaddingBit <> 0) then
164 inc(FFrameSize);
166 // Layer III slots
167 if (FLayer = 3) then
168 begin
169 if (FVersion = MPEG1) then
170 begin
171 if (FMode = SingleChannel) then
172 Val1 := 17
173 else
174 Val1 := 32;
176 if (FProtectionBit <> 0) then
177 Val2 := 0
178 else
179 Val2 := 2;
181 FNumSlots := FFramesize - Val1 - Val2 - 4;
182 // header size
183 end
184 else
185 begin // MPEG-2 LSF
186 if (FMode = SingleChannel) then
187 Val1 := 9
188 else
189 Val1 := 17;
191 if (FProtectionBit <> 0) then
192 Val2 := 0
193 else
194 Val2 := 2;
196 FNumSlots := FFramesize - Val1 - Val2 - 4;
197 // header size
198 end;
199 end
200 else
201 FNumSlots := 0;
202 end;
204 dec(FFrameSize, 4); // subtract header size
206 Result := FFrameSize;
207 end;
209 function newHeader: pHeader;
210 begin
211 New(Result, Create);
212 with Result^ do
213 begin
214 FFrameSize := 0;
215 FNumSlots := 0;
216 FCRC := nil;
217 FOffset := nil;
218 FInitialSync := False;
219 end;
220 end;
222 destructor THeader.Destroy;
223 begin
224 if (FOffset <> nil) then
225 FreeMem(FOffset);
227 inherited;
228 end;
230 function THeader.GetChecksumOK: boolean;
231 begin
232 Result := (FChecksum = FCRC.Checksum);
233 end;
235 function THeader.GetChecksums: boolean;
236 begin
237 Result := (FProtectionBit = 0);
238 end;
240 function THeader.GetFrequency: cardinal;
241 begin
242 Result := FREQUENCIES[FVersion, FSampleFrequency];
243 end;
245 function THeader.GetPadding: boolean;
246 begin
247 Result := (FPaddingBit <> 0);
248 end;
250 // Returns the maximum number of frames in the stream
251 function THeader.MaxNumberOfFrames(Stream: PBitStream): integer;
252 begin
253 Result := Stream.FileSize div (FFrameSize + 4 - FPaddingBit);
254 end;
256 // Returns the minimum number of frames in the stream
257 function THeader.MinNumberOfFrames(Stream: PBitStream): integer;
258 begin
259 Result := Stream.FileSize div (FFrameSize + 5 - FPaddingBit);
260 end;
262 const
263 MSPerFrameArray: array[0..2, TSampleFrequency] of single = ((8.707483, 8.0, 12.0, 0),
264 (26.12245, 24.0, 36.0, 0),
265 (26.12245, 24.0, 36.0, 0));
267 function THeader.MSPerFrame: single;
268 begin
269 Result := MSperFrameArray[FLayer - 1, FSampleFrequency];
270 end;
272 function THeader.ReadHeader(Stream: PBitStream; var CRC: PCRC16): boolean;
273 var
274 HeaderString, ChannelBitrate: cardinal;
275 max, cf, lf, i: integer;
276 begin
277 Result := False;
278 if (not FInitialSync) then
279 begin
280 if (not Stream.GetHeader(@HeaderString, INITIAL_SYNC)) then
281 exit;
283 FVersion := TVersion((HeaderString shr 19) and 1);
284 FSampleFrequency := TSampleFrequency((HeaderString shr 10) and 3);
285 if (FSampleFrequency = Unknown) then
286 begin
287 // report error - not supported header
288 exit;
289 end;
291 Stream.SetSyncWord(HeaderString and $FFF80CC0);
293 FInitialSync := True;
294 end
295 else
296 begin
297 if (not Stream.GetHeader(@HeaderString, STRICT_SYNC)) then
298 begin
299 exit;
300 end;
301 end;
303 FLayer := 4 - (HeaderString shr 17) and 3;
304 FProtectionBit := (HeaderString shr 16) and 1;
305 FBitrateIndex := (HeaderString shr 12) and $F;
306 FPaddingBit := (HeaderString shr 9) and 1;
307 FMode := TMode((HeaderString shr 6) and 3);
308 FModeExtension := (HeaderString shr 4) and 3;
310 if (FMode = JointStereo) then
311 FIntensityStereoBound := (FModeExtension shl 2) + 4
312 else
313 FIntensityStereoBound := 0; // should never be used
315 FCopyright := ((HeaderString shr 3) and 1 <> 0);
316 FOriginal := ((HeaderString shr 2) and 1 <> 0);
318 // calculate number of subbands:
319 if (FLayer = 1) then
320 FNumberOfSubbands := 32
321 else
322 begin
323 ChannelBitrate := FBitrateIndex;
325 // calculate bitrate per channel:
326 if (FMode <> SingleChannel) then
327 if (ChannelBitrate = 4) then
328 ChannelBitrate := 1
329 else
330 dec(ChannelBitrate, 4);
332 if ((ChannelBitrate = 1) or (ChannelBitrate = 2)) then
333 begin
334 if (FSampleFrequency = ThirtyTwo) then
335 FNumberOfSubbands := 12
336 else
337 FNumberOfSubbands := 8;
338 end
339 else
340 begin
341 if ((FSampleFrequency = FourtyEight) or ((ChannelBitrate >= 3) and
342 (ChannelBitrate <= 5))) then
343 FNumberOfSubbands := 27
344 else
345 FNumberOfSubbands := 30;
346 end;
347 end;
349 if (FIntensityStereoBound > FNumberOfSubbands) then
350 FIntensityStereoBound := FNumberOfSubbands;
352 // calculate framesize and nSlots
353 CalculateFrameSize;
355 // read framedata:
356 if (not Stream.ReadFrame(FFrameSize)) then
357 begin
358 exit;
359 end;
361 if (FProtectionBit = 0) then
362 begin
363 // frame contains a crc checksum
364 FChecksum := Stream.GetBits(16);
365 if (FCRC = nil) then
366 FCRC := NewCRC16;
368 FCRC.AddBits(HeaderString, 16);
369 CRC := FCRC;
370 end
371 else
372 CRC := nil;
374 {$IFDEF SEEK_STOP}
375 if (FSampleFrequency = FourtyFourPointOne) then
376 begin
377 if (FOffset = nil) then
378 begin
379 max := MaxNumberOfFrames(Stream);
380 FOffset := AllocMem(Max * sizeof(cardinal));
382 for i := 0 to max - 1 do
383 FOffset[i] := 0;
384 end;
386 cf := Stream.CurrentFrame;
387 lf := Stream.LastFrame;
388 if ((cf > 0) and (cf = lf)) then
389 FOffset[cf] := FOffset[cf - 1] + FPaddingBit
390 else
391 FOffset[0] := FPaddingBit;
392 end;
393 {$ENDIF}
395 Result := True;
396 end;
398 // Stream searching routines
399 function THeader.StreamSeek(Stream: PBitStream;
400 SeekPos: cardinal): boolean;
401 begin
402 if (FSampleFrequency = FourtyFourPointOne) then
403 Result := Stream.SeekPad(SeekPos, FFrameSize - FPaddingBit, PObj(@Self), FOffset)
404 else
405 Result := Stream.Seek(SeekPos, FFrameSize);
406 end;
408 function THeader.TotalMS(Stream: PBitStream): single;
409 begin
410 Result := MaxNumberOfFrames(Stream) * MSPerFrame;
411 end;
413 end.