]> git.xonotic.org Git - xonotic/darkplaces.git/blob - snd_mem.c
changed now showfps calculates the fps - hopefully an improvement
[xonotic/darkplaces.git] / snd_mem.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
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 the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20
21
22 #include "quakedef.h"
23
24 #include "snd_main.h"
25 #include "snd_ogg.h"
26 #include "snd_wav.h"
27 #include "snd_modplug.h"
28
29
30 /*
31 ====================
32 Snd_CreateRingBuffer
33
34 If "buffer" is NULL, the function allocates one buffer of "sampleframes" sample frames itself
35 (if "sampleframes" is 0, the function chooses the size).
36 ====================
37 */
38 snd_ringbuffer_t *Snd_CreateRingBuffer (const snd_format_t* format, unsigned int sampleframes, void* buffer)
39 {
40         snd_ringbuffer_t *ringbuffer;
41
42         // If the caller provides a buffer, it must give us its size
43         if (sampleframes == 0 && buffer != NULL)
44                 return NULL;
45
46         ringbuffer = (snd_ringbuffer_t*)Mem_Alloc(snd_mempool, sizeof (*ringbuffer));
47         memset(ringbuffer, 0, sizeof(*ringbuffer));
48         memcpy(&ringbuffer->format, format, sizeof(ringbuffer->format));
49
50         // If we haven't been given a buffer
51         if (buffer == NULL)
52         {
53                 unsigned int maxframes;
54                 size_t memsize;
55
56                 if (sampleframes == 0)
57                         maxframes = (format->speed + 1) / 2;  // Make the sound buffer large enough for containing 0.5 sec of sound
58                 else
59                         maxframes = sampleframes;
60
61                 memsize = maxframes * format->width * format->channels;
62                 ringbuffer->ring = Mem_Alloc(snd_mempool, memsize);
63                 ringbuffer->maxframes = maxframes;
64         }
65         else
66         {
67                 ringbuffer->ring = buffer;
68                 ringbuffer->maxframes = sampleframes;
69         }
70
71         return ringbuffer;
72 }
73
74
75 /*
76 ====================
77 Snd_CreateSndBuffer
78 ====================
79 */
80 snd_buffer_t *Snd_CreateSndBuffer (const unsigned char *samples, unsigned int sampleframes, const snd_format_t* in_format, unsigned int sb_speed)
81 {
82         size_t newsampleframes, memsize;
83         snd_buffer_t* sb;
84
85         newsampleframes = (double)sampleframes * (double)sb_speed / (double)in_format->speed;
86
87         memsize = newsampleframes * in_format->channels * in_format->width;
88         memsize += sizeof (*sb) - sizeof (sb->samples);
89
90         sb = (snd_buffer_t*)Mem_Alloc (snd_mempool, memsize);
91         sb->format.channels = in_format->channels;
92         sb->format.width = in_format->width;
93         sb->format.speed = sb_speed;
94         sb->maxframes = newsampleframes;
95         sb->nbframes = 0;
96
97         if (!Snd_AppendToSndBuffer (sb, samples, sampleframes, in_format))
98         {
99                 Mem_Free (sb);
100                 return NULL;
101         }
102
103         return sb;
104 }
105
106
107 /*
108 ====================
109 Snd_AppendToSndBuffer
110 ====================
111 */
112 qboolean Snd_AppendToSndBuffer (snd_buffer_t* sb, const unsigned char *samples, unsigned int sampleframes, const snd_format_t* format)
113 {
114         size_t srclength, outcount;
115         unsigned char *out_data;
116
117         //Con_DPrintf("ResampleSfx: %d samples @ %dHz -> %d samples @ %dHz\n",
118         //                      sampleframes, format->speed, outcount, sb->format.speed);
119
120         // If the formats are incompatible
121         if (sb->format.channels != format->channels || sb->format.width != format->width)
122         {
123                 Con_Print("AppendToSndBuffer: incompatible sound formats!\n");
124                 return false;
125         }
126
127         outcount = (double)sampleframes * (double)sb->format.speed / (double)format->speed;
128
129         // If the sound buffer is too short
130         if (outcount > sb->maxframes - sb->nbframes)
131         {
132                 Con_Print("AppendToSndBuffer: sound buffer too short!\n");
133                 return false;
134         }
135
136         out_data = &sb->samples[sb->nbframes * sb->format.width * sb->format.channels];
137         srclength = sampleframes * format->channels;
138
139         // Trivial case (direct transfer)
140         if (format->speed == sb->format.speed)
141         {
142                 if (format->width == 1)
143                 {
144                         size_t i;
145
146                         for (i = 0; i < srclength; i++)
147                                 ((signed char*)out_data)[i] = samples[i] - 128;
148                 }
149                 else  // if (format->width == 2)
150                         memcpy (out_data, samples, srclength * format->width);
151         }
152
153         // General case (linear interpolation with a fixed-point fractional
154         // step, 18-bit integer part and 14-bit fractional part)
155         // Can handle up to 2^18 (262144) samples per second (> 96KHz stereo)
156 #       define FRACTIONAL_BITS 14
157 #       define FRACTIONAL_MASK ((1 << FRACTIONAL_BITS) - 1)
158 #       define INTEGER_BITS (sizeof(samplefrac)*8 - FRACTIONAL_BITS)
159         else
160         {
161                 const unsigned int fracstep = (unsigned int)((double)format->speed / sb->format.speed * (1 << FRACTIONAL_BITS));
162                 size_t remain_in = srclength, total_out = 0;
163                 unsigned int samplefrac;
164                 const unsigned char *in_ptr = samples;
165                 unsigned char *out_ptr = out_data;
166
167                 // Check that we can handle one second of that sound
168                 if (format->speed * format->channels > (1 << INTEGER_BITS))
169                 {
170                         Con_Printf ("ResampleSfx: sound quality too high for resampling (%uHz, %u channel(s))\n",
171                                            format->speed, format->channels);
172                         return 0;
173                 }
174
175                 // We work 1 sec at a time to make sure we don't accumulate any
176                 // significant error when adding "fracstep" over several seconds, and
177                 // also to be able to handle very long sounds.
178                 while (total_out < outcount)
179                 {
180                         size_t tmpcount, interpolation_limit, i, j;
181                         unsigned int srcsample;
182
183                         samplefrac = 0;
184
185                         // If more than 1 sec of sound remains to be converted
186                         if (outcount - total_out > sb->format.speed)
187                         {
188                                 tmpcount = sb->format.speed;
189                                 interpolation_limit = tmpcount;  // all samples can be interpolated
190                         }
191                         else
192                         {
193                                 tmpcount = outcount - total_out;
194                                 interpolation_limit = (int)ceil((double)(((remain_in / format->channels) - 1) << FRACTIONAL_BITS) / fracstep);
195                                 if (interpolation_limit > tmpcount)
196                                         interpolation_limit = tmpcount;
197                         }
198
199                         // 16 bit samples
200                         if (format->width == 2)
201                         {
202                                 const short* in_ptr_short;
203
204                                 // Interpolated part
205                                 for (i = 0; i < interpolation_limit; i++)
206                                 {
207                                         srcsample = (samplefrac >> FRACTIONAL_BITS) * format->channels;
208                                         in_ptr_short = &((const short*)in_ptr)[srcsample];
209
210                                         for (j = 0; j < format->channels; j++)
211                                         {
212                                                 int a, b;
213
214                                                 a = *in_ptr_short;
215                                                 b = *(in_ptr_short + format->channels);
216                                                 *((short*)out_ptr) = (((b - a) * (samplefrac & FRACTIONAL_MASK)) >> FRACTIONAL_BITS) + a;
217
218                                                 in_ptr_short++;
219                                                 out_ptr += sizeof (short);
220                                         }
221
222                                         samplefrac += fracstep;
223                                 }
224
225                                 // Non-interpolated part
226                                 for (/* nothing */; i < tmpcount; i++)
227                                 {
228                                         srcsample = (samplefrac >> FRACTIONAL_BITS) * format->channels;
229                                         in_ptr_short = &((const short*)in_ptr)[srcsample];
230
231                                         for (j = 0; j < format->channels; j++)
232                                         {
233                                                 *((short*)out_ptr) = *in_ptr_short;
234
235                                                 in_ptr_short++;
236                                                 out_ptr += sizeof (short);
237                                         }
238
239                                         samplefrac += fracstep;
240                                 }
241                         }
242                         // 8 bit samples
243                         else  // if (format->width == 1)
244                         {
245                                 const unsigned char* in_ptr_byte;
246
247                                 // Convert up to 1 sec of sound
248                                 for (i = 0; i < interpolation_limit; i++)
249                                 {
250                                         srcsample = (samplefrac >> FRACTIONAL_BITS) * format->channels;
251                                         in_ptr_byte = &((const unsigned char*)in_ptr)[srcsample];
252
253                                         for (j = 0; j < format->channels; j++)
254                                         {
255                                                 int a, b;
256
257                                                 a = *in_ptr_byte - 128;
258                                                 b = *(in_ptr_byte + format->channels) - 128;
259                                                 *((signed char*)out_ptr) = (((b - a) * (samplefrac & FRACTIONAL_MASK)) >> FRACTIONAL_BITS) + a;
260
261                                                 in_ptr_byte++;
262                                                 out_ptr += sizeof (signed char);
263                                         }
264
265                                         samplefrac += fracstep;
266                                 }
267
268                                 // Non-interpolated part
269                                 for (/* nothing */; i < tmpcount; i++)
270                                 {
271                                         srcsample = (samplefrac >> FRACTIONAL_BITS) * format->channels;
272                                         in_ptr_byte = &((const unsigned char*)in_ptr)[srcsample];
273
274                                         for (j = 0; j < format->channels; j++)
275                                         {
276                                                 *((signed char*)out_ptr) = *in_ptr_byte - 128;
277
278                                                 in_ptr_byte++;
279                                                 out_ptr += sizeof (signed char);
280                                         }
281
282                                         samplefrac += fracstep;
283                                 }
284                         }
285
286                         // Update the counters and the buffer position
287                         remain_in -= format->speed * format->channels;
288                         in_ptr += format->speed * format->channels * format->width;
289                         total_out += tmpcount;
290                 }
291         }
292
293         sb->nbframes += outcount;
294         return true;
295 }
296
297
298 //=============================================================================
299
300 /*
301 ==============
302 S_LoadSound
303 ==============
304 */
305 qboolean S_LoadSound (sfx_t *sfx, qboolean complain)
306 {
307         char namebuffer[MAX_QPATH + 16];
308         size_t len;
309
310         // See if already loaded
311         if (sfx->fetcher != NULL)
312                 return true;
313
314         // If we weren't able to load it previously, no need to retry
315         // Note: S_PrecacheSound clears this flag to cause a retry
316         if (sfx->flags & SFXFLAG_FILEMISSING)
317                 return false;
318
319         // No sound?
320         if (snd_renderbuffer == NULL)
321                 return false;
322
323         // Initialize volume peak to 0; if ReplayGain is supported, the loader will change this away
324         sfx->volume_peak = 0.0;
325
326         if (developer_loading.integer)
327                 Con_Printf("loading sound %s\n", sfx->name);
328
329         // LordHavoc: if the sound filename does not begin with sound/, try adding it
330         if (strncasecmp(sfx->name, "sound/", 6))
331         {
332                 dpsnprintf (namebuffer, sizeof(namebuffer), "sound/%s", sfx->name);
333                 len = strlen(namebuffer);
334                 if (len >= 4 && !strcasecmp (namebuffer + len - 4, ".wav"))
335                 {
336                         if (S_LoadWavFile (namebuffer, sfx))
337                                 return true;
338                         memcpy (namebuffer + len - 3, "ogg", 4);
339                 }
340                 if (len >= 4 && !strcasecmp (namebuffer + len - 4, ".ogg"))
341                 {
342                         if (OGG_LoadVorbisFile (namebuffer, sfx))
343                                 return true;
344                 }
345                 else
346                 {
347                         if (ModPlug_LoadModPlugFile (namebuffer, sfx))
348                                 return true;
349                 }
350         }
351
352         // LordHavoc: then try without the added sound/ as wav and ogg
353         dpsnprintf (namebuffer, sizeof(namebuffer), "%s", sfx->name);
354         len = strlen(namebuffer);
355         // request foo.wav: tries foo.wav, then foo.ogg
356         // request foo.ogg: tries foo.ogg only
357         // request foo.mod: tries foo.mod only
358         if (len >= 4 && !strcasecmp (namebuffer + len - 4, ".wav"))
359         {
360                 if (S_LoadWavFile (namebuffer, sfx))
361                         return true;
362                 memcpy (namebuffer + len - 3, "ogg", 4);
363         }
364         if (len >= 4 && !strcasecmp (namebuffer + len - 4, ".ogg"))
365         {
366                 if (OGG_LoadVorbisFile (namebuffer, sfx))
367                         return true;
368         }
369         else
370         {
371                 if (ModPlug_LoadModPlugFile (namebuffer, sfx))
372                         return true;
373         }
374
375         // Can't load the sound!
376         sfx->flags |= SFXFLAG_FILEMISSING;
377         if (complain)
378                 Con_DPrintf("failed to load sound \"%s\"\n", sfx->name);
379         return false;
380 }