GLSoundFileObjects.pas 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. //
  2. // This unit is part of the GLScene Engine, http://glscene.org
  3. //
  4. unit GLSoundFileObjects;
  5. (*
  6. Support classes for loading various fileformats.
  7. These classes work together like vector file formats or Delphi's TGraphic classes.
  8. *)
  9. interface
  10. {$I GLScene.inc}
  11. uses
  12. Winapi.MMSystem,
  13. System.Classes,
  14. System.SysUtils,
  15. VCL.Consts,
  16. GLApplicationFileIO,
  17. GLCrossPlatform;
  18. type
  19. {Defines a sound sampling quality. }
  20. TGLSoundSampling = class (TPersistent)
  21. private
  22. FOwner : TPersistent;
  23. FFrequency : Integer;
  24. FNbChannels : Integer;
  25. FBitsPerSample : Integer;
  26. protected
  27. function GetOwner : TPersistent; override;
  28. public
  29. constructor Create(AOwner: TPersistent);
  30. destructor Destroy; override;
  31. procedure Assign(Source: TPersistent); override;
  32. function BytesPerSec : Integer;
  33. function BytesPerSample : Integer;
  34. function WaveFormat : TWaveFormatEx;
  35. published
  36. {Sampling frequency in Hz (= samples per sec) }
  37. property Frequency : Integer read FFrequency write FFrequency default 22050;
  38. {Nb of sampling channels.
  39. 1 = mono, 2 = stereo, etc. }
  40. property NbChannels : Integer read FNbChannels write FNbChannels default 1;
  41. {Nb of bits per sample.
  42. Common values are 8 and 16 bits. }
  43. property BitsPerSample : Integer read FBitsPerSample write FBitsPerSample default 8;
  44. end;
  45. {Abstract base class for different Sound file formats.
  46. The actual implementation for these files (WAV, RAW...) must be done
  47. seperately. The concept for TGLSoundFile is very similar to TGraphic
  48. (see Delphi Help).
  49. Default implementation for LoadFromFile/SaveToFile are to directly call the
  50. relevent stream-based methods, ie. you will just have to override the stream
  51. methods in most cases. }
  52. TGLSoundFile = class (TGLDataFile)
  53. private
  54. FSampling : TGLSoundSampling;
  55. protected
  56. procedure SetSampling(const val : TGLSoundSampling);
  57. public
  58. constructor Create(AOwner: TPersistent); override;
  59. destructor Destroy; override;
  60. procedure PlayOnWaveOut; virtual;
  61. {Returns a pointer to the sample data viewed as an in-memory WAV File. }
  62. function WAVData : Pointer; virtual; abstract;
  63. {Returns the size (in bytes) of the WAVData. }
  64. function WAVDataSize : Integer; virtual; abstract;
  65. {Returns a pointer to the sample data viewed as an in-memory PCM buffer. }
  66. function PCMData : Pointer; virtual; abstract;
  67. {Length of PCM data, in bytes. }
  68. function LengthInBytes : Integer; virtual; abstract;
  69. {Nb of intensity samples in the sample. }
  70. function LengthInSamples : Integer;
  71. {Length of play of the sample at nominal speed in seconds. }
  72. function LengthInSec : Single;
  73. property Sampling : TGLSoundSampling read FSampling write SetSampling;
  74. end;
  75. TGLSoundFileClass = class of TGLSoundFile;
  76. TGLSoundFileFormat = record
  77. SoundFileClass : TGLSoundFileClass;
  78. Extension : String;
  79. Description : String;
  80. DescResID : Integer;
  81. end;
  82. PSoundFileFormat = ^TGLSoundFileFormat;
  83. TGLSoundFileFormatsList = class(TList)
  84. public
  85. destructor Destroy; override;
  86. procedure Add(const Ext, Desc: String; DescID: Integer; AClass: TGLSoundFileClass);
  87. function FindExt(Ext: string): TGLSoundFileClass;
  88. procedure Remove(AClass: TGLSoundFileClass);
  89. procedure BuildFilterStrings(SoundFileClass: TGLSoundFileClass; out Descriptions, Filters: string);
  90. end;
  91. function GetGLSoundFileFormats : TGLSoundFileFormatsList;
  92. procedure RegisterSoundFileFormat(const AExtension, ADescription: String; AClass: TGLSoundFileClass);
  93. procedure UnregisterSoundFileClass(AClass: TGLSoundFileClass);
  94. // ------------------------------------------------------------------
  95. implementation
  96. // ------------------------------------------------------------------
  97. var
  98. vSoundFileFormats : TGLSoundFileFormatsList;
  99. function GetGLSoundFileFormats : TGLSoundFileFormatsList;
  100. begin
  101. if not Assigned(vSoundFileFormats)then
  102. vSoundFileFormats := TGLSoundFileFormatsList.Create;
  103. Result := vSoundFileFormats;
  104. end;
  105. procedure RegisterSoundFileFormat(const AExtension, ADescription: String; AClass: TGLSoundFileClass);
  106. begin
  107. RegisterClass(AClass);
  108. GetGLSoundFileFormats.Add(AExtension, ADescription, 0, AClass);
  109. end;
  110. procedure UnregisterSoundFileClass(AClass: TGLSoundFileClass);
  111. begin
  112. if Assigned(vSoundFileFormats) then
  113. vSoundFileFormats.Remove(AClass);
  114. end;
  115. // ------------------
  116. // ------------------ TGLSoundSampling ------------------
  117. // ------------------
  118. constructor TGLSoundSampling.Create(AOwner: TPersistent);
  119. begin
  120. inherited Create;
  121. FOwner:=AOwner;
  122. FFrequency:=22050;
  123. FNbChannels:=1;
  124. FBitsPerSample:=8;
  125. end;
  126. destructor TGLSoundSampling.Destroy;
  127. begin
  128. inherited Destroy;
  129. end;
  130. procedure TGLSoundSampling.Assign(Source: TPersistent);
  131. begin
  132. if Source is TGLSoundSampling then begin
  133. FFrequency:=TGLSoundSampling(Source).Frequency;
  134. FNbChannels:=TGLSoundSampling(Source).NbChannels;
  135. FBitsPerSample:=TGLSoundSampling(Source).BitsPerSample;
  136. end else inherited;
  137. end;
  138. function TGLSoundSampling.GetOwner : TPersistent;
  139. begin
  140. Result:=FOwner;
  141. end;
  142. function TGLSoundSampling.BytesPerSec : Integer;
  143. begin
  144. Result:=(FFrequency*FBitsPerSample*FNbChannels) shr 3;
  145. end;
  146. function TGLSoundSampling.BytesPerSample : Integer;
  147. begin
  148. Result:=FBitsPerSample shr 3;
  149. end;
  150. function TGLSoundSampling.WaveFormat : TWaveFormatEx;
  151. begin
  152. Result.nSamplesPerSec:=Frequency;
  153. Result.nChannels:=NbChannels;
  154. Result.wFormatTag:=Wave_Format_PCM;
  155. Result.nAvgBytesPerSec:=BytesPerSec;
  156. Result.wBitsPerSample:=BitsPerSample;
  157. Result.nBlockAlign:=NbChannels*BytesPerSample;
  158. Result.cbSize:=0;
  159. end;
  160. // ------------------
  161. // ------------------ TGLSoundFile ------------------
  162. // ------------------
  163. constructor TGLSoundFile.Create(AOwner: TPersistent);
  164. begin
  165. inherited;
  166. FSampling:=TGLSoundSampling.Create(Self);
  167. end;
  168. destructor TGLSoundFile.Destroy;
  169. begin
  170. FSampling.Free;
  171. inherited;
  172. end;
  173. procedure TGLSoundFile.SetSampling(const val : TGLSoundSampling);
  174. begin
  175. FSampling.Assign(val);
  176. end;
  177. procedure TGLSoundFile.PlayOnWaveOut;
  178. begin
  179. // GLSoundFileObjects.PlayOnWaveOut(PCMData, LengthInSamples, Sampling);
  180. end;
  181. function TGLSoundFile.LengthInSamples : Integer;
  182. var
  183. d : Integer;
  184. begin
  185. d:=Sampling.BytesPerSample*Sampling.NbChannels;
  186. if d>0 then
  187. Result:=LengthInBytes div d
  188. else Result:=0;
  189. end;
  190. function TGLSoundFile.LengthInSec : Single;
  191. begin
  192. Result:=LengthInBytes/Sampling.BytesPerSec;
  193. end;
  194. // ------------------
  195. // ------------------ TGLSoundFileFormatsList ------------------
  196. // ------------------
  197. destructor TGLSoundFileFormatsList.Destroy;
  198. var
  199. i : Integer;
  200. begin
  201. for i:=0 to Count-1 do Dispose(PSoundFileFormat(Items[i]));
  202. inherited;
  203. end;
  204. procedure TGLSoundFileFormatsList.Add(const Ext, Desc: String; DescID: Integer;
  205. AClass: TGLSoundFileClass);
  206. var
  207. newRec: PSoundFileFormat;
  208. begin
  209. New(newRec);
  210. with newRec^ do begin
  211. Extension := AnsiLowerCase(Ext);
  212. SoundFileClass := AClass;
  213. Description := Desc;
  214. DescResID := DescID;
  215. end;
  216. inherited Add(NewRec);
  217. end;
  218. function TGLSoundFileFormatsList.FindExt(Ext: string): TGLSoundFileClass;
  219. var
  220. i : Integer;
  221. begin
  222. Ext := AnsiLowerCase(Ext);
  223. for I := Count-1 downto 0 do with PSoundFileFormat(Items[I])^ do
  224. if (Extension = Ext) or ('.'+Extension = Ext) then begin
  225. Result := SoundFileClass;
  226. Exit;
  227. end;
  228. Result := nil;
  229. end;
  230. procedure TGLSoundFileFormatsList.Remove(AClass: TGLSoundFileClass);
  231. var
  232. i : Integer;
  233. p : PSoundFileFormat;
  234. begin
  235. for I := Count-1 downto 0 do begin
  236. P := PSoundFileFormat(Items[I]);
  237. if P^.SoundFileClass.InheritsFrom(AClass) then begin
  238. Dispose(P);
  239. Delete(I);
  240. end;
  241. end;
  242. end;
  243. procedure TGLSoundFileFormatsList.BuildFilterStrings(SoundFileClass: TGLSoundFileClass;
  244. out Descriptions, Filters: string);
  245. var
  246. c, i : Integer;
  247. p : PSoundFileFormat;
  248. begin
  249. Descriptions := '';
  250. Filters := '';
  251. C := 0;
  252. for I := Count-1 downto 0 do begin
  253. P := PSoundFileFormat(Items[I]);
  254. if P^.SoundFileClass.InheritsFrom(SoundFileClass) and (P^.Extension <> '') then
  255. with P^ do begin
  256. if C <> 0 then begin
  257. Descriptions := Descriptions+'|';
  258. Filters := Filters+';';
  259. end;
  260. if (Description = '') and (DescResID <> 0) then
  261. Description := LoadStr(DescResID);
  262. FmtStr(Descriptions, '%s%s (*.%s)|*.%2:s',
  263. [Descriptions, Description, Extension]);
  264. FmtStr(Filters, '%s*.%s', [Filters, Extension]);
  265. Inc(C);
  266. end;
  267. end;
  268. if C > 1 then
  269. FmtStr(Descriptions, '%s (%s)|%1:s|%s', [sAllFilter, Filters, Descriptions]);
  270. end;
  271. // ------------------------------------------------------------------
  272. initialization
  273. // ------------------------------------------------------------------
  274. finalization
  275. FreeAndNil(vSoundFileFormats);
  276. end.