source: trunk/Packages/uos/uos_libxmp.pas

Last change on this file was 664, checked in by chronos, 3 days ago
  • Added: Ability to play music in background in start screen and in-game. Used uos as audio library.
File size: 13.0 KB
Line 
1unit uos_libxmp;
2{This unit is part of United Openlibraries of Sound (uos)}
3
4{This is the Pascal Wrapper + Dynamic loading of libxmp library.
5 Load library with xmp_load() and release with xmp_unload().
6 License : modified LGPL.
7 by Fred vS | fiens@hotmail.com | 2024}
8
9{$mode objfpc}{$H+}
10{$PACKRECORDS C}
11
12interface
13
14uses
15 dynlibs,
16 sysutils,
17 CTypes;
18
19const
20 XMP_VERSION = '4.6.0';
21 XMP_VERCODE = $040600;
22 XMP_VER_MAJOR = 4;
23 XMP_VER_MINOR = 6;
24 XMP_VER_RELEASE = 0;
25
26const
27{$IFDEF windows}
28 XMP_LIB_NAME = 'libxmp.dll';
29{$ENDIF}
30
31{$IFDEF unix}
32 {$IFDEF darwin}
33 XMP_LIB_NAME = 'libxmp.dylib';
34 {$ELSE}
35 XMP_LIB_NAME = 'libxmp.so.4.6.0';
36 {$ENDIF}
37{$ENDIF}
38
39const
40 XMP_NAME_SIZE = 64;
41
42 // Note event constants
43 XMP_KEY_OFF = $81;
44 XMP_KEY_CUT = $82;
45 XMP_KEY_FADE = $83;
46
47 // Sample format flags
48 XMP_FORMAT_8BIT = 1 shl 0;
49 XMP_FORMAT_UNSIGNED = 1 shl 1;
50 XMP_FORMAT_MONO = 1 shl 2;
51
52 // Player parameters
53 XMP_PLAYER_AMP = 0;
54 XMP_PLAYER_MIX = 1;
55 XMP_PLAYER_INTERP = 2;
56 XMP_PLAYER_DSP = 3;
57 XMP_PLAYER_FLAGS = 4;
58 XMP_PLAYER_CFLAGS = 5;
59 XMP_PLAYER_SMPCTL = 6;
60 XMP_PLAYER_VOLUME = 7;
61 XMP_PLAYER_STATE = 8;
62 XMP_PLAYER_SMIX_VOLUME = 9;
63 XMP_PLAYER_DEFPAN = 10;
64 XMP_PLAYER_MODE = 11;
65 XMP_PLAYER_MIXER_TYPE = 12;
66 XMP_PLAYER_VOICES = 13;
67
68 // Interpolation types
69 XMP_INTERP_NEAREST = 0;
70 XMP_INTERP_LINEAR = 1;
71 XMP_INTERP_SPLINE = 2;
72
73 // DSP effect types
74 XMP_DSP_LOWPASS = 1 shl 0;
75 XMP_DSP_ALL = XMP_DSP_LOWPASS;
76
77 // Player state
78 XMP_STATE_UNLOADED = 0;
79 XMP_STATE_LOADED = 1;
80 XMP_STATE_PLAYING = 2;
81
82 // Player flags
83 XMP_FLAGS_VBLANK = 1 shl 0;
84 XMP_FLAGS_FX9BUG = 1 shl 1;
85 XMP_FLAGS_FIXLOOP = 1 shl 2;
86 XMP_FLAGS_A500 = 1 shl 3;
87
88 // Player modes
89 XMP_MODE_AUTO = 0;
90 XMP_MODE_MOD = 1;
91 XMP_MODE_NOISETRACKER = 2;
92 XMP_MODE_PROTRACKER = 3;
93 XMP_MODE_S3M = 4;
94 XMP_MODE_ST3 = 5;
95 XMP_MODE_ST3GUS = 6;
96 XMP_MODE_XM = 7;
97 XMP_MODE_FT2 = 8;
98 XMP_MODE_IT = 9;
99 XMP_MODE_ITSMP = 10;
100
101 // Mixer types
102 XMP_MIXER_STANDARD = 0;
103 XMP_MIXER_A500 = 1;
104 XMP_MIXER_A500F = 2;
105
106 // Sample flags
107 XMP_SMPCTL_SKIP = 1 shl 0;
108
109 // Limits
110 XMP_MAX_KEYS = 121;
111 XMP_MAX_ENV_POINTS = 32;
112 XMP_MAX_MOD_LENGTH = 256;
113 XMP_MAX_CHANNELS = 64;
114 XMP_MAX_SRATE = 49170;
115 XMP_MIN_SRATE = 4000;
116 XMP_MIN_BPM = 20;
117 XMP_MAX_FRAMESIZE = 5 * XMP_MAX_SRATE * 2 div XMP_MIN_BPM;
118
119 // Error codes
120 XMP_END = 1;
121 XMP_ERROR_INTERNAL = 2;
122 XMP_ERROR_FORMAT = 3;
123 XMP_ERROR_LOAD = 4;
124 XMP_ERROR_DEPACK = 5;
125 XMP_ERROR_SYSTEM = 6;
126 XMP_ERROR_INVALID = 7;
127 XMP_ERROR_STATE = 8;
128
129type
130 xmp_context = PChar;
131
132type
133 xmp_channel = record
134 pan: integer; // Pan de canal (0x80 centrum)
135 vol: integer; // Volume of canal
136 flg: integer; // Flags of canal
137 end;
138
139 xmp_pattern = record
140 rows: integer;
141 index: array[1..1] of integer;
142 end;
143
144 xmp_event = record
145 note: byte;
146 ins: byte;
147 vol: byte;
148 fxt: byte;
149 fxp: byte;
150 f2t: byte;
151 f2p: byte;
152 _flag: byte;
153 end;
154
155 xmp_track = record
156 rows: integer;
157 event: array[1..1] of xmp_event;
158 end;
159
160 xmp_envelope = record
161 flg: integer;
162 npt: integer;
163 scl: integer;
164 sus: integer;
165 sue: integer;
166 lps: integer;
167 lpe: integer;
168 Data: array[1..XMP_MAX_ENV_POINTS * 2] of smallint;
169 end;
170
171 xmp_subinstrument = record
172 vol: integer;
173 gvl: integer;
174 pan: integer;
175 xpo: integer;
176 fin: integer;
177 vwf: integer;
178 vde: integer;
179 vra: integer;
180 vsw: integer;
181 rvv: integer;
182 sid: integer;
183 nna: integer;
184 dct: integer;
185 dca: integer;
186 ifc: integer;
187 ifr: integer;
188 end;
189
190 xmp_instrument = record
191 Name: array[0..31] of char;
192 vol: integer;
193 nsm: integer;
194 rls: integer;
195 aei: xmp_envelope;
196 pei: xmp_envelope;
197 fei: xmp_envelope;
198 map: array[0..XMP_MAX_KEYS] of record
199 ins: byte;
200 xpo: shortint;
201 end;
202 sub: ^xmp_subinstrument;
203 extra: Pointer;
204 end;
205
206 xmp_sample = record
207 Name: array[0..31] of char;
208 len: integer;
209 lps: integer;
210 lpe: integer;
211 flg: integer;
212 Data: PByte;
213 end;
214
215 xmp_sequence = record
216 entry_point: integer;
217 duration: integer;
218 end;
219
220 xmp_module = record
221 Name: array[0..XMP_NAME_SIZE - 1] of char;
222 typ: array[0..XMP_NAME_SIZE - 1] of char;
223 pat: integer;
224 trk: integer;
225 chn: integer;
226 ins: integer;
227 smp: integer;
228 spd: integer;
229 bpm: integer;
230 len: integer;
231 rst: integer;
232 gvl: integer;
233 xxp: ^xmp_pattern;
234 xxt: ^xmp_track;
235 xxi: ^xmp_instrument;
236 xxs: ^xmp_sample;
237 xxc: array[0..XMP_MAX_CHANNELS - 1] of xmp_channel;
238 xxo: array[0..XMP_MAX_MOD_LENGTH] of byte;
239 end;
240
241 xmp_test_info = record
242 Name: array[0..XMP_NAME_SIZE - 1] of char;
243 type_: array[0..XMP_NAME_SIZE - 1] of char;
244 end;
245
246 xmp_module_info = record
247 md5: array[0..15] of byte;
248 vol_base: integer;
249 module: ^xmp_module;
250 comment: PChar;
251 num_sequences: integer;
252 seq_data: ^xmp_sequence;
253 end;
254
255 xmp_channel_info = record
256 period: longword;
257 position: longword;
258 pitchbend: smallint;
259 note: byte;
260 instrument: byte;
261 sample: byte;
262 volume: byte;
263 pan: byte;
264 reserved: byte;
265 event: xmp_event;
266 end;
267
268 xmp_frame_info = record
269 pos: integer;
270 pattern: integer;
271 row: integer;
272 num_rows: integer;
273 frame: integer;
274 speed: integer;
275 bpm: integer;
276 time: integer;
277 total_time: integer;
278 frame_time: integer;
279 buffer: Pointer;
280 buffer_size: integer;
281 total_size: integer;
282 volume: integer;
283 loop_count: integer;
284 virt_channels: integer;
285 virt_used: integer;
286 sequence: integer;
287 channel_info: array[0..XMP_MAX_CHANNELS - 1] of xmp_channel_info;
288 end;
289
290 xmp_callbacks = record
291 read_func: function(dest: Pointer; len, nmemb: longword; priv: Pointer): longword;
292 seek_func: function(priv: Pointer; offset: longint; whence: integer): integer;
293 tell_func: function(priv: Pointer): longint;
294 close_func: function(priv: Pointer): integer;
295 end;
296
297 { Dynamic load : Vars that will hold our dynamically loaded functions...
298
299 *************************** functions ******************************* }
300
301var
302 xmp_create_context: function: pointer; cdecl;
303 xmp_free_context: procedure(ctx: Pointer); cdecl;
304 xmp_load_module: function(ctx: Pointer; const filename: PChar): Integer; cdecl;
305 xmp_load_module_from_memory: function(ctx: xmp_context; const Data: Pointer; size: longint): integer; cdecl;
306 xmp_load_module_from_file: function(ctx: xmp_context; file_: Pointer; size: longint): integer; cdecl;
307 xmp_load_module_from_callbacks: function(ctx: xmp_context; file_: Pointer; callbacks: xmp_callbacks): integer; cdecl;
308 xmp_test_module: function(const filename: PChar; info: xmp_test_info): Integer; cdecl;
309 xmp_release_module: procedure(ctx: xmp_context); cdecl;
310 xmp_start_player: function(ctx: xmp_context; rate: Integer; flags: Integer): Integer; cdecl;
311 xmp_play_buffer: function(ctx: xmp_context; buffer: Pointer; size: Integer; loop: Integer): Integer; cdecl;
312 xmp_get_frame_info: procedure(ctx: xmp_context; var info: xmp_frame_info); cdecl;
313 xmp_end_player: procedure(ctx: xmp_context); cdecl;
314 xmp_get_module_info: procedure(ctx: xmp_context; var info: xmp_module_info); cdecl;
315 xmp_get_format_list: function(): PAnsiChar; cdecl;
316 xmp_stop_module: procedure(ctx: xmp_context); cdecl;
317 xmp_restart_module: procedure(ctx: xmp_context); cdecl;
318 xmp_channel_vol: function(ctx: xmp_context; channel: Integer; volume: Integer): Integer; cdecl;
319 xmp_set_player: function(ctx: xmp_context; param: Integer; value: Integer): Integer; cdecl;
320 xmp_set_position: function(ctx: xmp_context; pos: Integer): Integer; cdecl;
321 xmp_seek_time: function(ctx: xmp_context; time: Integer): Integer; cdecl;
322
323// Not used yet...
324//function xmp_test_module_from_memory(const data: Pointer; size: LongInt; info: xmp_test_info): Integer; cdecl; external 'xmp';
325//function xmp_test_module_from_file(file_: Pointer; info: xmp_test_info): Integer; cdecl; external 'xmp';
326//function xmp_test_module_from_callbacks(file_: Pointer; callbacks: xmp_callbacks; info: xmp_test_info): Integer; cdecl; external 'xmp';
327//procedure xmp_scan_module(ctx: xmp_context); cdecl; external 'xmp';
328//function xmp_play_frame(ctx: xmp_context): Integer; cdecl; external 'xmp';
329//procedure xmp_inject_event(ctx: xmp_context; channel: Integer; var event: xmp_event); cdecl; external 'xmp';//function xmp_next_position(ctx: xmp_context): Integer; cdecl; external 'xmp';
330//function xmp_prev_position(ctx: xmp_context): Integer; cdecl; external 'xmp';
331//function xmp_set_position(ctx: xmp_context; pos: Integer): Integer; cdecl; external 'xmp';
332//function xmp_set_row(ctx: xmp_context; row: Integer): Integer; cdecl; external 'xmp';
333//function xmp_set_tempo_factor(ctx: xmp_context; factor: Double): Integer; cdecl; external 'xmp';//function xmp_seek_time(ctx: xmp_context; time: Integer): Integer; cdecl; external 'xmp';
334//function xmp_channel_mute(ctx: xmp_context; channel: Integer; mute: Integer): Integer; cdecl; external 'xmp';//function xmp_get_player(ctx: xmp_context; param: Integer): Integer; cdecl; external 'xmp';
335//function xmp_set_instrument_path(ctx: xmp_context; const path: PChar): Integer; cdecl; external 'xmp';
336
337
338{Special function for dynamic loading of lib ...}
339
340var
341 xmp_Handle: TLibHandle = dynlibs.NilHandle;
342 {$if defined(cpu32) and defined(windows)} // try load dependency if not in /windows/system32/
343 gc_Handle :TLibHandle=dynlibs.NilHandle;
344 {$endif}
345var
346 ReferenceCounter: cardinal = 0; // Reference counter
347
348function xmp_IsLoaded: Boolean; inline;
349
350function xmp_Load(const libfilename: string): Boolean; // load the lib
351
352procedure xmp_Unload(); // unload and frees the lib from memory : do not forget to call it before close application.
353
354implementation
355
356function xmp_IsLoaded: boolean;
357begin
358 Result := (xmp_Handle <> dynlibs.NilHandle);
359end;
360
361Function xmp_Load(const libfilename:string) :boolean;
362var
363thelib, thelibgcc: string;
364begin
365 Result := False;
366 if xmp_Handle<>0 then
367begin
368 Inc(ReferenceCounter);
369 result:=true {is it already there ?}
370end else
371begin
372 {$if defined(cpu32) and defined(windows)}
373 if Length(libfilename) = 0 then thelibgcc := 'libgcc_s_dw2-1.dll' else
374 thelibgcc := IncludeTrailingBackslash(ExtractFilePath(libfilename)) + 'libgcc_s_dw2-1.dll';
375 gc_Handle:= DynLibs.SafeLoadLibrary(thelibgcc);
376 {$endif}
377
378{go & load the library}
379 if Length(libfilename) = 0 then thelib := XMP_LIB_NAME else thelib := libfilename;
380 xmp_Handle:=DynLibs.LoadLibrary(thelib); // obtain the handle we want
381 if xmp_Handle <> DynLibs.NilHandle then
382begin {now we tie the functions to the VARs from above}
383
384Pointer(xmp_create_context):=DynLibs.GetProcedureAddress(xmp_Handle,PChar('xmp_create_context'));
385Pointer(xmp_free_context):=DynLibs.GetProcedureAddress(xmp_Handle,PChar('xmp_free_context'));
386Pointer(xmp_load_module):=DynLibs.GetProcedureAddress(xmp_Handle,PChar('xmp_load_module'));
387Pointer(xmp_load_module_from_memory):=DynLibs.GetProcedureAddress(xmp_Handle,PChar('xmp_load_module_from_memory'));
388Pointer(xmp_load_module_from_file):=DynLibs.GetProcedureAddress(xmp_Handle,PChar('xmp_load_module_from_file'));
389Pointer(xmp_load_module_from_callbacks):=DynLibs.GetProcedureAddress(xmp_Handle,PChar('xmp_load_module_from_callbacks'));
390Pointer(xmp_test_module):=DynLibs.GetProcedureAddress(xmp_Handle,PChar('xmp_test_module'));
391Pointer(xmp_release_module):=DynLibs.GetProcedureAddress(xmp_Handle,PChar('xmp_release_module'));
392Pointer(xmp_start_player):=DynLibs.GetProcedureAddress(xmp_Handle,PChar('xmp_start_player'));
393Pointer(xmp_play_buffer):=DynLibs.GetProcedureAddress(xmp_Handle,PChar('xmp_play_buffer'));
394Pointer(xmp_get_frame_info):=DynLibs.GetProcedureAddress(xmp_Handle,PChar('xmp_get_frame_info'));
395Pointer(xmp_end_player):=DynLibs.GetProcedureAddress(xmp_Handle,PChar('xmp_end_player'));
396Pointer(xmp_get_module_info):=DynLibs.GetProcedureAddress(xmp_Handle,PChar('xmp_get_module_info'));
397Pointer(xmp_get_format_list):=DynLibs.GetProcedureAddress(xmp_Handle,PChar('xmp_get_format_list'));
398Pointer(xmp_stop_module):=DynLibs.GetProcedureAddress(xmp_Handle,PChar('xmp_stop_module'));
399Pointer(xmp_restart_module):=DynLibs.GetProcedureAddress(xmp_Handle,PChar('xmp_restart_module'));
400Pointer(xmp_channel_vol):=DynLibs.GetProcedureAddress(xmp_Handle,PChar('xmp_channel_vol'));
401Pointer(xmp_set_player):=DynLibs.GetProcedureAddress(xmp_Handle,PChar('xmp_set_player'));
402Pointer(xmp_set_position):=DynLibs.GetProcedureAddress(xmp_Handle,PChar('xmp_set_position'));
403Pointer(xmp_seek_time):=DynLibs.GetProcedureAddress(xmp_Handle,PChar('xmp_seek_time'));
404
405end;
406 Result := xmp_IsLoaded;
407 ReferenceCounter:=1;
408end;
409
410end;
411
412Procedure xmp_Unload;
413begin
414 if ReferenceCounter > 0 then
415 dec(ReferenceCounter);
416 if ReferenceCounter > 0 then
417 exit;
418 if xmp_IsLoaded then
419 begin
420 DynLibs.UnloadLibrary(xmp_Handle);
421 xmp_Handle:=DynLibs.NilHandle;
422 {$if defined(cpu32) and defined(windows)}
423 if gc_Handle <> DynLibs.NilHandle then begin
424 DynLibs.UnloadLibrary(gc_Handle);
425 gc_Handle:=DynLibs.NilHandle;
426 end;
427 {$endif}
428 end;
429end;
430
431
432end.
433
Note: See TracBrowser for help on using the repository browser.