diff --git a/engine/client/s_utils.c b/engine/client/s_utils.c index 0026334a..fc5a4bb2 100644 --- a/engine/client/s_utils.c +++ b/engine/client/s_utils.c @@ -16,204 +16,6 @@ GNU General Public License for more details. #include "common.h" #include "sound.h" -// hardcoded macros to test for zero crossing -#define ZERO_X_8( b ) (( b ) < 2 && ( b ) > -2 ) -#define ZERO_X_16( b ) (( b ) < 512 && ( b ) > -512 ) - -//----------------------------------------------------------------------------- -// Purpose: Search backward for a zero crossing starting at sample -// Input : sample - starting point -// Output : position of zero crossing -//----------------------------------------------------------------------------- -int S_ZeroCrossingBefore( wavdata_t *pWaveData, int sample ) -{ - if( pWaveData == NULL ) - return sample; - - if( pWaveData->type == WF_PCMDATA ) - { - int sampleSize; - - sampleSize = pWaveData->width * pWaveData->channels; - - // this can never be zero -- other functions divide by this. - // This should never happen, but avoid crashing - if( sampleSize <= 0 ) sampleSize = 1; - - if( pWaveData->width == 1 ) - { - signed char *pData = (signed char *)(pWaveData->buffer + sample * sampleSize); - qboolean zero = false; - - if( pWaveData->channels == 1 ) - { - while( sample > 0 && !zero ) - { - if( ZERO_X_8( *pData )) - { - zero = true; - } - else - { - sample--; - pData--; - } - } - } - else - { - while( sample > 0 && !zero ) - { - if( ZERO_X_8( *pData ) && ZERO_X_8( pData[1] )) - { - zero = true; - } - else - { - sample--; - pData--; - } - } - } - } - else - { - short *pData = (short *)(pWaveData->buffer + sample * sampleSize); - qboolean zero = false; - - if( pWaveData->channels == 1 ) - { - while( sample > 0 && !zero ) - { - if( ZERO_X_16(*pData )) - { - zero = true; - } - else - { - pData--; - sample--; - } - } - } - else - { - while( sample > 0 && !zero ) - { - if( ZERO_X_16( *pData ) && ZERO_X_16( pData[1] )) - { - zero = true; - } - else - { - sample--; - pData--; - } - } - } - } - } - - return sample; -} - -//----------------------------------------------------------------------------- -// Purpose: Search forward for a zero crossing -// Input : sample - starting point -// Output : position of found zero crossing -//----------------------------------------------------------------------------- -int S_ZeroCrossingAfter( wavdata_t *pWaveData, int sample ) -{ - if( pWaveData == NULL ) - return sample; - - if( pWaveData->type == WF_PCMDATA ) - { - int sampleSize; - - sampleSize = pWaveData->width * pWaveData->channels; - - // this can never be zero -- other functions divide by this. - // This should never happen, but avoid crashing - if( sampleSize <= 0 ) sampleSize = 1; - - if( pWaveData->width == 1 ) // 8-bit - { - signed char *pData = (signed char *)(pWaveData->buffer + sample * sampleSize); - qboolean zero = false; - - if( pWaveData->channels == 1 ) - { - while( sample < pWaveData->samples && !zero ) - { - if( ZERO_X_8( *pData )) - { - zero = true; - } - else - { - sample++; - pData++; - } - } - } - else - { - while( sample < pWaveData->samples && !zero ) - { - if( ZERO_X_8( *pData ) && ZERO_X_8( pData[1] )) - { - zero = true; - } - else - { - sample++; - pData++; - } - } - } - } - else - { - short *pData = (short *)(pWaveData->buffer + sample * sampleSize); - qboolean zero = false; - - if( pWaveData->channels == 1 ) - { - while( sample > 0 && !zero ) - { - if( ZERO_X_16( *pData )) - { - zero = true; - } - else - { - pData++; - sample++; - } - } - } - else - { - while( sample > 0 && !zero ) - { - if( ZERO_X_16( *pData ) && ZERO_X_16( pData[1] )) - { - zero = true; - } - else - { - sample++; - pData++; - } - } - } - } - } - - return sample; -} - //----------------------------------------------------------------------------- // Purpose: wrap the position wrt looping // Input : samplePosition - absolute position @@ -279,28 +81,3 @@ int S_GetOutputData( wavdata_t *pSource, void **pData, int samplePosition, int s return sampleCount; } - -// move the current position to newPosition -void S_SetSampleStart( channel_t *pChan, wavdata_t *pSource, int newPosition ) -{ - if( pSource ) - newPosition = S_ZeroCrossingAfter( pSource, newPosition ); - - pChan->pMixer.sample = newPosition; -} - -// end playback at newEndPosition -void S_SetSampleEnd( channel_t *pChan, wavdata_t *pSource, int newEndPosition ) -{ - // forced end of zero means play the whole sample - if( !newEndPosition ) newEndPosition = 1; - - if( pSource ) - newEndPosition = S_ZeroCrossingBefore( pSource, newEndPosition ); - - // past current position? limit. - if( newEndPosition < pChan->pMixer.sample ) - newEndPosition = pChan->pMixer.sample; - - pChan->pMixer.forcedEndSample = newEndPosition; -} diff --git a/engine/client/s_vox.c b/engine/client/s_vox.c index 8ee8b81f..388ca74b 100644 --- a/engine/client/s_vox.c +++ b/engine/client/s_vox.c @@ -18,10 +18,126 @@ GNU General Public License for more details. #include "const.h" #include +#define TRIM_SCAN_MAX 255 +#define TRIM_SAMPLES_BELOW_8 2 +#define TRIM_SAMPLES_BELOW_16 512 // 65k * 2 / 256 + +#define CVOXFILESENTENCEMAX 4096 + static int cszrawsentences = 0; static char *rgpszrawsentence[CVOXFILESENTENCEMAX]; static const char *voxperiod = "_period", *voxcomma = "_comma"; +static qboolean S_ShouldTrimSample8( const int8_t *buf, int channels ) +{ + if( abs( buf[0] ) > TRIM_SAMPLES_BELOW_8 ) + return false; + + if( channels >= 2 && abs( buf[1] ) > TRIM_SAMPLES_BELOW_8 ) + return false; + + return true; +} + +static qboolean S_ShouldTrimSample16( const int16_t *buf, int channels ) +{ + if( abs( buf[0] ) > TRIM_SAMPLES_BELOW_16 ) + return false; + + if( channels >= 2 && abs( buf[1] ) > TRIM_SAMPLES_BELOW_16 ) + return false; + + return true; +} + +static int S_TrimStart( const wavdata_t *wav, int start ) +{ + size_t channels = wav->channels, width = wav->width, i; + + if( wav->type != WF_PCMDATA ) + return start; + + if( width == 1 ) + { + const int8_t *data = (const int8_t *)&wav->buffer[channels * width * start]; + + for( i = 0; i < TRIM_SCAN_MAX && start < wav->samples; i++ ) + { + if( !S_ShouldTrimSample8( data, wav->channels )) + break; + + start += channels; + data += channels; + } + } + else if( width == 2 ) + { + const int16_t *data = (const int16_t *)&wav->buffer[channels * width * start]; + + for( i = 0; i < TRIM_SCAN_MAX && start < wav->samples; i++ ) + { + if( !S_ShouldTrimSample16( data, wav->channels )) + break; + + start += channels; + data += channels; + } + } + + return start; +} + +static int S_TrimEnd( const wavdata_t *wav, int end ) +{ + size_t channels = wav->channels, width = wav->width, i; + + if( wav->type != WF_PCMDATA ) + return end; + + if( width == 1 ) + { + const int8_t *data = (const int8_t *)&wav->buffer[channels * width * end]; + + for( i = 0; i < TRIM_SCAN_MAX && end > 0; i++ ) + { + if( !S_ShouldTrimSample8( data, wav->channels )) + break; + + end -= channels; + data -= channels; + } + } + else if( width == 2 ) + { + const int16_t *data = (const int16_t *)&wav->buffer[channels * width * end]; + + for( i = 0; i < TRIM_SCAN_MAX && end > 0; i++ ) + { + if( !S_ShouldTrimSample16( data, wav->channels )) + break; + + end -= channels; + data -= channels; + } + } + + return end; +} + +static void S_TrimStartEndTimes( channel_t *ch, wavdata_t *wav, int start, int end ) +{ + ch->pMixer.sample = start = S_TrimStart( wav, start ); + + // don't overrun the buffer while trimming end + if( end == 0 ) + end = wav->samples - wav->channels; + + if( end < start ) + end = start; + + ch->pMixer.forcedEndSample = S_TrimEnd( wav, end ); +} + // return number of samples mixed int VOX_MixDataToDevice( channel_t *pchan, int sampleCount, int outputRate, int outputOffset ) { @@ -78,11 +194,7 @@ void VOX_LoadWord( channel_t *ch ) if( end <= start ) end = 0; - if( start ) - S_SetSampleStart( ch, data, start * 0.01f * samples ); - - if( end ) - S_SetSampleEnd( ch, data, end * 0.01f * samples ); + S_TrimStartEndTimes( ch, data, start * 0.01f * samples, end * 0.01f * samples ); } void VOX_FreeWord( channel_t *ch ) diff --git a/engine/client/sound.h b/engine/client/sound.h index a7a1d65e..e463c97a 100644 --- a/engine/client/sound.h +++ b/engine/client/sound.h @@ -305,8 +305,6 @@ int S_ZeroCrossingAfter( wavdata_t *pWaveData, int sample ); int S_ZeroCrossingBefore( wavdata_t *pWaveData, int sample ); int S_ConvertLoopedPosition( wavdata_t *pSource, int samplePosition, qboolean use_loop ); int S_GetOutputData( wavdata_t *pSource, void **pData, int samplePosition, int sampleCount, qboolean use_loop ); -void S_SetSampleStart( channel_t *pChan, wavdata_t *pSource, int newPosition ); -void S_SetSampleEnd( channel_t *pChan, wavdata_t *pSource, int newEndPosition ); // // s_vox.c diff --git a/engine/client/vox.h b/engine/client/vox.h index 56967959..e9966714 100644 --- a/engine/client/vox.h +++ b/engine/client/vox.h @@ -17,7 +17,6 @@ GNU General Public License for more details. #define VOX_H #define CVOXWORDMAX 64 -#define CVOXFILESENTENCEMAX 4096 #define SENTENCE_INDEX -99999 // unique sentence index