]> icculus.org git repositories - divverent/darkplaces.git/blob - snd_mem.c
changed R_TimeReport to call glFinish to improve the accuracy of the reports on each...
[divverent/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
28
29 /*
30 ================
31 ResampleSfx
32 ================
33 */
34 size_t ResampleSfx (const qbyte *in_data, size_t in_length, const snd_format_t* in_format, qbyte *out_data, const char* sfxname)
35 {
36         size_t srclength, outcount, i;
37
38         srclength = in_length * in_format->channels;
39         outcount = (double)in_length * shm->format.speed / in_format->speed;
40
41         //Con_DPrintf("ResampleSfx(%s): %d samples @ %dHz -> %d samples @ %dHz\n",
42         //                      sfxname, in_length, in_format->speed, outcount, shm->format.speed);
43
44         // Trivial case (direct transfer)
45         if (in_format->speed == shm->format.speed)
46         {
47                 if (in_format->width == 1)
48                 {
49                         for (i = 0; i < srclength; i++)
50                                 ((signed char*)out_data)[i] = in_data[i] - 128;
51                 }
52                 else  // if (in_format->width == 2)
53                         memcpy (out_data, in_data, srclength * in_format->width);
54         }
55
56         // General case (linear interpolation with a fixed-point fractional
57         // step, 18-bit integer part and 14-bit fractional part)
58         // Can handle up to 2^18 (262144) samples per second (> 96KHz stereo)
59 #       define FRACTIONAL_BITS 14
60 #       define FRACTIONAL_MASK ((1 << FRACTIONAL_BITS) - 1)
61 #       define INTEGER_BITS (sizeof(samplefrac)*8 - FRACTIONAL_BITS)
62         else
63         {
64                 const unsigned int fracstep = (double)in_format->speed / shm->format.speed * (1 << FRACTIONAL_BITS);
65                 size_t remain_in = srclength, total_out = 0;
66                 unsigned int samplefrac;
67                 const qbyte *in_ptr = in_data;
68                 qbyte *out_ptr = out_data;
69
70                 // Check that we can handle one second of that sound
71                 if (in_format->speed * in_format->channels > (1 << INTEGER_BITS))
72                 {
73                         Con_Printf ("ResampleSfx: sound quality too high for resampling (%uHz, %u channel(s))",
74                                            in_format->speed, in_format->channels);
75                         return 0;
76                 }
77
78                 // We work 1 sec at a time to make sure we don't accumulate any
79                 // significant error when adding "fracstep" over several seconds, and
80                 // also to be able to handle very long sounds.
81                 while (total_out < outcount)
82                 {
83                         size_t tmpcount;
84
85                         samplefrac = 0;
86
87                         // If more than 1 sec of sound remains to be converted
88                         if (outcount - total_out > shm->format.speed)
89                                 tmpcount = shm->format.speed;
90                         else
91                                 tmpcount = outcount - total_out;
92
93                         // Convert up to 1 sec of sound
94                         for (i = 0; i < tmpcount; i++)
95                         {
96                                 unsigned int j = 0;
97                                 unsigned int srcsample = (samplefrac >> FRACTIONAL_BITS) * in_format->channels;
98                                 int a, b;
99
100                                 // 16 bit samples
101                                 if (in_format->width == 2)
102                                 {
103                                         for (j = 0; j < in_format->channels; j++, srcsample++)
104                                         {
105                                                 // No value to interpolate with?
106                                                 if (srcsample + in_format->channels < remain_in)
107                                                 {
108                                                         a = ((const short*)in_ptr)[srcsample];
109                                                         b = ((const short*)in_ptr)[srcsample + in_format->channels];
110                                                         *((short*)out_ptr) = (((b - a) * (samplefrac & FRACTIONAL_MASK)) >> FRACTIONAL_BITS) + a;
111                                                 }
112                                                 else
113                                                         *((short*)out_ptr) = ((const short*)in_ptr)[srcsample];
114
115                                                 out_ptr += sizeof (short);
116                                         }
117                                 }
118                                 // 8 bit samples
119                                 else  // if (in_format->width == 1)
120                                 {
121                                         for (j = 0; j < in_format->channels; j++, srcsample++)
122                                         {
123                                                 // No more value to interpolate with?
124                                                 if (srcsample + in_format->channels < remain_in)
125                                                 {
126                                                         a = ((const qbyte*)in_ptr)[srcsample] - 128;
127                                                         b = ((const qbyte*)in_ptr)[srcsample + in_format->channels] - 128;
128                                                         *((signed char*)out_ptr) = (((b - a) * (samplefrac & FRACTIONAL_MASK)) >> FRACTIONAL_BITS) + a;
129                                                 }
130                                                 else
131                                                         *((signed char*)out_ptr) = ((const qbyte*)in_ptr)[srcsample] - 128;
132
133                                                 out_ptr += sizeof (signed char);
134                                         }
135                                 }
136
137                                 samplefrac += fracstep;
138                         }
139
140                         // Update the counters and the buffer position
141                         remain_in -= in_format->speed * in_format->channels;
142                         in_ptr += in_format->speed * in_format->channels * in_format->width;
143                         total_out += tmpcount;
144                 }
145         }
146
147         return outcount;
148 }
149
150 //=============================================================================
151
152 /*
153 ==============
154 S_LoadSound
155 ==============
156 */
157 qboolean S_LoadSound (sfx_t *s, qboolean complain)
158 {
159         char namebuffer[MAX_QPATH + 16];
160         size_t len;
161
162         if (!shm || !shm->format.speed)
163                 return false;
164
165         // If we weren't able to load it previously, no need to retry
166         if (s->flags & SFXFLAG_FILEMISSING)
167                 return false;
168
169         // See if in memory
170         if (s->fetcher != NULL)
171         {
172                 if (s->format.speed != shm->format.speed)
173                         Con_Printf ("S_LoadSound: sound %s hasn't been resampled (%uHz instead of %uHz)", s->name);
174                 return true;
175         }
176
177         // LordHavoc: if the sound filename does not begin with sound/, try adding it
178         if (strncasecmp(s->name, "sound/", 6))
179         {
180                 len = dpsnprintf (namebuffer, sizeof(namebuffer), "sound/%s", s->name);
181                 if (len < 0)
182                 {
183                         // name too long
184                         Con_Printf("S_LoadSound: name \"%s\" is too long\n", s->name);
185                         return false;
186                 }
187                 if (S_LoadWavFile (namebuffer, s))
188                         return true;
189                 if (len >= 4 && !strcasecmp (namebuffer + len - 4, ".wav"))
190                         strcpy (namebuffer + len - 3, "ogg");
191                 if (OGG_LoadVorbisFile (namebuffer, s))
192                         return true;
193         }
194
195         // LordHavoc: then try without the added sound/ as wav and ogg
196         len = dpsnprintf (namebuffer, sizeof(namebuffer), "%s", s->name);
197         if (len < 0)
198         {
199                 // name too long
200                 Con_Printf("S_LoadSound: name \"%s\" is too long\n", s->name);
201                 return false;
202         }
203         if (S_LoadWavFile (namebuffer, s))
204                 return true;
205         if (len >= 4 && !strcasecmp (namebuffer + len - 4, ".wav"))
206                 strcpy (namebuffer + len - 3, "ogg");
207         if (OGG_LoadVorbisFile (namebuffer, s))
208                 return true;
209
210         // Can't load the sound!
211         s->flags |= SFXFLAG_FILEMISSING;
212         if (complain)
213                 Con_Printf("S_LoadSound: Couldn't load \"%s\"\n", s->name);
214         return false;
215 }
216
217 void S_UnloadSound (sfx_t *s)
218 {
219         if (s->fetcher != NULL)
220         {
221                 unsigned int i;
222
223                 // Stop all channels that use this sound
224                 for (i = 0; i < total_channels ; i++)
225                         if (channels[i].sfx == s)
226                                 S_StopChannel (i);
227
228                 s->fetcher = NULL;
229                 s->fetcher_data = NULL;
230                 Mem_FreePool(&s->mempool);
231         }
232 }