Modified the sound code so it can handle sounds outside of a "sound" subdirectory.
[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 // snd_mem.c: sound caching
21
22 #include "quakedef.h"
23
24 #include "snd_ogg.h"
25 #include "snd_wav.h"
26
27
28 /*
29 ================
30 ResampleSfx
31 ================
32 */
33 size_t ResampleSfx (const qbyte *in_data, size_t in_length, const snd_format_t* in_format, qbyte *out_data, const char* sfxname)
34 {
35         int samplefrac, fracstep;
36         size_t i, srcsample, srclength, outcount;
37
38         // this is usually 0.5 (128), 1 (256), or 2 (512)
39         fracstep = ((double) in_format->speed / (double) shm->format.speed) * 256.0;
40
41         srclength = in_length * in_format->channels;
42
43         outcount = (double) in_length * (double) shm->format.speed / (double) in_format->speed;
44         Con_DPrintf("ResampleSfx: resampling sound \"%s\" from %dHz to %dHz (%d samples to %d samples)\n",
45                                 sfxname, in_format->speed, shm->format.speed, in_length, outcount);
46
47 // resample / decimate to the current source rate
48
49         if (fracstep == 256)
50         {
51                 // fast case for direct transfer
52                 if (in_format->width == 1) // 8bit
53                         for (i = 0;i < srclength;i++)
54                                 ((signed char *)out_data)[i] = ((unsigned char *)in_data)[i] - 128;
55                 else //if (sb->width == 2) // 16bit
56                         for (i = 0;i < srclength;i++)
57                                 ((short *)out_data)[i] = ((short *)in_data)[i];
58         }
59         else
60         {
61                 // general case
62                 samplefrac = 0;
63                 if ((fracstep & 255) == 0) // skipping points on perfect multiple
64                 {
65                         srcsample = 0;
66                         fracstep >>= 8;
67                         if (in_format->width == 2)
68                         {
69                                 short *out = (short*)out_data;
70                                 const short *in = (const short*)in_data;
71                                 if (in_format->channels == 2) // LordHavoc: stereo sound support
72                                 {
73                                         fracstep <<= 1;
74                                         for (i=0 ; i<outcount ; i++)
75                                         {
76                                                 *out++ = in[srcsample  ];
77                                                 *out++ = in[srcsample+1];
78                                                 srcsample += fracstep;
79                                         }
80                                 }
81                                 else
82                                 {
83                                         for (i=0 ; i<outcount ; i++)
84                                         {
85                                                 *out++ = in[srcsample];
86                                                 srcsample += fracstep;
87                                         }
88                                 }
89                         }
90                         else
91                         {
92                                 signed char *out = out_data;
93                                 const unsigned char *in = in_data;
94                                 if (in_format->channels == 2)
95                                 {
96                                         fracstep <<= 1;
97                                         for (i=0 ; i<outcount ; i++)
98                                         {
99                                                 *out++ = in[srcsample  ] - 128;
100                                                 *out++ = in[srcsample+1] - 128;
101                                                 srcsample += fracstep;
102                                         }
103                                 }
104                                 else
105                                 {
106                                         for (i=0 ; i<outcount ; i++)
107                                         {
108                                                 *out++ = in[srcsample  ] - 128;
109                                                 srcsample += fracstep;
110                                         }
111                                 }
112                         }
113                 }
114                 else
115                 {
116                         int sample;
117                         int a, b;
118                         if (in_format->width == 2)
119                         {
120                                 short *out = (short*)out_data;
121                                 const short *in = (const short*)in_data;
122                                 if (in_format->channels == 2)
123                                 {
124                                         for (i=0 ; i<outcount ; i++)
125                                         {
126                                                 srcsample = (samplefrac >> 8) << 1;
127                                                 a = in[srcsample  ];
128                                                 if (srcsample+2 >= srclength)
129                                                         b = 0;
130                                                 else
131                                                         b = in[srcsample+2];
132                                                 sample = (((b - a) * (samplefrac & 255)) >> 8) + a;
133                                                 *out++ = (short) sample;
134                                                 a = in[srcsample+1];
135                                                 if (srcsample+2 >= srclength)
136                                                         b = 0;
137                                                 else
138                                                         b = in[srcsample+3];
139                                                 sample = (((b - a) * (samplefrac & 255)) >> 8) + a;
140                                                 *out++ = (short) sample;
141                                                 samplefrac += fracstep;
142                                         }
143                                 }
144                                 else
145                                 {
146                                         for (i=0 ; i<outcount ; i++)
147                                         {
148                                                 srcsample = samplefrac >> 8;
149                                                 a = in[srcsample  ];
150                                                 if (srcsample+1 >= srclength)
151                                                         b = 0;
152                                                 else
153                                                         b = in[srcsample+1];
154                                                 sample = (((b - a) * (samplefrac & 255)) >> 8) + a;
155                                                 *out++ = (short) sample;
156                                                 samplefrac += fracstep;
157                                         }
158                                 }
159                         }
160                         else
161                         {
162                                 signed char *out = out_data;
163                                 const unsigned char *in = in_data;
164                                 if (in_format->channels == 2)
165                                 {
166                                         for (i=0 ; i<outcount ; i++)
167                                         {
168                                                 srcsample = (samplefrac >> 8) << 1;
169                                                 a = (int) in[srcsample  ] - 128;
170                                                 if (srcsample+2 >= srclength)
171                                                         b = 0;
172                                                 else
173                                                         b = (int) in[srcsample+2] - 128;
174                                                 sample = (((b - a) * (samplefrac & 255)) >> 8) + a;
175                                                 *out++ = (signed char) sample;
176                                                 a = (int) in[srcsample+1] - 128;
177                                                 if (srcsample+2 >= srclength)
178                                                         b = 0;
179                                                 else
180                                                         b = (int) in[srcsample+3] - 128;
181                                                 sample = (((b - a) * (samplefrac & 255)) >> 8) + a;
182                                                 *out++ = (signed char) sample;
183                                                 samplefrac += fracstep;
184                                         }
185                                 }
186                                 else
187                                 {
188                                         for (i=0 ; i<outcount ; i++)
189                                         {
190                                                 srcsample = samplefrac >> 8;
191                                                 a = (int) in[srcsample  ] - 128;
192                                                 if (srcsample+1 >= srclength)
193                                                         b = 0;
194                                                 else
195                                                         b = (int) in[srcsample+1] - 128;
196                                                 sample = (((b - a) * (samplefrac & 255)) >> 8) + a;
197                                                 *out++ = (signed char) sample;
198                                                 samplefrac += fracstep;
199                                         }
200                                 }
201                         }
202                 }
203         }
204
205         return outcount;
206 }
207
208 //=============================================================================
209
210 /*
211 ==============
212 S_LoadSound
213 ==============
214 */
215 qboolean S_LoadSound (sfx_t *s, qboolean complain)
216 {
217         char namebuffer[MAX_QPATH];
218         size_t len;
219         qboolean modified_name = false;
220
221         // see if still in memory
222         if (!shm || !shm->format.speed)
223                 return false;
224         if (s->fetcher != NULL)
225         {
226                 if (s->format.speed != shm->format.speed)
227                         Sys_Error ("S_LoadSound: sound %s hasn't been resampled (%uHz instead of %uHz)", s->name);
228                 return true;
229         }
230
231         len = strlcpy (namebuffer, s->name, sizeof (namebuffer));
232         if (len >= sizeof (namebuffer))
233                 return false;
234
235         // Try to load it as a WAV file
236         if (S_LoadWavFile (namebuffer, s))
237                 return true;
238
239         // Else, try to load it as an Ogg Vorbis file
240         if (!strcasecmp (namebuffer + len - 4, ".wav"))
241         {
242                 strcpy (namebuffer + len - 3, "ogg");
243                 modified_name = true;
244         }
245         if (OGG_LoadVorbisFile (namebuffer, s))
246                 return true;
247
248         // Can't load the sound!
249         if (!complain)
250                 s->flags |= SFXFLAG_SILENTLYMISSING;
251         else
252                 s->flags &= ~SFXFLAG_SILENTLYMISSING;
253         if (complain)
254         {
255                 if (modified_name)
256                         strcpy (namebuffer + len - 3, "wav");
257                 Con_Printf("Couldn't load %s\n", namebuffer);
258         }
259         return false;
260 }
261
262 void S_UnloadSound(sfx_t *s)
263 {
264         if (s->fetcher != NULL)
265         {
266                 unsigned int i;
267
268                 s->fetcher = NULL;
269                 s->fetcher_data = NULL;
270                 Mem_FreePool(&s->mempool);
271
272                 // At this point, some per-channel data pointers may point to freed zones.
273                 // Practically, it shouldn't be a problem; but it's wrong, so we fix that
274                 for (i = 0; i < total_channels ; i++)
275                         if (channels[i].sfx == s)
276                                 channels[i].fetcher_data = NULL;
277         }
278 }