snd_cache.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
  6. Doom 3 Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #include "../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "snd_local.h"
  23. #define USE_SOUND_CACHE_ALLOCATOR
  24. #ifdef USE_SOUND_CACHE_ALLOCATOR
  25. static idDynamicBlockAlloc<byte, 1<<20, 1<<10> soundCacheAllocator;
  26. #else
  27. static idDynamicAlloc<byte, 1<<20, 1<<10> soundCacheAllocator;
  28. #endif
  29. /*
  30. ===================
  31. idSoundCache::idSoundCache()
  32. ===================
  33. */
  34. idSoundCache::idSoundCache() {
  35. soundCacheAllocator.Init();
  36. soundCacheAllocator.SetLockMemory( true );
  37. listCache.AssureSize( 1024, NULL );
  38. listCache.SetGranularity( 256 );
  39. insideLevelLoad = false;
  40. }
  41. /*
  42. ===================
  43. idSoundCache::~idSoundCache()
  44. ===================
  45. */
  46. idSoundCache::~idSoundCache() {
  47. listCache.DeleteContents( true );
  48. soundCacheAllocator.Shutdown();
  49. }
  50. /*
  51. ===================
  52. idSoundCache::::GetObject
  53. returns a single cached object pointer
  54. ===================
  55. */
  56. const idSoundSample* idSoundCache::GetObject( const int index ) const {
  57. if (index<0 || index>listCache.Num()) {
  58. return NULL;
  59. }
  60. return listCache[index];
  61. }
  62. /*
  63. ===================
  64. idSoundCache::FindSound
  65. Adds a sound object to the cache and returns a handle for it.
  66. ===================
  67. */
  68. idSoundSample *idSoundCache::FindSound( const idStr& filename, bool loadOnDemandOnly ) {
  69. idStr fname;
  70. fname = filename;
  71. fname.BackSlashesToSlashes();
  72. fname.ToLower();
  73. declManager->MediaPrint( "%s\n", fname.c_str() );
  74. // check to see if object is already in cache
  75. for( int i = 0; i < listCache.Num(); i++ ) {
  76. idSoundSample *def = listCache[i];
  77. if ( def && def->name == fname ) {
  78. def->levelLoadReferenced = true;
  79. if ( def->purged && !loadOnDemandOnly ) {
  80. def->Load();
  81. }
  82. return def;
  83. }
  84. }
  85. // create a new entry
  86. idSoundSample *def = new idSoundSample;
  87. int shandle = listCache.FindNull();
  88. if ( shandle != -1 ) {
  89. listCache[shandle] = def;
  90. } else {
  91. shandle = listCache.Append( def );
  92. }
  93. def->name = fname;
  94. def->levelLoadReferenced = true;
  95. def->onDemand = loadOnDemandOnly;
  96. def->purged = true;
  97. if ( !loadOnDemandOnly ) {
  98. // this may make it a default sound if it can't be loaded
  99. def->Load();
  100. }
  101. return def;
  102. }
  103. /*
  104. ===================
  105. idSoundCache::ReloadSounds
  106. Completely nukes the current cache
  107. ===================
  108. */
  109. void idSoundCache::ReloadSounds( bool force ) {
  110. int i;
  111. for( i = 0; i < listCache.Num(); i++ ) {
  112. idSoundSample *def = listCache[i];
  113. if ( def ) {
  114. def->Reload( force );
  115. }
  116. }
  117. }
  118. /*
  119. ====================
  120. BeginLevelLoad
  121. Mark all file based images as currently unused,
  122. but don't free anything. Calls to ImageFromFile() will
  123. either mark the image as used, or create a new image without
  124. loading the actual data.
  125. ====================
  126. */
  127. void idSoundCache::BeginLevelLoad() {
  128. insideLevelLoad = true;
  129. for ( int i = 0 ; i < listCache.Num() ; i++ ) {
  130. idSoundSample *sample = listCache[ i ];
  131. if ( !sample ) {
  132. continue;
  133. }
  134. if ( com_purgeAll.GetBool() ) {
  135. sample->PurgeSoundSample();
  136. }
  137. sample->levelLoadReferenced = false;
  138. }
  139. soundCacheAllocator.FreeEmptyBaseBlocks();
  140. }
  141. /*
  142. ====================
  143. EndLevelLoad
  144. Free all samples marked as unused
  145. ====================
  146. */
  147. void idSoundCache::EndLevelLoad() {
  148. int useCount, purgeCount;
  149. common->Printf( "----- idSoundCache::EndLevelLoad -----\n" );
  150. insideLevelLoad = false;
  151. // purge the ones we don't need
  152. useCount = 0;
  153. purgeCount = 0;
  154. for ( int i = 0 ; i < listCache.Num() ; i++ ) {
  155. idSoundSample *sample = listCache[ i ];
  156. if ( !sample ) {
  157. continue;
  158. }
  159. if ( sample->purged ) {
  160. continue;
  161. }
  162. if ( !sample->levelLoadReferenced ) {
  163. // common->Printf( "Purging %s\n", sample->name.c_str() );
  164. purgeCount += sample->objectMemSize;
  165. sample->PurgeSoundSample();
  166. } else {
  167. useCount += sample->objectMemSize;
  168. }
  169. }
  170. soundCacheAllocator.FreeEmptyBaseBlocks();
  171. common->Printf( "%5ik referenced\n", useCount / 1024 );
  172. common->Printf( "%5ik purged\n", purgeCount / 1024 );
  173. }
  174. /*
  175. ===================
  176. idSoundCache::PrintMemInfo
  177. ===================
  178. */
  179. void idSoundCache::PrintMemInfo( MemInfo_t *mi ) {
  180. int i, j, num = 0, total = 0;
  181. int *sortIndex;
  182. idFile *f;
  183. f = fileSystem->OpenFileWrite( mi->filebase + "_sounds.txt" );
  184. if ( !f ) {
  185. return;
  186. }
  187. // count
  188. for ( i = 0; i < listCache.Num(); i++, num++ ) {
  189. if ( !listCache[i] ) {
  190. break;
  191. }
  192. }
  193. // sort first
  194. sortIndex = new int[num];
  195. for ( i = 0; i < num; i++ ) {
  196. sortIndex[i] = i;
  197. }
  198. for ( i = 0; i < num - 1; i++ ) {
  199. for ( j = i + 1; j < num; j++ ) {
  200. if ( listCache[sortIndex[i]]->objectMemSize < listCache[sortIndex[j]]->objectMemSize ) {
  201. int temp = sortIndex[i];
  202. sortIndex[i] = sortIndex[j];
  203. sortIndex[j] = temp;
  204. }
  205. }
  206. }
  207. // print next
  208. for ( i = 0; i < num; i++ ) {
  209. idSoundSample *sample = listCache[sortIndex[i]];
  210. // this is strange
  211. if ( !sample ) {
  212. continue;
  213. }
  214. total += sample->objectMemSize;
  215. f->Printf( "%s %s\n", idStr::FormatNumber( sample->objectMemSize ).c_str(), sample->name.c_str() );
  216. }
  217. mi->soundAssetsTotal = total;
  218. f->Printf( "\nTotal sound bytes allocated: %s\n", idStr::FormatNumber( total ).c_str() );
  219. fileSystem->CloseFile( f );
  220. delete[] sortIndex;
  221. }
  222. /*
  223. ==========================================================================
  224. idSoundSample
  225. ==========================================================================
  226. */
  227. /*
  228. ===================
  229. idSoundSample::idSoundSample
  230. ===================
  231. */
  232. idSoundSample::idSoundSample() {
  233. memset( &objectInfo, 0, sizeof(waveformatex_t) );
  234. objectSize = 0;
  235. objectMemSize = 0;
  236. nonCacheData = NULL;
  237. amplitudeData = NULL;
  238. openalBuffer = 0;
  239. hardwareBuffer = false;
  240. defaultSound = false;
  241. onDemand = false;
  242. purged = false;
  243. levelLoadReferenced = false;
  244. }
  245. /*
  246. ===================
  247. idSoundSample::~idSoundSample
  248. ===================
  249. */
  250. idSoundSample::~idSoundSample() {
  251. PurgeSoundSample();
  252. }
  253. /*
  254. ===================
  255. idSoundSample::LengthIn44kHzSamples
  256. ===================
  257. */
  258. int idSoundSample::LengthIn44kHzSamples( void ) const {
  259. // objectSize is samples
  260. if ( objectInfo.nSamplesPerSec == 11025 ) {
  261. return objectSize << 2;
  262. } else if ( objectInfo.nSamplesPerSec == 22050 ) {
  263. return objectSize << 1;
  264. } else {
  265. return objectSize << 0;
  266. }
  267. }
  268. /*
  269. ===================
  270. idSoundSample::MakeDefault
  271. ===================
  272. */
  273. void idSoundSample::MakeDefault( void ) {
  274. int i;
  275. float v;
  276. int sample;
  277. memset( &objectInfo, 0, sizeof( objectInfo ) );
  278. objectInfo.nChannels = 1;
  279. objectInfo.wBitsPerSample = 16;
  280. objectInfo.nSamplesPerSec = 44100;
  281. objectSize = MIXBUFFER_SAMPLES * 2;
  282. objectMemSize = objectSize * sizeof( short );
  283. nonCacheData = (byte *)soundCacheAllocator.Alloc( objectMemSize );
  284. short *ncd = (short *)nonCacheData;
  285. for ( i = 0; i < MIXBUFFER_SAMPLES; i ++ ) {
  286. v = sin( idMath::PI * 2 * i / 64 );
  287. sample = v * 0x4000;
  288. ncd[i*2+0] = sample;
  289. ncd[i*2+1] = sample;
  290. }
  291. alGetError();
  292. alGenBuffers( 1, &openalBuffer );
  293. if ( alGetError() != AL_NO_ERROR ) {
  294. common->Error( "idSoundCache: error generating OpenAL hardware buffer" );
  295. }
  296. alGetError();
  297. alBufferData( openalBuffer, objectInfo.nChannels==1?AL_FORMAT_MONO16:AL_FORMAT_STEREO16, nonCacheData, objectMemSize, objectInfo.nSamplesPerSec );
  298. if ( alGetError() != AL_NO_ERROR ) {
  299. common->Error( "idSoundCache: error loading data into OpenAL hardware buffer" );
  300. } else {
  301. hardwareBuffer = true;
  302. }
  303. defaultSound = true;
  304. }
  305. /*
  306. ===================
  307. idSoundSample::CheckForDownSample
  308. ===================
  309. */
  310. void idSoundSample::CheckForDownSample( void ) {
  311. if ( !idSoundSystemLocal::s_force22kHz.GetBool() ) {
  312. return;
  313. }
  314. if ( objectInfo.wFormatTag != WAVE_FORMAT_TAG_PCM || objectInfo.nSamplesPerSec != 44100 ) {
  315. return;
  316. }
  317. int shortSamples = objectSize >> 1;
  318. short *converted = (short *)soundCacheAllocator.Alloc( shortSamples * sizeof( short ) );
  319. if ( objectInfo.nChannels == 1 ) {
  320. for ( int i = 0; i < shortSamples; i++ ) {
  321. converted[i] = ((short *)nonCacheData)[i*2];
  322. }
  323. } else {
  324. for ( int i = 0; i < shortSamples; i += 2 ) {
  325. converted[i+0] = ((short *)nonCacheData)[i*2+0];
  326. converted[i+1] = ((short *)nonCacheData)[i*2+1];
  327. }
  328. }
  329. soundCacheAllocator.Free( nonCacheData );
  330. nonCacheData = (byte *)converted;
  331. objectSize >>= 1;
  332. objectMemSize >>= 1;
  333. objectInfo.nAvgBytesPerSec >>= 1;
  334. objectInfo.nSamplesPerSec >>= 1;
  335. }
  336. /*
  337. ===================
  338. idSoundSample::GetNewTimeStamp
  339. ===================
  340. */
  341. ID_TIME_T idSoundSample::GetNewTimeStamp( void ) const {
  342. ID_TIME_T timestamp;
  343. fileSystem->ReadFile( name, NULL, &timestamp );
  344. if ( timestamp == FILE_NOT_FOUND_TIMESTAMP ) {
  345. idStr oggName = name;
  346. oggName.SetFileExtension( ".ogg" );
  347. fileSystem->ReadFile( oggName, NULL, &timestamp );
  348. }
  349. return timestamp;
  350. }
  351. /*
  352. ===================
  353. idSoundSample::Load
  354. Loads based on name, possibly doing a MakeDefault if necessary
  355. ===================
  356. */
  357. void idSoundSample::Load( void ) {
  358. defaultSound = false;
  359. purged = false;
  360. hardwareBuffer = false;
  361. timestamp = GetNewTimeStamp();
  362. if ( timestamp == FILE_NOT_FOUND_TIMESTAMP ) {
  363. common->Warning( "Couldn't load sound '%s' using default", name.c_str() );
  364. MakeDefault();
  365. return;
  366. }
  367. // load it
  368. idWaveFile fh;
  369. waveformatex_t info;
  370. if ( fh.Open( name, &info ) == -1 ) {
  371. common->Warning( "Couldn't load sound '%s' using default", name.c_str() );
  372. MakeDefault();
  373. return;
  374. }
  375. if ( info.nChannels != 1 && info.nChannels != 2 ) {
  376. common->Warning( "idSoundSample: %s has %i channels, using default", name.c_str(), info.nChannels );
  377. fh.Close();
  378. MakeDefault();
  379. return;
  380. }
  381. if ( info.wBitsPerSample != 16 ) {
  382. common->Warning( "idSoundSample: %s is %dbits, expected 16bits using default", name.c_str(), info.wBitsPerSample );
  383. fh.Close();
  384. MakeDefault();
  385. return;
  386. }
  387. if ( info.nSamplesPerSec != 44100 && info.nSamplesPerSec != 22050 && info.nSamplesPerSec != 11025 ) {
  388. common->Warning( "idSoundCache: %s is %dHz, expected 11025, 22050 or 44100 Hz. Using default", name.c_str(), info.nSamplesPerSec );
  389. fh.Close();
  390. MakeDefault();
  391. return;
  392. }
  393. objectInfo = info;
  394. objectSize = fh.GetOutputSize();
  395. objectMemSize = fh.GetMemorySize();
  396. nonCacheData = (byte *)soundCacheAllocator.Alloc( objectMemSize );
  397. fh.Read( nonCacheData, objectMemSize, NULL );
  398. // optionally convert it to 22kHz to save memory
  399. CheckForDownSample();
  400. // create hardware audio buffers
  401. // PCM loads directly
  402. if ( objectInfo.wFormatTag == WAVE_FORMAT_TAG_PCM ) {
  403. alGetError();
  404. alGenBuffers( 1, &openalBuffer );
  405. if ( alGetError() != AL_NO_ERROR )
  406. common->Error( "idSoundCache: error generating OpenAL hardware buffer" );
  407. if ( alIsBuffer( openalBuffer ) ) {
  408. alGetError();
  409. alBufferData( openalBuffer, objectInfo.nChannels==1?AL_FORMAT_MONO16:AL_FORMAT_STEREO16, nonCacheData, objectMemSize, objectInfo.nSamplesPerSec );
  410. if ( alGetError() != AL_NO_ERROR ) {
  411. common->Error( "idSoundCache: error loading data into OpenAL hardware buffer" );
  412. } else {
  413. hardwareBuffer = true;
  414. }
  415. }
  416. // OGG decompressed at load time (when smaller than s_decompressionLimit seconds, 6 seconds by default)
  417. if ( objectInfo.wFormatTag == WAVE_FORMAT_TAG_OGG ) {
  418. if ( ( objectSize < ( ( int ) objectInfo.nSamplesPerSec * idSoundSystemLocal::s_decompressionLimit.GetInteger() ) ) ) {
  419. alGetError();
  420. alGenBuffers( 1, &openalBuffer );
  421. if ( alGetError() != AL_NO_ERROR )
  422. common->Error( "idSoundCache: error generating OpenAL hardware buffer" );
  423. if ( alIsBuffer( openalBuffer ) ) {
  424. idSampleDecoder *decoder = idSampleDecoder::Alloc();
  425. float *destData = (float *)soundCacheAllocator.Alloc( ( LengthIn44kHzSamples() + 1 ) * sizeof( float ) );
  426. // Decoder *always* outputs 44 kHz data
  427. decoder->Decode( this, 0, LengthIn44kHzSamples(), destData );
  428. // Downsample back to original frequency (save memory)
  429. if ( objectInfo.nSamplesPerSec == 11025 ) {
  430. for ( int i = 0; i < objectSize; i++ ) {
  431. if ( destData[i*4] < -32768.0f )
  432. ((short *)destData)[i] = -32768;
  433. else if ( destData[i*4] > 32767.0f )
  434. ((short *)destData)[i] = 32767;
  435. else
  436. ((short *)destData)[i] = idMath::FtoiFast( destData[i*4] );
  437. }
  438. } else if ( objectInfo.nSamplesPerSec == 22050 ) {
  439. for ( int i = 0; i < objectSize; i++ ) {
  440. if ( destData[i*2] < -32768.0f )
  441. ((short *)destData)[i] = -32768;
  442. else if ( destData[i*2] > 32767.0f )
  443. ((short *)destData)[i] = 32767;
  444. else
  445. ((short *)destData)[i] = idMath::FtoiFast( destData[i*2] );
  446. }
  447. } else {
  448. for ( int i = 0; i < objectSize; i++ ) {
  449. if ( destData[i] < -32768.0f )
  450. ((short *)destData)[i] = -32768;
  451. else if ( destData[i] > 32767.0f )
  452. ((short *)destData)[i] = 32767;
  453. else
  454. ((short *)destData)[i] = idMath::FtoiFast( destData[i] );
  455. }
  456. }
  457. alGetError();
  458. alBufferData( openalBuffer, objectInfo.nChannels==1?AL_FORMAT_MONO16:AL_FORMAT_STEREO16, destData, objectSize * sizeof( short ), objectInfo.nSamplesPerSec );
  459. if ( alGetError() != AL_NO_ERROR )
  460. common->Error( "idSoundCache: error loading data into OpenAL hardware buffer" );
  461. else {
  462. hardwareBuffer = true;
  463. }
  464. soundCacheAllocator.Free( (byte *)destData );
  465. idSampleDecoder::Free( decoder );
  466. }
  467. }
  468. }
  469. }
  470. fh.Close();
  471. }
  472. /*
  473. ===================
  474. idSoundSample::PurgeSoundSample
  475. ===================
  476. */
  477. void idSoundSample::PurgeSoundSample() {
  478. purged = true;
  479. alGetError();
  480. alDeleteBuffers( 1, &openalBuffer );
  481. if ( alGetError() != AL_NO_ERROR ) {
  482. common->Error( "idSoundCache: error unloading data from OpenAL hardware buffer" );
  483. } else {
  484. openalBuffer = 0;
  485. hardwareBuffer = false;
  486. }
  487. if ( amplitudeData ) {
  488. soundCacheAllocator.Free( amplitudeData );
  489. amplitudeData = NULL;
  490. }
  491. if ( nonCacheData ) {
  492. soundCacheAllocator.Free( nonCacheData );
  493. nonCacheData = NULL;
  494. }
  495. }
  496. /*
  497. ===================
  498. idSoundSample::Reload
  499. ===================
  500. */
  501. void idSoundSample::Reload( bool force ) {
  502. if ( !force ) {
  503. ID_TIME_T newTimestamp;
  504. // check the timestamp
  505. newTimestamp = GetNewTimeStamp();
  506. if ( newTimestamp == FILE_NOT_FOUND_TIMESTAMP ) {
  507. if ( !defaultSound ) {
  508. common->Warning( "Couldn't load sound '%s' using default", name.c_str() );
  509. MakeDefault();
  510. }
  511. return;
  512. }
  513. if ( newTimestamp == timestamp ) {
  514. return; // don't need to reload it
  515. }
  516. }
  517. common->Printf( "reloading %s\n", name.c_str() );
  518. PurgeSoundSample();
  519. Load();
  520. }
  521. /*
  522. ===================
  523. idSoundSample::FetchFromCache
  524. Returns true on success.
  525. ===================
  526. */
  527. bool idSoundSample::FetchFromCache( int offset, const byte **output, int *position, int *size, const bool allowIO ) {
  528. offset &= 0xfffffffe;
  529. if ( objectSize == 0 || offset < 0 || offset > objectSize * (int)sizeof( short ) || !nonCacheData ) {
  530. return false;
  531. }
  532. if ( output ) {
  533. *output = nonCacheData + offset;
  534. }
  535. if ( position ) {
  536. *position = 0;
  537. }
  538. if ( size ) {
  539. *size = objectSize * sizeof( short ) - offset;
  540. if ( *size > SCACHE_SIZE ) {
  541. *size = SCACHE_SIZE;
  542. }
  543. }
  544. return true;
  545. }