Author: Liran Shahar
Access each chunk within a wave file is a tricky business but sometime you need to
access the actual samples/data to get what you want...so how can that be done?
Answer:
A WAV file is binary file in the RIFF format, RIFF format enables the user to haev
multiple information in the same file which can either be used or not.
The information is stored in chunks, each chunk have its type (4 chars) and side
(dword) so it can be skipped if you are not interested in the data or to be read
from the file.
You can download the demo software that shows wave file in a signal display graph
with functions as: paning, zoom, multiple audio channels and more from
http://www.com-n-sense.com/ftproot/SignalDisplay.zip
http://www.com-n-sense.com/ftproot/SignalDisplay.zip
(the zip file contains the wavefileparser component and signaldisplay component).
The following code parses WAV files into accessable chunks:
1 {*=========================================================================
2 =====
3 Copyright (C) 2002, All rights reserved, Com-N-Sense Ltd
4 ================================================================================
5 File: WaveFileParser.pas
6 Author: Liran Shahar, Com-N-Sense Ltd
7 Updated: 24/03/2002
8 Purpose: Parsing wave file into chunks
9 ================================================================================
10 24/03/2002, Liran Shahar
11 - Initial release.
12 ==============================================================================*}
13 unit WaveFileParser;
14
15 interface
16
17 uses
18 Sysutils, Classes;
19
20 type
21 TChunkType = array[1..4] of char;
22
23 PChunk = ^TChunk;
24 TChunk = packed record
25 cType: TChunkType;
26 dwSize: cardinal;
27 pData: pointer;
28 end;
29
30 TcnsWaveFileParser = class(TPersistent)
31 private
32 FFilename: AnsiString;
33 Chunks: TList;
34 protected
35 procedure SetFilename(AFilename: AnsiString); virtual;
36 function GetChunksCount: integer; virtual;
37 function GetChunk(Index: integer): PChunk; virtual;
38 procedure ProcessFile; virtual;
39 procedure ClearChunks; virtual;
40 public
41 constructor Create; virtual;
42 destructor Destroy; override;
43 function GetChunkByType(ChunkType: TChunkType): PChunk; virtual;
44 property Filename: AnsiString read FFilename write SetFilename;
45 property ChunksCount: integer read GetChunksCount;
46 property Chunk[Index: integer]: PChunk read GetChunk;
47 end;
48
49 implementation
50
51 const
52 RIFF_SIGNATURE = 'RIFF';
53 WAVE_SIGNATURE = 'WAVE';
54
55 type
56 TRIFFHeader = packed record
57 cSignature: TChunkType;
58 dwSize: cardinal;
59 cType: TChunkType;
60 end;
61
62 constructor TcnsWaveFileParser.Create;
63 begin
64 inherited Create;
65 FFilename := '';
66 Chunks := TList.Create;
67 end;
68
69 destructor TcnsWaveFileParser.Destroy;
70 begin
71 ClearChunks;
72 inherited Destroy;
73 end;
74
75 procedure TcnsWaveFileParser.SetFilename(AFilename: AnsiString);
76 begin
77 if FFilename <> AFilename then
78 begin
79 ClearChunks;
80 FFilename := AFilename;
81 ProcessFile;
82 end; // if
83 end;
84
85 function TcnsWaveFileParser.GetChunksCount: integer;
86 begin
87 Result := Chunks.Count;
88 end;
89
90 function TcnsWaveFileParser.GetChunk(Index: integer): PChunk;
91 begin
92 Result := nil;
93 if (Index > -1) and (Index < Chunks.Count) then
94 Result := Chunks[Index];
95 end;
96
97 procedure TcnsWaveFileParser.ProcessFile;
98 var
99 WaveFile: TFileStream;
100 Header: TRIFFHeader;
101 Chunk: PChunk;
102 begin
103 try
104 WaveFile := TFileStream.Create(FFilename, fmOpenRead + fmShareDenyWrite);
105 WaveFile.read(Header, sizeof(Header));
106 if (AnsiCompareText(Header.cSignature, RIFF_SIGNATURE) = 0) and
107 (AnsiCompareText(Header.cType, WAVE_SIGNATURE) = 0) then
108 begin
109 while WaveFile.Position < WaveFile.Size do
110 begin
111 Chunk := AllocMem(sizeof(TChunk));
112 with Chunk^ do
113 begin
114 WaveFile.read(cType, sizeof(cType));
115 WaveFile.read(dwSize, sizeof(dwSize));
116 pData := AllocMem(dwSize);
117 WaveFile.read(pData^, dwSize);
118 end; // with
119 Chunks.Add(Chunk);
120 end; // while
121 end; // if
122 finally
123 FreeAndNil(WaveFile);
124 end;
125 end;
126
127 procedure TcnsWaveFileParser.ClearChunks;
128 var
129 Chunk: PChunk;
130 begin
131 while Chunks.Count > 0 do
132 begin
133 Chunk := Chunks[0];
134 Chunks.Delete(0);
135 if assigned(Chunk^.pData) then
136 FreeMem(Chunk^.pData);
137 dispose(Chunk);
138 end; // while
139 end;
140
141 function TcnsWaveFileParser.GetChunkByType(ChunkType: TChunkType): PChunk;
142 var
143 iIndex: integer;
144 begin
145 Result := nil;
146 iIndex := 0;
147 while iIndex < Chunks.Count do
148 if AnsiCompareText(PChunk(Chunks[iIndex])^.cType, ChunkType) = 0 then
149 begin
150 Result := Chunks[iIndex];
151 break;
152 end
153 else
154 iIndex := iIndex + 1;
155 end;
156
157 end.
Component Download: http://www.com-n-sense.com/ftproot/SignalDisplay.ziphttp://www.com-n-sense.com/ftproot/SignalDisplay.zip
|