| 229 | } |
| 230 | |
| 231 | void Mixer::read(int16_t* outBuffer, size_t frameCount, ExtraMixFunction extraMixFunction) { |
| 232 | // Make this method as least locky as possible by copying all the needed |
| 233 | // member data before the expensive audio / effect stuff. |
| 234 | float speed; |
| 235 | unsigned sampleRate; |
| 236 | unsigned channels; |
| 237 | float volume; |
| 238 | float volumeVelocity; |
| 239 | float targetVolume; |
| 240 | Map<MixerGroup, RampedValue> groupVolumes; |
| 241 | |
| 242 | { |
| 243 | MutexLocker locker(m_mutex); |
| 244 | speed = m_speed; |
| 245 | sampleRate = m_sampleRate; |
| 246 | channels = m_channels; |
| 247 | volume = m_volume.value; |
| 248 | volumeVelocity = m_volume.velocity; |
| 249 | targetVolume = m_volume.target; |
| 250 | groupVolumes = m_groupVolumes; |
| 251 | } |
| 252 | |
| 253 | size_t bufferSize = frameCount * m_channels; |
| 254 | m_mixBuffer.resize(bufferSize, 0); |
| 255 | |
| 256 | float time = (float)frameCount / sampleRate; |
| 257 | float beginVolume = volume; |
| 258 | float endVolume = approach(targetVolume, volume, volumeVelocity * time); |
| 259 | |
| 260 | Map<MixerGroup, float> groupEndVolumes; |
| 261 | for (auto p : groupVolumes) |
| 262 | groupEndVolumes[p.first] = approach(p.second.target, p.second.value, p.second.velocity * time); |
| 263 | |
| 264 | auto sampleStartTime = Time::millisecondsSinceEpoch(); |
| 265 | unsigned millisecondsInBuffer = (bufferSize * 1000) / (channels * sampleRate); |
| 266 | auto sampleEndTime = sampleStartTime + millisecondsInBuffer; |
| 267 | |
| 268 | for (size_t i = 0; i < bufferSize; ++i) |
| 269 | outBuffer[i] = 0; |
| 270 | |
| 271 | { |
| 272 | MutexLocker locker(m_queueMutex); |
| 273 | // Mix all active sounds |
| 274 | for (auto& p : m_audios) { |
| 275 | auto& audioInstance = p.first; |
| 276 | auto& audioState = p.second; |
| 277 | |
| 278 | MutexLocker audioLocker(audioInstance->m_mutex); |
| 279 | |
| 280 | if (audioInstance->m_finished) |
| 281 | continue; |
| 282 | |
| 283 | if (audioInstance->m_clockStart && *audioInstance->m_clockStart > sampleEndTime) |
| 284 | continue; |
| 285 | |
| 286 | float groupVolume = groupVolumes[audioInstance->m_mixerGroup].value; |
| 287 | float groupEndVolume = groupEndVolumes[audioInstance->m_mixerGroup]; |
| 288 |
nothing calls this directly
no test coverage detected