/* ==================== idSampleDecoder::GetNumUsedBlocks ==================== */ int idSampleDecoder::GetNumUsedBlocks( void ) { return decoderMemoryAllocator.GetNumUsedBlocks(); }
/* ==================== idSampleDecoder::GetUsedBlockMemory ==================== */ int idSampleDecoder::GetUsedBlockMemory( void ) { return decoderMemoryAllocator.GetUsedBlockMemory(); }
/* ==================== idSampleDecoder::Init ==================== */ void idSampleDecoder::Init( void ) { decoderMemoryAllocator.Init(); decoderMemoryAllocator.SetLockMemory( true ); decoderMemoryAllocator.SetFixedBlocks( idSoundSystemLocal::s_realTimeDecoding.GetBool() ? 10 : 1 ); }
/* ==================== idSampleDecoder::Shutdown ==================== */ void idSampleDecoder::Shutdown( void ) { decoderMemoryAllocator.Shutdown(); sampleDecoderAllocator.Shutdown(); }
void *_decoder_realloc( void *memblock, size_t size ) { void *ptr = decoderMemoryAllocator.Resize( (byte *)memblock, size ); assert( size == 0 || ptr != NULL ); return ptr; }
void _decoder_free( void *memblock ) { decoderMemoryAllocator.Free( (byte *)memblock ); }
void *_decoder_malloc( size_t size ) { void *ptr = decoderMemoryAllocator.Alloc( size ); assert( size == 0 || ptr != NULL ); return ptr; }
void *_decoder_calloc( size_t num, size_t size ) { void *ptr = decoderMemoryAllocator.Alloc( num * size ); assert( ( num * size ) == 0 || ptr != NULL ); memset( ptr, 0, num * size ); return ptr; }
/* ================ idStr::PurgeMemory ================ */ void idStr::PurgeMemory( void ) { #ifdef USE_STRING_DATA_ALLOCATOR stringDataAllocator.FreeEmptyBaseBlocks(); #endif }
/* ==================== idSampleDecoderLocal::DecodeOGG ==================== */ int idSampleDecoderLocal::DecodeOGG( idSoundSample *sample, int sampleOffset44k, int sampleCount44k, float *dest ) { int readSamples, totalSamples; int shift = 22050 / sample->objectInfo.nSamplesPerSec; int sampleOffset = sampleOffset44k >> shift; int sampleCount = sampleCount44k >> shift; // open OGG file if not yet opened if ( lastSample == NULL ) { // make sure there is enough space for another decoder if ( decoderMemoryAllocator.GetFreeBlockMemory() < MIN_OGGVORBIS_MEMORY ) { return 0; } if ( sample->nonCacheData == NULL ) { assert( false ); // this should never happen failed = true; return 0; } file.SetData( (const char *)sample->nonCacheData, sample->objectMemSize ); if ( ov_openFile( &file, &ogg ) < 0 ) { failed = true; return 0; } lastFormat = WAVE_FORMAT_TAG_OGG; lastSample = sample; } // seek to the right offset if necessary if ( sampleOffset != lastSampleOffset ) { if ( ov_pcm_seek( &ogg, sampleOffset / sample->objectInfo.nChannels ) != 0 ) { failed = true; return 0; } } lastSampleOffset = sampleOffset; // decode OGG samples totalSamples = sampleCount; readSamples = 0; do { float **samples; int ret = ov_read_float( &ogg, &samples, totalSamples / sample->objectInfo.nChannels, NULL ); if ( ret == 0 ) { failed = true; break; } if ( ret < 0 ) { failed = true; return 0; } ret *= sample->objectInfo.nChannels; SIMDProcessor->UpSampleOGGTo44kHz( dest + ( readSamples << shift ), samples, ret, sample->objectInfo.nSamplesPerSec, sample->objectInfo.nChannels ); readSamples += ret; totalSamples -= ret; } while( totalSamples > 0 ); lastSampleOffset += readSamples; return ( readSamples << shift ); }
/* ================ idStr::ShutdownMemory ================ */ void idStr::ShutdownMemory( void ) { #ifdef USE_STRING_DATA_ALLOCATOR stringDataAllocator.Shutdown(); #endif }
/* ================ idStr::InitMemory ================ */ void idStr::InitMemory( void ) { #ifdef USE_STRING_DATA_ALLOCATOR stringDataAllocator.Init(); #endif }
=========================================================================== */ #include "sys/platform.h" #include "idlib/math/Vector.h" #include "idlib/Heap.h" #include "framework/Common.h" #include "idlib/Str.h" #if !defined( ID_REDIRECT_NEWDELETE ) && !defined( MACOS_X ) #define USE_STRING_DATA_ALLOCATOR #endif #ifdef USE_STRING_DATA_ALLOCATOR static idDynamicBlockAlloc<char, 1<<18, 128> stringDataAllocator; #endif idVec4 g_color_table[16] = { idVec4(0.0f, 0.0f, 0.0f, 1.0f), idVec4(1.0f, 0.0f, 0.0f, 1.0f), // S_COLOR_RED idVec4(0.0f, 1.0f, 0.0f, 1.0f), // S_COLOR_GREEN idVec4(1.0f, 1.0f, 0.0f, 1.0f), // S_COLOR_YELLOW idVec4(0.0f, 0.0f, 1.0f, 1.0f), // S_COLOR_BLUE idVec4(0.0f, 1.0f, 1.0f, 1.0f), // S_COLOR_CYAN idVec4(1.0f, 0.0f, 1.0f, 1.0f), // S_COLOR_MAGENTA idVec4(1.0f, 1.0f, 1.0f, 1.0f), // S_COLOR_WHITE idVec4(0.5f, 0.5f, 0.5f, 1.0f), // S_COLOR_GRAY idVec4(0.0f, 0.0f, 0.0f, 1.0f), // S_COLOR_BLACK idVec4(0.0f, 0.0f, 0.0f, 1.0f),
/* =================== idSoundCache::~idSoundCache () =================== */ idSoundCache::~idSoundCache() { listCache.DeleteContents( true ); soundCacheAllocator.Shutdown(); }
/* =================== idSoundSample::Load Loads based on name, possibly doing a MakeDefault if necessary =================== */ void idSoundSample::Load( void ) { defaultSound = false; purged = false; hardwareBuffer = false; timestamp = GetNewTimeStamp(); if( timestamp == FILE_NOT_FOUND_TIMESTAMP ) { common->DWarning( "Couldn't load sound '%s' using default", name.c_str() ); MakeDefault(); return; } // load it idWaveFile fh; waveformatex_t info; if( fh.Open( name, &info ) == -1 ) { common->DWarning( "Couldn't load sound '%s' using default", name.c_str() ); MakeDefault(); return; } if( info.nChannels != 1 && info.nChannels != 2 ) { common->DWarning( "idSoundSample: %s has %i channels, using default", name.c_str(), info.nChannels ); fh.Close(); MakeDefault(); return; } if( info.wBitsPerSample != 16 ) { common->DWarning( "idSoundSample: %s is %dbits, expected 16bits using default", name.c_str(), info.wBitsPerSample ); fh.Close(); MakeDefault(); return; } if( info.nSamplesPerSec != 44100 && info.nSamplesPerSec != 22050 && info.nSamplesPerSec != 11025 ) { common->DWarning( "idSoundCache: %s is %dHz, expected 11025, 22050 or 44100 Hz. Using default", name.c_str(), info.nSamplesPerSec ); fh.Close(); MakeDefault(); return; } objectInfo = info; objectSize = fh.GetOutputSize(); objectMemSize = fh.GetMemorySize(); nonCacheData = ( byte * ) soundCacheAllocator.Alloc( objectMemSize ); fh.Read( nonCacheData, objectMemSize, NULL ); // optionally convert it to 22kHz to save memory CheckForDownSample(); // create hardware audio buffers if( idSoundSystemLocal::useOpenAL ) { // PCM loads directly if( objectInfo.wFormatTag == WAVE_FORMAT_TAG_PCM ) { alGetError(); alGenBuffers( 1, &openalBuffer ); if( alGetError() != AL_NO_ERROR ) { common->Error( "idSoundCache: error generating OpenAL hardware buffer" ); } if( alIsBuffer( openalBuffer ) ) { alGetError(); alBufferData( openalBuffer, objectInfo.nChannels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, nonCacheData, objectMemSize, objectInfo.nSamplesPerSec ); if( alGetError() != AL_NO_ERROR ) { common->Error( "idSoundCache: error loading data into OpenAL hardware buffer" ); } else { // removed the code here as it causes // micro stutter in the camera. hardwareBuffer = true; } } } // OGG decompressed at load time (when smaller than s_decompressionLimit seconds, 6 seconds by default) if( objectInfo.wFormatTag == WAVE_FORMAT_TAG_OGG ) { if( ( alIsExtensionPresent( ID_ALCHAR "EAX-RAM" ) == AL_TRUE ) && ( objectSize < ( ( int ) objectInfo.nSamplesPerSec * idSoundSystemLocal::s_decompressionLimit.GetInteger() ) ) ) { alGetError(); alGenBuffers( 1, &openalBuffer ); if( alGetError() != AL_NO_ERROR ) { common->Error( "idSoundCache: error generating OpenAL hardware buffer" ); } if( alIsBuffer( openalBuffer ) ) { idSampleDecoder *decoder = idSampleDecoder::Alloc(); float *destData = ( float * ) soundCacheAllocator.Alloc( ( LengthIn44kHzSamples() + 1 ) * sizeof( float ) ); // Decoder *always* outputs 44 kHz data decoder->Decode( this, 0, LengthIn44kHzSamples(), destData ); // Downsample back to original frequency (save memory) if( objectInfo.nSamplesPerSec == 11025 ) { for( int i = 0; i < objectSize; i++ ) { if( destData[i * 4] < -32768.0f ) { ( ( short * ) destData ) [i] = -32768; } else if( destData[i * 4] > 32767.0f ) { ( ( short * ) destData ) [i] = 32767; } else { ( ( short * ) destData ) [i] = idMath::FtoiFast( destData[i * 4] ); } } } else if( objectInfo.nSamplesPerSec == 22050 ) { for( int i = 0; i < objectSize; i++ ) { if( destData[i * 2] < -32768.0f ) { ( ( short * ) destData ) [i] = -32768; } else if( destData[i * 2] > 32767.0f ) { ( ( short * ) destData ) [i] = 32767; } else { ( ( short * ) destData ) [i] = idMath::FtoiFast( destData[i * 2] ); } } } else { for( int i = 0; i < objectSize; i++ ) { if( destData[i] < -32768.0f ) { ( ( short * ) destData ) [i] = -32768; } else if( destData[i] > 32767.0f ) { ( ( short * ) destData ) [i] = 32767; } else { ( ( short * ) destData ) [i] = idMath::FtoiFast( destData[i] ); } } } alGetError(); alBufferData( openalBuffer, objectInfo.nChannels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, destData, objectSize * sizeof( short ), objectInfo.nSamplesPerSec ); if( alGetError() != AL_NO_ERROR ) { common->Error( "idSoundCache: error loading data into OpenAL hardware buffer" ); } else { // removed the code here as it causes // micro stutter in the camera. hardwareBuffer = true; } soundCacheAllocator.Free( ( byte * ) destData ); idSampleDecoder::Free( decoder ); } } } // Free memory if sample was loaded into hardware if( hardwareBuffer ) { soundCacheAllocator.Free( nonCacheData ); nonCacheData = NULL; } } fh.Close(); }