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