* GetSampleOffset * * Retrieves the voice position, fixed-point fraction, and bufferlist item * using the givem offset type and offset. If the offset is out of range, * returns an empty optional. */
| 363 | * returns an empty optional. |
| 364 | */ |
| 365 | al::optional<VoicePos> GetSampleOffset(al::deque<ALbufferQueueItem> &BufferList, ALenum OffsetType, |
| 366 | double Offset) |
| 367 | { |
| 368 | /* Find the first valid Buffer in the Queue */ |
| 369 | const ALbuffer *BufferFmt{nullptr}; |
| 370 | for(auto &item : BufferList) |
| 371 | { |
| 372 | BufferFmt = item.mBuffer; |
| 373 | if(BufferFmt) break; |
| 374 | } |
| 375 | if(!BufferFmt) |
| 376 | return al::nullopt; |
| 377 | |
| 378 | /* Get sample frame offset */ |
| 379 | ALuint offset{0u}, frac{0u}; |
| 380 | double dbloff, dblfrac; |
| 381 | switch(OffsetType) |
| 382 | { |
| 383 | case AL_SEC_OFFSET: |
| 384 | dblfrac = std::modf(Offset*BufferFmt->mSampleRate, &dbloff); |
| 385 | offset = static_cast<ALuint>(mind(dbloff, std::numeric_limits<ALuint>::max())); |
| 386 | frac = static_cast<ALuint>(mind(dblfrac*MixerFracOne, MixerFracOne-1.0)); |
| 387 | break; |
| 388 | |
| 389 | case AL_SAMPLE_OFFSET: |
| 390 | dblfrac = std::modf(Offset, &dbloff); |
| 391 | offset = static_cast<ALuint>(mind(dbloff, std::numeric_limits<ALuint>::max())); |
| 392 | frac = static_cast<ALuint>(mind(dblfrac*MixerFracOne, MixerFracOne-1.0)); |
| 393 | break; |
| 394 | |
| 395 | case AL_BYTE_OFFSET: |
| 396 | /* Determine the ByteOffset (and ensure it is block aligned) */ |
| 397 | offset = static_cast<ALuint>(Offset); |
| 398 | if(BufferFmt->OriginalType == UserFmtIMA4) |
| 399 | { |
| 400 | const ALuint align{(BufferFmt->OriginalAlign-1)/2 + 4}; |
| 401 | offset /= align * BufferFmt->channelsFromFmt(); |
| 402 | offset *= BufferFmt->OriginalAlign; |
| 403 | } |
| 404 | else if(BufferFmt->OriginalType == UserFmtMSADPCM) |
| 405 | { |
| 406 | const ALuint align{(BufferFmt->OriginalAlign-2)/2 + 7}; |
| 407 | offset /= align * BufferFmt->channelsFromFmt(); |
| 408 | offset *= BufferFmt->OriginalAlign; |
| 409 | } |
| 410 | else |
| 411 | offset /= BufferFmt->frameSizeFromFmt(); |
| 412 | frac = 0; |
| 413 | break; |
| 414 | } |
| 415 | |
| 416 | /* Find the bufferlist item this offset belongs to. */ |
| 417 | ALuint totalBufferLen{0u}; |
| 418 | for(auto &item : BufferList) |
| 419 | { |
| 420 | if(totalBufferLen > offset) |
| 421 | break; |
| 422 | if(item.mSampleLen > offset-totalBufferLen) |
no test coverage detected