2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
37 #include "alcontext.h"
41 #include "sample_cvt.h"
46 constexpr ALbitfieldSOFT INVALID_STORAGE_MASK
{~unsigned(AL_MAP_READ_BIT_SOFT
|
47 AL_MAP_WRITE_BIT_SOFT
| AL_MAP_PERSISTENT_BIT_SOFT
| AL_PRESERVE_DATA_BIT_SOFT
)};
48 constexpr ALbitfieldSOFT MAP_READ_WRITE_FLAGS
{AL_MAP_READ_BIT_SOFT
| AL_MAP_WRITE_BIT_SOFT
};
49 constexpr ALbitfieldSOFT INVALID_MAP_FLAGS
{~unsigned(AL_MAP_READ_BIT_SOFT
| AL_MAP_WRITE_BIT_SOFT
|
50 AL_MAP_PERSISTENT_BIT_SOFT
)};
53 ALbuffer
*AllocBuffer(ALCcontext
*context
)
55 ALCdevice
*device
= context
->Device
;
56 std::unique_lock
<almtx_t
> buflock
{device
->BufferLock
};
58 auto sublist
= std::find_if(device
->BufferList
.begin(), device
->BufferList
.end(),
59 [](const BufferSubList
&entry
) noexcept
-> bool
60 { return entry
.FreeMask
!= 0; }
63 auto lidx
= std::distance(device
->BufferList
.begin(), sublist
);
64 ALbuffer
*buffer
{nullptr};
66 if(LIKELY(sublist
!= device
->BufferList
.end()))
68 slidx
= CTZ64(sublist
->FreeMask
);
69 buffer
= sublist
->Buffers
+ slidx
;
73 /* Don't allocate so many list entries that the 32-bit ID could
76 if(UNLIKELY(device
->BufferList
.size() >= 1<<25))
79 alSetError(context
, AL_OUT_OF_MEMORY
, "Too many buffers allocated");
82 device
->BufferList
.emplace_back();
83 sublist
= device
->BufferList
.end() - 1;
84 sublist
->FreeMask
= ~U64(0);
85 sublist
->Buffers
= reinterpret_cast<ALbuffer
*>(al_calloc(16, sizeof(ALbuffer
)*64));
86 if(UNLIKELY(!sublist
->Buffers
))
88 device
->BufferList
.pop_back();
90 alSetError(context
, AL_OUT_OF_MEMORY
, "Failed to allocate buffer batch");
95 buffer
= sublist
->Buffers
+ slidx
;
98 buffer
= new (buffer
) ALbuffer
{};
99 /* Add 1 to avoid buffer ID 0. */
100 buffer
->id
= ((lidx
<<6) | slidx
) + 1;
102 sublist
->FreeMask
&= ~(U64(1)<<slidx
);
107 void FreeBuffer(ALCdevice
*device
, ALbuffer
*buffer
)
109 ALuint id
{buffer
->id
- 1};
110 ALsizei lidx
= id
>> 6;
111 ALsizei slidx
= id
& 0x3f;
113 al_free(buffer
->data
);
114 buffer
->data
= nullptr;
117 device
->BufferList
[lidx
].FreeMask
|= U64(1) << slidx
;
120 inline ALbuffer
*LookupBuffer(ALCdevice
*device
, ALuint id
)
122 ALuint lidx
= (id
-1) >> 6;
123 ALsizei slidx
= (id
-1) & 0x3f;
125 if(UNLIKELY(lidx
>= device
->BufferList
.size()))
127 BufferSubList
&sublist
= device
->BufferList
[lidx
];
128 if(UNLIKELY(sublist
.FreeMask
& (U64(1)<<slidx
)))
130 return sublist
.Buffers
+ slidx
;
134 ALsizei
SanitizeAlignment(UserFmtType type
, ALsizei align
)
141 if(type
== UserFmtIMA4
)
143 /* Here is where things vary:
144 * nVidia and Apple use 64+1 sample frames per block -> block_size=36 bytes per channel
145 * Most PC sound software uses 2040+1 sample frames per block -> block_size=1024 bytes per channel
149 if(type
== UserFmtMSADPCM
)
154 if(type
== UserFmtIMA4
)
156 /* IMA4 block alignment must be a multiple of 8, plus 1. */
157 if((align
&7) == 1) return align
;
160 if(type
== UserFmtMSADPCM
)
162 /* MSADPCM block alignment must be a multiple of 2. */
163 if((align
&1) == 0) return align
;
171 const ALchar
*NameFromUserFmtType(UserFmtType type
)
175 case UserFmtUByte
: return "Unsigned Byte";
176 case UserFmtShort
: return "Signed Short";
177 case UserFmtFloat
: return "Float32";
178 case UserFmtDouble
: return "Float64";
179 case UserFmtMulaw
: return "muLaw";
180 case UserFmtAlaw
: return "aLaw";
181 case UserFmtIMA4
: return "IMA4 ADPCM";
182 case UserFmtMSADPCM
: return "MSADPCM";
184 return "<internal type error>";
190 * Loads the specified data into the buffer, using the specified format.
192 void LoadData(ALCcontext
*context
, ALbuffer
*ALBuf
, ALuint freq
, ALsizei size
, UserFmtChannels SrcChannels
, UserFmtType SrcType
, const ALvoid
*data
, ALbitfieldSOFT access
)
194 if(UNLIKELY(ReadRef(&ALBuf
->ref
) != 0 || ALBuf
->MappedAccess
!= 0))
195 SETERR_RETURN(context
, AL_INVALID_OPERATION
,, "Modifying storage for in-use buffer %u",
198 /* Currently no channel configurations need to be converted. */
199 FmtChannels DstChannels
{FmtMono
};
202 case UserFmtMono
: DstChannels
= FmtMono
; break;
203 case UserFmtStereo
: DstChannels
= FmtStereo
; break;
204 case UserFmtRear
: DstChannels
= FmtRear
; break;
205 case UserFmtQuad
: DstChannels
= FmtQuad
; break;
206 case UserFmtX51
: DstChannels
= FmtX51
; break;
207 case UserFmtX61
: DstChannels
= FmtX61
; break;
208 case UserFmtX71
: DstChannels
= FmtX71
; break;
209 case UserFmtBFormat2D
: DstChannels
= FmtBFormat2D
; break;
210 case UserFmtBFormat3D
: DstChannels
= FmtBFormat3D
; break;
212 if(UNLIKELY((long)SrcChannels
!= (long)DstChannels
))
213 SETERR_RETURN(context
, AL_INVALID_ENUM
,, "Invalid format");
215 /* IMA4 and MSADPCM convert to 16-bit short. */
216 FmtType DstType
{FmtUByte
};
219 case UserFmtUByte
: DstType
= FmtUByte
; break;
220 case UserFmtShort
: DstType
= FmtShort
; break;
221 case UserFmtFloat
: DstType
= FmtFloat
; break;
222 case UserFmtDouble
: DstType
= FmtDouble
; break;
223 case UserFmtAlaw
: DstType
= FmtAlaw
; break;
224 case UserFmtMulaw
: DstType
= FmtMulaw
; break;
225 case UserFmtIMA4
: DstType
= FmtShort
; break;
226 case UserFmtMSADPCM
: DstType
= FmtShort
; break;
229 /* TODO: Currently we can only map samples when they're not converted. To
230 * allow it would need some kind of double-buffering to hold onto a copy of
233 if((access
&MAP_READ_WRITE_FLAGS
))
235 if(UNLIKELY((long)SrcType
!= (long)DstType
))
236 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "%s samples cannot be mapped",
237 NameFromUserFmtType(SrcType
));
240 ALsizei unpackalign
{ATOMIC_LOAD_SEQ(&ALBuf
->UnpackAlign
)};
241 ALsizei align
{SanitizeAlignment(SrcType
, unpackalign
)};
242 if(UNLIKELY(align
< 1))
243 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Invalid unpack alignment %d for %s samples",
244 unpackalign
, NameFromUserFmtType(SrcType
));
246 if((access
&AL_PRESERVE_DATA_BIT_SOFT
))
248 /* Can only preserve data with the same format and alignment. */
249 if(UNLIKELY(ALBuf
->FmtChannels
!= DstChannels
|| ALBuf
->OriginalType
!= SrcType
))
250 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Preserving data of mismatched format");
251 if(UNLIKELY(ALBuf
->OriginalAlign
!= align
))
252 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Preserving data of mismatched alignment");
255 /* Convert the input/source size in bytes to sample frames using the unpack
258 ALsizei SrcByteAlign
{
259 (SrcType
== UserFmtIMA4
) ? ((align
-1)/2 + 4) * ChannelsFromUserFmt(SrcChannels
) :
260 (SrcType
== UserFmtMSADPCM
) ? ((align
-2)/2 + 7) * ChannelsFromUserFmt(SrcChannels
) :
261 (align
* FrameSizeFromUserFmt(SrcChannels
, SrcType
))
263 if(UNLIKELY((size
%SrcByteAlign
) != 0))
264 SETERR_RETURN(context
, AL_INVALID_VALUE
,,
265 "Data size %d is not a multiple of frame size %d (%d unpack alignment)",
266 size
, SrcByteAlign
, align
);
268 if(UNLIKELY(size
/SrcByteAlign
> std::numeric_limits
<ALsizei
>::max()/align
))
269 SETERR_RETURN(context
, AL_OUT_OF_MEMORY
,,
270 "Buffer size overflow, %d blocks x %d samples per block", size
/SrcByteAlign
, align
);
271 ALsizei frames
{size
/ SrcByteAlign
* align
};
273 /* Convert the sample frames to the number of bytes needed for internal
276 ALsizei NumChannels
{ChannelsFromFmt(DstChannels
)};
277 ALsizei FrameSize
{NumChannels
* BytesFromFmt(DstType
)};
278 if(UNLIKELY(frames
> std::numeric_limits
<ALsizei
>::max()/FrameSize
))
279 SETERR_RETURN(context
, AL_OUT_OF_MEMORY
,,
280 "Buffer size overflow, %d frames x %d bytes per frame", frames
, FrameSize
);
281 ALsizei newsize
{frames
*FrameSize
};
283 /* Round up to the next 16-byte multiple. This could reallocate only when
284 * increasing or the new size is less than half the current, but then the
285 * buffer's AL_SIZE would not be very reliable for accounting buffer memory
286 * usage, and reporting the real size could cause problems for apps that
287 * use AL_SIZE to try to get the buffer's play length.
289 if(LIKELY(newsize
<= std::numeric_limits
<ALsizei
>::max()-15))
290 newsize
= (newsize
+15) & ~0xf;
291 if(newsize
!= ALBuf
->BytesAlloc
)
293 void *temp
{al_malloc(16, (size_t)newsize
)};
294 if(UNLIKELY(!temp
&& newsize
))
295 SETERR_RETURN(context
, AL_OUT_OF_MEMORY
,, "Failed to allocate %d bytes of storage",
297 if((access
&AL_PRESERVE_DATA_BIT_SOFT
))
299 ALsizei tocopy
{std::min(newsize
, ALBuf
->BytesAlloc
)};
300 if(tocopy
> 0) memcpy(temp
, ALBuf
->data
, tocopy
);
302 al_free(ALBuf
->data
);
304 ALBuf
->BytesAlloc
= newsize
;
307 if(SrcType
== UserFmtIMA4
)
309 assert(DstType
== FmtShort
);
310 if(data
!= nullptr && ALBuf
->data
!= nullptr)
311 Convert_ALshort_ALima4(static_cast<ALshort
*>(ALBuf
->data
),
312 static_cast<const ALubyte
*>(data
), NumChannels
, frames
, align
);
313 ALBuf
->OriginalAlign
= align
;
315 else if(SrcType
== UserFmtMSADPCM
)
317 assert(DstType
== FmtShort
);
318 if(data
!= nullptr && ALBuf
->data
!= nullptr)
319 Convert_ALshort_ALmsadpcm(static_cast<ALshort
*>(ALBuf
->data
),
320 static_cast<const ALubyte
*>(data
), NumChannels
, frames
, align
);
321 ALBuf
->OriginalAlign
= align
;
325 assert((long)SrcType
== (long)DstType
);
326 if(data
!= nullptr && ALBuf
->data
!= nullptr)
327 memcpy(ALBuf
->data
, data
, frames
*FrameSize
);
328 ALBuf
->OriginalAlign
= 1;
330 ALBuf
->OriginalSize
= size
;
331 ALBuf
->OriginalType
= SrcType
;
333 ALBuf
->Frequency
= freq
;
334 ALBuf
->FmtChannels
= DstChannels
;
335 ALBuf
->FmtType
= DstType
;
336 ALBuf
->Access
= access
;
338 ALBuf
->SampleLen
= frames
;
339 ALBuf
->LoopStart
= 0;
340 ALBuf
->LoopEnd
= ALBuf
->SampleLen
;
343 using DecompResult
= std::tuple
<bool, UserFmtChannels
, UserFmtType
>;
344 DecompResult
DecomposeUserFormat(ALenum format
)
348 UserFmtChannels channels
;
351 static constexpr std::array
<FormatMap
,46> UserFmtList
{{
352 { AL_FORMAT_MONO8
, UserFmtMono
, UserFmtUByte
},
353 { AL_FORMAT_MONO16
, UserFmtMono
, UserFmtShort
},
354 { AL_FORMAT_MONO_FLOAT32
, UserFmtMono
, UserFmtFloat
},
355 { AL_FORMAT_MONO_DOUBLE_EXT
, UserFmtMono
, UserFmtDouble
},
356 { AL_FORMAT_MONO_IMA4
, UserFmtMono
, UserFmtIMA4
},
357 { AL_FORMAT_MONO_MSADPCM_SOFT
, UserFmtMono
, UserFmtMSADPCM
},
358 { AL_FORMAT_MONO_MULAW
, UserFmtMono
, UserFmtMulaw
},
359 { AL_FORMAT_MONO_ALAW_EXT
, UserFmtMono
, UserFmtAlaw
},
361 { AL_FORMAT_STEREO8
, UserFmtStereo
, UserFmtUByte
},
362 { AL_FORMAT_STEREO16
, UserFmtStereo
, UserFmtShort
},
363 { AL_FORMAT_STEREO_FLOAT32
, UserFmtStereo
, UserFmtFloat
},
364 { AL_FORMAT_STEREO_DOUBLE_EXT
, UserFmtStereo
, UserFmtDouble
},
365 { AL_FORMAT_STEREO_IMA4
, UserFmtStereo
, UserFmtIMA4
},
366 { AL_FORMAT_STEREO_MSADPCM_SOFT
, UserFmtStereo
, UserFmtMSADPCM
},
367 { AL_FORMAT_STEREO_MULAW
, UserFmtStereo
, UserFmtMulaw
},
368 { AL_FORMAT_STEREO_ALAW_EXT
, UserFmtStereo
, UserFmtAlaw
},
370 { AL_FORMAT_REAR8
, UserFmtRear
, UserFmtUByte
},
371 { AL_FORMAT_REAR16
, UserFmtRear
, UserFmtShort
},
372 { AL_FORMAT_REAR32
, UserFmtRear
, UserFmtFloat
},
373 { AL_FORMAT_REAR_MULAW
, UserFmtRear
, UserFmtMulaw
},
375 { AL_FORMAT_QUAD8_LOKI
, UserFmtQuad
, UserFmtUByte
},
376 { AL_FORMAT_QUAD16_LOKI
, UserFmtQuad
, UserFmtShort
},
378 { AL_FORMAT_QUAD8
, UserFmtQuad
, UserFmtUByte
},
379 { AL_FORMAT_QUAD16
, UserFmtQuad
, UserFmtShort
},
380 { AL_FORMAT_QUAD32
, UserFmtQuad
, UserFmtFloat
},
381 { AL_FORMAT_QUAD_MULAW
, UserFmtQuad
, UserFmtMulaw
},
383 { AL_FORMAT_51CHN8
, UserFmtX51
, UserFmtUByte
},
384 { AL_FORMAT_51CHN16
, UserFmtX51
, UserFmtShort
},
385 { AL_FORMAT_51CHN32
, UserFmtX51
, UserFmtFloat
},
386 { AL_FORMAT_51CHN_MULAW
, UserFmtX51
, UserFmtMulaw
},
388 { AL_FORMAT_61CHN8
, UserFmtX61
, UserFmtUByte
},
389 { AL_FORMAT_61CHN16
, UserFmtX61
, UserFmtShort
},
390 { AL_FORMAT_61CHN32
, UserFmtX61
, UserFmtFloat
},
391 { AL_FORMAT_61CHN_MULAW
, UserFmtX61
, UserFmtMulaw
},
393 { AL_FORMAT_71CHN8
, UserFmtX71
, UserFmtUByte
},
394 { AL_FORMAT_71CHN16
, UserFmtX71
, UserFmtShort
},
395 { AL_FORMAT_71CHN32
, UserFmtX71
, UserFmtFloat
},
396 { AL_FORMAT_71CHN_MULAW
, UserFmtX71
, UserFmtMulaw
},
398 { AL_FORMAT_BFORMAT2D_8
, UserFmtBFormat2D
, UserFmtUByte
},
399 { AL_FORMAT_BFORMAT2D_16
, UserFmtBFormat2D
, UserFmtShort
},
400 { AL_FORMAT_BFORMAT2D_FLOAT32
, UserFmtBFormat2D
, UserFmtFloat
},
401 { AL_FORMAT_BFORMAT2D_MULAW
, UserFmtBFormat2D
, UserFmtMulaw
},
403 { AL_FORMAT_BFORMAT3D_8
, UserFmtBFormat3D
, UserFmtUByte
},
404 { AL_FORMAT_BFORMAT3D_16
, UserFmtBFormat3D
, UserFmtShort
},
405 { AL_FORMAT_BFORMAT3D_FLOAT32
, UserFmtBFormat3D
, UserFmtFloat
},
406 { AL_FORMAT_BFORMAT3D_MULAW
, UserFmtBFormat3D
, UserFmtMulaw
},
410 for(const auto &fmt
: UserFmtList
)
412 if(fmt
.format
== format
)
414 std::get
<0>(ret
) = true;
415 std::get
<1>(ret
) = fmt
.channels
;
416 std::get
<2>(ret
) = fmt
.type
;
426 AL_API ALvoid AL_APIENTRY
alGenBuffers(ALsizei n
, ALuint
*buffers
)
428 ContextRef context
{GetContextRef()};
429 if(UNLIKELY(!context
)) return;
433 alSetError(context
.get(), AL_INVALID_VALUE
, "Generating %d buffers", n
);
439 /* Special handling for the easy and normal case. */
440 ALbuffer
*buffer
= AllocBuffer(context
.get());
441 if(buffer
) buffers
[0] = buffer
->id
;
445 /* Store the allocated buffer IDs in a separate local list, to avoid
446 * modifying the user storage in case of failure.
448 std::vector
<ALuint
> ids
;
451 ALbuffer
*buffer
= AllocBuffer(context
.get());
454 alDeleteBuffers(ids
.size(), ids
.data());
458 ids
.emplace_back(buffer
->id
);
460 std::copy(ids
.begin(), ids
.end(), buffers
);
464 AL_API ALvoid AL_APIENTRY
alDeleteBuffers(ALsizei n
, const ALuint
*buffers
)
466 ContextRef context
{GetContextRef()};
467 if(UNLIKELY(!context
)) return;
471 alSetError(context
.get(), AL_INVALID_VALUE
, "Deleting %d buffers", n
);
477 ALCdevice
*device
= context
->Device
;
478 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
480 /* First try to find any buffers that are invalid or in-use. */
481 const ALuint
*buffers_end
= buffers
+ n
;
482 auto invbuf
= std::find_if(buffers
, buffers_end
,
483 [device
, &context
](ALuint bid
) -> bool
485 if(!bid
) return false;
486 ALbuffer
*ALBuf
= LookupBuffer(device
, bid
);
489 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", bid
);
492 if(UNLIKELY(ReadRef(&ALBuf
->ref
) != 0))
494 alSetError(context
.get(), AL_INVALID_OPERATION
, "Deleting in-use buffer %u", bid
);
500 if(LIKELY(invbuf
== buffers_end
))
502 /* All good. Delete non-0 buffer IDs. */
503 std::for_each(buffers
, buffers_end
,
504 [device
](ALuint bid
) -> void
505 { if(bid
) FreeBuffer(device
, LookupBuffer(device
, bid
)); }
510 AL_API ALboolean AL_APIENTRY
alIsBuffer(ALuint buffer
)
512 ContextRef context
{GetContextRef()};
515 ALCdevice
*device
= context
->Device
;
516 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
517 if(!buffer
|| LookupBuffer(device
, buffer
))
524 AL_API ALvoid AL_APIENTRY
alBufferData(ALuint buffer
, ALenum format
, const ALvoid
*data
, ALsizei size
, ALsizei freq
)
525 { alBufferStorageSOFT(buffer
, format
, data
, size
, freq
, 0); }
527 AL_API
void AL_APIENTRY
alBufferStorageSOFT(ALuint buffer
, ALenum format
, const ALvoid
*data
, ALsizei size
, ALsizei freq
, ALbitfieldSOFT flags
)
529 ContextRef context
{GetContextRef()};
530 if(UNLIKELY(!context
)) return;
532 ALCdevice
*device
= context
->Device
;
533 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
535 ALbuffer
*albuf
= LookupBuffer(device
, buffer
);
537 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
538 else if(UNLIKELY(size
< 0))
539 alSetError(context
.get(), AL_INVALID_VALUE
, "Negative storage size %d", size
);
540 else if(UNLIKELY(freq
< 1))
541 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid sample rate %d", freq
);
542 else if(UNLIKELY((flags
&INVALID_STORAGE_MASK
) != 0))
543 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid storage flags 0x%x",
544 flags
&INVALID_STORAGE_MASK
);
545 else if(UNLIKELY((flags
&AL_MAP_PERSISTENT_BIT_SOFT
) && !(flags
&MAP_READ_WRITE_FLAGS
)))
546 alSetError(context
.get(), AL_INVALID_VALUE
,
547 "Declaring persistently mapped storage without read or write access");
550 UserFmtType srctype
{UserFmtUByte
};
551 UserFmtChannels srcchannels
{UserFmtMono
};
554 std::tie(success
, srcchannels
, srctype
) = DecomposeUserFormat(format
);
555 if(UNLIKELY(!success
))
556 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid format 0x%04x", format
);
558 LoadData(context
.get(), albuf
, freq
, size
, srcchannels
, srctype
, data
, flags
);
562 AL_API
void* AL_APIENTRY
alMapBufferSOFT(ALuint buffer
, ALsizei offset
, ALsizei length
, ALbitfieldSOFT access
)
564 ContextRef context
{GetContextRef()};
565 if(UNLIKELY(!context
)) return nullptr;
567 ALCdevice
*device
= context
->Device
;
568 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
570 ALbuffer
*albuf
= LookupBuffer(device
, buffer
);
572 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
573 else if(UNLIKELY((access
&INVALID_MAP_FLAGS
) != 0))
574 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid map flags 0x%x", access
&INVALID_MAP_FLAGS
);
575 else if(UNLIKELY(!(access
&MAP_READ_WRITE_FLAGS
)))
576 alSetError(context
.get(), AL_INVALID_VALUE
, "Mapping buffer %u without read or write access",
580 ALbitfieldSOFT unavailable
= (albuf
->Access
^access
) & access
;
581 if(UNLIKELY(ReadRef(&albuf
->ref
) != 0 && !(access
&AL_MAP_PERSISTENT_BIT_SOFT
)))
582 alSetError(context
.get(), AL_INVALID_OPERATION
,
583 "Mapping in-use buffer %u without persistent mapping", buffer
);
584 else if(UNLIKELY(albuf
->MappedAccess
!= 0))
585 alSetError(context
.get(), AL_INVALID_OPERATION
, "Mapping already-mapped buffer %u", buffer
);
586 else if(UNLIKELY((unavailable
&AL_MAP_READ_BIT_SOFT
)))
587 alSetError(context
.get(), AL_INVALID_VALUE
,
588 "Mapping buffer %u for reading without read access", buffer
);
589 else if(UNLIKELY((unavailable
&AL_MAP_WRITE_BIT_SOFT
)))
590 alSetError(context
.get(), AL_INVALID_VALUE
,
591 "Mapping buffer %u for writing without write access", buffer
);
592 else if(UNLIKELY((unavailable
&AL_MAP_PERSISTENT_BIT_SOFT
)))
593 alSetError(context
.get(), AL_INVALID_VALUE
,
594 "Mapping buffer %u persistently without persistent access", buffer
);
595 else if(UNLIKELY(offset
< 0 || offset
>= albuf
->OriginalSize
||
596 length
<= 0 || length
> albuf
->OriginalSize
- offset
))
597 alSetError(context
.get(), AL_INVALID_VALUE
, "Mapping invalid range %d+%d for buffer %u",
598 offset
, length
, buffer
);
601 void *retval
= (ALbyte
*)albuf
->data
+ offset
;
602 albuf
->MappedAccess
= access
;
603 albuf
->MappedOffset
= offset
;
604 albuf
->MappedSize
= length
;
612 AL_API
void AL_APIENTRY
alUnmapBufferSOFT(ALuint buffer
)
614 ContextRef context
{GetContextRef()};
615 if(UNLIKELY(!context
)) return;
617 ALCdevice
*device
= context
->Device
;
618 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
620 ALbuffer
*albuf
= LookupBuffer(device
, buffer
);
622 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
623 else if(albuf
->MappedAccess
== 0)
624 alSetError(context
.get(), AL_INVALID_OPERATION
, "Unmapping unmapped buffer %u", buffer
);
627 albuf
->MappedAccess
= 0;
628 albuf
->MappedOffset
= 0;
629 albuf
->MappedSize
= 0;
633 AL_API
void AL_APIENTRY
alFlushMappedBufferSOFT(ALuint buffer
, ALsizei offset
, ALsizei length
)
635 ContextRef context
{GetContextRef()};
636 if(UNLIKELY(!context
)) return;
638 ALCdevice
*device
= context
->Device
;
639 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
641 ALbuffer
*albuf
= LookupBuffer(device
, buffer
);
643 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
644 else if(UNLIKELY(!(albuf
->MappedAccess
&AL_MAP_WRITE_BIT_SOFT
)))
645 alSetError(context
.get(), AL_INVALID_OPERATION
,
646 "Flushing buffer %u while not mapped for writing", buffer
);
647 else if(UNLIKELY(offset
< albuf
->MappedOffset
||
648 offset
>= albuf
->MappedOffset
+albuf
->MappedSize
||
649 length
<= 0 || length
> albuf
->MappedOffset
+albuf
->MappedSize
-offset
))
650 alSetError(context
.get(), AL_INVALID_VALUE
, "Flushing invalid range %d+%d on buffer %u",
651 offset
, length
, buffer
);
654 /* FIXME: Need to use some method of double-buffering for the mixer and
655 * app to hold separate memory, which can be safely transfered
656 * asynchronously. Currently we just say the app shouldn't write where
657 * OpenAL's reading, and hope for the best...
659 std::atomic_thread_fence(std::memory_order_seq_cst
);
663 AL_API ALvoid AL_APIENTRY
alBufferSubDataSOFT(ALuint buffer
, ALenum format
, const ALvoid
*data
, ALsizei offset
, ALsizei length
)
665 ContextRef context
{GetContextRef()};
666 if(UNLIKELY(!context
)) return;
668 ALCdevice
*device
= context
->Device
;
669 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
671 ALbuffer
*albuf
= LookupBuffer(device
, buffer
);
674 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
678 UserFmtType srctype
{UserFmtUByte
};
679 UserFmtChannels srcchannels
{UserFmtMono
};
681 std::tie(success
, srcchannels
, srctype
) = DecomposeUserFormat(format
);
682 if(UNLIKELY(!success
))
684 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid format 0x%04x", format
);
688 ALsizei unpack_align
{ATOMIC_LOAD_SEQ(&albuf
->UnpackAlign
)};
689 ALsizei align
{SanitizeAlignment(srctype
, unpack_align
)};
690 if(UNLIKELY(align
< 1))
691 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid unpack alignment %d", unpack_align
);
692 else if(UNLIKELY((long)srcchannels
!= (long)albuf
->FmtChannels
||
693 srctype
!= albuf
->OriginalType
))
694 alSetError(context
.get(), AL_INVALID_ENUM
, "Unpacking data with mismatched format");
695 else if(UNLIKELY(align
!= albuf
->OriginalAlign
))
696 alSetError(context
.get(), AL_INVALID_VALUE
,
697 "Unpacking data with alignment %u does not match original alignment %u",
698 align
, albuf
->OriginalAlign
);
699 else if(UNLIKELY(albuf
->MappedAccess
!= 0))
700 alSetError(context
.get(), AL_INVALID_OPERATION
, "Unpacking data into mapped buffer %u",
704 ALsizei num_chans
{ChannelsFromFmt(albuf
->FmtChannels
)};
705 ALsizei frame_size
{num_chans
* BytesFromFmt(albuf
->FmtType
)};
707 (albuf
->OriginalType
== UserFmtIMA4
) ? ((align
-1)/2 + 4) * num_chans
:
708 (albuf
->OriginalType
== UserFmtMSADPCM
) ? ((align
-2)/2 + 7) * num_chans
:
712 if(UNLIKELY(offset
< 0 || length
< 0 || offset
> albuf
->OriginalSize
||
713 length
> albuf
->OriginalSize
-offset
))
714 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid data sub-range %d+%d on buffer %u",
715 offset
, length
, buffer
);
716 else if(UNLIKELY((offset
%byte_align
) != 0))
717 alSetError(context
.get(), AL_INVALID_VALUE
,
718 "Sub-range offset %d is not a multiple of frame size %d (%d unpack alignment)",
719 offset
, byte_align
, align
);
720 else if(UNLIKELY((length
%byte_align
) != 0))
721 alSetError(context
.get(), AL_INVALID_VALUE
,
722 "Sub-range length %d is not a multiple of frame size %d (%d unpack alignment)",
723 length
, byte_align
, align
);
726 /* offset -> byte offset, length -> sample count */
727 offset
= offset
/byte_align
* align
* frame_size
;
728 length
= length
/byte_align
* align
;
730 void *dst
= static_cast<ALbyte
*>(albuf
->data
) + offset
;
731 if(srctype
== UserFmtIMA4
&& albuf
->FmtType
== FmtShort
)
732 Convert_ALshort_ALima4(static_cast<ALshort
*>(dst
),
733 static_cast<const ALubyte
*>(data
), num_chans
, length
, align
);
734 else if(srctype
== UserFmtMSADPCM
&& albuf
->FmtType
== FmtShort
)
735 Convert_ALshort_ALmsadpcm(static_cast<ALshort
*>(dst
),
736 static_cast<const ALubyte
*>(data
), num_chans
, length
, align
);
739 assert((long)srctype
== (long)albuf
->FmtType
);
740 memcpy(dst
, data
, length
*frame_size
);
747 AL_API
void AL_APIENTRY
alBufferSamplesSOFT(ALuint
UNUSED(buffer
),
748 ALuint
UNUSED(samplerate
), ALenum
UNUSED(internalformat
), ALsizei
UNUSED(samples
),
749 ALenum
UNUSED(channels
), ALenum
UNUSED(type
), const ALvoid
*UNUSED(data
))
751 ContextRef context
{GetContextRef()};
752 if(UNLIKELY(!context
)) return;
754 alSetError(context
.get(), AL_INVALID_OPERATION
, "alBufferSamplesSOFT not supported");
757 AL_API
void AL_APIENTRY
alBufferSubSamplesSOFT(ALuint
UNUSED(buffer
),
758 ALsizei
UNUSED(offset
), ALsizei
UNUSED(samples
),
759 ALenum
UNUSED(channels
), ALenum
UNUSED(type
), const ALvoid
*UNUSED(data
))
761 ContextRef context
{GetContextRef()};
762 if(UNLIKELY(!context
)) return;
764 alSetError(context
.get(), AL_INVALID_OPERATION
, "alBufferSubSamplesSOFT not supported");
767 AL_API
void AL_APIENTRY
alGetBufferSamplesSOFT(ALuint
UNUSED(buffer
),
768 ALsizei
UNUSED(offset
), ALsizei
UNUSED(samples
),
769 ALenum
UNUSED(channels
), ALenum
UNUSED(type
), ALvoid
*UNUSED(data
))
771 ContextRef context
{GetContextRef()};
772 if(UNLIKELY(!context
)) return;
774 alSetError(context
.get(), AL_INVALID_OPERATION
, "alGetBufferSamplesSOFT not supported");
777 AL_API ALboolean AL_APIENTRY
alIsBufferFormatSupportedSOFT(ALenum
UNUSED(format
))
779 ContextRef context
{GetContextRef()};
780 if(!context
) return AL_FALSE
;
782 alSetError(context
.get(), AL_INVALID_OPERATION
, "alIsBufferFormatSupportedSOFT not supported");
787 AL_API
void AL_APIENTRY
alBufferf(ALuint buffer
, ALenum param
, ALfloat
UNUSED(value
))
789 ContextRef context
{GetContextRef()};
790 if(UNLIKELY(!context
)) return;
792 ALCdevice
*device
= context
->Device
;
793 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
795 if(UNLIKELY(LookupBuffer(device
, buffer
) == nullptr))
796 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
800 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid buffer float property 0x%04x", param
);
805 AL_API
void AL_APIENTRY
alBuffer3f(ALuint buffer
, ALenum param
, ALfloat
UNUSED(value1
), ALfloat
UNUSED(value2
), ALfloat
UNUSED(value3
))
807 ContextRef context
{GetContextRef()};
808 if(UNLIKELY(!context
)) return;
810 ALCdevice
*device
= context
->Device
;
811 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
813 if(UNLIKELY(LookupBuffer(device
, buffer
) == nullptr))
814 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
818 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid buffer 3-float property 0x%04x", param
);
823 AL_API
void AL_APIENTRY
alBufferfv(ALuint buffer
, ALenum param
, const ALfloat
*values
)
825 ContextRef context
{GetContextRef()};
826 if(UNLIKELY(!context
)) return;
828 ALCdevice
*device
= context
->Device
;
829 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
831 if(UNLIKELY(LookupBuffer(device
, buffer
) == nullptr))
832 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
833 else if(UNLIKELY(!values
))
834 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
838 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid buffer float-vector property 0x%04x", param
);
843 AL_API
void AL_APIENTRY
alBufferi(ALuint buffer
, ALenum param
, ALint value
)
845 ContextRef context
{GetContextRef()};
846 if(UNLIKELY(!context
)) return;
848 ALCdevice
*device
= context
->Device
;
849 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
851 ALbuffer
*albuf
= LookupBuffer(device
, buffer
);
853 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
856 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT
:
857 if(UNLIKELY(value
< 0))
858 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid unpack block alignment %d", value
);
860 ATOMIC_STORE_SEQ(&albuf
->UnpackAlign
, value
);
863 case AL_PACK_BLOCK_ALIGNMENT_SOFT
:
864 if(UNLIKELY(value
< 0))
865 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid pack block alignment %d", value
);
867 ATOMIC_STORE_SEQ(&albuf
->PackAlign
, value
);
871 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid buffer integer property 0x%04x", param
);
876 AL_API
void AL_APIENTRY
alBuffer3i(ALuint buffer
, ALenum param
, ALint
UNUSED(value1
), ALint
UNUSED(value2
), ALint
UNUSED(value3
))
878 ContextRef context
{GetContextRef()};
879 if(UNLIKELY(!context
)) return;
881 ALCdevice
*device
= context
->Device
;
882 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
884 if(UNLIKELY(LookupBuffer(device
, buffer
) == nullptr))
885 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
889 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid buffer 3-integer property 0x%04x", param
);
894 AL_API
void AL_APIENTRY
alBufferiv(ALuint buffer
, ALenum param
, const ALint
*values
)
900 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT
:
901 case AL_PACK_BLOCK_ALIGNMENT_SOFT
:
902 alBufferi(buffer
, param
, values
[0]);
907 ContextRef context
{GetContextRef()};
908 if(UNLIKELY(!context
)) return;
910 ALCdevice
*device
= context
->Device
;
911 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
913 ALbuffer
*albuf
= LookupBuffer(device
, buffer
);
915 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
916 else if(UNLIKELY(!values
))
917 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
920 case AL_LOOP_POINTS_SOFT
:
921 if(UNLIKELY(ReadRef(&albuf
->ref
) != 0))
922 alSetError(context
.get(), AL_INVALID_OPERATION
, "Modifying in-use buffer %u's loop points",
924 else if(UNLIKELY(values
[0] >= values
[1] || values
[0] < 0 || values
[1] > albuf
->SampleLen
))
925 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid loop point range %d -> %d o buffer %u",
926 values
[0], values
[1], buffer
);
929 albuf
->LoopStart
= values
[0];
930 albuf
->LoopEnd
= values
[1];
935 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid buffer integer-vector property 0x%04x",
941 AL_API ALvoid AL_APIENTRY
alGetBufferf(ALuint buffer
, ALenum param
, ALfloat
*value
)
943 ContextRef context
{GetContextRef()};
944 if(UNLIKELY(!context
)) return;
946 ALCdevice
*device
= context
->Device
;
947 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
949 ALbuffer
*albuf
= LookupBuffer(device
, buffer
);
951 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
952 else if(UNLIKELY(!value
))
953 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
957 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid buffer float property 0x%04x", param
);
962 AL_API
void AL_APIENTRY
alGetBuffer3f(ALuint buffer
, ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
964 ContextRef context
{GetContextRef()};
965 if(UNLIKELY(!context
)) return;
967 ALCdevice
*device
= context
->Device
;
968 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
970 if(UNLIKELY(LookupBuffer(device
, buffer
) == nullptr))
971 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
972 else if(UNLIKELY(!value1
|| !value2
|| !value3
))
973 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
977 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid buffer 3-float property 0x%04x", param
);
982 AL_API
void AL_APIENTRY
alGetBufferfv(ALuint buffer
, ALenum param
, ALfloat
*values
)
986 case AL_SEC_LENGTH_SOFT
:
987 alGetBufferf(buffer
, param
, values
);
991 ContextRef context
{GetContextRef()};
992 if(UNLIKELY(!context
)) return;
994 ALCdevice
*device
= context
->Device
;
995 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
997 if(UNLIKELY(LookupBuffer(device
, buffer
) == nullptr))
998 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
999 else if(UNLIKELY(!values
))
1000 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
1004 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid buffer float-vector property 0x%04x", param
);
1009 AL_API ALvoid AL_APIENTRY
alGetBufferi(ALuint buffer
, ALenum param
, ALint
*value
)
1011 ContextRef context
{GetContextRef()};
1012 if(UNLIKELY(!context
)) return;
1014 ALCdevice
*device
= context
->Device
;
1015 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
1017 ALbuffer
*albuf
= LookupBuffer(device
, buffer
);
1018 if(UNLIKELY(!albuf
))
1019 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
1020 else if(UNLIKELY(!value
))
1021 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
1025 *value
= albuf
->Frequency
;
1029 *value
= BytesFromFmt(albuf
->FmtType
) * 8;
1033 *value
= ChannelsFromFmt(albuf
->FmtChannels
);
1037 *value
= albuf
->SampleLen
* FrameSizeFromFmt(albuf
->FmtChannels
,
1041 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT
:
1042 *value
= ATOMIC_LOAD_SEQ(&albuf
->UnpackAlign
);
1045 case AL_PACK_BLOCK_ALIGNMENT_SOFT
:
1046 *value
= ATOMIC_LOAD_SEQ(&albuf
->PackAlign
);
1050 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid buffer integer property 0x%04x", param
);
1055 AL_API
void AL_APIENTRY
alGetBuffer3i(ALuint buffer
, ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
1057 ContextRef context
{GetContextRef()};
1058 if(UNLIKELY(!context
)) return;
1060 ALCdevice
*device
= context
->Device
;
1061 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
1063 if(UNLIKELY(LookupBuffer(device
, buffer
) == nullptr))
1064 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
1065 else if(UNLIKELY(!value1
|| !value2
|| !value3
))
1066 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
1070 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid buffer 3-integer property 0x%04x", param
);
1075 AL_API
void AL_APIENTRY
alGetBufferiv(ALuint buffer
, ALenum param
, ALint
*values
)
1083 case AL_INTERNAL_FORMAT_SOFT
:
1084 case AL_BYTE_LENGTH_SOFT
:
1085 case AL_SAMPLE_LENGTH_SOFT
:
1086 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT
:
1087 case AL_PACK_BLOCK_ALIGNMENT_SOFT
:
1088 alGetBufferi(buffer
, param
, values
);
1092 ContextRef context
{GetContextRef()};
1093 if(UNLIKELY(!context
)) return;
1095 ALCdevice
*device
= context
->Device
;
1096 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
1098 ALbuffer
*albuf
= LookupBuffer(device
, buffer
);
1099 if(UNLIKELY(!albuf
))
1100 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
1101 else if(UNLIKELY(!values
))
1102 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
1105 case AL_LOOP_POINTS_SOFT
:
1106 values
[0] = albuf
->LoopStart
;
1107 values
[1] = albuf
->LoopEnd
;
1111 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid buffer integer-vector property 0x%04x",
1117 ALsizei
BytesFromUserFmt(UserFmtType type
)
1121 case UserFmtUByte
: return sizeof(ALubyte
);
1122 case UserFmtShort
: return sizeof(ALshort
);
1123 case UserFmtFloat
: return sizeof(ALfloat
);
1124 case UserFmtDouble
: return sizeof(ALdouble
);
1125 case UserFmtMulaw
: return sizeof(ALubyte
);
1126 case UserFmtAlaw
: return sizeof(ALubyte
);
1127 case UserFmtIMA4
: break; /* not handled here */
1128 case UserFmtMSADPCM
: break; /* not handled here */
1132 ALsizei
ChannelsFromUserFmt(UserFmtChannels chans
)
1136 case UserFmtMono
: return 1;
1137 case UserFmtStereo
: return 2;
1138 case UserFmtRear
: return 2;
1139 case UserFmtQuad
: return 4;
1140 case UserFmtX51
: return 6;
1141 case UserFmtX61
: return 7;
1142 case UserFmtX71
: return 8;
1143 case UserFmtBFormat2D
: return 3;
1144 case UserFmtBFormat3D
: return 4;
1149 ALsizei
BytesFromFmt(FmtType type
)
1153 case FmtUByte
: return sizeof(ALubyte
);
1154 case FmtShort
: return sizeof(ALshort
);
1155 case FmtFloat
: return sizeof(ALfloat
);
1156 case FmtDouble
: return sizeof(ALdouble
);
1157 case FmtMulaw
: return sizeof(ALubyte
);
1158 case FmtAlaw
: return sizeof(ALubyte
);
1162 ALsizei
ChannelsFromFmt(FmtChannels chans
)
1166 case FmtMono
: return 1;
1167 case FmtStereo
: return 2;
1168 case FmtRear
: return 2;
1169 case FmtQuad
: return 4;
1170 case FmtX51
: return 6;
1171 case FmtX61
: return 7;
1172 case FmtX71
: return 8;
1173 case FmtBFormat2D
: return 3;
1174 case FmtBFormat3D
: return 4;
1181 * ReleaseALBuffers()
1183 * INTERNAL: Called to destroy any buffers that still exist on the device
1185 ALvoid
ReleaseALBuffers(ALCdevice
*device
)
1187 size_t leftover
= 0;
1188 for(auto &sublist
: device
->BufferList
)
1190 ALuint64 usemask
= ~sublist
.FreeMask
;
1193 ALsizei idx
= CTZ64(usemask
);
1194 ALbuffer
*buffer
= sublist
.Buffers
+ idx
;
1196 al_free(buffer
->data
);
1197 buffer
->data
= nullptr;
1198 buffer
->~ALbuffer();
1202 usemask
&= ~(U64(1) << idx
);
1204 sublist
.FreeMask
= ~usemask
;
1207 WARN("(%p) Deleted " SZFMT
" Buffer%s\n", device
, leftover
, (leftover
==1)?"":"s");