GLFileWAV.pas 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. //
  2. // This unit is part of the GLScene Engine, http://glscene.org
  3. //
  4. {
  5. Support for Windows WAV format.
  6. }
  7. unit GLFileWAV;
  8. interface
  9. {$I GLScene.inc}
  10. uses
  11. Winapi.MMSystem,
  12. System.Classes,
  13. GLApplicationFileIO,
  14. GLSoundFileObjects;
  15. type
  16. {Support for Windows WAV format. }
  17. TGLWAVFile = class (TGLSoundFile)
  18. private
  19. {$IFDEF MSWINDOWS}
  20. waveFormat : TWaveFormatEx;
  21. pcmOffset : Integer;
  22. {$ENDIF}
  23. FPCMDataLength: Integer;
  24. data : array of Byte; // used to store WAVE bitstream
  25. protected
  26. public
  27. function CreateCopy(AOwner: TPersistent) : TGLDataFile; override;
  28. class function Capabilities : TGLDataFileCapabilities; override;
  29. procedure LoadFromStream(Stream: TStream); override;
  30. procedure SaveToStream(Stream: TStream); override;
  31. procedure PlayOnWaveOut; override;
  32. function WAVData : Pointer; override;
  33. function WAVDataSize : Integer; override;
  34. function PCMData : Pointer; override;
  35. function LengthInBytes : Integer; override;
  36. end;
  37. //------------------------------------------------------
  38. implementation
  39. //------------------------------------------------------
  40. {$IFDEF MSWINDOWS}
  41. type
  42. TRIFFChunkInfo = packed record
  43. ckID : FOURCC;
  44. ckSize : LongInt;
  45. end;
  46. const
  47. WAVE_Format_ADPCM = 2;
  48. {$ENDIF}
  49. // ------------------
  50. // ------------------ TGLWAVFile ------------------
  51. // ------------------
  52. function TGLWAVFile.CreateCopy(AOwner: TPersistent) : TGLDataFile;
  53. begin
  54. Result:=inherited CreateCopy(AOwner);
  55. if Assigned(Result) then begin
  56. {$IFDEF MSWINDOWS}
  57. TGLWAVFile(Result).waveFormat:=waveFormat;
  58. {$ENDIF}
  59. TGLWAVFile(Result).data := Copy(data);
  60. end;
  61. end;
  62. class function TGLWAVFile.Capabilities : TGLDataFileCapabilities;
  63. begin
  64. Result:=[dfcRead, dfcWrite];
  65. end;
  66. procedure TGLWAVFile.LoadFromStream(stream : TStream);
  67. {$IFDEF MSWINDOWS}
  68. var
  69. ck : TRIFFChunkInfo;
  70. dw, bytesToGo, startPosition, totalSize : Integer;
  71. id : Cardinal;
  72. dwDataOffset, dwDataSamples, dwDataLength : Integer;
  73. begin
  74. // this WAVE loading code is an adaptation of the 'minimalist' sample from
  75. // the Microsoft DirectX SDK.
  76. Assert(Assigned(stream));
  77. dwDataOffset:=0;
  78. dwDataLength:=0;
  79. // Check RIFF Header
  80. startPosition:=stream.Position;
  81. stream.Read(ck, SizeOf(TRIFFChunkInfo));
  82. Assert((ck.ckID=mmioStringToFourCC('RIFF',0)), 'RIFF required');
  83. totalSize:=ck.ckSize+SizeOf(TRIFFChunkInfo);
  84. stream.Read(id, SizeOf(Integer));
  85. Assert((id=mmioStringToFourCC('WAVE',0)), 'RIFF-WAVE required');
  86. // lookup for 'fmt '
  87. repeat
  88. stream.Read(ck, SizeOf(TRIFFChunkInfo));
  89. bytesToGo:=ck.ckSize;
  90. if (ck.ckID = mmioStringToFourCC('fmt ',0)) then begin
  91. if waveFormat.wFormatTag=0 then begin
  92. dw:=ck.ckSize;
  93. if dw>SizeOf(TWaveFormatEx) then
  94. dw:=SizeOf(TWaveFormatEx);
  95. stream.Read(waveFormat, dw);
  96. bytesToGo:=ck.ckSize-dw;
  97. end;
  98. // other 'fmt ' chunks are ignored (?)
  99. end else if (ck.ckID = mmioStringToFourCC('fact',0)) then begin
  100. if (dwDataSamples = 0) and (waveFormat.wFormatTag = WAVE_Format_ADPCM) then begin
  101. stream.Read(dwDataSamples, SizeOf(LongInt));
  102. Dec(bytesToGo, SizeOf(LongInt));
  103. end;
  104. // other 'fact' chunks are ignored (?)
  105. end else if (ck.ckID = mmioStringToFourCC('data',0)) then begin
  106. dwDataOffset:=stream.Position-startPosition;
  107. dwDataLength := ck.ckSize;
  108. Break;
  109. end;
  110. // all other sub-chunks are ignored, move to the next chunk
  111. stream.Seek(bytesToGo, soFromCurrent);
  112. until Stream.Position = 2048; // this should never be reached
  113. // Only PCM wave format is recognized
  114. // Assert((waveFormat.wFormatTag=Wave_Format_PCM), 'PCM required');
  115. // seek start of data
  116. pcmOffset:=dwDataOffset;
  117. FPCMDataLength:=dwDataLength;
  118. SetLength(data, totalSize);
  119. stream.Position:=startPosition;
  120. if totalSize>0 then
  121. stream.Read(data[0], totalSize);
  122. // update Sampling data
  123. with waveFormat do begin
  124. Sampling.Frequency:=nSamplesPerSec;
  125. Sampling.NbChannels:=nChannels;
  126. Sampling.BitsPerSample:=wBitsPerSample;
  127. end;
  128. {$ELSE}
  129. begin
  130. Assert(Assigned(stream));
  131. SetLength(data, stream.Size);
  132. if Length(data)>0 then
  133. stream.Read(data[0], Length(data));
  134. {$ENDIF}
  135. end;
  136. procedure TGLWAVFile.SaveToStream(stream: TStream);
  137. begin
  138. if Length(data)>0 then
  139. stream.Write(data[0], Length(data));
  140. end;
  141. procedure TGLWAVFile.PlayOnWaveOut;
  142. begin
  143. {$IFDEF MSWINDOWS}
  144. PlaySound(WAVData, 0, SND_ASYNC+SND_MEMORY);
  145. {$ENDIF}
  146. // GLSoundFileObjects.PlayOnWaveOut(PCMData, LengthInBytes, waveFormat);
  147. end;
  148. function TGLWAVFile.WAVData : Pointer;
  149. begin
  150. if Length(data)>0 then
  151. Result:=@data[0]
  152. else Result:=nil;
  153. end;
  154. function TGLWAVFile.WAVDataSize : Integer;
  155. begin
  156. Result:=Length(data);
  157. end;
  158. function TGLWAVFile.PCMData : Pointer;
  159. begin
  160. {$IFDEF MSWINDOWS}
  161. if Length(data)>0 then
  162. Result:=@data[pcmOffset]
  163. else Result:=nil;
  164. {$ELSE}
  165. Result:=nil;
  166. {$ENDIF}
  167. end;
  168. function TGLWAVFile.LengthInBytes : Integer;
  169. begin
  170. Result:=FPCMDataLength;
  171. end;
  172. initialization
  173. RegisterSoundFileFormat('wav', 'Windows WAV files', TGLWAVFile);
  174. end.