madopenal.pas 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. program test;
  2. {$mode objfpc}
  3. uses
  4. classes, sysutils, ctypes, openal, mad, ogg, vorbis, a52, dts, modplug, matroska;
  5. var
  6. source : TStream;
  7. codec : Integer;
  8. codec_bs : Longword;
  9. codec_read : function(const Buffer: Pointer; const Count: Longword): Longword = nil;
  10. codec_rate : Longword;
  11. codec_chan : Longword;
  12. function source_read_func(datasource: pointer; ptr: pointer; size: cuint): cuint; cdecl;
  13. begin
  14. Result := TStream(datasource).Read(ptr^, size);
  15. end;
  16. function source_read_func_ogg(ptr: pointer; size, nmemb: csize_t; datasource: pointer): csize_t; cdecl;
  17. begin
  18. Result := TStream(datasource).Read(ptr^, size*nmemb);
  19. end;
  20. function source_seek_func(datasource: pointer; offset: clong; whence: cint): clong; cdecl;
  21. begin
  22. case whence of
  23. {SEEK_SET} 0: Result := TStream(datasource).Seek(offset, soFromBeginning);
  24. {SEEK_CUR} 1: Result := TStream(datasource).Seek(offset, soFromCurrent);
  25. {SEEK_END} 2: Result := TStream(datasource).Seek(offset, soFromEnd);
  26. else Result := 0;
  27. end;
  28. end;
  29. function source_seek_func_ogg(datasource: pointer; offset: ogg_int64_t; whence: cint): cint; cdecl;
  30. begin
  31. case whence of
  32. {SEEK_SET} 0: TStream(datasource).Seek(offset, soFromBeginning);
  33. {SEEK_CUR} 1: TStream(datasource).Seek(offset, soFromCurrent);
  34. {SEEK_END} 2: TStream(datasource).Seek(offset, soFromEnd);
  35. end;
  36. Result := 0;
  37. end;
  38. function source_close_func(datasource: pointer): cint; cdecl;
  39. begin
  40. TStream(datasource).Position := 0;
  41. Result := 0;
  42. end;
  43. function source_tell_func(datasource: pointer): clong; cdecl;
  44. begin
  45. Result := TStream(datasource).Position;
  46. end;
  47. // mad
  48. var
  49. mad_decoder: pmad_decoder;
  50. {procedure mad_reset;
  51. begin
  52. mad_stream_finish(m_stream);
  53. mad_stream_init(m_stream);
  54. source.Position := 0;
  55. end;}
  56. function mad_read(const Buffer: Pointer; const Count: Longword): Longword;
  57. var
  58. Res: cint;
  59. begin
  60. Res := mad_decoder_read(mad_decoder, Buffer, Count);
  61. if Res < 0 then
  62. Result := 0 else
  63. Result := Res;
  64. end;
  65. // oggvorbis
  66. var
  67. ogg_file : OggVorbis_File;
  68. ogg_callbacks : ov_callbacks;
  69. {procedure ogg_reset;
  70. begin
  71. ov_pcm_seek(ogg_file, 0);
  72. end;}
  73. function ogg_read(const Buffer: Pointer; const Count: Longword): Longword;
  74. var
  75. Res: clong;
  76. begin
  77. Res := ov_read_ext(ogg_file, Buffer, Count, false, 2, true);
  78. if Res < 0 then
  79. Result := 0 else
  80. Result := Res;
  81. end;
  82. // a52
  83. var
  84. a52_decoder : pa52_decoder;
  85. function a52_read(const Buffer: Pointer; const Count: Longword): Longword;
  86. var
  87. Res: cint;
  88. begin
  89. Res := a52_decoder_read(a52_decoder, Buffer, Count);
  90. if Res < 0 then
  91. Result := 0 else
  92. Result := Res;
  93. end;
  94. // dts
  95. var
  96. dts_decoder : pdts_decoder;
  97. function dts_read(const Buffer: Pointer; const Count: Longword): Longword;
  98. var
  99. Res: cint;
  100. begin
  101. //WriteLn('enter dts_decoder_read');
  102. Res := dts_decoder_read(dts_decoder, Buffer, Count);
  103. //WriteLn('leave dts_decoder_read ', Res);
  104. if Res < 0 then
  105. Result := 0 else
  106. Result := Res;
  107. end;
  108. // modplug
  109. var
  110. mod_file: PModPlugFile;
  111. function mod_read(const Buffer: Pointer; const Count: Longword): Longword;
  112. var
  113. Res: cint;
  114. begin
  115. Res := ModPlug_Read(mod_file, Buffer, Count);
  116. if Res < 0 then
  117. Result := 0 else
  118. Result := Res;
  119. end;
  120. // openal
  121. const
  122. al_format : array[1..2] of ALenum = (AL_FORMAT_MONO16, AL_FORMAT_STEREO16);
  123. // Note: if you lower the al_bufcount, then you have to modify the al_polltime also!
  124. al_bufcount = 4;
  125. al_polltime = 100;
  126. var
  127. al_device : PALCdevice;
  128. al_context : PALCcontext;
  129. al_source : ALuint;
  130. al_buffers : array[0..al_bufcount-1] of ALuint;
  131. al_bufsize : Longword;
  132. al_readbuf : Pointer;
  133. procedure alPlay;
  134. var
  135. i: Integer;
  136. begin
  137. alSourceStop(al_source);
  138. alSourceRewind(al_source);
  139. alSourcei(al_source, AL_BUFFER, 0);
  140. for i := 0 to al_bufcount - 1 do
  141. begin
  142. if codec_read(al_readbuf, al_bufsize) = 0 then
  143. Break;
  144. //alBufferData(al_buffers[i], al_format[codec_chan], al_readbuf, al_bufsize, codec_rate);
  145. alBufferWriteData_LOKI(al_buffers[i], al_format[codec_chan], al_readbuf, al_bufsize, codec_rate, al_format[codec_chan]);
  146. alSourceQueueBuffers(al_source, 1, @al_buffers[i]);
  147. end;
  148. // Under windows, AL_LOOPING = AL_TRUE breaks queueing, no idea why
  149. alSourcei(al_source, AL_LOOPING, AL_FALSE);
  150. alSourcePlay(al_source);
  151. end;
  152. procedure alStop;
  153. begin
  154. alSourceStop(al_source);
  155. alSourceRewind(al_source);
  156. alSourcei(al_source, AL_BUFFER, 0);
  157. end;
  158. function alProcess: Boolean;
  159. var
  160. processed : ALint;
  161. buffer : ALuint;
  162. begin
  163. alGetSourcei(al_source, AL_BUFFERS_PROCESSED, processed);
  164. while (processed > 0) and (processed <= al_bufcount) do
  165. begin
  166. Write('.');
  167. alSourceUnqueueBuffers(al_source, 1, @buffer);
  168. if codec_read(al_readbuf, al_bufsize) = 0 then
  169. begin
  170. alStop;
  171. Exit(False);
  172. end;
  173. //alBufferData(buffer, al_format[codec_chan], al_readbuf, al_bufsize, codec_rate);
  174. alBufferWriteData_LOKI(buffer, al_format[codec_chan], al_readbuf, al_bufsize, codec_rate, al_format[codec_chan]);
  175. alSourceQueueBuffers(al_source, 1, @buffer);
  176. Dec(processed);
  177. end;
  178. Result := True;
  179. end;
  180. var
  181. Filename: String;
  182. ov: pvorbis_info;
  183. tmp: pointer;
  184. begin
  185. // define codec
  186. WriteLn('Define codec');
  187. Writeln(' (1) mp3');
  188. Writeln(' (2) ogg');
  189. Writeln(' (3) ac3');
  190. Writeln(' (4) dts');
  191. Writeln(' (5) xm,mod,it,s3m');
  192. Writeln(' (6) mka');
  193. Write('Enter: '); ReadLn(codec);
  194. Write('File: '); ReadLn(Filename);
  195. {codec := 4;
  196. Filename := 'test.dts';}
  197. // load file
  198. source := TFileStream.Create(Filename, fmOpenRead);
  199. // inittialize codec
  200. case codec of
  201. 1: // mad
  202. begin
  203. mad_decoder := mad_decoder_init(source, @source_read_func, @source_seek_func, @source_close_func, @source_tell_func);
  204. codec_read := @mad_read;
  205. codec_rate := 44100;
  206. codec_chan := 2;
  207. codec_bs := 2*codec_chan;
  208. end;
  209. 2: // oggvorbis
  210. begin
  211. ogg_callbacks.read := @source_read_func_ogg;
  212. ogg_callbacks.seek := @source_seek_func_ogg;
  213. ogg_callbacks.close := @source_close_func;
  214. ogg_callbacks.tell := @source_tell_func;
  215. if ov_open_callbacks(source, ogg_file, nil, 0, ogg_callbacks) >= 0 then
  216. begin
  217. ov := ov_info(ogg_file, -1);
  218. codec_read := @ogg_read;
  219. codec_rate := ov^.rate;
  220. codec_chan := ov^.channels;
  221. codec_bs := 2*codec_chan;
  222. end;
  223. end;
  224. 3: // a52
  225. begin
  226. a52_decoder := a52_decoder_init(0, source, @source_read_func, @source_seek_func, @source_close_func, @source_tell_func);
  227. codec_read := @a52_read;
  228. codec_rate := 44100;//48000;
  229. codec_chan := 2;
  230. codec_bs := 2*codec_chan;
  231. end;
  232. 4: // a52
  233. begin
  234. dts_decoder := dts_decoder_init(0, source, @source_read_func, @source_seek_func, @source_close_func, @source_tell_func);
  235. codec_read := @dts_read;
  236. codec_rate := 44100;//48000;
  237. codec_chan := 2;
  238. codec_bs := 2*codec_chan;
  239. end;
  240. 5: // modplug
  241. begin
  242. GetMem(tmp, source.Size);
  243. source.Read(tmp^, source.Size);
  244. mod_file := ModPlug_Load(tmp, source.Size);
  245. FreeMem(tmp);
  246. codec_read := @mod_read;
  247. codec_rate := 44100;//48000;
  248. codec_chan := 2;
  249. codec_bs := 2*codec_chan;
  250. end;
  251. end;
  252. if not Assigned(codec_read) then
  253. Exit;
  254. //al_bufsize := 20000 - (20000 mod codec_bs);
  255. al_bufsize := 20000 - (20000 mod codec_bs);
  256. WriteLn('Codec Blocksize : ', codec_bs);
  257. WriteLn('Codec Rate : ', codec_rate);
  258. WriteLn('Codec Channels : ', codec_chan);
  259. WriteLn('OpenAL Buffers : ', al_bufcount);
  260. WriteLn('OpenAL Buffer Size : ', al_bufsize);
  261. // init openal
  262. al_device := alcOpenDevice(nil);
  263. al_context := alcCreateContext(al_device, nil);
  264. alcMakeContextCurrent(al_context);
  265. alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
  266. alGenSources(1, @al_source);
  267. alGenBuffers(al_bufcount, @al_buffers);
  268. GetMem(al_readbuf, al_bufsize);
  269. // play
  270. alPlay;
  271. while alProcess do
  272. Sleep(al_polltime);
  273. // finalize openal
  274. alDeleteSources(1, @al_source);
  275. alDeleteBuffers(al_bufcount, @al_buffers);
  276. alcDestroyContext(al_context);
  277. alcCloseDevice(al_device);
  278. FreeMem(al_readbuf);
  279. // finalize codec
  280. case codec of
  281. 1: // mad
  282. begin
  283. mad_decoder_free(mad_decoder);
  284. end;
  285. 2: // oggvorbis
  286. begin
  287. ov_clear(ogg_file);
  288. end;
  289. 3: // a52
  290. begin
  291. a52_decoder_free(a52_decoder);
  292. end;
  293. 4: // dts
  294. begin
  295. dts_decoder_free(dts_decoder);
  296. end;
  297. 5: // modplug
  298. begin
  299. ModPlug_Unload(mod_file);
  300. end;
  301. end;
  302. // close file
  303. source.Free;
  304. end.