diff options
author | Chris Robinson <[email protected]> | 2020-04-04 01:52:29 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2020-04-04 01:52:29 -0700 |
commit | fc906c97f52fd13549dfdfae229d0dc6d60a2865 (patch) | |
tree | 278b33097cd082f85442fe785579e6b78969e652 /al | |
parent | 902f5a0dd267e0849e93e863a24a0a350d1696f9 (diff) |
Track a buffer's ambisonic order
Diffstat (limited to 'al')
-rw-r--r-- | al/buffer.cpp | 31 | ||||
-rw-r--r-- | al/buffer.h | 6 | ||||
-rw-r--r-- | al/source.cpp | 26 |
3 files changed, 42 insertions, 21 deletions
diff --git a/al/buffer.cpp b/al/buffer.cpp index a84f56a6..4acd1158 100644 --- a/al/buffer.cpp +++ b/al/buffer.cpp @@ -273,8 +273,6 @@ ALuint ChannelsFromUserFmt(UserFmtChannels chans, ALuint ambiorder) noexcept } return 0; } -inline ALuint FrameSizeFromUserFmt(UserFmtChannels chans, UserFmtType type, ALuint ambiorder) noexcept -{ return ChannelsFromUserFmt(chans, ambiorder) * BytesFromUserFmt(type); } constexpr ALbitfieldSOFT INVALID_STORAGE_MASK{~unsigned(AL_MAP_READ_BIT_SOFT | @@ -462,6 +460,9 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, ALuint size, SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid unpack alignment %u for %s samples", unpackalign, NameFromUserFmtType(SrcType)); + const ALuint ambiorder{(DstChannels == FmtBFormat2D || DstChannels == FmtBFormat3D) ? + ALBuf->UnpackAmbiOrder : 0}; + if((access&AL_PRESERVE_DATA_BIT_SOFT)) { /* Can only preserve data with the same format and alignment. */ @@ -469,15 +470,17 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, ALuint size, SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched format"); if UNLIKELY(ALBuf->OriginalAlign != align) SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched alignment"); + if(ALBuf->AmbiOrder != ambiorder) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched order"); } /* Convert the input/source size in bytes to sample frames using the unpack * block alignment. */ - const ALuint SrcByteAlign{ - (SrcType == UserFmtIMA4) ? ((align-1)/2 + 4) * ChannelsFromUserFmt(SrcChannels, 1) : - (SrcType == UserFmtMSADPCM) ? ((align-2)/2 + 7) * ChannelsFromUserFmt(SrcChannels, 1) : - (align * FrameSizeFromUserFmt(SrcChannels, SrcType, 1))}; + const ALuint SrcByteAlign{ChannelsFromUserFmt(SrcChannels, ambiorder) * + ((SrcType == UserFmtIMA4) ? (align-1)/2 + 4 : + (SrcType == UserFmtMSADPCM) ? (align-2)/2 + 7 : + (align * BytesFromUserFmt(SrcType)))}; if UNLIKELY((size%SrcByteAlign) != 0) SETERR_RETURN(context, AL_INVALID_VALUE,, "Data size %d is not a multiple of frame size %d (%d unpack alignment)", @@ -491,7 +494,7 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, ALuint size, /* Convert the sample frames to the number of bytes needed for internal * storage. */ - ALuint NumChannels{ChannelsFromFmt(DstChannels, 1)}; + ALuint NumChannels{ChannelsFromFmt(DstChannels, ambiorder)}; ALuint FrameSize{NumChannels * BytesFromFmt(DstType)}; if UNLIKELY(frames > std::numeric_limits<size_t>::max()/FrameSize) SETERR_RETURN(context, AL_OUT_OF_MEMORY,, @@ -513,7 +516,7 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, ALuint size, const size_t tocopy{minz(newdata.size(), ALBuf->mData.size())}; std::copy_n(ALBuf->mData.begin(), tocopy, newdata.begin()); } - ALBuf->mData = std::move(newdata); + newdata.swap(ALBuf->mData); } if(SrcType == UserFmtIMA4) @@ -546,6 +549,7 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, ALuint size, ALBuf->mFmtChannels = DstChannels; ALBuf->mFmtType = DstType; ALBuf->Access = access; + ALBuf->AmbiOrder = ambiorder; ALBuf->Callback = nullptr; ALBuf->UserData = nullptr; @@ -597,8 +601,11 @@ void PrepareCallback(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, if UNLIKELY(static_cast<long>(SrcType) != static_cast<long>(DstType)) SETERR_RETURN(context, AL_INVALID_ENUM,, "Unsupported callback format"); - ALBuf->mData = al::vector<al::byte,16>(FrameSizeFromFmt(DstChannels, DstType, 1) * - size_t{BUFFERSIZE + (MAX_RESAMPLER_PADDING>>1)}); + const ALuint ambiorder{(DstChannels == FmtBFormat2D || DstChannels == FmtBFormat3D) ? + ALBuf->UnpackAmbiOrder : 0}; + + al::vector<al::byte,16>(FrameSizeFromFmt(DstChannels, DstType, ambiorder) * + size_t{BUFFERSIZE + (MAX_RESAMPLER_PADDING>>1)}).swap(ALBuf->mData); ALBuf->Callback = callback; ALBuf->UserData = userptr; @@ -611,6 +618,7 @@ void PrepareCallback(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, ALBuf->mFmtChannels = DstChannels; ALBuf->mFmtType = DstType; ALBuf->Access = 0; + ALBuf->AmbiOrder = ambiorder; ALBuf->SampleLen = 0; ALBuf->LoopStart = 0; @@ -976,6 +984,9 @@ START_API_FUNC context->setError(AL_INVALID_VALUE, "Unpacking data with alignment %u does not match original alignment %u", align, albuf->OriginalAlign); + else if UNLIKELY((albuf->mFmtChannels == FmtBFormat2D || albuf->mFmtChannels == FmtBFormat3D) + && albuf->UnpackAmbiOrder != albuf->AmbiOrder) + context->setError(AL_INVALID_VALUE, "Unpacking data with mismatched ambisonic order"); else if UNLIKELY(albuf->MappedAccess != 0) context->setError(AL_INVALID_OPERATION, "Unpacking data into mapped buffer %u", buffer); else diff --git a/al/buffer.h b/al/buffer.h index 44ada667..2e98e927 100644 --- a/al/buffer.h +++ b/al/buffer.h @@ -79,6 +79,8 @@ struct ALbuffer { ALenum AmbiLayout{AL_FUMA_SOFT}; ALenum AmbiScaling{AL_FUMA_SOFT}; + /* AmbiOrder is only updated when loading new data. */ + ALuint AmbiOrder{0}; LPALBUFFERCALLBACKTYPESOFT Callback{nullptr}; void *UserData{nullptr}; @@ -88,6 +90,7 @@ struct ALbuffer { ALuint UnpackAlign{0}; ALuint PackAlign{0}; + ALuint UnpackAmbiOrder{1}; ALbitfieldSOFT MappedAccess{0u}; ALsizei MappedOffset{0}; @@ -100,7 +103,8 @@ struct ALbuffer { ALuint id{0}; inline ALuint bytesFromFmt() const noexcept { return BytesFromFmt(mFmtType); } - inline ALuint channelsFromFmt() const noexcept { return ChannelsFromFmt(mFmtChannels, 1); } + inline ALuint channelsFromFmt() const noexcept + { return ChannelsFromFmt(mFmtChannels, AmbiOrder); } inline ALuint frameSizeFromFmt() const noexcept { return channelsFromFmt() * bytesFromFmt(); } DISABLE_ALLOC() diff --git a/al/source.cpp b/al/source.cpp index 57ad151d..7d32de34 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -447,7 +447,7 @@ void InitVoice(Voice *voice, ALsource *source, ALbufferlistitem *BufferList, ALC voice->mSampleSize = buffer->bytesFromFmt(); voice->mAmbiLayout = static_cast<AmbiLayout>(buffer->AmbiLayout); voice->mAmbiScaling = static_cast<AmbiNorm>(buffer->AmbiScaling); - voice->mAmbiOrder = 1; + voice->mAmbiOrder = buffer->AmbiOrder; if(buffer->Callback) voice->mFlags |= VOICE_IS_CALLBACK; else if(source->SourceType == AL_STATIC) voice->mFlags |= VOICE_IS_STATIC; @@ -466,8 +466,7 @@ void InitVoice(Voice *voice, ALsource *source, ALbufferlistitem *BufferList, ALC /* Don't need to set the VOICE_IS_AMBISONIC flag if the device is not * higher order than the voice. No HF scaling is necessary to mix it. */ - if((voice->mFmtChannels == FmtBFormat2D || voice->mFmtChannels == FmtBFormat3D) - && device->mAmbiOrder > voice->mAmbiOrder) + if(voice->mAmbiOrder && device->mAmbiOrder > voice->mAmbiOrder) { const uint8_t *OrderFromChan{(voice->mFmtChannels == FmtBFormat2D) ? AmbiIndex::OrderFrom2DChannel.data() : @@ -3203,6 +3202,7 @@ START_API_FUNC BufferList = nullptr; for(ALsizei i{0};i < nb;i++) { + bool fmt_mismatch{false}; ALbuffer *buffer{nullptr}; if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == nullptr) { @@ -3242,13 +3242,19 @@ START_API_FUNC if(BufferFmt == nullptr) BufferFmt = buffer; - else if(BufferFmt->Frequency != buffer->Frequency || - BufferFmt->mFmtChannels != buffer->mFmtChannels || - ((BufferFmt->mFmtChannels == FmtBFormat2D || - BufferFmt->mFmtChannels == FmtBFormat3D) && - (BufferFmt->AmbiLayout != buffer->AmbiLayout || - BufferFmt->AmbiScaling != buffer->AmbiScaling)) || - BufferFmt->OriginalType != buffer->OriginalType) + else + { + fmt_mismatch |= BufferFmt->Frequency != buffer->Frequency; + fmt_mismatch |= BufferFmt->mFmtChannels != buffer->mFmtChannels; + if(BufferFmt->mFmtChannels == FmtBFormat2D || BufferFmt->mFmtChannels == FmtBFormat3D) + { + fmt_mismatch |= BufferFmt->AmbiLayout != buffer->AmbiLayout; + fmt_mismatch |= BufferFmt->AmbiScaling != buffer->AmbiScaling; + } + fmt_mismatch |= BufferFmt->AmbiOrder != buffer->AmbiOrder; + fmt_mismatch |= BufferFmt->OriginalType != buffer->OriginalType; + } + if(fmt_mismatch) { context->setError(AL_INVALID_OPERATION, "Queueing buffer with mismatched format"); |