fpwavreader.pas 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  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. unit fpwavreader;
  14. {$mode objfpc}{$H+}
  15. interface
  16. uses
  17. fpWavFormat,
  18. Classes;
  19. type
  20. { TWaveReader }
  21. TWavReader = class(TObject)
  22. private
  23. DataChunk: TChunkHeader;
  24. ChunkPos: Int64;
  25. EoF: Boolean;
  26. fStream: TStream;
  27. FFileName: string;
  28. public
  29. fmt : TWaveFormat;
  30. destructor Destroy; override;
  31. function LoadFromFile(const FileName: string): Boolean;
  32. function LoadFromStream(AStream: TStream): Boolean;
  33. function ReadBuf(var Buffer; BufferSize: Integer): Integer;
  34. end;
  35. implementation
  36. uses
  37. SysUtils;
  38. procedure LEtoN(var fmt: TWaveFormat); overload;
  39. begin
  40. with fmt, ChunkHeader do begin
  41. Size := LEtoN(Size);
  42. Format := LEtoN(Format);
  43. Channels := LEtoN(Channels);
  44. SampleRate := LEtoN(SampleRate);
  45. ByteRate := LEtoN(ByteRate);
  46. BlockAlign := LEtoN(BlockAlign);
  47. BitsPerSample := LEtoN(BitsPerSample);
  48. end;
  49. end;
  50. { TWaveReader }
  51. destructor TWavReader.Destroy;
  52. begin
  53. if (FFileName <> '') and Assigned(fStream) then begin
  54. fStream.Free;
  55. end;
  56. inherited Destroy;
  57. end;
  58. function TWavReader.LoadFromFile(const FileName: string):Boolean;
  59. begin
  60. if (FFileName <> '') and Assigned(fStream) then begin
  61. fStream.Free;
  62. end;
  63. fStream := TFileStream.Create(FileName, fmOpenRead + fmShareDenyWrite);
  64. if Assigned(fStream) then begin
  65. Result := LoadFromStream(fStream);
  66. FFileName := FileName;
  67. end else begin
  68. Result := False;
  69. end;
  70. end;
  71. function TWavReader.LoadFromStream(AStream:TStream):Boolean;
  72. var
  73. riff: TRiffHeader;
  74. begin
  75. fStream := AStream;
  76. FFileName := '';
  77. Result := fStream.Read(riff, sizeof(riff)) = sizeof(riff);
  78. riff.ChunkHeader.Size := LEtoN(riff.ChunkHeader.Size);
  79. Result := Result and (riff.ChunkHeader.ID = AUDIO_CHUNK_ID_RIFF) and (riff.Format = AUDIO_CHUNK_ID_WAVE);
  80. Result := Result and (fStream.Read(fmt, sizeof(fmt)) = sizeof(fmt));
  81. LEtoN(fmt);
  82. Result := Result and (fmt.ChunkHeader.ID = AUDIO_CHUNK_ID_fmt);
  83. if Result and (fmt.Format <> 1) then
  84. Exit(False);
  85. end;
  86. function Min(a, b: Integer): Integer;
  87. begin
  88. if a < b then begin
  89. Result := a;
  90. end else begin
  91. Result := b;
  92. end;
  93. end;
  94. function TWavReader.ReadBuf(var Buffer; BufferSize: Integer): Integer;
  95. var
  96. sz: Integer;
  97. p: TByteArray absolute Buffer;
  98. i: Integer;
  99. begin
  100. i := 0;
  101. while (not EoF) and (i < bufferSize) do begin
  102. if ChunkPos >= DataChunk.Size then begin
  103. sz := fstream.Read(DataChunk, sizeof(DataChunk));
  104. EoF := sz < sizeof(DataChunk);
  105. if not EoF then begin
  106. DataChunk.Size := LEtoN(DataChunk.Size);
  107. if DataChunk.Id <> AUDIO_CHUNK_ID_data then
  108. ChunkPos := DataChunk.Size
  109. else
  110. ChunkPos := 0;
  111. end;
  112. end else begin
  113. sz := Min(BufferSize, DataChunk.Size - ChunkPos);
  114. sz := fStream.Read(p[i], sz);
  115. EoF := sz <= 0;
  116. Inc(ChunkPos, sz);
  117. Inc(i, sz);
  118. end;
  119. end;
  120. Result := i;
  121. end;
  122. end.