1 /*
2 ===========================================================================
3 Copyright (C) 1999 - 2005, Id Software, Inc.
4 Copyright (C) 2000 - 2013, Raven Software, Inc.
5 Copyright (C) 2001 - 2013, Activision, Inc.
6 Copyright (C) 2013 - 2015, OpenJK contributors
7 
8 This file is part of the OpenJK source code.
9 
10 OpenJK is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License version 2 as
12 published by the Free Software Foundation.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 ===========================================================================
22 */
23 
24 // snd_mem.c: sound caching
25 #include "../server/exe_headers.h"
26 
27 #include "snd_local.h"
28 #include "cl_mp3.h"
29 
30 #include <string>
31 
32 #ifdef USE_OPENAL
33 // Open AL
34 void S_PreProcessLipSync(sfx_t *sfx);
35 extern int s_UseOpenAL;
36 #endif
37 /*
38 ===============================================================================
39 
40 WAV loading
41 
42 ===============================================================================
43 */
44 
45 byte	*data_p;
46 byte 	*iff_end;
47 byte 	*last_chunk;
48 byte 	*iff_data;
49 int 	iff_chunk_len;
50 extern sfx_t		s_knownSfx[];
51 extern	int			s_numSfx;
52 
53 extern cvar_t		*s_lip_threshold_1;
54 extern cvar_t		*s_lip_threshold_2;
55 extern cvar_t		*s_lip_threshold_3;
56 extern cvar_t		*s_lip_threshold_4;
57 
GetLittleShort(void)58 short GetLittleShort(void)
59 {
60 	short val = 0;
61 	val = *data_p;
62 	val = (short)(val + (*(data_p+1)<<8));
63 	data_p += 2;
64 	return val;
65 }
66 
GetLittleLong(void)67 int GetLittleLong(void)
68 {
69 	int val = 0;
70 	val = *data_p;
71 	val = val + (*(data_p+1)<<8);
72 	val = val + (*(data_p+2)<<16);
73 	val = val + (*(data_p+3)<<24);
74 	data_p += 4;
75 	return val;
76 }
77 
FindNextChunk(const char * name)78 void FindNextChunk(const char *name)
79 {
80 	while (1)
81 	{
82 		data_p=last_chunk;
83 
84 		if (data_p >= iff_end)
85 		{	// didn't find the chunk
86 			data_p = NULL;
87 			return;
88 		}
89 
90 		data_p += 4;
91 		iff_chunk_len = GetLittleLong();
92 		if (iff_chunk_len < 0)
93 		{
94 			data_p = NULL;
95 			return;
96 		}
97 		data_p -= 8;
98 		last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
99 		if (!strncmp((char *)data_p, name, 4))
100 			return;
101 	}
102 }
103 
FindChunk(const char * name)104 void FindChunk(const char *name)
105 {
106 	last_chunk = iff_data;
107 	FindNextChunk (name);
108 }
109 
110 
DumpChunks(void)111 void DumpChunks(void)
112 {
113 	char	str[5];
114 
115 	str[4] = 0;
116 	data_p=iff_data;
117 	do
118 	{
119 		memcpy (str, data_p, 4);
120 		data_p += 4;
121 		iff_chunk_len = GetLittleLong();
122 		Com_Printf ("0x%x : %s (%d)\n", (intptr_t)(data_p - 4), str, iff_chunk_len);
123 		data_p += (iff_chunk_len + 1) & ~1;
124 	} while (data_p < iff_end);
125 }
126 
127 /*
128 ============
129 GetWavinfo
130 ============
131 */
GetWavinfo(const char * name,byte * wav,int wavlength)132 wavinfo_t GetWavinfo (const char *name, byte *wav, int wavlength)
133 {
134 	wavinfo_t	info;
135 	int		samples;
136 
137 	memset (&info, 0, sizeof(info));
138 
139 	if (!wav)
140 		return info;
141 
142 	iff_data = wav;
143 	iff_end = wav + wavlength;
144 
145 // find "RIFF" chunk
146 	FindChunk("RIFF");
147 	if (!(data_p && !strncmp((char *)data_p+8, "WAVE", 4)))
148 	{
149 		Com_Printf("Missing RIFF/WAVE chunks\n");
150 		return info;
151 	}
152 
153 // get "fmt " chunk
154 	iff_data = data_p + 12;
155 // DumpChunks ();
156 
157 	FindChunk("fmt ");
158 	if (!data_p)
159 	{
160 		Com_Printf("Missing fmt chunk\n");
161 		return info;
162 	}
163 	data_p += 8;
164 	info.format = GetLittleShort();
165 	info.channels = GetLittleShort();
166 	info.rate = GetLittleLong();
167 	data_p += 4+2;
168 	info.width = GetLittleShort() / 8;
169 
170 	if (info.format != 1)
171 	{
172 		Com_Printf("Microsoft PCM format only\n");
173 		return info;
174 	}
175 
176 
177 // find data chunk
178 	FindChunk("data");
179 	if (!data_p)
180 	{
181 		Com_Printf("Missing data chunk\n");
182 		return info;
183 	}
184 
185 	data_p += 4;
186 	samples = GetLittleLong () / info.width;
187 
188 	if (info.samples)
189 	{
190 		if (samples < info.samples)
191 			Com_Error (ERR_DROP, "Sound %s has a bad loop length", name);
192 	}
193 	else
194 		info.samples = samples;
195 
196 	info.dataofs = data_p - wav;
197 
198 
199 	return info;
200 }
201 
202 
203 /*
204 ================
205 ResampleSfx
206 
207 resample / decimate to the current source rate
208 ================
209 */
ResampleSfx(sfx_t * sfx,int iInRate,int iInWidth,byte * pData)210 void ResampleSfx (sfx_t *sfx, int iInRate, int iInWidth, byte *pData)
211 {
212 	int		iOutCount;
213 	int		iSrcSample;
214 	float	fStepScale;
215 	int		i;
216 	int		iSample;
217 	unsigned int uiSampleFrac, uiFracStep;	// uiSampleFrac MUST be unsigned, or large samples (eg music tracks) crash
218 
219 	fStepScale = (float)iInRate / dma.speed;	// this is usually 0.5, 1, or 2
220 
221 	// When stepscale is > 1 (we're downsampling), we really ought to run a low pass filter on the samples
222 
223 	iOutCount = (int)(sfx->iSoundLengthInSamples / fStepScale);
224 	sfx->iSoundLengthInSamples = iOutCount;
225 
226 	sfx->pSoundData = (short *) SND_malloc( sfx->iSoundLengthInSamples*2 ,sfx );
227 
228 	sfx->fVolRange	= 0;
229 	uiSampleFrac	= 0;
230 	uiFracStep		= (int)(fStepScale*256);
231 
232 	for (i=0 ; i<sfx->iSoundLengthInSamples ; i++)
233 	{
234 		iSrcSample = uiSampleFrac >> 8;
235 		uiSampleFrac += uiFracStep;
236 		if (iInWidth == 2) {
237 			iSample = LittleShort ( ((short *)pData)[iSrcSample] );
238 		} else {
239 			iSample = (int)( (unsigned char)(pData[iSrcSample]) - 128) << 8;
240 		}
241 
242 		sfx->pSoundData[i] = (short)iSample;
243 
244 		// work out max vol for this sample...
245 		//
246 		if (iSample < 0)
247 			iSample = -iSample;
248 		if (sfx->fVolRange < (iSample >> 8) )
249 		{
250 			sfx->fVolRange =  iSample >> 8;
251 		}
252 	}
253 }
254 
255 
256 //=============================================================================
257 
258 
S_LoadSound_Finalize(wavinfo_t * info,sfx_t * sfx,byte * data)259 void S_LoadSound_Finalize(wavinfo_t	*info, sfx_t *sfx, byte *data)
260 {
261 	float	stepscale	= (float)info->rate / dma.speed;
262 	int		len			= (int)(info->samples / stepscale);
263 
264 	len *= info->width;
265 
266 	sfx->eSoundCompressionMethod = ct_16;
267 	sfx->iSoundLengthInSamples	 = info->samples;
268 	ResampleSfx( sfx, info->rate, info->width, data + info->dataofs );
269 }
270 
271 
272 
273 
274 
275 // maybe I'm re-inventing the wheel, here, but I can't see any functions that already do this, so...
276 //
Filename_WithoutPath(const char * psFilename)277 char *Filename_WithoutPath(const char *psFilename)
278 {
279 	static char sString[MAX_QPATH];	// !!
280 	const char *p = strrchr(psFilename,'\\');
281 
282   	if (!p++)
283 		p=psFilename;
284 
285 	strcpy(sString,p);
286 
287 	return sString;
288 
289 }
290 
291 // returns (eg) "\dir\name" for "\dir\name.bmp"
292 //
Filename_WithoutExt(const char * psFilename)293 char *Filename_WithoutExt(const char *psFilename)
294 {
295 	static char sString[MAX_QPATH];	// !
296 
297 	strcpy(sString,psFilename);
298 
299 	char *p = strrchr(sString,'.');
300 	char *p2= strrchr(sString,'\\');
301 
302 	// special check, make sure the first suffix we found from the end wasn't just a directory suffix (eg on a path'd filename with no extension anyway)
303 	//
304 	if (p && (p2==0 || (p2 && p>p2)))
305 		*p=0;
306 
307 	return sString;
308 
309 }
310 
311 
312 
313 int iFilesFound;
314 int iFilesUpdated;
315 int iErrors;
316 qboolean qbForceRescan;
317 qboolean qbForceStereo;
318 std::string strErrors;
319 
R_CheckMP3s(const char * psDir)320 void R_CheckMP3s( const char *psDir )
321 {
322 //	Com_Printf(va("Scanning Dir: %s\n",psDir));
323 	Com_Printf(".");	// stops useful info scrolling off screen
324 
325 	char	**sysFiles, **dirFiles;
326 	int		numSysFiles, i, numdirs;
327 
328 	dirFiles = FS_ListFiles( psDir, "/", &numdirs);
329 	if (numdirs > 2)
330 	{
331 		for (i=2;i<numdirs;i++)
332 		{
333 			char	sDirName[MAX_QPATH];
334 			sprintf(sDirName, "%s\\%s", psDir, dirFiles[i]);
335 			R_CheckMP3s(sDirName);
336 		}
337 	}
338 
339 	sysFiles = FS_ListFiles( psDir, ".mp3", &numSysFiles );
340 	for(i=0; i<numSysFiles; i++)
341 	{
342 		char	sFilename[MAX_QPATH];
343 		sprintf(sFilename,"%s\\%s", psDir, sysFiles[i]);
344 
345 		Com_Printf("%sFound file: %s",!i?"\n":"",sFilename);
346 
347 		iFilesFound++;
348 
349 		// read it in...
350 		//
351 		byte *pbData = NULL;
352 		int iSize = FS_ReadFile( sFilename, (void **)&pbData);
353 
354 		if (pbData)
355 		{
356 			id3v1_1* pTAG;
357 
358 			// do NOT check 'qbForceRescan' here as an opt, because we need to actually fill in 'pTAG' if there is one...
359 			//
360 			qboolean qbTagNeedsUpdating = (/* qbForceRescan || */ !MP3_ReadSpecialTagInfo(pbData, iSize, &pTAG))?qtrue:qfalse;
361 
362 			if (pTAG == NULL || qbTagNeedsUpdating || qbForceRescan)
363 			{
364 				Com_Printf(" ( Updating )\n");
365 
366 				// I need to scan this file to get the volume...
367 				//
368 				// For EF1 I used a temp sfx_t struct, but I can't do that now with this new alloc scheme,
369 				//	I have to ask for it legally, so I'll keep re-using one, and restoring it's name after use.
370 				//	(slightly dodgy, but works ok if no-one else changes stuff)
371 				//
372 				//sfx_t SFX = {0};
373 				extern sfx_t *S_FindName( const char *name );
374 				//
375 				static sfx_t *pSFX = NULL;
376 				const char sReservedSFXEntrynameForMP3[] = "reserved_for_mp3";	// ( strlen() < MAX_QPATH )
377 
378 				if (pSFX == NULL)	// once only
379 				{
380 					pSFX = S_FindName(sReservedSFXEntrynameForMP3);	// always returns, else ERR_FATAL
381 				}
382 
383 				if (MP3_IsValid(sFilename,pbData, iSize, qbForceStereo))
384 				{
385 					wavinfo_t info;
386 
387 					int iRawPCMDataSize = MP3_GetUnpackedSize(sFilename, pbData, iSize, qtrue, qbForceStereo);
388 
389 					if (iRawPCMDataSize)	// should always be true, unless file is fucked, in which case, stop this conversion process
390 					{
391 						float fMaxVol = 128;	// any old default
392 						int iActualUnpackedSize = iRawPCMDataSize;	// default, override later if not doing music
393 
394 						if (!qbForceStereo)	// no point for stereo files, which are for music and therefore no lip-sync
395 						{
396 							byte *pbUnpackBuffer = (byte *) Z_Malloc( iRawPCMDataSize+10, TAG_TEMP_WORKSPACE, qfalse );	// won't return if fails
397 
398 							iActualUnpackedSize = MP3_UnpackRawPCM( sFilename, pbData, iSize, pbUnpackBuffer );
399 							if (iActualUnpackedSize != iRawPCMDataSize)
400 							{
401 								Com_Error(ERR_DROP, "******* Whoah! MP3 %s unpacked to %d bytes, but size calc said %d!\n",sFilename,iActualUnpackedSize,iRawPCMDataSize);
402 							}
403 
404 							// fake up a WAV structure so I can use the other post-load sound code such as volume calc for lip-synching
405 							//
406 							MP3_FakeUpWAVInfo( sFilename, pbData, iSize, iActualUnpackedSize,
407 												// these params are all references...
408 												info.format, info.rate, info.width, info.channels, info.samples, info.dataofs
409 												);
410 
411 							S_LoadSound_Finalize(&info, pSFX, pbUnpackBuffer);	// all this just for lipsynch. Oh well.
412 
413 							fMaxVol = pSFX->fVolRange;
414 
415 							// free sfx->data...
416 							//
417 							{
418 								#ifndef INT_MIN
419 								#define INT_MIN     (-2147483647 - 1) /* minimum (signed) int value */
420 								#endif
421 								//
422 								pSFX->iLastTimeUsed = INT_MIN;		// force this to be oldest sound file, therefore disposable...
423 								pSFX->bInMemory = true;
424 								SND_FreeOldestSound();		// ... and do the disposal
425 
426 								// now set our temp SFX struct back to default name so nothing else accidentally uses it...
427 								//
428 								strcpy(pSFX->sSoundName, sReservedSFXEntrynameForMP3);
429 								pSFX->bDefaultSound = false;
430 							}
431 
432 //							OutputDebugString(va("File: \"%s\"   MaxVol %f\n",sFilename,pSFX->fVolRange));
433 
434 							// other stuff...
435 							//
436 							Z_Free(pbUnpackBuffer);
437 						}
438 
439 						// well, time to update the file now...
440 						//
441 						fileHandle_t f = FS_FOpenFileWrite( sFilename );
442 						if (f)
443 						{
444 							// write the file back out, but omitting the tag if there was one...
445 							//
446 							int iWritten = FS_Write(pbData, iSize-(pTAG?sizeof(*pTAG):0), f);
447 
448 							if (iWritten)
449 							{
450 								// make up a new tag if we didn't find one in the original file...
451 								//
452 								id3v1_1 TAG;
453 								if (!pTAG)
454 								{
455 									pTAG = &TAG;
456 									memset(&TAG,0,sizeof(TAG));
457 									strncpy(pTAG->id,"TAG",3);
458 								}
459 
460 								strncpy(pTAG->title,	Filename_WithoutPath(Filename_WithoutExt(sFilename)), sizeof(pTAG->title));
461 								strncpy(pTAG->artist,	"Raven Software",						sizeof(pTAG->artist)	);
462 								strncpy(pTAG->year,		"2002",									sizeof(pTAG->year)		);
463 								strncpy(pTAG->comment,	va("%s %g",sKEY_MAXVOL,fMaxVol),		sizeof(pTAG->comment)	);
464 								strncpy(pTAG->album,	va("%s %d",sKEY_UNCOMP,iActualUnpackedSize),sizeof(pTAG->album)	);
465 
466 								if (FS_Write( pTAG, sizeof(*pTAG), f ))	// NZ = success
467 								{
468 									iFilesUpdated++;
469 								}
470 								else
471 								{
472 									Com_Printf("*********** Failed write to file \"%s\"!\n",sFilename);
473 									iErrors++;
474 									strErrors += va("Failed to write: \"%s\"\n",sFilename);
475 								}
476 							}
477 							else
478 							{
479 								Com_Printf("*********** Failed write to file \"%s\"!\n",sFilename);
480 								iErrors++;
481 								strErrors += va("Failed to write: \"%s\"\n",sFilename);
482 							}
483 							FS_FCloseFile( f );
484 						}
485 						else
486 						{
487 							Com_Printf("*********** Failed to re-open for write \"%s\"!\n",sFilename);
488 							iErrors++;
489 							strErrors += va("Failed to re-open for write: \"%s\"\n",sFilename);
490 						}
491 					}
492 					else
493 					{
494 						Com_Error(ERR_DROP, "******* This MP3 should be deleted: \"%s\"\n",sFilename);
495 					}
496 				}
497 				else
498 				{
499 					Com_Printf("*********** File was not a valid MP3!: \"%s\"\n",sFilename);
500 					iErrors++;
501 					strErrors += va("Not game-legal MP3 format: \"%s\"\n",sFilename);
502 				}
503 			}
504 			else
505 			{
506 				Com_Printf(" ( OK )\n");
507 			}
508 
509 			FS_FreeFile( pbData );
510 		}
511 	}
512 	FS_FreeFileList( sysFiles );
513 	FS_FreeFileList( dirFiles );
514 }
515 
516 // this console-function is for development purposes, and makes sure that sound/*.mp3 /s have tags in them
517 //	specifying stuff like their max volume (and uncompressed size) etc...
518 //
S_MP3_CalcVols_f(void)519 void S_MP3_CalcVols_f( void )
520 {
521 	char sStartDir[MAX_QPATH] = {"sound"};
522 	const char sUsage[] = "Usage: mp3_calcvols [-rescan] <startdir>\ne.g. mp3_calcvols sound/chars";
523 
524 	if (Cmd_Argc() == 1 || Cmd_Argc()>4)	// 3 optional arguments
525 	{
526 		Com_Printf(sUsage);
527 		return;
528 	}
529 
530 	S_StopAllSounds();
531 
532 
533 	qbForceRescan = qfalse;
534 	qbForceStereo = qfalse;
535 	iFilesFound		= 0;
536 	iFilesUpdated	= 0;
537 	iErrors			= 0;
538 	strErrors		= "";
539 
540 	for (int i=1; i<Cmd_Argc(); i++)
541 	{
542 		if (Cmd_Argv(i)[0] == '-')
543 		{
544 			if (!Q_stricmp(Cmd_Argv(i),"-rescan"))
545 			{
546 				qbForceRescan = qtrue;
547 			}
548 			else
549 			if (!Q_stricmp(Cmd_Argv(i),"-stereo"))
550 			{
551 				qbForceStereo = qtrue;
552 			}
553 			else
554 			{
555 				// unknown switch...
556 				//
557 				Com_Printf(sUsage);
558 				return;
559 			}
560 			continue;
561 		}
562 		strcpy(sStartDir,Cmd_Argv(i));
563 	}
564 
565 	Com_Printf(va("Starting Scan for Updates in Dir: %s\n",sStartDir));
566 	R_CheckMP3s( sStartDir );
567 
568 	Com_Printf("\n%d files found/scanned, %d files updated      ( %d errors total)\n",iFilesFound,iFilesUpdated,iErrors);
569 
570 	if (iErrors)
571 	{
572 		Com_Printf("\nBad Files:\n%s\n",strErrors.c_str());
573 	}
574 }
575 
576 
577 
578 
579 
580 // adjust filename for foreign languages and WAV/MP3 issues.
581 //
582 // returns qfalse if failed to load, else fills in *pData
583 //
584 extern	cvar_t	*com_buildScript;
S_LoadSound_FileLoadAndNameAdjuster(char * psFilename,byte ** pData,int * piSize,int iNameStrlen)585 static qboolean S_LoadSound_FileLoadAndNameAdjuster(char *psFilename, byte **pData, int *piSize, int iNameStrlen)
586 {
587 	char *psVoice = strstr(psFilename,"chars");
588 	if (psVoice)
589 	{
590 		// cache foreign voices...
591 		//
592 		if (com_buildScript->integer)
593 		{
594 			fileHandle_t hFile;
595 			//German
596 			strncpy(psVoice,"chr_d",5);	// same number of letters as "chars"
597 			FS_FOpenFileRead(psFilename, &hFile, qfalse);		//cache the wav
598 			if (!hFile)
599 			{
600 				strcpy(&psFilename[iNameStrlen-3],"mp3");		//not there try mp3
601 				FS_FOpenFileRead(psFilename, &hFile, qfalse);	//cache the mp3
602 			}
603 			if (hFile)
604 			{
605 				FS_FCloseFile(hFile);
606 			}
607 			strcpy(&psFilename[iNameStrlen-3],"wav");	//put it back to wav
608 
609 			//French
610 			strncpy(psVoice,"chr_f",5);	// same number of letters as "chars"
611 			FS_FOpenFileRead(psFilename, &hFile, qfalse);		//cache the wav
612 			if (!hFile)
613 			{
614 				strcpy(&psFilename[iNameStrlen-3],"mp3");		//not there try mp3
615 				FS_FOpenFileRead(psFilename, &hFile, qfalse);	//cache the mp3
616 			}
617 			if (hFile)
618 			{
619 				FS_FCloseFile(hFile);
620 			}
621 			strcpy(&psFilename[iNameStrlen-3],"wav");	//put it back to wav
622 
623 			//Spanish
624 			strncpy(psVoice,"chr_e",5);	// same number of letters as "chars"
625 			FS_FOpenFileRead(psFilename, &hFile, qfalse);		//cache the wav
626 			if (!hFile)
627 			{
628 				strcpy(&psFilename[iNameStrlen-3],"mp3");		//not there try mp3
629 				FS_FOpenFileRead(psFilename, &hFile, qfalse);	//cache the mp3
630 			}
631 			if (hFile)
632 			{
633 				FS_FCloseFile(hFile);
634 			}
635 			strcpy(&psFilename[iNameStrlen-3],"wav");	//put it back to wav
636 
637 			strncpy(psVoice,"chars",5);	//put it back to chars
638 		}
639 
640 		// account for foreign voices...
641 		//
642 		extern cvar_t* s_language;
643 		if (s_language && Q_stricmp("DEUTSCH",s_language->string)==0)
644 		{
645 			strncpy(psVoice,"chr_d",5);	// same number of letters as "chars"
646 		}
647 		else if (s_language && Q_stricmp("FRANCAIS",s_language->string)==0)
648 		{
649 			strncpy(psVoice,"chr_f",5);	// same number of letters as "chars"
650 		}
651 		else if (s_language && Q_stricmp("ESPANOL",s_language->string)==0)
652 		{
653 			strncpy(psVoice,"chr_e",5);	// same number of letters as "chars"
654 		}
655 		else
656 		{
657 			psVoice = NULL;	// use this ptr as a flag as to whether or not we substituted with a foreign version
658 		}
659 	}
660 
661 	*piSize = FS_ReadFile( psFilename, (void **)pData );	// try WAV
662 	if ( !*pData ) {
663 		psFilename[iNameStrlen-3] = 'm';
664 		psFilename[iNameStrlen-2] = 'p';
665 		psFilename[iNameStrlen-1] = '3';
666 		*piSize = FS_ReadFile( psFilename, (void **)pData );	// try MP3
667 
668 		if ( !*pData )
669 		{
670 			//hmmm, not found, ok, maybe we were trying a foreign noise ("arghhhhh.mp3" that doesn't matter?) but it
671 			// was missing?   Can't tell really, since both types are now in sound/chars. Oh well, fall back to English for now...
672 
673 			if (psVoice)	// were we trying to load foreign?
674 			{
675 				// yep, so fallback to re-try the english...
676 				//
677 #ifndef FINAL_BUILD
678 				Com_Printf(S_COLOR_YELLOW "Foreign file missing: \"%s\"! (using English...)\n",psFilename);
679 #endif
680 
681 				strncpy(psVoice,"chars",5);
682 
683 				psFilename[iNameStrlen-3] = 'w';
684 				psFilename[iNameStrlen-2] = 'a';
685 				psFilename[iNameStrlen-1] = 'v';
686 				*piSize = FS_ReadFile( psFilename, (void **)pData );	// try English WAV
687 				if ( !*pData )
688 				{
689 					psFilename[iNameStrlen-3] = 'm';
690 					psFilename[iNameStrlen-2] = 'p';
691 					psFilename[iNameStrlen-1] = '3';
692 					*piSize = FS_ReadFile( psFilename, (void **)pData );	// try English MP3
693 				}
694 			}
695 
696 			if (!*pData)
697 			{
698 				return qfalse;	// sod it, give up...
699 			}
700 		}
701 	}
702 
703 	return qtrue;
704 }
705 
706 // returns qtrue if this dir is allowed to keep loaded MP3s, else qfalse if they should be WAV'd instead...
707 //
708 // note that this is passed the original, un-language'd name
709 //
710 // (I was going to remove this, but on kejim_post I hit an assert because someone had got an ambient sound when the
711 //	perimter fence goes online that was an MP3, then it tried to get added as looping. Presumably it sounded ok or
712 //	they'd have noticed, but we therefore need to stop other levels using those. "sound/ambience" I can check for,
713 //	but doors etc could be anything. Sigh...)
714 //
715 #define SOUND_CHARS_DIR "sound/chars/"
716 #define SOUND_CHARS_DIR_LENGTH 12 // strlen( SOUND_CHARS_DIR )
S_LoadSound_DirIsAllowedToKeepMP3s(const char * psFilename)717 static qboolean S_LoadSound_DirIsAllowedToKeepMP3s( const char *psFilename )
718 {
719 	if ( Q_stricmpn( psFilename, SOUND_CHARS_DIR, SOUND_CHARS_DIR_LENGTH ) == 0 )
720 		return qtrue;	// found a dir that's allowed to keep MP3s
721 
722 	return qfalse;
723 }
724 
725 /*
726 ==============
727 S_LoadSound
728 
729 The filename may be different than sfx->name in the case
730 of a forced fallback of a player specific sound	(or of a wav/mp3 substitution now -Ste)
731 ==============
732 */
733 qboolean gbInsideLoadSound = qfalse;
S_LoadSound_Actual(sfx_t * sfx)734 static qboolean S_LoadSound_Actual( sfx_t *sfx )
735 {
736 	byte	*data;
737 	short	*samples;
738 	wavinfo_t	info;
739 	int		size;
740 	char	*psExt;
741 	char	sLoadName[MAX_QPATH];
742 
743 	int		len = strlen(sfx->sSoundName);
744 	if (len<5)
745 	{
746 		return qfalse;
747 	}
748 
749 	// player specific sounds are never directly loaded...
750 	//
751 	if ( sfx->sSoundName[0] == '*') {
752 		return qfalse;
753 	}
754 	// make up a local filename to try wav/mp3 substitutes...
755 	//
756 	Q_strncpyz(sLoadName, sfx->sSoundName, sizeof(sLoadName));
757 	Q_strlwr( sLoadName );
758 	//
759 	// Ensure name has an extension (which it must have, but you never know), and get ptr to it...
760 	//
761 	psExt = &sLoadName[strlen(sLoadName)-4];
762 	if (*psExt != '.')
763 	{
764 		//Com_Printf( "WARNING: soundname '%s' does not have 3-letter extension\n",sLoadName);
765 		COM_DefaultExtension(sLoadName,sizeof(sLoadName),".wav");	// so psExt below is always valid
766 		psExt = &sLoadName[strlen(sLoadName)-4];
767 		len = strlen(sLoadName);
768 	}
769 
770 	if (!S_LoadSound_FileLoadAndNameAdjuster(sLoadName, &data, &size, len))
771 	{
772 		return qfalse;
773 	}
774 
775 	SND_TouchSFX(sfx);
776 //=========
777 	if (Q_stricmpn(psExt,".mp3",4)==0)
778 	{
779 		// load MP3 file instead...
780 		//
781 		if (MP3_IsValid(sLoadName,data, size, qfalse))
782 		{
783 			int iRawPCMDataSize = MP3_GetUnpackedSize(sLoadName,data,size,qfalse,qfalse);
784 
785 			if (S_LoadSound_DirIsAllowedToKeepMP3s(sfx->sSoundName)	// NOT sLoadName, this uses original un-languaged name
786 				&&
787 				MP3Stream_InitFromFile(sfx, data, size, sLoadName, iRawPCMDataSize + 2304 /* + 1 MP3 frame size, jic */,qfalse)
788 				)
789 			{
790 //				Com_DPrintf("(Keeping file \"%s\" as MP3)\n",sLoadName);
791 
792 #ifdef USE_OPENAL
793 				if (s_UseOpenAL)
794 				{
795 					// Create space for lipsync data (4 lip sync values per streaming AL buffer)
796 					if (strstr(sfx->sSoundName, "chars") )
797 						sfx->lipSyncData = (char *)Z_Malloc(16, TAG_SND_RAWDATA, qfalse);
798 					else
799 						sfx->lipSyncData = NULL;
800 				}
801 #endif
802 			}
803 			else
804 			{
805 				// small file, not worth keeping as MP3 since it would increase in size (with MP3 header etc)...
806 				//
807 				Com_DPrintf("S_LoadSound: Unpacking MP3 file \"%s\" to wav.\n",sLoadName);
808 				//
809 				// unpack and convert into WAV...
810 				//
811 				{
812 					byte *pbUnpackBuffer = (byte *) Z_Malloc( iRawPCMDataSize+10 +2304 /* <g> */, TAG_TEMP_WORKSPACE, qfalse );	// won't return if fails
813 
814 					{
815 						int iResultBytes = MP3_UnpackRawPCM( sLoadName, data, size, pbUnpackBuffer, qfalse );
816 
817 						if (iResultBytes!= iRawPCMDataSize){
818 							Com_Printf(S_COLOR_YELLOW"**** MP3 %s final unpack size %d different to previous value %d\n",sLoadName,iResultBytes,iRawPCMDataSize);
819 							//assert (iResultBytes == iRawPCMDataSize);
820 						}
821 
822 
823 						// fake up a WAV structure so I can use the other post-load sound code such as volume calc for lip-synching
824 						//
825 						// (this is a bit crap really, but it lets me drop through into existing code)...
826 						//
827 						MP3_FakeUpWAVInfo( sLoadName, data, size, iResultBytes,
828 											// these params are all references...
829 											info.format, info.rate, info.width, info.channels, info.samples, info.dataofs,
830 											qfalse
831 										);
832 
833 						S_LoadSound_Finalize(&info,sfx,pbUnpackBuffer);
834 
835 #ifdef Q3_BIG_ENDIAN
836 						// the MP3 decoder returns the samples in the correct endianness, but ResampleSfx byteswaps them,
837 						// so we have to swap them again...
838 						sfx->fVolRange	= 0;
839 
840 						for (int i = 0; i < sfx->iSoundLengthInSamples; i++)
841 						{
842 							sfx->pSoundData[i] = LittleShort(sfx->pSoundData[i]);
843 							// C++11 defines double abs(short) which is not what we want here,
844 							// because double >> int is not defined. Force interpretation as int
845 							if (sfx->fVolRange < (abs(static_cast<int>(sfx->pSoundData[i])) >> 8))
846 							{
847 								sfx->fVolRange = abs(static_cast<int>(sfx->pSoundData[i])) >> 8;
848 							}
849 						}
850 #endif
851 
852 						// Open AL
853 #ifdef USE_OPENAL
854 						if (s_UseOpenAL)
855 						{
856 							if (strstr(sfx->sSoundName, "chars"))
857 							{
858 								sfx->lipSyncData = (char *)Z_Malloc((sfx->iSoundLengthInSamples / 1000) + 1, TAG_SND_RAWDATA, qfalse);
859 								S_PreProcessLipSync(sfx);
860 							}
861 							else
862 								sfx->lipSyncData = NULL;
863 
864 							// Clear Open AL Error state
865 							alGetError();
866 
867 							// Generate AL Buffer
868 							ALuint Buffer;
869 							alGenBuffers(1, &Buffer);
870 							if (alGetError() == AL_NO_ERROR)
871 							{
872 								// Copy audio data to AL Buffer
873 								alBufferData(Buffer, AL_FORMAT_MONO16, sfx->pSoundData, sfx->iSoundLengthInSamples*2, 22050);
874 								if (alGetError() == AL_NO_ERROR)
875 								{
876 									sfx->Buffer = Buffer;
877 									Z_Free(sfx->pSoundData);
878 									sfx->pSoundData = NULL;
879 								}
880 							}
881 						}
882 #endif
883 
884 						Z_Free(pbUnpackBuffer);
885 					}
886 				}
887 			}
888 		}
889 		else
890 		{
891 			// MP3_IsValid() will already have printed any errors via Com_Printf at this point...
892 			//
893 			FS_FreeFile (data);
894 			return qfalse;
895 		}
896 	}
897 	else
898 	{
899 		// loading a WAV, presumably...
900 
901 //=========
902 
903 		info = GetWavinfo( sLoadName, data, size );
904 		if ( info.channels != 1 ) {
905 			Com_Printf ("%s is a stereo wav file\n", sLoadName);
906 			FS_FreeFile (data);
907 			return qfalse;
908 		}
909 
910 /*		if ( info.width == 1 ) {
911 			Com_Printf(S_COLOR_YELLOW "WARNING: %s is a 8 bit wav file\n", sLoadName);
912 		}
913 
914 		if ( info.rate != 22050 ) {
915 			Com_Printf(S_COLOR_YELLOW "WARNING: %s is not a 22kHz wav file\n", sLoadName);
916 		}
917 */
918 		samples = (short *)Z_Malloc(info.samples * sizeof(short) * 2, TAG_TEMP_WORKSPACE, qfalse);
919 
920 		sfx->eSoundCompressionMethod = ct_16;
921 		sfx->iSoundLengthInSamples	 = info.samples;
922 		sfx->pSoundData = NULL;
923 		ResampleSfx( sfx, info.rate, info.width, data + info.dataofs );
924 
925 		// Open AL
926 #ifdef USE_OPENAL
927 		if (s_UseOpenAL)
928 		{
929 			if ((strstr(sfx->sSoundName, "chars")) || (strstr(sfx->sSoundName, "CHARS")))
930 			{
931 				sfx->lipSyncData = (char *)Z_Malloc((sfx->iSoundLengthInSamples / 1000) + 1, TAG_SND_RAWDATA, qfalse);
932 				S_PreProcessLipSync(sfx);
933 			}
934 			else
935 				sfx->lipSyncData = NULL;
936 
937 			// Clear Open AL Error State
938 			alGetError();
939 
940 			// Generate AL Buffer
941 			ALuint Buffer;
942 			alGenBuffers(1, &Buffer);
943 			if (alGetError() == AL_NO_ERROR)
944 			{
945 				// Copy audio data to AL Buffer
946 				alBufferData(Buffer, AL_FORMAT_MONO16, sfx->pSoundData, sfx->iSoundLengthInSamples*2, 22050);
947 				if (alGetError() == AL_NO_ERROR)
948 				{
949 					// Store AL Buffer in sfx struct, and release sample data
950 					sfx->Buffer = Buffer;
951 					Z_Free(sfx->pSoundData);
952 					sfx->pSoundData = NULL;
953 				}
954 			}
955 		}
956 #endif
957 
958 		Z_Free(samples);
959 	}
960 
961 	FS_FreeFile( data );
962 
963 	return qtrue;
964 }
965 
966 
967 // wrapper function for above so I can guarantee that we don't attempt any audio-dumping during this call because
968 //	of a z_malloc() fail recovery...
969 //
S_LoadSound(sfx_t * sfx)970 qboolean S_LoadSound( sfx_t *sfx )
971 {
972 	gbInsideLoadSound = qtrue;	// !!!!!!!!!!!!!
973 
974 		qboolean bReturn = S_LoadSound_Actual( sfx );
975 
976 	gbInsideLoadSound = qfalse;	// !!!!!!!!!!!!!
977 
978 	return bReturn;
979 }
980 
981 #ifdef USE_OPENAL
982 /*
983 	Precalculate the lipsync values for the whole sample
984 */
S_PreProcessLipSync(sfx_t * sfx)985 void S_PreProcessLipSync(sfx_t *sfx)
986 {
987 	int i, j;
988 	int sample;
989 	int sampleTotal = 0;
990 
991 	j = 0;
992 	for (i = 0; i < sfx->iSoundLengthInSamples; i += 100)
993 	{
994 		sample = LittleShort(sfx->pSoundData[i]);
995 
996 		sample = sample >> 8;
997 		sampleTotal += sample * sample;
998 		if (((i + 100) % 1000) == 0)
999 		{
1000 			sampleTotal /= 10;
1001 
1002 			if (sampleTotal < sfx->fVolRange *  s_lip_threshold_1->value)
1003 			{
1004 				// tell the scripts that are relying on this that we are still going, but actually silent right now.
1005 				sample = -1;
1006 			}
1007 			else if (sampleTotal < sfx->fVolRange * s_lip_threshold_2->value)
1008 				sample = 1;
1009 			else if (sampleTotal < sfx->fVolRange * s_lip_threshold_3->value)
1010 				sample = 2;
1011 			else if (sampleTotal < sfx->fVolRange * s_lip_threshold_4->value)
1012 				sample = 3;
1013 			else
1014 				sample = 4;
1015 
1016 			sfx->lipSyncData[j] = sample;
1017 			j++;
1018 
1019 			sampleTotal = 0;
1020 		}
1021 	}
1022 
1023 	if ((i % 1000) == 0)
1024 		return;
1025 
1026 	i -= 100;
1027 	i = i % 1000;
1028 	i = i / 100;
1029 	// Process last < 1000 samples
1030 	if (i != 0)
1031 		sampleTotal /= i;
1032 	else
1033 		sampleTotal = 0;
1034 
1035 	if (sampleTotal < sfx->fVolRange * s_lip_threshold_1->value)
1036 	{
1037 		// tell the scripts that are relying on this that we are still going, but actually silent right now.
1038 		sample = -1;
1039 	}
1040 	else if (sampleTotal < sfx->fVolRange * s_lip_threshold_2->value)
1041 		sample = 1;
1042 	else if (sampleTotal < sfx->fVolRange * s_lip_threshold_3->value)
1043 		sample = 2;
1044 	else if (sampleTotal < sfx->fVolRange * s_lip_threshold_4->value)
1045 		sample = 3;
1046 	else
1047 		sample = 4;
1048 
1049 	sfx->lipSyncData[j] = sample;
1050 }
1051 #endif
1052