]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - snd_xmp.c
cmd: Use reentrant mutex for cbufs. Fixes deadlock when expanding aliases in some...
[xonotic/darkplaces.git] / snd_xmp.c
1 /*
2         Copyright (C) 2014 nyov <nyov@nexnode.net>
3
4         This program is free software; you can redistribute it and/or
5         modify it under the terms of the GNU General Public License
6         as published by the Free Software Foundation; either version 2
7         of the License, or (at your option) any later version.
8
9         This program is distributed in the hope that it will be useful,
10         but WITHOUT ANY WARRANTY; without even the implied warranty of
11         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13         See the GNU General Public License for more details.
14
15         You should have received a copy of the GNU General Public License
16         along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 /*
19  * libxmp is licensed under the terms of the Lesser General Public License 2.1
20  */
21
22
23 #include "quakedef.h"
24 #include "snd_main.h"
25 #include "snd_xmp.h"
26
27 #ifdef LINK_TO_LIBXMP
28 #include <xmp.h>
29 #if ((XMP_VERCODE+0) < 0x040200)
30 #error libxmp version 4.2 or newer is required when linking to libxmp
31 #endif
32
33 /* libxmp API */
34 // Version and player information
35 #define qxmp_version xmp_version // const char *xmp_version
36 #define qxmp_vercode xmp_vercode // const unsigned int xmp_vercode
37 //#define qxmp_get_format_list xmp_get_format_list // char **xmp_get_format_list()
38 // Context creation
39 #define qxmp_create_context xmp_create_context // xmp_context xmp_create_context()
40 #define qxmp_free_context xmp_free_context // void xmp_free_context(xmp_context c)
41 // Module loading
42 //#define qxmp_test_module xmp_test_module // int xmp_test_module(char *path, struct xmp_test_info *test_info)
43 //#define qxmp_load_module xmp_load_module // int xmp_load_module(xmp_context c, char *path)
44 #define qxmp_load_module_from_memory xmp_load_module_from_memory // int xmp_load_module_from_memory(xmp_context c, void *mem, long size)
45 //#define qxmp_load_module_from_file xmp_load_module_from_file // int xmp_load_module_from_file(xmp_context c, FILE *f, long size)
46 #define qxmp_release_module xmp_release_module // void xmp_release_module(xmp_context c)
47 //#define qxmp_scan_module xmp_scan_module // void xmp_scan_module(xmp_context c)
48 #define qxmp_get_module_info xmp_get_module_info // void xmp_get_module_info(xmp_context c, struct xmp_module_info *info)
49 // Module playing
50 #define qxmp_start_player xmp_start_player // int xmp_start_player(xmp_context c, int rate, int format)
51 #define qxmp_play_frame xmp_play_frame // int xmp_play_frame(xmp_context c)
52 #define qxmp_play_buffer xmp_play_buffer // int xmp_play_buffer(xmp_context c, void *buffer, int size, int loop)
53 #define qxmp_get_frame_info xmp_get_frame_info // void xmp_get_frame_info(xmp_context c, struct xmp_frame_info *info)
54 #define qxmp_end_player xmp_end_player // void xmp_end_player(xmp_context c)
55 // Player control
56 //#define qxmp_next_position xmp_next_position // int xmp_next_position(xmp_context c)
57 //#define qxmp_prev_position xmp_prev_position// int xmp_prev_position(xmp_context c)
58 //#define qxmp_set_position xmp_set_position // int xmp_set_position(xmp_context c, int pos)
59 //#define qxmp_stop_module xmp_stop_module // void xmp_stop_module(xmp_context c)
60 //#define qxmp_restart_module xmp_restart_module // void xmp_restart_module(xmp_context c)
61 //#define qxmp_seek_time xmp_seek_time // int xmp_seek_time(xmp_context c, int time)
62 //#define qxmp_channel_mute xmp_channel_mute // int xmp_channel_mute(xmp_context c, int channel, int status)
63 //#define qxmp_channel_vol xmp_channel_vol // int xmp_channel_vol(xmp_context c, int channel, int vol)
64 //#define qxmp_inject_event xmp_inject_event // void xmp_inject_event(xmp_context c, int channel, struct xmp_event *event)
65 // Player parameter setting
66 //#define qxmp_set_instrument_path xmp_set_instrument_path // int xmp_set_instrument_path(xmp_context c, char *path)
67 #define qxmp_get_player xmp_get_player // int xmp_get_player(xmp_context c, int param)
68 #define qxmp_set_player xmp_set_player // int xmp_set_player(xmp_context c, int param, int val)
69
70 #define xmp_dll 1
71
72 qboolean XMP_OpenLibrary (void) {return true;}
73 void XMP_CloseLibrary (void) {}
74 #else
75
76 /* libxmp ABI */
77 /*
78 =================================================================
79
80   definitions from xmp.h
81
82 =================================================================
83 */
84
85 // constants from libxmp
86 #define XMP_NAME_SIZE           64      /* Size of module name and type */
87
88 /* sample format flags */
89 #define XMP_FORMAT_8BIT         (1 << 0) /* Mix to 8-bit instead of 16 */
90 #define XMP_FORMAT_UNSIGNED     (1 << 1) /* Mix to unsigned samples */
91 #define XMP_FORMAT_MONO         (1 << 2) /* Mix to mono instead of stereo */
92
93 /* player parameters */
94 #define XMP_PLAYER_AMP          0       /* Amplification factor */
95 #define XMP_PLAYER_MIX          1       /* Stereo mixing */
96 #define XMP_PLAYER_INTERP       2       /* Interpolation type */
97 #define XMP_PLAYER_DSP          3       /* DSP effect flags */
98 #define XMP_PLAYER_FLAGS        4       /* Player flags */
99 #define XMP_PLAYER_CFLAGS       5       /* Player flags for current module */
100 #define XMP_PLAYER_SMPCTL       6       /* Sample control flags */
101 #define XMP_PLAYER_VOLUME       7       /* Player module volume */
102 #define XMP_PLAYER_STATE        8       /* Internal player state */
103 #define XMP_PLAYER_SMIX_VOLUME  9       /* SMIX volume */
104 #define XMP_PLAYER_DEFPAN       10      /* Default pan setting */
105
106 /* interpolation types */
107 #define XMP_INTERP_NEAREST      0       /* Nearest neighbor */
108 #define XMP_INTERP_LINEAR       1       /* Linear (default) */
109 #define XMP_INTERP_SPLINE       2       /* Cubic spline */
110
111 /* player state */
112 #define XMP_STATE_UNLOADED      0       /* Context created */
113 #define XMP_STATE_LOADED        1       /* Module loaded */
114 #define XMP_STATE_PLAYING       2       /* Module playing */
115
116 /* sample flags */
117 #define XMP_SMPCTL_SKIP         (1 << 0) /* Don't load samples */
118
119 /* limits */
120 //#define XMP_MAX_KEYS          121     /* Number of valid keys */
121 //#define XMP_MAX_ENV_POINTS    32      /* Max number of envelope points */
122 #define XMP_MAX_MOD_LENGTH      256     /* Max number of patterns in module */
123 //#define XMP_MAX_CHANNELS      64      /* Max number of channels in module */
124 #define XMP_MAX_SRATE           49170   /* max sampling rate (Hz) */
125 #define XMP_MIN_SRATE           4000    /* min sampling rate (Hz) */
126 //#define XMP_MIN_BPM           20      /* min BPM */
127 #define XMP_MAX_FRAMESIZE       (5 * XMP_MAX_SRATE * 2 / XMP_MIN_BPM)
128
129 /* error codes */
130 #define XMP_END                 1
131 #define XMP_ERROR_INTERNAL      2       /* Internal error */
132 #define XMP_ERROR_FORMAT        3       /* Unsupported module format */
133 #define XMP_ERROR_LOAD          4       /* Error loading file */
134 #define XMP_ERROR_DEPACK        5       /* Error depacking file */
135 #define XMP_ERROR_SYSTEM        6       /* System error */
136 #define XMP_ERROR_INVALID       7       /* Invalid parameter */
137 #define XMP_ERROR_STATE         8       /* Invalid player state */
138
139 // types from libxmp
140 typedef char *xmp_context;
141
142 static const char **qxmp_version;
143 static const unsigned int *qxmp_vercode;
144
145 struct xmp_channel {
146         int pan;                        /* Channel pan (0x80 is center) */
147         int vol;                        /* Channel volume */
148 #define XMP_CHANNEL_SYNTH       (1 << 0)  /* Channel is synthesized */
149 #define XMP_CHANNEL_MUTE        (1 << 1)  /* Channel is muted */
150         int flg;                        /* Channel flags */
151 };
152
153 //struct xmp_sequence {
154 //      int entry_point;
155 //      int duration;
156 //};
157
158 struct xmp_module {
159         char name[XMP_NAME_SIZE];       /* Module title */
160         char type[XMP_NAME_SIZE];       /* Module format */
161         int pat;                        /* Number of patterns */
162         int trk;                        /* Number of tracks */
163         int chn;                        /* Tracks per pattern */
164         int ins;                        /* Number of instruments */
165         int smp;                        /* Number of samples */
166         int spd;                        /* Initial speed */
167         int bpm;                        /* Initial BPM */
168         int len;                        /* Module length in patterns */
169         int rst;                        /* Restart position */
170         int gvl;                        /* Global volume */
171
172         struct xmp_pattern **xxp;       /* Patterns */
173         struct xmp_track **xxt;         /* Tracks */
174         struct xmp_instrument *xxi;     /* Instruments */
175         struct xmp_sample *xxs;         /* Samples */
176         struct xmp_channel xxc[64];     /* Channel info */
177         unsigned char xxo[XMP_MAX_MOD_LENGTH];  /* Orders */
178 };
179
180 //struct xmp_test_info {
181 //      char name[XMP_NAME_SIZE];       /* Module title */
182 //      char type[XMP_NAME_SIZE];       /* Module format */
183 //};
184
185 struct xmp_module_info {
186         unsigned char md5[16];          /* MD5 message digest */
187         int vol_base;                   /* Volume scale */
188         struct xmp_module *mod;         /* Pointer to module data */
189         char *comment;                  /* Comment text, if any */
190         int num_sequences;              /* Number of valid sequences */
191         struct xmp_sequence *seq_data;  /* Pointer to sequence data */
192 };
193
194 struct xmp_frame_info
195 // {                    /* Current frame information */
196 //      int pos;                        /* Current position */
197 //      int pattern;                    /* Current pattern */
198 //      int row;                        /* Current row in pattern */
199 //      int num_rows;                   /* Number of rows in current pattern */
200 //      int frame;                      /* Current frame */
201 //      int speed;                      /* Current replay speed */
202 //      int bpm;                        /* Current bpm */
203 //      int time;                       /* Current module time in ms */
204 //      int total_time;                 /* Estimated replay time in ms*/
205 //      int frame_time;                 /* Frame replay time in us */
206 //      void *buffer;                   /* Pointer to sound buffer */
207 //      int buffer_size;                /* Used buffer size */
208 //      int total_size;                 /* Total buffer size */
209 //      int volume;                     /* Current master volume */
210 //      int loop_count;                 /* Loop counter */
211 //      int virt_channels;              /* Number of virtual channels */
212 //      int virt_used;                  /* Used virtual channels */
213 //      int sequence;                   /* Current sequence */
214 //
215 //      struct xmp_channel_info {       /* Current channel information */
216 //              unsigned int period;    /* Sample period */
217 //              unsigned int position;  /* Sample position */
218 //              short pitchbend;        /* Linear bend from base note*/
219 //              unsigned char note;     /* Current base note number */
220 //              unsigned char instrument; /* Current instrument number */
221 //              unsigned char sample;   /* Current sample number */
222 //              unsigned char volume;   /* Current volume */
223 //              unsigned char pan;      /* Current stereo pan */
224 //              unsigned char reserved; /* Reserved */
225 //              struct xmp_event event; /* Current track event */
226 //      } channel_info[XMP_MAX_CHANNELS];
227 //}
228 ;
229
230 // Functions exported from libxmp
231 static xmp_context (*qxmp_create_context)  (void);
232 static void        (*qxmp_free_context)    (xmp_context);
233 //static int         (*qxmp_test_module)     (char *, struct xmp_test_info *);
234 //static int         (*qxmp_load_module)     (xmp_context, char *);
235 //static void        (*qxmp_scan_module)     (xmp_context);
236 static void        (*qxmp_release_module)  (xmp_context);
237 static int         (*qxmp_start_player)    (xmp_context, int, int);
238 static int         (*qxmp_play_frame)      (xmp_context);
239 static int         (*qxmp_play_buffer)     (xmp_context, void *, int, int);
240 static void        (*qxmp_get_frame_info)  (xmp_context, struct xmp_frame_info *);
241 static void        (*qxmp_end_player)      (xmp_context);
242 //static void        (*qxmp_inject_event)    (xmp_context, int, struct xmp_event *);
243 static void        (*qxmp_get_module_info) (xmp_context, struct xmp_module_info *);
244 //static char      **(*qxmp_get_format_list) (void); // FIXME: did I do this right?
245 //static int         (*qxmp_next_position)   (xmp_context);
246 //static int         (*qxmp_prev_position)   (xmp_context);
247 //static int         (*qxmp_set_position)    (xmp_context, int);
248 //static void        (*qxmp_stop_module)     (xmp_context);
249 //static void        (*qxmp_restart_module)  (xmp_context);
250 //static int         (*qxmp_seek_time)       (xmp_context, int);
251 //static int         (*qxmp_channel_mute)    (xmp_context, int, int);
252 //static int         (*qxmp_channel_vol)     (xmp_context, int, int);
253 static int         (*qxmp_set_player)      (xmp_context, int, int);
254 static int         (*qxmp_get_player)      (xmp_context, int);
255 //static int         (*qxmp_set_instrument_path) (xmp_context, char *);
256 static int         (*qxmp_load_module_from_memory) (xmp_context, void *, long);
257 //static int         (*qxmp_load_module_from_file) (xmp_context, void *, long);
258 //static int        (XMP_EXPORT *qxmp_load_module_from_file) (xmp_context, void *, long);
259
260 /* External sample mixer API */
261 /*
262 static int         (*qxmp_start_smix)       (xmp_context, int, int);
263 static void        (*qxmp_end_smix)         (xmp_context);
264 static int         (*qxmp_smix_play_instrument)(xmp_context, int, int, int, int);
265 static int         (*qxmp_smix_play_sample) (xmp_context, int, int, int, int);
266 static int         (*qxmp_smix_channel_pan) (xmp_context, int, int);
267 static int         (*qxmp_smix_load_sample) (xmp_context, int, char *);
268 static int         (*qxmp_smix_release_sample) (xmp_context, int);
269 // end Functions exported from libxmp
270 */
271
272 /*
273 =================================================================
274
275   DarkPlaces definitions
276
277 =================================================================
278 */
279
280 static dllfunction_t xmpfuncs[] =
281 {
282         /* libxmp ABI */
283         // Version and player information
284         {"xmp_version",                 (void **) &qxmp_version},
285         {"xmp_vercode",                 (void **) &qxmp_vercode},
286 //      {"xmp_get_format_list",         (void **) &qxmp_get_format_list},
287         // Context creation
288         {"xmp_create_context",          (void **) &qxmp_create_context},
289         {"xmp_free_context",            (void **) &qxmp_free_context},
290         // Module loading
291 //      {"xmp_test_module",             (void **) &qxmp_test_module},
292 //      {"xmp_load_module",             (void **) &qxmp_load_module},
293         {"xmp_load_module_from_memory", (void **) &qxmp_load_module_from_memory}, // since libxmp 4.2.0
294 //      {"xmp_load_module_from_file",   (void **) &qxmp_load_module_from_file},   // since libxmp 4.3.0
295         {"xmp_release_module",          (void **) &qxmp_release_module},
296 //      {"xmp_scan_module",             (void **) &qxmp_scan_module},
297         {"xmp_get_module_info",         (void **) &qxmp_get_module_info},
298         // Module playing
299         {"xmp_start_player",            (void **) &qxmp_start_player},
300         {"xmp_play_frame",              (void **) &qxmp_play_frame},
301         {"xmp_play_buffer",             (void **) &qxmp_play_buffer},
302         {"xmp_get_frame_info",          (void **) &qxmp_get_frame_info},
303         {"xmp_end_player",              (void **) &qxmp_end_player},
304         // Player control
305 //      {"xmp_next_position",           (void **) &qxmp_next_position},
306 //      {"xmp_prev_position",           (void **) &qxmp_prev_position},
307 //      {"xmp_set_position",            (void **) &qxmp_set_position},
308 //      {"xmp_stop_module",             (void **) &qxmp_stop_module},
309 //      {"xmp_restart_module",          (void **) &qxmp_restart_module},
310 //      {"xmp_seek_time",               (void **) &qxmp_seek_time},
311 //      {"xmp_channel_mute",            (void **) &qxmp_channel_mute},
312 //      {"xmp_channel_vol",             (void **) &qxmp_channel_vol},
313 //      {"xmp_inject_event",            (void **) &qxmp_inject_event},
314         // Player parameter setting
315 //      {"xmp_set_instrument_path",     (void **) &qxmp_set_instrument_path},
316         {"xmp_get_player",              (void **) &qxmp_get_player},
317         {"xmp_set_player",              (void **) &qxmp_set_player},
318         /* smix */ // for completeness sake only, right now
319 //      {"xmp_start_smix",              (void **) &qxmp_start_smix},
320 //      {"xmp_end_smix",                (void **) &qxmp_end_smix},
321 //      {"xmp_smix_play_instrument",    (void **) &qxmp_smix_play_instrument},
322 //      {"xmp_smix_play_sample",        (void **) &qxmp_smix_play_sample},
323 //      {"xmp_smix_channel_pan",        (void **) &qxmp_smix_channel_pan},
324 //      {"xmp_smix_load_sample",        (void **) &qxmp_smix_load_sample},
325 //      {"xmp_smix_release_sample",     (void **) &qxmp_smix_release_sample},
326         {NULL, NULL}
327 };
328
329 // libxmp DLL handle
330 static dllhandle_t xmp_dll = NULL;
331
332
333 /*
334 =================================================================
335
336   DLL load & unload
337
338 =================================================================
339 */
340
341 /*
342 ====================
343 XMP_OpenLibrary
344
345 Try to load the libxmp DLL
346 ====================
347 */
348 qboolean XMP_OpenLibrary (void)
349 {
350         const char* dllnames_xmp [] =
351         {
352 #if defined(WIN32)
353                 "libxmp-4.dll",
354                 "libxmp.dll",
355 #elif defined(MACOSX) // FIXME: untested, please test a mac os build
356                 "libxmp.4.dylib",
357                 "libxmp.dylib",
358 #else
359                 "libxmp.so.4",
360                 "libxmp.so",
361 #endif
362                 NULL
363         };
364
365         if (xmp_dll) // Already loaded?
366                 return true;
367
368 // COMMANDLINEOPTION: Sound: -noxmp disables xmp module sound support
369         if (COM_CheckParm("-noxmp"))
370                 return false;
371
372         // Load the DLL
373         if (Sys_LoadLibrary (dllnames_xmp, &xmp_dll, xmpfuncs))
374         {
375                 if (*qxmp_vercode < 0x040200)
376                 {
377                         Con_Printf("Found incompatible XMP library version %s, not loading. (4.2.0 or higher required)\n", *qxmp_version);
378                         Sys_UnloadLibrary (&xmp_dll);
379                         return false;
380                 }
381                 if (developer_loading.integer >= 1)
382                         Con_Printf("XMP library loaded, version %s (0x0%x)\n", *qxmp_version, *qxmp_vercode);
383                 return true;
384         }
385         else
386                 return false;
387 }
388
389
390 /*
391 ====================
392 XMP_CloseLibrary
393
394 Unload the libxmp DLL
395 ====================
396 */
397 void XMP_CloseLibrary (void)
398 {
399         Sys_UnloadLibrary (&xmp_dll);
400 }
401
402 #endif
403
404 /*
405 =================================================================
406
407         Module file decoding
408
409 =================================================================
410 */
411
412 // Per-sfx data structure
413 typedef struct
414 {
415         unsigned char   *file;
416         size_t          filesize;
417 } xmp_stream_persfx_t;
418
419 // Per-channel data structure
420 typedef struct
421 {
422         xmp_context     playercontext;
423         int             bs;
424         int             buffer_firstframe;
425         int             buffer_numframes;
426         unsigned char   buffer[STREAM_BUFFERSIZE*4];
427 } xmp_stream_perchannel_t;
428
429
430 /*
431 ====================
432 XMP_GetSamplesFloat
433 ====================
434 */
435 static void XMP_GetSamplesFloat(channel_t *ch, sfx_t *sfx, int firstsampleframe, int numsampleframes, float *outsamplesfloat)
436 {
437         int i, len = numsampleframes * sfx->format.channels;
438         int f = sfx->format.width * sfx->format.channels; // bytes per frame in the buffer
439         xmp_stream_perchannel_t* per_ch = (xmp_stream_perchannel_t *)ch->fetcher_data;
440         xmp_stream_persfx_t* per_sfx = (xmp_stream_persfx_t *)sfx->fetcher_data;
441         const short *buf;
442         int newlength, done;
443         unsigned int format = 0;
444
445         // if this channel does not yet have a channel fetcher, make one
446         if (per_ch == NULL)
447         {
448                 // allocate a struct to keep track of our file position and buffer
449                 per_ch = (xmp_stream_perchannel_t *)Mem_Alloc(snd_mempool, sizeof(*per_ch));
450
451                 // create an xmp file context
452                 if ((per_ch->playercontext = qxmp_create_context()) == NULL)
453                 {
454                         //Con_Printf("error getting a libxmp file context; while trying to load file \"%s\"\n", filename);
455                         Mem_Free(per_ch);
456                         return;
457                 }
458                 // copy file to xmp
459                 if (qxmp_load_module_from_memory(per_ch->playercontext, (void *)per_sfx->file, (long)per_sfx->filesize) < 0)
460                 {
461                         qxmp_free_context(per_ch->playercontext);
462                         Mem_Free(per_ch);
463                         return;
464                 }
465
466                 // start playing the loaded file
467                 if (sfx->format.width == 1)    { format |= XMP_FORMAT_8BIT | XMP_FORMAT_UNSIGNED; } // else 16bit
468                 if (sfx->format.channels == 1) { format |= XMP_FORMAT_MONO; } // else stereo
469
470                 if (qxmp_start_player(per_ch->playercontext, sfx->format.speed, format) < 0)
471                 {
472                         Mem_Free(per_ch);
473                         return;
474                 }
475                 /* percentual left/right channel separation, default is 70. */
476                 if (sfx->format.channels == 2 && (qxmp_set_player(per_ch->playercontext, XMP_PLAYER_MIX, 50) != 0))
477                 {
478                         Mem_Free(per_ch);
479                         return;
480                 }
481                 /* interpolation type, default is XMP_INTERP_LINEAR */
482                 if (qxmp_set_player(per_ch->playercontext, XMP_PLAYER_INTERP, XMP_INTERP_SPLINE) != 0)
483                 {
484                         Mem_Free(per_ch);
485                         return;
486                 }
487
488                 per_ch->bs = 0;
489                 per_ch->buffer_firstframe = 0;
490                 per_ch->buffer_numframes = 0;
491                 // attach the struct to our channel
492                 ch->fetcher_data = (void *)per_ch;
493
494                 // reset internal xmp state / syncs buffer start with frame start
495                 qxmp_play_buffer(per_ch->playercontext, NULL, 0, 0);
496         }
497
498         // if the request is too large for our buffer, loop...
499         while (numsampleframes * f > (int)sizeof(per_ch->buffer))
500         {
501                 done = sizeof(per_ch->buffer) / f;
502                 XMP_GetSamplesFloat(ch, sfx, firstsampleframe, done, outsamplesfloat);
503                 firstsampleframe += done;
504                 numsampleframes -= done;
505                 outsamplesfloat += done * sfx->format.channels;
506         }
507
508         // seek if the request is before the current buffer (loop back)
509         // seek if the request starts beyond the current buffer by at least one frame (channel was zero volume for a while)
510         // do not seek if the request overlaps the buffer end at all (expected behavior)
511         if (per_ch->buffer_firstframe > firstsampleframe || per_ch->buffer_firstframe + per_ch->buffer_numframes < firstsampleframe)
512         {
513                 // we expect to decode forward from here so this will be our new buffer start
514                 per_ch->buffer_firstframe = firstsampleframe;
515                 per_ch->buffer_numframes = 0;
516                 // no seeking at this time
517         }
518
519         // render the file to pcm as needed
520         if (firstsampleframe + numsampleframes > per_ch->buffer_firstframe + per_ch->buffer_numframes)
521         {
522                 // first slide the buffer back, discarding any data preceding the range we care about
523                 int offset = firstsampleframe - per_ch->buffer_firstframe;
524                 int keeplength = per_ch->buffer_numframes - offset;
525                 if (keeplength > 0)
526                         memmove(per_ch->buffer, per_ch->buffer + offset * sfx->format.width * sfx->format.channels, keeplength * sfx->format.width * sfx->format.channels);
527                 per_ch->buffer_firstframe = firstsampleframe;
528                 per_ch->buffer_numframes -= offset;
529                 // render as much as we can fit in the buffer
530                 newlength = sizeof(per_ch->buffer) - per_ch->buffer_numframes * f;
531                 done = 0;
532 //              while (newlength > done && qxmp_play_buffer(per_ch->playercontext, (void *)((char *)per_ch->buffer + done), (int)(newlength - done), 1) == 0) // don't loop by default (TODO: fix pcm duration calculation first)
533                 while (newlength > done && qxmp_play_buffer(per_ch->playercontext, (void *)((char *)per_ch->buffer + done), (int)(newlength - done), 0) == 0) // loop forever
534                 {
535                         done += (int)(newlength - done);
536                 }
537                 // clear the missing space if any
538                 if (done < newlength)
539                 {
540                         memset(per_ch->buffer + done, 0, newlength - done);
541                 }
542                 // we now have more data in the buffer
543                 per_ch->buffer_numframes += done / f;
544         }
545
546         // convert the sample format for the caller
547         buf = (short *)((char *)per_ch->buffer + (firstsampleframe - per_ch->buffer_firstframe) * f);
548         for (i = 0;i < len;i++)
549                 outsamplesfloat[i] = buf[i] * (1.0f / 32768.0f);
550 }
551
552 /*
553 ====================
554 XMP_StopChannel
555 ====================
556 */
557 static void XMP_StopChannel(channel_t *ch)
558 {
559         xmp_stream_perchannel_t *per_ch = (xmp_stream_perchannel_t *)ch->fetcher_data;
560         if (per_ch != NULL)
561         {
562                 // stop the player
563                 qxmp_end_player(per_ch->playercontext);
564                 // free the module
565                 qxmp_release_module(per_ch->playercontext);
566                 // free the xmp playercontext
567                 qxmp_free_context(per_ch->playercontext);
568                 Mem_Free(per_ch);
569         }
570 }
571
572 /*
573 ====================
574 XMP_FreeSfx
575 ====================
576 */
577 static void XMP_FreeSfx(sfx_t *sfx)
578 {
579         xmp_stream_persfx_t* per_sfx = (xmp_stream_persfx_t *)sfx->fetcher_data;
580         // free the complete file we were keeping around
581         Mem_Free(per_sfx->file);
582         // free the file information structure
583         Mem_Free(per_sfx);
584 }
585
586 static const snd_fetcher_t xmp_fetcher = { XMP_GetSamplesFloat, XMP_StopChannel, XMP_FreeSfx };
587
588 /*
589 ===============
590 XMP_LoadModFile
591
592 Load an XMP module file into memory
593 ===============
594 */
595 qboolean XMP_LoadModFile(const char *filename, sfx_t *sfx)
596 {
597         fs_offset_t filesize;
598         unsigned char *data;
599         xmp_context xc;
600         xmp_stream_persfx_t* per_sfx;
601         struct xmp_module_info mi;
602
603 #ifndef LINK_TO_LIBXMP
604         if (!xmp_dll)
605                 return false;
606 #endif
607
608 // COMMANDLINEOPTION: Sound: -noxmp disables xmp module sound support
609         if (COM_CheckParm("-noxmp"))
610                 return false;
611
612         // Return if already loaded
613         if (sfx->fetcher != NULL)
614                 return true;
615
616         // Load the file
617         data = FS_LoadFile(filename, snd_mempool, false, &filesize);
618         if (data == NULL)
619                 return false;
620
621         // Create an xmp file context
622         if ((xc = qxmp_create_context()) == NULL)
623         {
624                 Con_Printf("error creating a libxmp file context; while trying to load file \"%s\"\n", filename);
625                 Mem_Free(data);
626                 return false;
627         }
628
629         if (developer_loading.integer >= 2)
630                 Con_Printf("Loading Module file (libxmp) \"%s\"\n", filename);
631
632         if (qxmp_load_module_from_memory(xc, (void *)data, (long)filesize) < 0) // Added in libxmp 4.2
633         {
634                 Con_Printf("error while trying to load xmp module \"%s\"\n", filename);
635                 qxmp_free_context(xc);
636                 Mem_Free(data);
637                 return false;
638         }
639
640         if (developer_loading.integer >= 2)
641                 Con_Printf ("\"%s\" will be streamed\n", filename);
642
643         // keep the file around
644         per_sfx = (xmp_stream_persfx_t *)Mem_Alloc (snd_mempool, sizeof (*per_sfx));
645         per_sfx->file = data;
646         per_sfx->filesize = filesize;
647         // set dp sfx
648         sfx->memsize += sizeof(*per_sfx);
649         sfx->memsize += filesize; // total memory used (including sfx_t and fetcher data)
650         if (S_GetSoundRate() > XMP_MAX_SRATE)
651                 sfx->format.speed = 48000;
652         else if (S_GetSoundRate() < XMP_MIN_SRATE)
653                 sfx->format.speed = 8000;
654         else
655                 sfx->format.speed = S_GetSoundRate();
656         sfx->format.width = S_GetSoundWidth();  // 2 = 16 bit samples
657         sfx->format.channels = S_GetSoundChannels();
658         sfx->flags |= SFXFLAG_STREAMED; // cf SFXFLAG_* defines
659         sfx->total_length = 1<<30; // 2147384647; // in (pcm) sample frames - they always loop (FIXME this breaks after 6 hours, we need support for a real "infinite" value!)
660         sfx->loopstart = sfx->total_length; // (modplug does it) in sample frames. equals total_length if not looped
661         sfx->fetcher_data = per_sfx;
662         sfx->fetcher = &xmp_fetcher;
663         sfx->volume_peak = 0;
664
665         qxmp_get_module_info(xc, &mi);
666         if (developer_loading.integer >= 2)
667         {
668                 Con_Printf("Decoding module (libxmp):\n"
669                         "    Module name  : %s\n"
670                         "    Module type  : %s\n"
671                         "    Module length: %i patterns\n"
672                         "    Patterns     : %i\n"
673                         "    Instruments  : %i\n"
674                         "    Samples      : %i\n"
675                         "    Channels     : %i\n"
676                         "    Initial Speed: %i\n"
677                         "    Initial BPM  : %i\n"
678                         "    Restart Pos. : %i\n"
679                         "    Global Volume: %i\n",
680                         mi.mod->name, mi.mod->type,
681                         mi.mod->len, mi.mod->pat, mi.mod->ins, mi.mod->smp, mi.mod->chn,
682                         mi.mod->spd, mi.mod->bpm, mi.mod->rst, mi.mod->gvl
683                 );
684         }
685         else if (developer_loading.integer == 1)
686                 Con_Printf("Decoding module (libxmp) \"%s\" (%s)\n", mi.mod->name, mi.mod->type);
687
688         qxmp_free_context(xc);
689         return true;
690 }