zglModPlug.pas 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. {
  2. * Copyright (c) 2012 Andrey Kemka
  3. *
  4. * This software is provided 'as-is', without any express or
  5. * implied warranty. In no event will the authors be held
  6. * liable for any damages arising from the use of this software.
  7. *
  8. * Permission is granted to anyone to use this software for any purpose,
  9. * including commercial applications, and to alter it and redistribute
  10. * it freely, subject to the following restrictions:
  11. *
  12. * 1. The origin of this software must not be misrepresented;
  13. * you must not claim that you wrote the original software.
  14. * If you use this software in a product, an acknowledgment
  15. * in the product documentation would be appreciated but
  16. * is not required.
  17. *
  18. * 2. Altered source versions must be plainly marked as such,
  19. * and must not be misrepresented as being the original software.
  20. *
  21. * 3. This notice may not be removed or altered from any
  22. * source distribution.
  23. }
  24. unit zglModPlug;
  25. {$I zglCustomConfig.cfg}
  26. {$IFDEF FPC}
  27. {$MODE DELPHI}
  28. {$PACKRECORDS C}
  29. {$MINENUMSIZE 4}
  30. {$ENDIF}
  31. interface
  32. uses
  33. {$IFDEF USE_ZENGL_STATIC}
  34. zgl_types,
  35. zgl_application,
  36. zgl_main,
  37. zgl_sound,
  38. zgl_log,
  39. zgl_file,
  40. zgl_memory,
  41. zgl_utils
  42. {$ELSE}
  43. zglHeader
  44. {$ENDIF}
  45. ;
  46. const
  47. {$IFDEF WINDOWS}
  48. libmodplug = 'libmodplug.dll';
  49. {$ENDIF}
  50. {$IFDEF LINUX}
  51. libmodplug = 'libmodplug.so';
  52. {$ENDIF}
  53. {$IFDEF MACOSX}
  54. libmodplug = 'libmodplug.dylib';
  55. {$ENDIF}
  56. MAX_FORMATS = 22;
  57. procedure InitModPlug;
  58. procedure FreeModPlug;
  59. implementation
  60. const
  61. MODPLUG_ENABLE_OVERSAMPLING = 1 shl 0;
  62. MODPLUG_ENABLE_NOISE_REDUCTION = 1 shl 1;
  63. MODPLUG_ENABLE_REVERB = 1 shl 2;
  64. MODPLUG_ENABLE_MEGABASS = 1 shl 3;
  65. MODPLUG_ENABLE_SURROUND = 1 shl 4;
  66. MODPLUG_RESAMPLE_NEAREST = 0;
  67. MODPLUG_RESAMPLE_LINEAR = 1;
  68. MODPLUG_RESAMPLE_SPLINE = 2;
  69. MODPLUG_RESAMPLE_FIR = 3;
  70. type
  71. PModPlugFile = ^ModPlugFile;
  72. ModPlugFile = record
  73. end;
  74. var
  75. Decoders : array[ 0..MAX_FORMATS - 1 ] of zglTSoundDecoder;
  76. FORMATS : array[ 0..MAX_FORMATS - 1 ] of UTF8String = ( 'MOD', 'IT', 'S3M', 'XM', 'IT', '669', 'AMF', 'AMS', 'DBM', 'DMF', 'DSM', 'FAR',
  77. 'MDL', 'MED', 'MTM', 'OKT', 'PTM', 'STM', 'ULT', 'UMX', 'MT2', 'PSM' );
  78. mpLoad : Boolean;
  79. mpInit : Boolean;
  80. mpLibrary : {$IFDEF WIN32} LongWord {$ELSE} Pointer {$ENDIF};
  81. ModPlug_Load : function(data: pointer; size: longint): PModPlugFile; cdecl;
  82. ModPlug_Unload : procedure(_file: PModPlugFile); cdecl;
  83. ModPlug_Read : function(_file: PModPlugFile; buffer: pointer; size: longint): longint; cdecl;
  84. ModPlug_Seek : procedure(_file: PModPlugFile; millisecond: longint); cdecl;
  85. ModPlug_GetLength : function(_file: PModPlugFile): longint; cdecl;
  86. function mp_DecoderOpen( var Stream : zglTSoundStream; const FileName : UTF8String ) : Boolean;
  87. var
  88. mem : zglTMemory;
  89. begin
  90. if not mpLoad Then InitModPlug();
  91. if not mpInit Then exit;
  92. mem_LoadFromFile( mem, FileName );
  93. PModPlugFile( Stream._data ) := ModPlug_Load( mem.Memory, mem.Size );
  94. mem_Free( mem );
  95. if Assigned( Stream._data ) Then
  96. begin
  97. Result := TRUE;
  98. Stream.Bits := 16;
  99. Stream.Frequency := 44100;
  100. Stream.Channels := 2;
  101. Stream.Duration := ModPlug_GetLength( PModPlugFile( Stream._data ) );
  102. Stream.BufferSize := 64 * 1024;
  103. zgl_GetMem( Pointer( Stream.Buffer ), Stream.BufferSize );
  104. end else
  105. Result := FALSE;
  106. end;
  107. function mp_DecoderOpenMem( var Stream : zglTSoundStream; const Memory : zglTMemory ) : Boolean;
  108. begin
  109. if not mpLoad Then InitModPlug;
  110. if not mpInit Then exit;
  111. PModPlugFile( Stream._data ) := ModPlug_Load( Memory.Memory, Memory.Size );
  112. if Assigned( Stream._data ) Then
  113. begin
  114. Result := TRUE;
  115. Stream.Bits := 16;
  116. Stream.Frequency := 44100;
  117. Stream.Channels := 2;
  118. Stream.Duration := ModPlug_GetLength( PModPlugFile( Stream._data ) );
  119. Stream.BufferSize := 64 * 1024;
  120. zgl_GetMem( Pointer( Stream.Buffer ), Stream.BufferSize );
  121. end else
  122. Result := FALSE;
  123. end;
  124. function mp_DecoderRead( var Stream : zglTSoundStream; Buffer : PByteArray; Bytes : LongWord; out _End : Boolean ) : LongWord;
  125. begin
  126. if not mpInit Then exit;
  127. Result := ModPlug_Read( PModPlugFile( Stream._data ), @Buffer[ 0 ], Bytes );
  128. _End := Result = 0;
  129. end;
  130. procedure mp_DecoderLoop( var Stream : zglTSoundStream );
  131. begin
  132. if not mpInit Then exit;
  133. ModPlug_Seek( PModPlugFile( Stream._data ), 0 );
  134. end;
  135. procedure mp_DecoderClose( var Stream : zglTSoundStream );
  136. begin
  137. if not mpInit Then exit;
  138. ModPlug_Unload( PModPlugFile( Stream._data ) );
  139. Stream._data := nil;
  140. end;
  141. procedure InitModPlug;
  142. begin
  143. {$IFDEF LINUX}
  144. {$IFNDEF ANDROID}
  145. mpLibrary := dlopen( PAnsiChar( './' + libmodplug + '.1' ), $001 );
  146. if mpLibrary = LIB_ERROR Then mpLibrary := dlopen( PAnsiChar( libmodplug + '.1' ), $001 );
  147. if mpLibrary = LIB_ERROR Then mpLibrary := dlopen( PAnsiChar( libmodplug + '.0' ), $001 );
  148. {$ELSE}
  149. mpLibrary := dlopen( libmodplug, $001 );
  150. {$ENDIF}
  151. {$ENDIF}
  152. {$IFDEF WINDOWS}
  153. mpLibrary := dlopen( libmodplug );
  154. {$ENDIF}
  155. {$IFDEF MACOSX}
  156. mpLibrary := dlopen( PAnsiChar( PAnsiChar( zgl_Get( DIRECTORY_APPLICATION ) ) + 'Contents/Frameworks/' + libmodplug ), $001 );
  157. {$ENDIF}
  158. if mpLibrary <> LIB_ERROR Then
  159. begin
  160. ModPlug_Load := dlsym( mpLibrary, 'ModPlug_Load' );
  161. ModPlug_Unload := dlsym( mpLibrary, 'ModPlug_Unload' );
  162. ModPlug_Read := dlsym( mpLibrary, 'ModPlug_Read' );
  163. ModPlug_Seek := dlsym( mpLibrary, 'ModPlug_Seek' );
  164. ModPlug_GetLength := dlsym( mpLibrary, 'ModPlug_GetLength' );
  165. log_Add( 'ModPlug: Successful initialized' );
  166. mpInit := TRUE;
  167. end else
  168. begin
  169. log_Add( 'ModPlug: Error while loading ' + libmodplug );
  170. mpInit := FALSE;
  171. end;
  172. mpLoad := TRUE;
  173. end;
  174. procedure FreeModPlug;
  175. begin
  176. mpInit := FALSE;
  177. dlclose( mpLibrary );
  178. end;
  179. var
  180. i : Integer;
  181. initialization
  182. for i := 0 to MAX_FORMATS - 1 do
  183. begin
  184. Decoders[ i ].Ext := FORMATS[ i ];
  185. Decoders[ i ].Open := @mp_DecoderOpen;
  186. Decoders[ i ].OpenMem := @mp_DecoderOpenMem;
  187. Decoders[ i ].Read := @mp_DecoderRead;
  188. Decoders[ i ].Seek := nil;
  189. Decoders[ i ].Loop := @mp_DecoderLoop;
  190. Decoders[ i ].Close := @mp_DecoderClose;
  191. zgl_Reg( SND_FORMAT_EXTENSION, @FORMATS[ i, 1 ] );
  192. zgl_Reg( SND_FORMAT_FILE_LOADER, nil );
  193. zgl_Reg( SND_FORMAT_MEM_LOADER, nil );
  194. zgl_Reg( SND_FORMAT_DECODER, @Decoders[ i ] );
  195. end;
  196. finalization
  197. if mpInit Then
  198. FreeModPlug();
  199. end.