snd_cache.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710
  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. common->Printf( "----------------------------------------\n" );
  174. }
  175. /*
  176. ===================
  177. idSoundCache::PrintMemInfo
  178. ===================
  179. */
  180. void idSoundCache::PrintMemInfo( MemInfo_t *mi ) {
  181. int i, j, num = 0, total = 0;
  182. int *sortIndex;
  183. idFile *f;
  184. f = fileSystem->OpenFileWrite( mi->filebase + "_sounds.txt" );
  185. if ( !f ) {
  186. return;
  187. }
  188. // count
  189. for ( i = 0; i < listCache.Num(); i++, num++ ) {
  190. if ( !listCache[i] ) {
  191. break;
  192. }
  193. }
  194. // sort first
  195. sortIndex = new int[num];
  196. for ( i = 0; i < num; i++ ) {
  197. sortIndex[i] = i;
  198. }
  199. for ( i = 0; i < num - 1; i++ ) {
  200. for ( j = i + 1; j < num; j++ ) {
  201. if ( listCache[sortIndex[i]]->objectMemSize < listCache[sortIndex[j]]->objectMemSize ) {
  202. int temp = sortIndex[i];
  203. sortIndex[i] = sortIndex[j];
  204. sortIndex[j] = temp;
  205. }
  206. }
  207. }
  208. // print next
  209. for ( i = 0; i < num; i++ ) {
  210. idSoundSample *sample = listCache[sortIndex[i]];
  211. // this is strange
  212. if ( !sample ) {
  213. continue;
  214. }
  215. total += sample->objectMemSize;
  216. f->Printf( "%s %s\n", idStr::FormatNumber( sample->objectMemSize ).c_str(), sample->name.c_str() );
  217. }
  218. mi->soundAssetsTotal = total;
  219. f->Printf( "\nTotal sound bytes allocated: %s\n", idStr::FormatNumber( total ).c_str() );
  220. fileSystem->CloseFile( f );
  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 = NULL;
  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. if ( idSoundSystemLocal::useOpenAL ) {
  292. alGetError();
  293. alGenBuffers( 1, &openalBuffer );
  294. if ( alGetError() != AL_NO_ERROR ) {
  295. common->Error( "idSoundCache: error generating OpenAL hardware buffer" );
  296. }
  297. alGetError();
  298. alBufferData( openalBuffer, objectInfo.nChannels==1?AL_FORMAT_MONO16:AL_FORMAT_STEREO16, nonCacheData, objectMemSize, objectInfo.nSamplesPerSec );
  299. if ( alGetError() != AL_NO_ERROR ) {
  300. common->Error( "idSoundCache: error loading data into OpenAL hardware buffer" );
  301. } else {
  302. hardwareBuffer = true;
  303. }
  304. }
  305. defaultSound = true;
  306. }
  307. /*
  308. ===================
  309. idSoundSample::CheckForDownSample
  310. ===================
  311. */
  312. void idSoundSample::CheckForDownSample( void ) {
  313. if ( !idSoundSystemLocal::s_force22kHz.GetBool() ) {
  314. return;
  315. }
  316. if ( objectInfo.wFormatTag != WAVE_FORMAT_TAG_PCM || objectInfo.nSamplesPerSec != 44100 ) {
  317. return;
  318. }
  319. int shortSamples = objectSize >> 1;
  320. short *converted = (short *)soundCacheAllocator.Alloc( shortSamples * sizeof( short ) );
  321. if ( objectInfo.nChannels == 1 ) {
  322. for ( int i = 0; i < shortSamples; i++ ) {
  323. converted[i] = ((short *)nonCacheData)[i*2];
  324. }
  325. } else {
  326. for ( int i = 0; i < shortSamples; i += 2 ) {
  327. converted[i+0] = ((short *)nonCacheData)[i*2+0];
  328. converted[i+1] = ((short *)nonCacheData)[i*2+1];
  329. }
  330. }
  331. soundCacheAllocator.Free( nonCacheData );
  332. nonCacheData = (byte *)converted;
  333. objectSize >>= 1;
  334. objectMemSize >>= 1;
  335. objectInfo.nAvgBytesPerSec >>= 1;
  336. objectInfo.nSamplesPerSec >>= 1;
  337. }
  338. /*
  339. ===================
  340. idSoundSample::GetNewTimeStamp
  341. ===================
  342. */
  343. ID_TIME_T idSoundSample::GetNewTimeStamp( void ) const {
  344. ID_TIME_T timestamp;
  345. fileSystem->ReadFile( name, NULL, &timestamp );
  346. if ( timestamp == FILE_NOT_FOUND_TIMESTAMP ) {
  347. idStr oggName = name;
  348. oggName.SetFileExtension( ".ogg" );
  349. fileSystem->ReadFile( oggName, NULL, &timestamp );
  350. }
  351. return timestamp;
  352. }
  353. /*
  354. ===================
  355. idSoundSample::Load
  356. Loads based on name, possibly doing a MakeDefault if necessary
  357. ===================
  358. */
  359. void idSoundSample::Load( void ) {
  360. defaultSound = false;
  361. purged = false;
  362. hardwareBuffer = false;
  363. timestamp = GetNewTimeStamp();
  364. if ( timestamp == FILE_NOT_FOUND_TIMESTAMP ) {
  365. common->Warning( "Couldn't load sound '%s' using default", name.c_str() );
  366. MakeDefault();
  367. return;
  368. }
  369. // load it
  370. idWaveFile fh;
  371. waveformatex_t info;
  372. if ( fh.Open( name, &info ) == -1 ) {
  373. common->Warning( "Couldn't load sound '%s' using default", name.c_str() );
  374. MakeDefault();
  375. return;
  376. }
  377. if ( info.nChannels != 1 && info.nChannels != 2 ) {
  378. common->Warning( "idSoundSample: %s has %i channels, using default", name.c_str(), info.nChannels );
  379. fh.Close();
  380. MakeDefault();
  381. return;
  382. }
  383. if ( info.wBitsPerSample != 16 ) {
  384. common->Warning( "idSoundSample: %s is %dbits, expected 16bits using default", name.c_str(), info.wBitsPerSample );
  385. fh.Close();
  386. MakeDefault();
  387. return;
  388. }
  389. if ( info.nSamplesPerSec != 44100 && info.nSamplesPerSec != 22050 && info.nSamplesPerSec != 11025 ) {
  390. common->Warning( "idSoundCache: %s is %dHz, expected 11025, 22050 or 44100 Hz. Using default", name.c_str(), info.nSamplesPerSec );
  391. fh.Close();
  392. MakeDefault();
  393. return;
  394. }
  395. objectInfo = info;
  396. objectSize = fh.GetOutputSize();
  397. objectMemSize = fh.GetMemorySize();
  398. nonCacheData = (byte *)soundCacheAllocator.Alloc( objectMemSize );
  399. fh.Read( nonCacheData, objectMemSize, NULL );
  400. // optionally convert it to 22kHz to save memory
  401. CheckForDownSample();
  402. // create hardware audio buffers
  403. if ( idSoundSystemLocal::useOpenAL ) {
  404. // PCM loads directly
  405. if ( objectInfo.wFormatTag == WAVE_FORMAT_TAG_PCM ) {
  406. alGetError();
  407. alGenBuffers( 1, &openalBuffer );
  408. if ( alGetError() != AL_NO_ERROR )
  409. common->Error( "idSoundCache: error generating OpenAL hardware buffer" );
  410. if ( alIsBuffer( openalBuffer ) ) {
  411. alGetError();
  412. alBufferData( openalBuffer, objectInfo.nChannels==1?AL_FORMAT_MONO16:AL_FORMAT_STEREO16, nonCacheData, objectMemSize, objectInfo.nSamplesPerSec );
  413. if ( alGetError() != AL_NO_ERROR ) {
  414. common->Error( "idSoundCache: error loading data into OpenAL hardware buffer" );
  415. } else {
  416. // Compute amplitude block size
  417. int blockSize = 512 * objectInfo.nSamplesPerSec / 44100 ;
  418. // Allocate amplitude data array
  419. amplitudeData = (byte *)soundCacheAllocator.Alloc( ( objectSize / blockSize + 1 ) * 2 * sizeof( short) );
  420. // Creating array of min/max amplitude pairs per blockSize samples
  421. int i;
  422. for ( i = 0; i < objectSize; i+=blockSize ) {
  423. short min = 32767;
  424. short max = -32768;
  425. int j;
  426. for ( j = 0; j < Min( objectSize - i, blockSize ); j++ ) {
  427. min = ((short *)nonCacheData)[ i + j ] < min ? ((short *)nonCacheData)[ i + j ] : min;
  428. max = ((short *)nonCacheData)[ i + j ] > max ? ((short *)nonCacheData)[ i + j ] : max;
  429. }
  430. ((short *)amplitudeData)[ ( i / blockSize ) * 2 ] = min;
  431. ((short *)amplitudeData)[ ( i / blockSize ) * 2 + 1 ] = max;
  432. }
  433. hardwareBuffer = true;
  434. }
  435. }
  436. }
  437. // OGG decompressed at load time (when smaller than s_decompressionLimit seconds, 6 seconds by default)
  438. if ( objectInfo.wFormatTag == WAVE_FORMAT_TAG_OGG ) {
  439. #if defined(MACOS_X)
  440. if ( ( objectSize < ( ( int ) objectInfo.nSamplesPerSec * idSoundSystemLocal::s_decompressionLimit.GetInteger() ) ) ) {
  441. #else
  442. if ( ( alIsExtensionPresent( ID_ALCHAR "EAX-RAM" ) == AL_TRUE ) && ( objectSize < ( ( int ) objectInfo.nSamplesPerSec * idSoundSystemLocal::s_decompressionLimit.GetInteger() ) ) ) {
  443. #endif
  444. alGetError();
  445. alGenBuffers( 1, &openalBuffer );
  446. if ( alGetError() != AL_NO_ERROR )
  447. common->Error( "idSoundCache: error generating OpenAL hardware buffer" );
  448. if ( alIsBuffer( openalBuffer ) ) {
  449. idSampleDecoder *decoder = idSampleDecoder::Alloc();
  450. float *destData = (float *)soundCacheAllocator.Alloc( ( LengthIn44kHzSamples() + 1 ) * sizeof( float ) );
  451. // Decoder *always* outputs 44 kHz data
  452. decoder->Decode( this, 0, LengthIn44kHzSamples(), destData );
  453. // Downsample back to original frequency (save memory)
  454. if ( objectInfo.nSamplesPerSec == 11025 ) {
  455. for ( int i = 0; i < objectSize; i++ ) {
  456. if ( destData[i*4] < -32768.0f )
  457. ((short *)destData)[i] = -32768;
  458. else if ( destData[i*4] > 32767.0f )
  459. ((short *)destData)[i] = 32767;
  460. else
  461. ((short *)destData)[i] = idMath::FtoiFast( destData[i*4] );
  462. }
  463. } else if ( objectInfo.nSamplesPerSec == 22050 ) {
  464. for ( int i = 0; i < objectSize; i++ ) {
  465. if ( destData[i*2] < -32768.0f )
  466. ((short *)destData)[i] = -32768;
  467. else if ( destData[i*2] > 32767.0f )
  468. ((short *)destData)[i] = 32767;
  469. else
  470. ((short *)destData)[i] = idMath::FtoiFast( destData[i*2] );
  471. }
  472. } else {
  473. for ( int i = 0; i < objectSize; i++ ) {
  474. if ( destData[i] < -32768.0f )
  475. ((short *)destData)[i] = -32768;
  476. else if ( destData[i] > 32767.0f )
  477. ((short *)destData)[i] = 32767;
  478. else
  479. ((short *)destData)[i] = idMath::FtoiFast( destData[i] );
  480. }
  481. }
  482. alGetError();
  483. alBufferData( openalBuffer, objectInfo.nChannels==1?AL_FORMAT_MONO16:AL_FORMAT_STEREO16, destData, objectSize * sizeof( short ), objectInfo.nSamplesPerSec );
  484. if ( alGetError() != AL_NO_ERROR )
  485. common->Error( "idSoundCache: error loading data into OpenAL hardware buffer" );
  486. else {
  487. // Compute amplitude block size
  488. int blockSize = 512 * objectInfo.nSamplesPerSec / 44100 ;
  489. // Allocate amplitude data array
  490. amplitudeData = (byte *)soundCacheAllocator.Alloc( ( objectSize / blockSize + 1 ) * 2 * sizeof( short ) );
  491. // Creating array of min/max amplitude pairs per blockSize samples
  492. int i;
  493. for ( i = 0; i < objectSize; i+=blockSize ) {
  494. short min = 32767;
  495. short max = -32768;
  496. int j;
  497. for ( j = 0; j < Min( objectSize - i, blockSize ); j++ ) {
  498. min = ((short *)destData)[ i + j ] < min ? ((short *)destData)[ i + j ] : min;
  499. max = ((short *)destData)[ i + j ] > max ? ((short *)destData)[ i + j ] : max;
  500. }
  501. ((short *)amplitudeData)[ ( i / blockSize ) * 2 ] = min;
  502. ((short *)amplitudeData)[ ( i / blockSize ) * 2 + 1 ] = max;
  503. }
  504. hardwareBuffer = true;
  505. }
  506. soundCacheAllocator.Free( (byte *)destData );
  507. idSampleDecoder::Free( decoder );
  508. }
  509. }
  510. }
  511. // Free memory if sample was loaded into hardware
  512. if ( hardwareBuffer ) {
  513. soundCacheAllocator.Free( nonCacheData );
  514. nonCacheData = NULL;
  515. }
  516. }
  517. fh.Close();
  518. }
  519. /*
  520. ===================
  521. idSoundSample::PurgeSoundSample
  522. ===================
  523. */
  524. void idSoundSample::PurgeSoundSample() {
  525. purged = true;
  526. if ( hardwareBuffer && idSoundSystemLocal::useOpenAL ) {
  527. alGetError();
  528. alDeleteBuffers( 1, &openalBuffer );
  529. if ( alGetError() != AL_NO_ERROR ) {
  530. common->Error( "idSoundCache: error unloading data from OpenAL hardware buffer" );
  531. } else {
  532. openalBuffer = 0;
  533. hardwareBuffer = false;
  534. }
  535. }
  536. if ( amplitudeData ) {
  537. soundCacheAllocator.Free( amplitudeData );
  538. amplitudeData = NULL;
  539. }
  540. if ( nonCacheData ) {
  541. soundCacheAllocator.Free( nonCacheData );
  542. nonCacheData = NULL;
  543. }
  544. }
  545. /*
  546. ===================
  547. idSoundSample::Reload
  548. ===================
  549. */
  550. void idSoundSample::Reload( bool force ) {
  551. if ( !force ) {
  552. ID_TIME_T newTimestamp;
  553. // check the timestamp
  554. newTimestamp = GetNewTimeStamp();
  555. if ( newTimestamp == FILE_NOT_FOUND_TIMESTAMP ) {
  556. if ( !defaultSound ) {
  557. common->Warning( "Couldn't load sound '%s' using default", name.c_str() );
  558. MakeDefault();
  559. }
  560. return;
  561. }
  562. if ( newTimestamp == timestamp ) {
  563. return; // don't need to reload it
  564. }
  565. }
  566. common->Printf( "reloading %s\n", name.c_str() );
  567. PurgeSoundSample();
  568. Load();
  569. }
  570. /*
  571. ===================
  572. idSoundSample::FetchFromCache
  573. Returns true on success.
  574. ===================
  575. */
  576. bool idSoundSample::FetchFromCache( int offset, const byte **output, int *position, int *size, const bool allowIO ) {
  577. offset &= 0xfffffffe;
  578. if ( objectSize == 0 || offset < 0 || offset > objectSize * (int)sizeof( short ) || !nonCacheData ) {
  579. return false;
  580. }
  581. if ( output ) {
  582. *output = nonCacheData + offset;
  583. }
  584. if ( position ) {
  585. *position = 0;
  586. }
  587. if ( size ) {
  588. *size = objectSize * sizeof( short ) - offset;
  589. if ( *size > SCACHE_SIZE ) {
  590. *size = SCACHE_SIZE;
  591. }
  592. }
  593. return true;
  594. }