GXS.SoundFileObjects.pas 8.8 KB

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