SoundVoice.cpp (11029B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition 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 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. 23 24 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. 25 26 =========================================================================== 27 */ 28 #pragma hdrstop 29 #include "../idlib/precompiled.h" 30 31 #include "snd_local.h" 32 33 idCVar s_subFraction( "s_subFraction", "0.5", CVAR_ARCHIVE | CVAR_FLOAT, "Amount of each sound to send to the LFE channel" ); 34 35 idVec2 idSoundVoice_Base::speakerPositions[idWaveFile::CHANNEL_INDEX_MAX]; 36 int idSoundVoice_Base::speakerLeft[idWaveFile::CHANNEL_INDEX_MAX] = {0 }; 37 int idSoundVoice_Base::speakerRight[idWaveFile::CHANNEL_INDEX_MAX] = {0 }; 38 int idSoundVoice_Base::dstChannels = 0; 39 int idSoundVoice_Base::dstMask = 0; 40 int idSoundVoice_Base::dstCenter = -1; 41 int idSoundVoice_Base::dstLFE = -1; 42 int idSoundVoice_Base::dstMap[MAX_CHANNELS_PER_VOICE] = { 0 }; 43 int idSoundVoice_Base::invMap[idWaveFile::CHANNEL_INDEX_MAX] = { 0 }; 44 float idSoundVoice_Base::omniLevel = 1.0f; 45 46 /* 47 ======================== 48 idSoundVoice_Base::idSoundVoice_Base 49 ======================== 50 */ 51 idSoundVoice_Base::idSoundVoice_Base() : 52 position( 0.0f ), 53 gain( 1.0f ), 54 centerChannel( 0.0f ), 55 pitch( 1.0f ), 56 innerRadius( 32.0f ), 57 occlusion( 0.0f ), 58 channelMask( 0 ), 59 innerSampleRangeSqr( 0.0f ), 60 outerSampleRangeSqr( 0.0f ) 61 { 62 } 63 64 /* 65 ======================== 66 idSoundVoice_Base::InitSurround 67 ======================== 68 */ 69 void idSoundVoice_Base::InitSurround( int outputChannels, int channelMask ) { 70 71 speakerPositions[idWaveFile::CHANNEL_INDEX_FRONT_LEFT ].Set( 0.70710678118654752440084436210485f, 0.70710678118654752440084436210485f ); // 45 degrees 72 speakerPositions[idWaveFile::CHANNEL_INDEX_FRONT_RIGHT ].Set( 0.70710678118654752440084436210485f, -0.70710678118654752440084436210485f ); // 315 degrees 73 speakerPositions[idWaveFile::CHANNEL_INDEX_FRONT_CENTER ].Set( 0.0f, 0.0f ); // 0 degrees 74 speakerPositions[idWaveFile::CHANNEL_INDEX_LOW_FREQUENCY ].Set( 0.0f, 0.0f ); // - 75 speakerPositions[idWaveFile::CHANNEL_INDEX_BACK_LEFT ].Set( -0.70710678118654752440084436210485f, 0.70710678118654752440084436210485f ); // 135 degrees 76 speakerPositions[idWaveFile::CHANNEL_INDEX_BACK_RIGHT ].Set( -0.70710678118654752440084436210485f, -0.70710678118654752440084436210485f ); // 225 degrees 77 speakerPositions[idWaveFile::CHANNEL_INDEX_FRONT_LEFT_CENTER ].Set( 0.92387953251128675612818318939679f, 0.3826834323650897717284599840304f ); // 22.5 degrees 78 speakerPositions[idWaveFile::CHANNEL_INDEX_FRONT_RIGHT_CENTER ].Set( 0.92387953251128675612818318939679f, -0.3826834323650897717284599840304f ); // 337.5 degrees 79 speakerPositions[idWaveFile::CHANNEL_INDEX_BACK_CENTER ].Set( -1.0f, 0.0f ); // 180 degrees 80 speakerPositions[idWaveFile::CHANNEL_INDEX_SIDE_LEFT ].Set( 0.0f, 1.0f ); // 90 degrees 81 speakerPositions[idWaveFile::CHANNEL_INDEX_SIDE_RIGHT ].Set( 0.0f, -1.0f ); // 270 degrees 82 83 speakerLeft[idWaveFile::CHANNEL_INDEX_FRONT_LEFT_CENTER] = idWaveFile::CHANNEL_INDEX_FRONT_LEFT; 84 speakerLeft[idWaveFile::CHANNEL_INDEX_FRONT_LEFT] = idWaveFile::CHANNEL_INDEX_SIDE_LEFT; 85 speakerLeft[idWaveFile::CHANNEL_INDEX_SIDE_LEFT] = idWaveFile::CHANNEL_INDEX_BACK_LEFT; 86 speakerLeft[idWaveFile::CHANNEL_INDEX_BACK_LEFT] = idWaveFile::CHANNEL_INDEX_BACK_CENTER; 87 speakerLeft[idWaveFile::CHANNEL_INDEX_BACK_CENTER] = idWaveFile::CHANNEL_INDEX_BACK_RIGHT; 88 speakerLeft[idWaveFile::CHANNEL_INDEX_BACK_RIGHT] = idWaveFile::CHANNEL_INDEX_SIDE_RIGHT; 89 speakerLeft[idWaveFile::CHANNEL_INDEX_SIDE_RIGHT] = idWaveFile::CHANNEL_INDEX_FRONT_RIGHT; 90 speakerLeft[idWaveFile::CHANNEL_INDEX_FRONT_RIGHT] = idWaveFile::CHANNEL_INDEX_FRONT_RIGHT_CENTER; 91 speakerLeft[idWaveFile::CHANNEL_INDEX_FRONT_RIGHT_CENTER] = idWaveFile::CHANNEL_INDEX_FRONT_LEFT_CENTER; 92 93 speakerLeft[idWaveFile::CHANNEL_INDEX_FRONT_CENTER] = idWaveFile::CHANNEL_INDEX_FRONT_CENTER; 94 speakerLeft[idWaveFile::CHANNEL_INDEX_LOW_FREQUENCY] = idWaveFile::CHANNEL_INDEX_LOW_FREQUENCY; 95 96 speakerRight[idWaveFile::CHANNEL_INDEX_FRONT_RIGHT_CENTER] = idWaveFile::CHANNEL_INDEX_FRONT_RIGHT; 97 speakerRight[idWaveFile::CHANNEL_INDEX_FRONT_RIGHT] = idWaveFile::CHANNEL_INDEX_SIDE_RIGHT; 98 speakerRight[idWaveFile::CHANNEL_INDEX_SIDE_RIGHT] = idWaveFile::CHANNEL_INDEX_BACK_RIGHT; 99 speakerRight[idWaveFile::CHANNEL_INDEX_BACK_RIGHT] = idWaveFile::CHANNEL_INDEX_BACK_CENTER; 100 speakerRight[idWaveFile::CHANNEL_INDEX_BACK_CENTER] = idWaveFile::CHANNEL_INDEX_BACK_LEFT; 101 speakerRight[idWaveFile::CHANNEL_INDEX_BACK_LEFT] = idWaveFile::CHANNEL_INDEX_SIDE_LEFT; 102 speakerRight[idWaveFile::CHANNEL_INDEX_SIDE_LEFT] = idWaveFile::CHANNEL_INDEX_FRONT_LEFT; 103 speakerRight[idWaveFile::CHANNEL_INDEX_FRONT_LEFT] = idWaveFile::CHANNEL_INDEX_FRONT_LEFT_CENTER; 104 speakerRight[idWaveFile::CHANNEL_INDEX_FRONT_LEFT_CENTER] = idWaveFile::CHANNEL_INDEX_FRONT_RIGHT_CENTER; 105 106 speakerRight[idWaveFile::CHANNEL_INDEX_FRONT_CENTER] = idWaveFile::CHANNEL_INDEX_FRONT_CENTER; 107 speakerRight[idWaveFile::CHANNEL_INDEX_LOW_FREQUENCY] = idWaveFile::CHANNEL_INDEX_LOW_FREQUENCY; 108 109 dstChannels = outputChannels; 110 dstMask = channelMask; 111 112 // dstMap maps a destination channel to a speaker 113 // invMap maps a speaker to a destination channel 114 dstLFE = -1; 115 dstCenter = -1; 116 memset( dstMap, 0, sizeof( dstMap ) ); 117 memset( invMap, 0, sizeof( invMap ) ); 118 for ( int i = 0, c = 0; i < idWaveFile::CHANNEL_INDEX_MAX && c < MAX_CHANNELS_PER_VOICE; i++ ) { 119 if ( dstMask & BIT(i) ) { 120 if ( i == idWaveFile::CHANNEL_INDEX_LOW_FREQUENCY ) { 121 dstLFE = c; 122 } 123 if ( i == idWaveFile::CHANNEL_INDEX_FRONT_CENTER ) { 124 dstCenter = c; 125 } 126 dstMap[c] = i; 127 invMap[i] = c++; 128 } else { 129 // Remove this speaker from the chain 130 int right = speakerRight[i]; 131 int left = speakerLeft[i]; 132 speakerRight[left] = right; 133 speakerLeft[right] = left; 134 } 135 } 136 assert( ( dstLFE == -1 ) || ( ( dstMask & idWaveFile::CHANNEL_MASK_LOW_FREQUENCY ) != 0 ) ); 137 assert( ( dstCenter == -1 ) || ( ( dstMask & idWaveFile::CHANNEL_MASK_FRONT_CENTER ) != 0 ) ); 138 139 float omniChannels = (float)dstChannels; 140 if ( dstMask & idWaveFile::CHANNEL_MASK_LOW_FREQUENCY ) { 141 omniChannels -= 1.0f; 142 } 143 if ( dstMask & idWaveFile::CHANNEL_MASK_FRONT_CENTER ) { 144 omniChannels -= 1.0f; 145 } 146 if ( omniChannels > 0.0f ) { 147 omniLevel = 1.0f / omniChannels; 148 } else { 149 // This happens in mono mode 150 omniLevel = 1.0f; 151 } 152 } 153 154 /* 155 ======================== 156 idSoundVoice_Base::CalculateSurround 157 ======================== 158 */ 159 void idSoundVoice_Base::CalculateSurround( int srcChannels, float pLevelMatrix[ MAX_CHANNELS_PER_VOICE * MAX_CHANNELS_PER_VOICE ], float scale ) { 160 // Hack for mono 161 if ( dstChannels == 1 ) { 162 if ( srcChannels == 1 ) { 163 pLevelMatrix[ 0 ] = scale; 164 } else if ( srcChannels == 2 ) { 165 pLevelMatrix[ 0 ] = scale * 0.7071f; 166 pLevelMatrix[ 1 ] = scale * 0.7071f; 167 } 168 return; 169 } 170 171 #define MATINDEX( src, dst ) ( srcChannels * dst + src ) 172 173 float subFraction = s_subFraction.GetFloat(); 174 175 if ( srcChannels == 1 ) { 176 idVec2 p2 = position.ToVec2(); 177 178 float centerFraction = centerChannel; 179 180 float sqrLength = p2.LengthSqr(); 181 if ( sqrLength <= 0.01f ) { 182 // If we are on top of the listener, simply route all channels to each speaker equally 183 for ( int i = 0; i < dstChannels; i++ ) { 184 pLevelMatrix[MATINDEX( 0, i )] = omniLevel; 185 } 186 } else { 187 float invLength = idMath::InvSqrt( sqrLength ); 188 float distance = ( invLength * sqrLength ); 189 p2 *= invLength; 190 191 float spatialize = 1.0f; 192 if ( distance < innerRadius ) { 193 spatialize = distance / innerRadius; 194 } 195 float omni = omniLevel * ( 1.0f - spatialize ); 196 197 if ( dstCenter != -1 ) { 198 centerFraction *= Max( 0.0f, p2.x ); 199 spatialize *= ( 1.0f - centerFraction ); 200 omni *= ( 1.0f - centerFraction ); 201 } 202 203 float channelDots[MAX_CHANNELS_PER_VOICE] = { 0 }; 204 for ( int i = 0; i < dstChannels; i++ ) { 205 // Calculate the contribution to each destination channel 206 channelDots[i] = speakerPositions[dstMap[i]] * p2; 207 } 208 // Find the speaker nearest to the sound 209 int channelA = 0; 210 for ( int i = 1; i < dstChannels; i++ ) { 211 if ( channelDots[i] > channelDots[channelA] ) { 212 channelA = i; 213 } 214 } 215 int speakerA = dstMap[channelA]; 216 217 // Find the 2nd nearest speaker 218 int speakerB; 219 float speakerACross = ( speakerPositions[speakerA].x * p2.y ) - ( speakerPositions[speakerA].y * p2.x ); 220 if ( speakerACross > 0.0f ) { 221 speakerB = speakerLeft[speakerA]; 222 } else { 223 speakerB = speakerRight[speakerA]; 224 } 225 int channelB = invMap[speakerB]; 226 227 // Divide the amplitude between the 2 closest speakers 228 float distA = ( speakerPositions[speakerA] - p2 ).Length(); 229 float distB = ( speakerPositions[speakerB] - p2 ).Length(); 230 float distCinv = 1.0f / ( distA + distB ); 231 float volumes[MAX_CHANNELS_PER_VOICE] = { 0 }; 232 volumes[channelA] = ( distB * distCinv ); 233 volumes[channelB] = ( distA * distCinv ); 234 for ( int i = 0; i < dstChannels; i++ ) { 235 pLevelMatrix[MATINDEX( 0, i )] = ( volumes[i] * spatialize ) + omni; 236 } 237 } 238 if ( dstLFE != -1 ) { 239 pLevelMatrix[MATINDEX( 0, dstLFE )] = subFraction; 240 } 241 if ( dstCenter != -1 ) { 242 pLevelMatrix[MATINDEX( 0, dstCenter )] = centerFraction; 243 } 244 } else if ( srcChannels == 2 ) { 245 pLevelMatrix[ MATINDEX( 0, 0 ) ] = 1.0f; 246 pLevelMatrix[ MATINDEX( 1, 1 ) ] = 1.0f; 247 if ( dstLFE != -1 ) { 248 pLevelMatrix[ MATINDEX( 0, dstLFE ) ] = subFraction * 0.5f; 249 pLevelMatrix[ MATINDEX( 1, dstLFE ) ] = subFraction * 0.5f; 250 } 251 } else { 252 idLib::Warning( "We don't support %d channel sound files", srcChannels ); 253 } 254 for ( int i = 0; i < srcChannels * dstChannels; i++ ) { 255 pLevelMatrix[ i ] *= scale; 256 } 257 }