/* =================== idSoundSample::CheckForDownSample =================== */ void idSoundSample::CheckForDownSample( void ) { if( !idSoundSystemLocal::s_force22kHz.GetBool() ) { return; } if( objectInfo.wFormatTag != WAVE_FORMAT_TAG_PCM || objectInfo.nSamplesPerSec != 44100 ) { return; } int shortSamples = objectSize >> 1; short *converted = ( short * )soundCacheAllocator.Alloc( shortSamples * sizeof( short ) ); if( objectInfo.nChannels == 1 ) { for( int i = 0; i < shortSamples; i++ ) { converted[i] = ( ( short * )nonCacheData )[i * 2]; } } else { for( int i = 0; i < shortSamples; i += 2 ) { converted[i + 0] = ( ( short * )nonCacheData )[i * 2 + 0]; converted[i + 1] = ( ( short * )nonCacheData )[i * 2 + 1]; } } soundCacheAllocator.Free( nonCacheData ); nonCacheData = ( byte * )converted; objectSize >>= 1; objectMemSize >>= 1; objectInfo.nAvgBytesPerSec >>= 1; objectInfo.nSamplesPerSec >>= 1; }
/* =================== idSoundSample::MakeDefault =================== */ void idSoundSample::MakeDefault( void ) { int i; float v; int sample; memset( &objectInfo, 0, sizeof( objectInfo ) ); objectInfo.nChannels = 1; objectInfo.wBitsPerSample = 16; objectInfo.nSamplesPerSec = 44100; objectSize = MIXBUFFER_SAMPLES * 2; objectMemSize = objectSize * sizeof( short ); nonCacheData = ( byte * )soundCacheAllocator.Alloc( objectMemSize ); short *ncd = ( short * )nonCacheData; for( i = 0; i < MIXBUFFER_SAMPLES; i ++ ) { v = sin( idMath::PI * 2 * i / 64 ); sample = v * 0x4000; ncd[i * 2 + 0] = sample; ncd[i * 2 + 1] = sample; } if( idSoundSystemLocal::useOpenAL ) { alGetError(); alGenBuffers( 1, &openalBuffer ); if( alGetError() != AL_NO_ERROR ) { common->Error( "idSoundCache: error generating OpenAL hardware buffer" ); } 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 { hardwareBuffer = true; } } defaultSound = true; }
/* ============ idStr::ReAllocate ============ */ void idStr::ReAllocate( int amount, bool keepold ) { char* newbuffer; int newsize; int mod; //assert( data ); assert( amount > 0 ); mod = amount % STR_ALLOC_GRAN; if( !mod ) { newsize = amount; } else { newsize = amount + STR_ALLOC_GRAN - mod; } SetAlloced( newsize ); #ifdef USE_STRING_DATA_ALLOCATOR newbuffer = stringDataAllocator.Alloc( GetAlloced() ); #else newbuffer = new( TAG_STRING ) char[ GetAlloced() ]; #endif if( keepold && data ) { data[ len ] = '\0'; strcpy( newbuffer, data ); } if( data && data != baseBuffer ) { #ifdef USE_STRING_DATA_ALLOCATOR stringDataAllocator.Free( data ); #else delete [] data; #endif } data = newbuffer; }
/* =================== 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->Warning( "idSoundSample: %s has %i channels, using default", name.c_str(), info.nChannels ); fh.Close(); MakeDefault(); return; } if( info.wBitsPerSample != 16 ) { common->Warning( "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->Warning( "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 { 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 defined(MACOS_X) if( ( objectSize < ( ( int ) objectInfo.nSamplesPerSec * idSoundSystemLocal::s_decompressionLimit.GetInteger() ) ) ) { #else if( ( alIsExtensionPresent( ID_ALCHAR "EAX-RAM" ) == AL_TRUE ) && ( objectSize < ( ( int ) objectInfo.nSamplesPerSec * idSoundSystemLocal::s_decompressionLimit.GetInteger() ) ) ) { #endif 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 { hardwareBuffer = true; } soundCacheAllocator.Free( ( byte * )destData ); idSampleDecoder::Free( decoder ); } } } } fh.Close(); } /* =================== idSoundSample::PurgeSoundSample =================== */ void idSoundSample::PurgeSoundSample() { purged = true; if( hardwareBuffer && idSoundSystemLocal::useOpenAL ) { alGetError(); alDeleteBuffers( 1, &openalBuffer ); if( alGetError() != AL_NO_ERROR ) { common->Error( "idSoundCache: error unloading data from OpenAL hardware buffer" ); } else { openalBuffer = 0; hardwareBuffer = false; } } if( amplitudeData ) { soundCacheAllocator.Free( amplitudeData ); amplitudeData = NULL; } if( nonCacheData ) { soundCacheAllocator.Free( nonCacheData ); nonCacheData = NULL; } }
/* =================== 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->Warning( "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->Warning( "Couldn't load sound '%s' using default", name.c_str() ); MakeDefault(); return; } if ( info.nChannels != 1 && info.nChannels != 2 ) { common->Warning( "idSoundSample: %s has %i channels, using default", name.c_str(), info.nChannels ); fh.Close(); MakeDefault(); return; } if ( info.wBitsPerSample != 16 ) { common->Warning( "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->Warning( "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 // 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 { // Compute amplitude block size int blockSize = 512 * objectInfo.nSamplesPerSec / 44100 ; // Allocate amplitude data array amplitudeData = (byte *)soundCacheAllocator.Alloc( ( objectSize / blockSize + 1 ) * 2 * sizeof( short) ); // Creating array of min/max amplitude pairs per blockSize samples int i; for ( i = 0; i < objectSize; i+=blockSize ) { short min = 32767; short max = -32768; int j; for ( j = 0; j < Min( objectSize - i, blockSize ); j++ ) { min = ((short *)nonCacheData)[ i + j ] < min ? ((short *)nonCacheData)[ i + j ] : min; max = ((short *)nonCacheData)[ i + j ] > max ? ((short *)nonCacheData)[ i + j ] : max; } ((short *)amplitudeData)[ ( i / blockSize ) * 2 ] = min; ((short *)amplitudeData)[ ( i / blockSize ) * 2 + 1 ] = max; } 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 ( ( 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 { // Compute amplitude block size int blockSize = 512 * objectInfo.nSamplesPerSec / 44100 ; // Allocate amplitude data array amplitudeData = (byte *)soundCacheAllocator.Alloc( ( objectSize / blockSize + 1 ) * 2 * sizeof( short ) ); // Creating array of min/max amplitude pairs per blockSize samples int i; for ( i = 0; i < objectSize; i+=blockSize ) { short min = 32767; short max = -32768; int j; for ( j = 0; j < Min( objectSize - i, blockSize ); j++ ) { min = ((short *)destData)[ i + j ] < min ? ((short *)destData)[ i + j ] : min; max = ((short *)destData)[ i + j ] > max ? ((short *)destData)[ i + j ] : max; } ((short *)amplitudeData)[ ( i / blockSize ) * 2 ] = min; ((short *)amplitudeData)[ ( i / blockSize ) * 2 + 1 ] = max; } 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(); }
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; }
void *_decoder_malloc( size_t size ) { void *ptr = decoderMemoryAllocator.Alloc( size ); assert( size == 0 || ptr != NULL ); return ptr; }