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
26 #include "snd_local.h"
27 #include "snd_mp3.h"
28 #include "snd_ambient.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(char * name)78 void FindNextChunk(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 (!Q_strncmp((char *)data_p, name, 4))
100 return;
101 }
102 }
103
FindChunk(char * name)104 void FindChunk(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 && !Q_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 = qtrue;
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 = qfalse;
430 }
431
432 // Com_OPrintf("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 ) {
644 if ( !Q_stricmp( "DEUTSCH", s_language->string ) )
645 strncpy( psVoice, "chr_d", 5 ); // same number of letters as "chars"
646 else if ( !Q_stricmp( "FRANCAIS", s_language->string ) )
647 strncpy( psVoice, "chr_f", 5 ); // same number of letters as "chars"
648 else if ( !Q_stricmp( "ESPANOL", s_language->string ) )
649 strncpy( psVoice, "chr_e", 5 ); // same number of letters as "chars"
650 else
651 psVoice = NULL;
652 }
653 else
654 {
655 psVoice = NULL; // use this ptr as a flag as to whether or not we substituted with a foreign version
656 }
657 }
658
659 *piSize = FS_ReadFile( psFilename, (void **)pData ); // try WAV
660 if ( !*pData ) {
661 psFilename[iNameStrlen-3] = 'm';
662 psFilename[iNameStrlen-2] = 'p';
663 psFilename[iNameStrlen-1] = '3';
664 *piSize = FS_ReadFile( psFilename, (void **)pData ); // try MP3
665
666 if ( !*pData )
667 {
668 //hmmm, not found, ok, maybe we were trying a foreign noise ("arghhhhh.mp3" that doesn't matter?) but it
669 // was missing? Can't tell really, since both types are now in sound/chars. Oh well, fall back to English for now...
670
671 if (psVoice) // were we trying to load foreign?
672 {
673 // yep, so fallback to re-try the english...
674 //
675 #ifndef FINAL_BUILD
676 Com_Printf(S_COLOR_YELLOW "Foreign file missing: \"%s\"! (using English...)\n",psFilename);
677 #endif
678
679 strncpy(psVoice,"chars",5);
680
681 psFilename[iNameStrlen-3] = 'w';
682 psFilename[iNameStrlen-2] = 'a';
683 psFilename[iNameStrlen-1] = 'v';
684 *piSize = FS_ReadFile( psFilename, (void **)pData ); // try English WAV
685 if ( !*pData )
686 {
687 psFilename[iNameStrlen-3] = 'm';
688 psFilename[iNameStrlen-2] = 'p';
689 psFilename[iNameStrlen-1] = '3';
690 *piSize = FS_ReadFile( psFilename, (void **)pData ); // try English MP3
691 }
692 }
693
694 if (!*pData)
695 {
696 return qfalse; // sod it, give up...
697 }
698 }
699 }
700
701 return qtrue;
702 }
703
704 // returns qtrue if this dir is allowed to keep loaded MP3s, else qfalse if they should be WAV'd instead...
705 //
706 // note that this is passed the original, un-language'd name
707 //
708 // (I was going to remove this, but on kejim_post I hit an assert because someone had got an ambient sound when the
709 // perimter fence goes online that was an MP3, then it tried to get added as looping. Presumably it sounded ok or
710 // they'd have noticed, but we therefore need to stop other levels using those. "sound/ambience" I can check for,
711 // but doors etc could be anything. Sigh...)
712 //
713 #define SOUND_CHARS_DIR "sound/chars/"
714 #define SOUND_CHARS_DIR_LENGTH 12 // strlen( SOUND_CHARS_DIR )
S_LoadSound_DirIsAllowedToKeepMP3s(const char * psFilename)715 static qboolean S_LoadSound_DirIsAllowedToKeepMP3s(const char *psFilename)
716 {
717 if ( Q_stricmpn( psFilename, SOUND_CHARS_DIR, SOUND_CHARS_DIR_LENGTH ) == 0 )
718 return qtrue; // found a dir that's allowed to keep MP3s
719
720 return qfalse;
721 }
722
723 /*
724 ==============
725 S_LoadSound
726
727 The filename may be different than sfx->name in the case
728 of a forced fallback of a player specific sound (or of a wav/mp3 substitution now -Ste)
729 ==============
730 */
731 qboolean gbInsideLoadSound = qfalse;
S_LoadSound_Actual(sfx_t * sfx)732 static qboolean S_LoadSound_Actual( sfx_t *sfx )
733 {
734 byte *data;
735 short *samples;
736 wavinfo_t info;
737 int size;
738 char *psExt;
739 char sLoadName[MAX_QPATH];
740
741 int len = strlen(sfx->sSoundName);
742 if (len<5)
743 {
744 return qfalse;
745 }
746
747 // player specific sounds are never directly loaded...
748 //
749 if ( sfx->sSoundName[0] == '*') {
750 return qfalse;
751 }
752 // make up a local filename to try wav/mp3 substitutes...
753 //
754 Q_strncpyz(sLoadName, sfx->sSoundName, sizeof(sLoadName));
755 Q_strlwr( sLoadName );
756 //
757 // Ensure name has an extension (which it must have, but you never know), and get ptr to it...
758 //
759 psExt = &sLoadName[strlen(sLoadName)-4];
760 if (*psExt != '.')
761 {
762 //Com_Printf( "WARNING: soundname '%s' does not have 3-letter extension\n",sLoadName);
763 COM_DefaultExtension(sLoadName,sizeof(sLoadName),".wav"); // so psExt below is always valid
764 psExt = &sLoadName[strlen(sLoadName)-4];
765 len = strlen(sLoadName);
766 }
767
768 if (!S_LoadSound_FileLoadAndNameAdjuster(sLoadName, &data, &size, len))
769 {
770 return qfalse;
771 }
772
773 SND_TouchSFX(sfx);
774
775 //=========
776 if (Q_stricmpn(psExt,".mp3",4)==0)
777 {
778 // load MP3 file instead...
779 //
780 if (MP3_IsValid(sLoadName,data, size, qfalse))
781 {
782 int iRawPCMDataSize = MP3_GetUnpackedSize(sLoadName,data,size,qfalse,qfalse);
783
784 if (S_LoadSound_DirIsAllowedToKeepMP3s(sfx->sSoundName) // NOT sLoadName, this uses original un-languaged name
785 &&
786 MP3Stream_InitFromFile(sfx, data, size, sLoadName, iRawPCMDataSize + 2304 /* + 1 MP3 frame size, jic */,qfalse)
787 )
788 {
789 // Com_DPrintf("(Keeping file \"%s\" as MP3)\n",sLoadName);
790
791 #ifdef USE_OPENAL
792 if (s_UseOpenAL)
793 {
794 // Create space for lipsync data (4 lip sync values per streaming AL buffer)
795 if ((strstr(sfx->sSoundName, "chars")) || (strstr(sfx->sSoundName, "CHARS")))
796 sfx->lipSyncData = (char *)Z_Malloc(16, TAG_SND_RAWDATA, qfalse);
797 else
798 sfx->lipSyncData = NULL;
799 }
800 #endif
801 }
802 else
803 {
804 // small file, not worth keeping as MP3 since it would increase in size (with MP3 header etc)...
805 //
806 Com_DPrintf("S_LoadSound: Unpacking MP3 file(%i) \"%s\" to wav(%i).\n",size,sLoadName,iRawPCMDataSize);
807 //
808 // unpack and convert into WAV...
809 //
810 {
811 byte *pbUnpackBuffer = (byte *) Z_Malloc( iRawPCMDataSize+10 +2304 /* <g> */, TAG_TEMP_WORKSPACE, qfalse ); // won't return if fails
812
813 {
814 int iResultBytes = MP3_UnpackRawPCM( sLoadName, data, size, pbUnpackBuffer, qfalse );
815
816 if (iResultBytes!= iRawPCMDataSize){
817 Com_Printf(S_COLOR_YELLOW"**** MP3 %s final unpack size %d different to previous value %d\n",sLoadName,iResultBytes,iRawPCMDataSize);
818 //assert (iResultBytes == iRawPCMDataSize);
819 }
820
821
822 // fake up a WAV structure so I can use the other post-load sound code such as volume calc for lip-synching
823 //
824 // (this is a bit crap really, but it lets me drop through into existing code)...
825 //
826 MP3_FakeUpWAVInfo( sLoadName, data, size, iResultBytes,
827 // these params are all references...
828 info.format, info.rate, info.width, info.channels, info.samples, info.dataofs,
829 qfalse
830 );
831
832 S_LoadSound_Finalize(&info,sfx,pbUnpackBuffer);
833
834 #ifdef Q3_BIG_ENDIAN
835 // the MP3 decoder returns the samples in the correct endianness, but ResampleSfx byteswaps them,
836 // so we have to swap them again...
837 sfx->fVolRange = 0;
838
839 for (int i = 0; i < sfx->iSoundLengthInSamples; i++)
840 {
841 sfx->pSoundData[i] = LittleShort(sfx->pSoundData[i]);
842 // C++11 defines double abs(short) which is not what we want here,
843 // because double >> int is not defined. Force interpretation as int
844 if (sfx->fVolRange < (abs(static_cast<int>(sfx->pSoundData[i])) >> 8))
845 {
846 sfx->fVolRange = abs(static_cast<int>(sfx->pSoundData[i])) >> 8;
847 }
848 }
849 #endif
850
851 // Open AL
852 #ifdef USE_OPENAL
853 if (s_UseOpenAL)
854 {
855 if ((strstr(sfx->sSoundName, "chars")) || (strstr(sfx->sSoundName, "CHARS")))
856 {
857 sfx->lipSyncData = (char *)Z_Malloc((sfx->iSoundLengthInSamples / 1000) + 1, TAG_SND_RAWDATA, qfalse);
858 S_PreProcessLipSync(sfx);
859 }
860 else
861 sfx->lipSyncData = NULL;
862
863 // Clear Open AL Error state
864 alGetError();
865
866 // Generate AL Buffer
867 ALuint Buffer;
868 alGenBuffers(1, &Buffer);
869 if (alGetError() == AL_NO_ERROR)
870 {
871 // Copy audio data to AL Buffer
872 alBufferData(Buffer, AL_FORMAT_MONO16, sfx->pSoundData, sfx->iSoundLengthInSamples*2, 22050);
873 if (alGetError() == AL_NO_ERROR)
874 {
875 sfx->Buffer = Buffer;
876 Z_Free(sfx->pSoundData);
877 sfx->pSoundData = NULL;
878 }
879 }
880 }
881 #endif
882
883 Z_Free(pbUnpackBuffer);
884 }
885 }
886 }
887 }
888 else
889 {
890 // MP3_IsValid() will already have printed any errors via Com_Printf at this point...
891 //
892 FS_FreeFile (data);
893 return qfalse;
894 }
895 }
896 else
897 {
898 // loading a WAV, presumably...
899
900 //=========
901
902 info = GetWavinfo( sLoadName, data, size );
903 if ( info.channels != 1 ) {
904 Com_Printf ("%s is a stereo wav file\n", sLoadName);
905 FS_FreeFile (data);
906 return qfalse;
907 }
908
909 /* if ( info.width == 1 ) {
910 Com_Printf(S_COLOR_YELLOW "WARNING: %s is a 8 bit wav file\n", sLoadName);
911 }
912
913 if ( info.rate != 22050 ) {
914 Com_Printf(S_COLOR_YELLOW "WARNING: %s is not a 22kHz wav file\n", sLoadName);
915 }
916 */
917 samples = (short *)Z_Malloc(info.samples * sizeof(short) * 2, TAG_TEMP_WORKSPACE, qfalse);
918
919 sfx->eSoundCompressionMethod = ct_16;
920 sfx->iSoundLengthInSamples = info.samples;
921 sfx->pSoundData = NULL;
922 ResampleSfx( sfx, info.rate, info.width, data + info.dataofs );
923
924 // Open AL
925 #ifdef USE_OPENAL
926 if (s_UseOpenAL)
927 {
928 if ((strstr(sfx->sSoundName, "chars")) || (strstr(sfx->sSoundName, "CHARS")))
929 {
930 sfx->lipSyncData = (char *)Z_Malloc((sfx->iSoundLengthInSamples / 1000) + 1, TAG_SND_RAWDATA, qfalse);
931 S_PreProcessLipSync(sfx);
932 }
933 else
934 sfx->lipSyncData = NULL;
935
936 // Clear Open AL Error State
937 alGetError();
938
939 // Generate AL Buffer
940 ALuint Buffer;
941 alGenBuffers(1, &Buffer);
942 if (alGetError() == AL_NO_ERROR)
943 {
944 // Copy audio data to AL Buffer
945 alBufferData(Buffer, AL_FORMAT_MONO16, sfx->pSoundData, sfx->iSoundLengthInSamples*2, 22050);
946 if (alGetError() == AL_NO_ERROR)
947 {
948 // Store AL Buffer in sfx struct, and release sample data
949 sfx->Buffer = Buffer;
950 Z_Free(sfx->pSoundData);
951 sfx->pSoundData = NULL;
952 }
953 }
954 }
955 #endif
956
957 Z_Free(samples);
958 }
959
960 FS_FreeFile( data );
961
962 return qtrue;
963 }
964
965
966 // wrapper function for above so I can guarantee that we don't attempt any audio-dumping during this call because
967 // of a z_malloc() fail recovery...
968 //
S_LoadSound(sfx_t * sfx)969 qboolean S_LoadSound( sfx_t *sfx )
970 {
971 gbInsideLoadSound = qtrue; // !!!!!!!!!!!!!
972
973 qboolean bReturn = S_LoadSound_Actual( sfx );
974
975 gbInsideLoadSound = qfalse; // !!!!!!!!!!!!!
976
977 return bReturn;
978 }
979
980 #ifdef USE_OPENAL
981 /*
982 Precalculate the lipsync values for the whole sample
983 */
S_PreProcessLipSync(sfx_t * sfx)984 void S_PreProcessLipSync(sfx_t *sfx)
985 {
986 int i, j;
987 int sample;
988 int sampleTotal = 0;
989
990 j = 0;
991 for (i = 0; i < sfx->iSoundLengthInSamples; i += 100)
992 {
993 sample = LittleShort(sfx->pSoundData[i]);
994
995 sample = sample >> 8;
996 sampleTotal += sample * sample;
997 if (((i + 100) % 1000) == 0)
998 {
999 sampleTotal /= 10;
1000
1001 if (sampleTotal < sfx->fVolRange * s_lip_threshold_1->value)
1002 {
1003 // tell the scripts that are relying on this that we are still going, but actually silent right now.
1004 sample = -1;
1005 }
1006 else if (sampleTotal < sfx->fVolRange * s_lip_threshold_2->value)
1007 sample = 1;
1008 else if (sampleTotal < sfx->fVolRange * s_lip_threshold_3->value)
1009 sample = 2;
1010 else if (sampleTotal < sfx->fVolRange * s_lip_threshold_4->value)
1011 sample = 3;
1012 else
1013 sample = 4;
1014
1015 sfx->lipSyncData[j] = sample;
1016 j++;
1017
1018 sampleTotal = 0;
1019 }
1020 }
1021
1022 if ((i % 1000) == 0)
1023 return;
1024
1025 i -= 100;
1026 i = i % 1000;
1027 i = i / 100;
1028 // Process last < 1000 samples
1029 if (i != 0)
1030 sampleTotal /= i;
1031 else
1032 sampleTotal = 0;
1033
1034 if (sampleTotal < sfx->fVolRange * s_lip_threshold_1->value)
1035 {
1036 // tell the scripts that are relying on this that we are still going, but actually silent right now.
1037 sample = -1;
1038 }
1039 else if (sampleTotal < sfx->fVolRange * s_lip_threshold_2->value)
1040 sample = 1;
1041 else if (sampleTotal < sfx->fVolRange * s_lip_threshold_3->value)
1042 sample = 2;
1043 else if (sampleTotal < sfx->fVolRange * s_lip_threshold_4->value)
1044 sample = 3;
1045 else
1046 sample = 4;
1047
1048 sfx->lipSyncData[j] = sample;
1049 }
1050 #endif
1051