2
// This unit is part of the GLScene Engine https://github.com/glscene
5
Support for Windows WAV format.
8
17/11/09 - DaStr - Improved Unix compatibility
9
(thanks Predator) (BugtrackerID = 2893580)
10
25/07/09 - DaStr - Added $I GLScene.inc
11
26/05/09 - DanB - Fix for LengthInBytes when chunks occur after data chunk
12
06/05/09 - DanB - Creation from split from GLSoundFileObjects.pas
22
Classes, GLApplicationFileIO, GLSoundFileObjects{$IFDEF MSWINDOWS} ,MMSystem{$ENDIF};
28
{ Support for Windows WAV format. }
29
TGLWAVFile = class (TGLSoundFile)
33
waveFormat : TWaveFormatEx;
36
FPCMDataLength: Integer;
37
data : array of Byte; // used to store WAVE bitstream
44
function CreateCopy(AOwner: TPersistent) : TGLDataFile; override;
46
class function Capabilities : TGLDataFileCapabilities; override;
48
procedure LoadFromStream(Stream: TStream); override;
49
procedure SaveToStream(Stream: TStream); override;
51
procedure PlayOnWaveOut; override;
53
function WAVData : Pointer; override;
54
function WAVDataSize : Integer; override;
55
function PCMData : Pointer; override;
56
function LengthInBytes : Integer; override;
63
TRIFFChunkInfo = packed record
69
WAVE_Format_ADPCM = 2;
72
// ------------------ TGLWAVFile ------------------
77
function TGLWAVFile.CreateCopy(AOwner: TPersistent) : TGLDataFile;
79
Result:=inherited CreateCopy(AOwner);
80
if Assigned(Result) then begin
82
TGLWAVFile(Result).waveFormat:=waveFormat;
84
TGLWAVFile(Result).data := Copy(data);
90
class function TGLWAVFile.Capabilities : TGLDataFileCapabilities;
92
Result:=[dfcRead, dfcWrite];
97
procedure TGLWAVFile.LoadFromStream(stream : TStream);
101
dw, bytesToGo, startPosition, totalSize : Integer;
103
dwDataOffset, dwDataSamples, dwDataLength : Integer;
105
// this WAVE loading code is an adaptation of the 'minimalist' sample from
106
// the Microsoft DirectX SDK.
107
Assert(Assigned(stream));
112
startPosition:=stream.Position;
113
stream.Read(ck, SizeOf(TRIFFChunkInfo));
114
Assert((ck.ckID=mmioStringToFourCC('RIFF',0)), 'RIFF required');
115
totalSize:=ck.ckSize+SizeOf(TRIFFChunkInfo);
116
stream.Read(id, SizeOf(Integer));
117
Assert((id=mmioStringToFourCC('WAVE',0)), 'RIFF-WAVE required');
120
stream.Read(ck, SizeOf(TRIFFChunkInfo));
121
bytesToGo:=ck.ckSize;
122
if (ck.ckID = mmioStringToFourCC('fmt ',0)) then begin
123
if waveFormat.wFormatTag=0 then begin
125
if dw>SizeOf(TWaveFormatEx) then
126
dw:=SizeOf(TWaveFormatEx);
127
stream.Read(waveFormat, dw);
128
bytesToGo:=ck.ckSize-dw;
130
// other 'fmt ' chunks are ignored (?)
131
end else if (ck.ckID = mmioStringToFourCC('fact',0)) then begin
132
if (dwDataSamples = 0) and (waveFormat.wFormatTag = WAVE_Format_ADPCM) then begin
133
stream.Read(dwDataSamples, SizeOf(LongInt));
134
Dec(bytesToGo, SizeOf(LongInt));
136
// other 'fact' chunks are ignored (?)
137
end else if (ck.ckID = mmioStringToFourCC('data',0)) then begin
138
dwDataOffset:=stream.Position-startPosition;
139
dwDataLength := ck.ckSize;
142
// all other sub-chunks are ignored, move to the next chunk
143
stream.Seek(bytesToGo, soFromCurrent);
144
until Stream.Position = 2048; // this should never be reached
145
// Only PCM wave format is recognized
146
// Assert((waveFormat.wFormatTag=Wave_Format_PCM), 'PCM required');
147
// seek start of data
148
pcmOffset:=dwDataOffset;
149
FPCMDataLength:=dwDataLength;
150
SetLength(data, totalSize);
151
stream.Position:=startPosition;
153
stream.Read(data[0], totalSize);
154
// update Sampling data
155
with waveFormat do begin
156
Sampling.Frequency:=nSamplesPerSec;
157
Sampling.NbChannels:=nChannels;
158
Sampling.BitsPerSample:=wBitsPerSample;
162
Assert(Assigned(stream));
163
SetLength(data, stream.Size);
164
if Length(data)>0 then
165
stream.Read(data[0], Length(data));
171
procedure TGLWAVFile.SaveToStream(stream: TStream);
173
if Length(data)>0 then
174
stream.Write(data[0], Length(data));
179
procedure TGLWAVFile.PlayOnWaveOut;
182
PlaySound(WAVData, 0, SND_ASYNC+SND_MEMORY);
184
// GLSoundFileObjects.PlayOnWaveOut(PCMData, LengthInBytes, waveFormat);
189
function TGLWAVFile.WAVData : Pointer;
191
if Length(data)>0 then
198
function TGLWAVFile.WAVDataSize : Integer;
200
Result:=Length(data);
205
function TGLWAVFile.PCMData : Pointer;
208
if Length(data)>0 then
209
Result:=@data[pcmOffset]
218
function TGLWAVFile.LengthInBytes : Integer;
220
Result:=FPCMDataLength;
225
RegisterSoundFileFormat('wav', 'Windows WAV files', TGLWAVFile);