Mega Code Archive

 
Categories / Delphi / Files
 

How to parse a wave file

Title: How to parse a wave file? Question: 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 (the zip file contains the wavefileparser component and signaldisplay component). The following code parses WAV files into accessable chunks: (*============================================================================== Copyright (C) 2002, All rights reserved, Com-N-Sense Ltd ================================================================================ File: WaveFileParser.pas Author: Liran Shahar, Com-N-Sense Ltd Updated: 24/03/2022 Purpose: Parsing wave file into chunks ================================================================================ 24/03/2002, Liran Shahar - Initial release. ==============================================================================*) unit WaveFileParser; interface uses Sysutils,Classes; type TChunkType = array [1..4] of char; PChunk = ^TChunk; TChunk = packed record cType: TChunkType; dwSize: cardinal; pData: pointer; end; TcnsWaveFileParser = class(TPersistent) private FFilename: AnsiString; Chunks: TList; protected procedure SetFilename(AFilename: AnsiString); virtual; function GetChunksCount: integer; virtual; function GetChunk(Index: integer): PChunk; virtual; procedure ProcessFile; virtual; procedure ClearChunks; virtual; public constructor Create; virtual; destructor Destroy; override; function GetChunkByType(ChunkType: TChunkType): PChunk; virtual; property Filename: AnsiString read FFilename write SetFilename; property ChunksCount: integer read GetChunksCount; property Chunk[Index: integer]: PChunk read GetChunk; end; implementation const RIFF_SIGNATURE = 'RIFF'; WAVE_SIGNATURE = 'WAVE'; type TRIFFHeader = packed record cSignature: TChunkType; dwSize: cardinal; cType: TChunkType; end; constructor TcnsWaveFileParser.Create; begin inherited Create; FFilename := ''; Chunks := TList.Create; end; destructor TcnsWaveFileParser.Destroy; begin ClearChunks; inherited Destroy; end; procedure TcnsWaveFileParser.SetFilename(AFilename: AnsiString); begin if FFilename AFilename then begin ClearChunks; FFilename := AFilename; ProcessFile; end; // if end; function TcnsWaveFileParser.GetChunksCount: integer; begin Result := Chunks.Count; end; function TcnsWaveFileParser.GetChunk(Index: integer): PChunk; begin Result := nil; if (Index -1) and (Index end; procedure TcnsWaveFileParser.ProcessFile; var WaveFile: TFileStream; Header: TRIFFHeader; Chunk: PChunk; begin try WaveFile := TFileStream.Create(FFilename,fmOpenRead + fmShareDenyWrite); WaveFile.Read(Header,sizeof(Header)); if (AnsiCompareText(Header.cSignature,RIFF_SIGNATURE) = 0) and (AnsiCompareText(Header.cType,WAVE_SIGNATURE) = 0) then begin while WaveFile.Position begin Chunk := AllocMem(sizeof(TChunk)); with Chunk^ do begin WaveFile.Read(cType,sizeof(cType)); WaveFile.Read(dwSize,sizeof(dwSize)); pData := AllocMem(dwSize); WaveFile.Read(pData^,dwSize); end; // with Chunks.Add(Chunk); end; // while end; // if finally FreeAndNil(WaveFile); end; end; procedure TcnsWaveFileParser.ClearChunks; var Chunk: PChunk; begin while Chunks.Count 0 do begin Chunk := Chunks[0]; Chunks.Delete(0); if assigned(Chunk^.pData) then FreeMem(Chunk^.pData); dispose(Chunk); end; // while end; function TcnsWaveFileParser.GetChunkByType(ChunkType: TChunkType): PChunk; var iIndex: integer; begin Result := nil; iIndex := 0; while iIndex if AnsiCompareText(PChunk(Chunks[iIndex])^.cType,ChunkType) = 0 then begin Result := Chunks[iIndex]; break; end else iIndex := iIndex + 1; end; end.