fpwavreader.pas 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. {*****************************************************************************}
  2. {
  3. This file is part of the Free Pascal's "Free Components Library".
  4. Copyright (c) 2014 by Mazen NEIFER of the Free Pascal development team
  5. and was adapted from wavopenal.pas copyright (c) 2010 Dmitry Boyarintsev.
  6. RIFF/WAVE sound file reader implementation.
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. }
  13. {$IFNDEF FPC_DOTTEDUNITS}
  14. unit fpwavreader;
  15. {$ENDIF FPC_DOTTEDUNITS}
  16. {$mode objfpc}{$H+}
  17. interface
  18. {$IFDEF FPC_DOTTEDUNITS}
  19. uses
  20. System.Sound.Wav.Format,
  21. System.Classes;
  22. {$ELSE FPC_DOTTEDUNITS}
  23. uses
  24. fpWavFormat,
  25. Classes;
  26. {$ENDIF FPC_DOTTEDUNITS}
  27. type
  28. { TWaveReader }
  29. TWavReader = class(TObject)
  30. private
  31. DataChunk: TChunkHeader;
  32. ChunkPos: Int64;
  33. EoF: Boolean;
  34. fStream: TStream;
  35. FFileName: string;
  36. public
  37. fmt : TWaveFormat;
  38. destructor Destroy; override;
  39. function LoadFromFile(const FileName: string): Boolean;
  40. function LoadFromStream(AStream: TStream): Boolean;
  41. function ReadBuf(var Buffer; BufferSize: Integer): Integer;
  42. end;
  43. implementation
  44. {$IFDEF FPC_DOTTEDUNITS}
  45. uses
  46. System.SysUtils;
  47. {$ELSE FPC_DOTTEDUNITS}
  48. uses
  49. SysUtils;
  50. {$ENDIF FPC_DOTTEDUNITS}
  51. procedure LEtoN(var fmt: TWaveFormat); overload;
  52. begin
  53. with fmt, ChunkHeader do begin
  54. Size := LEtoN(Size);
  55. Format := LEtoN(Format);
  56. Channels := LEtoN(Channels);
  57. SampleRate := LEtoN(SampleRate);
  58. ByteRate := LEtoN(ByteRate);
  59. BlockAlign := LEtoN(BlockAlign);
  60. BitsPerSample := LEtoN(BitsPerSample);
  61. end;
  62. end;
  63. { TWaveReader }
  64. destructor TWavReader.Destroy;
  65. begin
  66. if (FFileName <> '') and Assigned(fStream) then begin
  67. fStream.Free;
  68. end;
  69. inherited Destroy;
  70. end;
  71. function TWavReader.LoadFromFile(const FileName: string):Boolean;
  72. begin
  73. if (FFileName <> '') and Assigned(fStream) then begin
  74. fStream.Free;
  75. end;
  76. fStream := TFileStream.Create(FileName, fmOpenRead + fmShareDenyWrite);
  77. if Assigned(fStream) then begin
  78. Result := LoadFromStream(fStream);
  79. FFileName := FileName;
  80. end else begin
  81. Result := False;
  82. end;
  83. end;
  84. function TWavReader.LoadFromStream(AStream:TStream):Boolean;
  85. var
  86. riff: TRiffHeader;
  87. begin
  88. fStream := AStream;
  89. FFileName := '';
  90. Result := fStream.Read(riff, sizeof(riff)) = sizeof(riff);
  91. riff.ChunkHeader.Size := LEtoN(riff.ChunkHeader.Size);
  92. Result := Result and (riff.ChunkHeader.ID = AUDIO_CHUNK_ID_RIFF) and (riff.Format = AUDIO_CHUNK_ID_WAVE);
  93. Result := Result and (fStream.Read(fmt, sizeof(fmt)) = sizeof(fmt));
  94. LEtoN(fmt);
  95. Result := Result and (fmt.ChunkHeader.ID = AUDIO_CHUNK_ID_fmt) and ((fmt.ChunkHeader.Size + 8) >= sizeof(fmt));
  96. if Result and ((fmt.ChunkHeader.Size + 8) > sizeof(fmt)) then
  97. fStream.Seek(Align((fmt.ChunkHeader.Size + 8) - sizeof(fmt), 2), soCurrent);
  98. end;
  99. function Min(a, b: Integer): Integer;
  100. begin
  101. if a < b then begin
  102. Result := a;
  103. end else begin
  104. Result := b;
  105. end;
  106. end;
  107. function TWavReader.ReadBuf(var Buffer; BufferSize: Integer): Integer;
  108. var
  109. sz: Integer;
  110. p: TByteArray absolute Buffer;
  111. i: Integer;
  112. begin
  113. i := 0;
  114. while (not EoF) and (i < bufferSize) do begin
  115. if ChunkPos >= DataChunk.Size then begin
  116. sz := fstream.Read(DataChunk, sizeof(DataChunk));
  117. EoF := sz < sizeof(DataChunk);
  118. if not EoF then begin
  119. DataChunk.Size := LEtoN(DataChunk.Size);
  120. if DataChunk.Id <> AUDIO_CHUNK_ID_data then begin
  121. ChunkPos := DataChunk.Size;
  122. fstream.Seek(DataChunk.Size, soCurrent);
  123. end
  124. else
  125. ChunkPos := 0;
  126. end;
  127. end else begin
  128. sz := Min(BufferSize, DataChunk.Size - ChunkPos);
  129. sz := fStream.Read(p[i], sz);
  130. EoF := sz <= 0;
  131. Inc(ChunkPos, sz);
  132. Inc(i, sz);
  133. end;
  134. end;
  135. Result := i;
  136. end;
  137. end.