]> git.xonotic.org Git - xonotic/darkplaces.git/blob - snd_modplug.c
Update build system, fix and enable ODE by default
[xonotic/darkplaces.git] / snd_modplug.c
1 /*
2         Copyright (C) 2003-2005  Mathieu Olivier
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, write to:
17
18                 Free Software Foundation, Inc.
19                 59 Temple Place - Suite 330
20                 Boston, MA  02111-1307, USA
21
22 */
23
24
25 #include "quakedef.h"
26 #include "snd_main.h"
27 #include "snd_modplug.h"
28
29 #ifdef LINK_TO_LIBMODPLUG
30
31 #include <libmodplug/modplug.h>
32 qboolean ModPlug_OpenLibrary (void)
33 {
34         return true; // statically linked
35 }
36 void ModPlug_CloseLibrary (void)
37 {
38 }
39 #define modplug_dll 1
40 #define qModPlug_Load ModPlug_Load
41 #define qModPlug_Unload ModPlug_Unload
42 #define qModPlug_Read ModPlug_Read
43 #define qModPlug_Seek ModPlug_Seek
44 #define qModPlug_GetSettings ModPlug_GetSettings
45 #define qModPlug_SetSettings ModPlug_SetSettings
46 #define qModPlug_SetMasterVolume ModPlug_SetMasterVolume
47
48 #else
49 // BEGIN SECTION FROM modplug.h
50
51         /*
52          * This source code is public domain.
53          *
54          * Authors: Kenton Varda <temporal@gauge3d.org> (C interface wrapper)
55          */
56
57         enum _ModPlug_Flags
58         {
59                         MODPLUG_ENABLE_OVERSAMPLING     = 1 << 0,  /* Enable oversampling (*highly* recommended) */
60                         MODPLUG_ENABLE_NOISE_REDUCTION  = 1 << 1,  /* Enable noise reduction */
61                         MODPLUG_ENABLE_REVERB           = 1 << 2,  /* Enable reverb */
62                         MODPLUG_ENABLE_MEGABASS         = 1 << 3,  /* Enable megabass */
63                         MODPLUG_ENABLE_SURROUND         = 1 << 4   /* Enable surround sound. */
64         };
65
66         enum _ModPlug_ResamplingMode
67         {
68                         MODPLUG_RESAMPLE_NEAREST = 0,  /* No interpolation (very fast, extremely bad sound quality) */
69                         MODPLUG_RESAMPLE_LINEAR  = 1,  /* Linear interpolation (fast, good quality) */
70                         MODPLUG_RESAMPLE_SPLINE  = 2,  /* Cubic spline interpolation (high quality) */
71                         MODPLUG_RESAMPLE_FIR     = 3   /* 8-tap fir filter (extremely high quality) */
72         };
73
74         typedef struct _ModPlug_Settings
75         {
76                         int mFlags;  /* One or more of the MODPLUG_ENABLE_* flags above, bitwise-OR'ed */
77                         
78                         /* Note that ModPlug always decodes sound at 44100kHz, 32 bit, stereo and then
79                          * down-mixes to the settings you choose. */
80                         int mChannels;       /* Number of channels - 1 for mono or 2 for stereo */
81                         int mBits;           /* Bits per sample - 8, 16, or 32 */
82                         int mFrequency;      /* Sampling rate - 11025, 22050, or 44100 */
83                         int mResamplingMode; /* One of MODPLUG_RESAMPLE_*, above */
84
85                         int mStereoSeparation; /* Stereo separation, 1 - 256 */
86                         int mMaxMixChannels; /* Maximum number of mixing channels (polyphony), 32 - 256 */
87                         
88                         int mReverbDepth;    /* Reverb level 0(quiet)-100(loud)      */
89                         int mReverbDelay;    /* Reverb delay in ms, usually 40-200ms */
90                         int mBassAmount;     /* XBass level 0(quiet)-100(loud)       */
91                         int mBassRange;      /* XBass cutoff in Hz 10-100            */
92                         int mSurroundDepth;  /* Surround level 0(quiet)-100(heavy)   */
93                         int mSurroundDelay;  /* Surround delay in ms, usually 5-40ms */
94                         int mLoopCount;      /* Number of times to loop.  Zero prevents looping.
95                                                                         -1 loops forever. */
96         } ModPlug_Settings;
97
98         struct _ModPlugFile;
99         typedef struct _ModPlugFile ModPlugFile;
100
101 // END SECTION FROM modplug.h
102
103 static ModPlugFile* (*qModPlug_Load) (const void* data, int size);
104 static void (*qModPlug_Unload) (ModPlugFile* file);
105 static int (*qModPlug_Read) (ModPlugFile* file, void* buffer, int size);
106 static void (*qModPlug_Seek) (ModPlugFile* file, int millisecond);
107 static void (*qModPlug_GetSettings) (ModPlug_Settings* settings);
108 static void (*qModPlug_SetSettings) (const ModPlug_Settings* settings);
109 typedef void (ModPlug_SetMasterVolume_t) (ModPlugFile* file,unsigned int cvol) ;
110 ModPlug_SetMasterVolume_t *qModPlug_SetMasterVolume;
111
112
113 static dllfunction_t modplugfuncs[] =
114 {
115         {"ModPlug_Load",                        (void **) &qModPlug_Load},
116         {"ModPlug_Unload",                      (void **) &qModPlug_Unload},
117         {"ModPlug_Read",                        (void **) &qModPlug_Read},
118         {"ModPlug_Seek",                        (void **) &qModPlug_Seek},
119         {"ModPlug_GetSettings",         (void **) &qModPlug_GetSettings},
120         {"ModPlug_SetSettings",         (void **) &qModPlug_SetSettings},
121         {NULL, NULL}
122 };
123
124 // Handles for the modplug and modplugfile DLLs
125 static dllhandle_t modplug_dll = NULL;
126
127 /*
128 =================================================================
129
130   DLL load & unload
131
132 =================================================================
133 */
134
135 /*
136 ====================
137 ModPlug_OpenLibrary
138
139 Try to load the modplugFile DLL
140 ====================
141 */
142 qboolean ModPlug_OpenLibrary (void)
143 {
144         const char* dllnames_modplug [] =
145         {
146 #if defined(WIN32)
147                 "libmodplug-1.dll",
148                 "modplug.dll",
149 #elif defined(MACOSX)
150                 "libmodplug.dylib",
151 #else
152                 "libmodplug.so.1",
153                 "libmodplug.so",
154 #endif
155                 NULL
156         };
157
158         // Already loaded?
159         if (modplug_dll)
160                 return true;
161
162 // COMMANDLINEOPTION: Sound: -nomodplug disables modplug sound support
163         if (COM_CheckParm("-nomodplug"))
164                 return false;
165
166 #ifdef __ANDROID__
167         Con_Print("Warning: no modplug support in Android yet.\n");
168         return false;
169 #endif
170
171         // Load the DLLs
172         // We need to load both by hand because some OSes seem to not load
173         // the modplug DLL automatically when loading the modplugFile DLL
174         if(Sys_LoadLibrary (dllnames_modplug, &modplug_dll, modplugfuncs))
175         {
176                 qModPlug_SetMasterVolume = (ModPlug_SetMasterVolume_t *) Sys_GetProcAddress(modplug_dll, "ModPlug_SetMasterVolume");
177                 if(!qModPlug_SetMasterVolume)
178                         Con_Print("Warning: modplug volume control not supported. Try getting a newer version of libmodplug.\n");
179                 return true;
180         }
181         else
182                 return false;
183 }
184
185
186 /*
187 ====================
188 ModPlug_CloseLibrary
189
190 Unload the modplugFile DLL
191 ====================
192 */
193 void ModPlug_CloseLibrary (void)
194 {
195         Sys_UnloadLibrary (&modplug_dll);
196 }
197 #endif
198
199
200 /*
201 =================================================================
202
203         modplug decoding
204
205 =================================================================
206 */
207
208 // Per-sfx data structure
209 typedef struct
210 {
211         unsigned char   *file;
212         size_t                  filesize;
213 } modplug_stream_persfx_t;
214
215 // Per-channel data structure
216 typedef struct
217 {
218         ModPlugFile     *mf;
219         int                             bs;
220         int                             buffer_firstframe;
221         int                             buffer_numframes;
222         unsigned char   buffer[STREAM_BUFFERSIZE*4];
223 } modplug_stream_perchannel_t;
224
225
226 /*
227 ====================
228 ModPlug_GetSamplesFloat
229 ====================
230 */
231 static void ModPlug_GetSamplesFloat(channel_t *ch, sfx_t *sfx, int firstsampleframe, int numsampleframes, float *outsamplesfloat)
232 {
233         modplug_stream_perchannel_t* per_ch = (modplug_stream_perchannel_t *)ch->fetcher_data;
234         modplug_stream_persfx_t* per_sfx = (modplug_stream_persfx_t *)sfx->fetcher_data;
235         int newlength, done, ret;
236         int f = sfx->format.width * sfx->format.channels; // bytes per frame
237         short *buf;
238         int i, len;
239
240         // If there's no fetcher structure attached to the channel yet
241         if (per_ch == NULL)
242         {
243                 per_ch = (modplug_stream_perchannel_t *)Mem_Alloc(snd_mempool, sizeof(*per_ch));
244
245                 // Open it with the modplugFile API
246                 per_ch->mf = qModPlug_Load(per_sfx->file, per_sfx->filesize);
247                 if (!per_ch->mf)
248                 {
249                         // we can't call Con_Printf here, not thread safe
250 //                      Con_Printf("error while reading ModPlug stream \"%s\"\n", per_sfx->name);
251                         Mem_Free(per_ch);
252                         return;
253                 }
254
255 #ifndef LINK_TO_LIBMODPLUG
256                 if(qModPlug_SetMasterVolume)
257 #endif
258                         qModPlug_SetMasterVolume(per_ch->mf, 512); // max volume, DP scales down!
259
260                 per_ch->bs = 0;
261
262                 per_ch->buffer_firstframe = 0;
263                 per_ch->buffer_numframes = 0;
264                 ch->fetcher_data = per_ch;
265         }
266
267         // if the request is too large for our buffer, loop...
268         while (numsampleframes * f > (int)sizeof(per_ch->buffer))
269         {
270                 done = sizeof(per_ch->buffer) / f;
271                 ModPlug_GetSamplesFloat(ch, sfx, firstsampleframe, done, outsamplesfloat);
272                 firstsampleframe += done;
273                 numsampleframes -= done;
274                 outsamplesfloat += done * sfx->format.channels;
275         }
276
277         // seek if the request is before the current buffer (loop back)
278         // seek if the request starts beyond the current buffer by at least one frame (channel was zero volume for a while)
279         // do not seek if the request overlaps the buffer end at all (expected behavior)
280         if (per_ch->buffer_firstframe > firstsampleframe || per_ch->buffer_firstframe + per_ch->buffer_numframes < firstsampleframe)
281         {
282                 // we expect to decode forward from here so this will be our new buffer start
283                 per_ch->buffer_firstframe = firstsampleframe;
284                 per_ch->buffer_numframes = 0;
285                 // we don't actually seek - we don't care much about timing on silent mod music streams and looping never happens
286                 //qModPlug_Seek(per_ch->mf, firstsampleframe * 1000.0 / sfx->format.speed);
287         }
288
289         // decompress the file as needed
290         if (firstsampleframe + numsampleframes > per_ch->buffer_firstframe + per_ch->buffer_numframes)
291         {
292                 // first slide the buffer back, discarding any data preceding the range we care about
293                 int offset = firstsampleframe - per_ch->buffer_firstframe;
294                 int keeplength = per_ch->buffer_numframes - offset;
295                 if (keeplength > 0)
296                         memmove(per_ch->buffer, per_ch->buffer + offset * sfx->format.width * sfx->format.channels, keeplength * sfx->format.width * sfx->format.channels);
297                 per_ch->buffer_firstframe = firstsampleframe;
298                 per_ch->buffer_numframes -= offset;
299                 // decompress as much as we can fit in the buffer
300                 newlength = sizeof(per_ch->buffer) - per_ch->buffer_numframes * f;
301                 done = 0;
302                 while (newlength > done && (ret = qModPlug_Read(per_ch->mf, (void *)((unsigned char *)per_ch->buffer + done), (int)(newlength - done))) > 0)
303                         done += ret;
304                 // clear the missing space if any
305                 if (done < newlength)
306                 {
307                         memset(per_ch->buffer + done, 0, newlength - done);
308                         // Argh. We didn't get as many samples as we wanted. Probably
309                         // libmodplug forgot what mLoopCount==-1 means... basically, this means
310                         // we can't loop like this. Try to let DP fix it later...
311                         sfx->total_length = firstsampleframe + done / f;
312                         sfx->loopstart = 0;
313                         // can't Con_Printf from this thread
314                         //if (newlength != done)
315                         //      Con_DPrintf("ModPlug_Fetch: wanted: %d, got: %d\n", newlength, done);
316                 }
317                 // we now have more data in the buffer
318                 per_ch->buffer_numframes += done / f;
319         }
320
321         // convert the sample format for the caller
322         buf = (short *)(per_ch->buffer + (firstsampleframe - per_ch->buffer_firstframe) * f);
323         len = numsampleframes * sfx->format.channels;
324         for (i = 0;i < len;i++)
325                 outsamplesfloat[i] = buf[i] * (1.0f / 32768.0f);
326 }
327
328
329 /*
330 ====================
331 ModPlug_StopChannel
332 ====================
333 */
334 static void ModPlug_StopChannel(channel_t *ch)
335 {
336         modplug_stream_perchannel_t *per_ch = (modplug_stream_perchannel_t *)ch->fetcher_data;
337
338         if (per_ch != NULL)
339         {
340                 // Free the modplug decoder
341                 qModPlug_Unload(per_ch->mf);
342
343                 Mem_Free(per_ch);
344         }
345 }
346
347
348 /*
349 ====================
350 ModPlug_FreeSfx
351 ====================
352 */
353 static void ModPlug_FreeSfx (sfx_t *sfx)
354 {
355         modplug_stream_persfx_t* per_sfx = (modplug_stream_persfx_t *)sfx->fetcher_data;
356
357         // Free the modplug file
358         Mem_Free(per_sfx->file);
359
360         // Free the stream structure
361         Mem_Free(per_sfx);
362 }
363
364
365 static const snd_fetcher_t modplug_fetcher = { ModPlug_GetSamplesFloat, ModPlug_StopChannel, ModPlug_FreeSfx };
366
367
368 /*
369 ====================
370 ModPlug_LoadmodplugFile
371
372 Load an modplug file into memory
373 ====================
374 */
375 qboolean ModPlug_LoadModPlugFile (const char *filename, sfx_t *sfx)
376 {
377         unsigned char *data;
378         fs_offset_t filesize;
379         ModPlugFile *mf;
380         modplug_stream_persfx_t* per_sfx;
381         ModPlug_Settings s;
382
383         if (!modplug_dll)
384                 return false;
385
386         // Already loaded?
387         if (sfx->fetcher != NULL)
388                 return true;
389
390         // Load the file
391         data = FS_LoadFile (filename, snd_mempool, false, &filesize);
392         if (data == NULL)
393                 return false;
394
395         if (developer_loading.integer >= 2)
396                 Con_Printf ("Loading ModPlug file \"%s\"\n", filename);
397
398         qModPlug_GetSettings(&s);
399         s.mFlags = MODPLUG_ENABLE_OVERSAMPLING | MODPLUG_ENABLE_NOISE_REDUCTION | MODPLUG_ENABLE_REVERB;
400         s.mChannels = 2;
401         s.mBits = 16;
402         s.mFrequency = 44100;
403         s.mResamplingMode = MODPLUG_RESAMPLE_SPLINE;
404         s.mLoopCount = -1;
405         qModPlug_SetSettings(&s);
406
407         // Open it with the modplugFile API
408         if (!(mf = qModPlug_Load (data, filesize)))
409         {
410                 Con_Printf ("error while opening ModPlug file \"%s\"\n", filename);
411                 Mem_Free(data);
412                 return false;
413         }
414
415 #ifndef LINK_TO_LIBMODPLUG
416         if(qModPlug_SetMasterVolume)
417 #endif
418                 qModPlug_SetMasterVolume(mf, 512); // max volume, DP scales down!
419
420         if (developer_loading.integer >= 2)
421                 Con_Printf ("\"%s\" will be streamed\n", filename);
422         per_sfx = (modplug_stream_persfx_t *)Mem_Alloc (snd_mempool, sizeof (*per_sfx));
423         per_sfx->file = data;
424         per_sfx->filesize = filesize;
425         sfx->memsize += sizeof(*per_sfx);
426         sfx->memsize += filesize;
427         sfx->format.speed = 44100; // modplug always works at that rate
428         sfx->format.width = 2;  // We always work with 16 bits samples
429         sfx->format.channels = 2; // stereo rulez ;) (MAYBE default to mono because Amiga MODs sound better then?)
430         sfx->fetcher_data = per_sfx;
431         sfx->fetcher = &modplug_fetcher;
432         sfx->flags |= SFXFLAG_STREAMED;
433         sfx->total_length = 1<<30; // 2147384647; // they always loop (FIXME this breaks after 6 hours, we need support for a real "infinite" value!)
434         sfx->loopstart = sfx->total_length; // modplug does it
435
436         return true;
437 }