* GetSampleOffset * * Retrieves the voice position, fixed-point fraction, and bufferlist item * using the source's stored offset and offset type. If the source has no * stored offset, or the offset is out of range, returns an empty optional. */
| 387 | * stored offset, or the offset is out of range, returns an empty optional. |
| 388 | */ |
| 389 | al::optional<VoicePos> GetSampleOffset(ALsource *Source) |
| 390 | { |
| 391 | al::optional<VoicePos> ret; |
| 392 | |
| 393 | /* Find the first valid Buffer in the Queue */ |
| 394 | const ALbuffer *BufferFmt{nullptr}; |
| 395 | ALbufferlistitem *BufferList{Source->queue}; |
| 396 | while(BufferList) |
| 397 | { |
| 398 | if((BufferFmt=BufferList->mBuffer) != nullptr) break; |
| 399 | BufferList = BufferList->mNext.load(std::memory_order_relaxed); |
| 400 | } |
| 401 | if(!BufferList) |
| 402 | { |
| 403 | Source->OffsetType = AL_NONE; |
| 404 | Source->Offset = 0.0; |
| 405 | return ret; |
| 406 | } |
| 407 | |
| 408 | /* Get sample frame offset */ |
| 409 | ALuint offset{0u}, frac{0u}; |
| 410 | ALdouble dbloff, dblfrac; |
| 411 | switch(Source->OffsetType) |
| 412 | { |
| 413 | case AL_BYTE_OFFSET: |
| 414 | /* Determine the ByteOffset (and ensure it is block aligned) */ |
| 415 | offset = static_cast<ALuint>(Source->Offset); |
| 416 | if(BufferFmt->OriginalType == UserFmtIMA4) |
| 417 | { |
| 418 | const ALuint align{(BufferFmt->OriginalAlign-1)/2 + 4}; |
| 419 | offset /= align * ChannelsFromFmt(BufferFmt->mFmtChannels); |
| 420 | offset *= BufferFmt->OriginalAlign; |
| 421 | } |
| 422 | else if(BufferFmt->OriginalType == UserFmtMSADPCM) |
| 423 | { |
| 424 | const ALuint align{(BufferFmt->OriginalAlign-2)/2 + 7}; |
| 425 | offset /= align * ChannelsFromFmt(BufferFmt->mFmtChannels); |
| 426 | offset *= BufferFmt->OriginalAlign; |
| 427 | } |
| 428 | else |
| 429 | offset /= FrameSizeFromFmt(BufferFmt->mFmtChannels, BufferFmt->mFmtType); |
| 430 | frac = 0; |
| 431 | break; |
| 432 | |
| 433 | case AL_SAMPLE_OFFSET: |
| 434 | dblfrac = std::modf(Source->Offset, &dbloff); |
| 435 | offset = static_cast<ALuint>(mind(dbloff, std::numeric_limits<ALuint>::max())); |
| 436 | frac = static_cast<ALuint>(mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0)); |
| 437 | break; |
| 438 | |
| 439 | case AL_SEC_OFFSET: |
| 440 | dblfrac = std::modf(Source->Offset*BufferFmt->Frequency, &dbloff); |
| 441 | offset = static_cast<ALuint>(mind(dbloff, std::numeric_limits<ALuint>::max())); |
| 442 | frac = static_cast<ALuint>(mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0)); |
| 443 | break; |
| 444 | } |
| 445 | Source->OffsetType = AL_NONE; |
| 446 | Source->Offset = 0.0; |
no test coverage detected