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
506 ALbuffer
*buffer
{bid
? LookupBuffer(device
, bid
) : nullptr};
507 if(buffer
) FreeBuffer(device
, buffer
);
513 AL_API ALboolean AL_APIENTRY
alIsBuffer(ALuint buffer
)
515 ContextRef context
{GetContextRef()};
518 ALCdevice
*device
= context
->Device
;
519 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
520 if(!buffer
|| LookupBuffer(device
, buffer
))
527 AL_API ALvoid AL_APIENTRY
alBufferData(ALuint buffer
, ALenum format
, const ALvoid
*data
, ALsizei size
, ALsizei freq
)
528 { alBufferStorageSOFT(buffer
, format
, data
, size
, freq
, 0); }
530 AL_API
void AL_APIENTRY
alBufferStorageSOFT(ALuint buffer
, ALenum format
, const ALvoid
*data
, ALsizei size
, ALsizei freq
, ALbitfieldSOFT flags
)
532 ContextRef context
{GetContextRef()};
533 if(UNLIKELY(!context
)) return;
535 ALCdevice
*device
= context
->Device
;
536 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
538 ALbuffer
*albuf
= LookupBuffer(device
, buffer
);
540 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
541 else if(UNLIKELY(size
< 0))
542 alSetError(context
.get(), AL_INVALID_VALUE
, "Negative storage size %d", size
);
543 else if(UNLIKELY(freq
< 1))
544 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid sample rate %d", freq
);
545 else if(UNLIKELY((flags
&INVALID_STORAGE_MASK
) != 0))
546 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid storage flags 0x%x",
547 flags
&INVALID_STORAGE_MASK
);
548 else if(UNLIKELY((flags
&AL_MAP_PERSISTENT_BIT_SOFT
) && !(flags
&MAP_READ_WRITE_FLAGS
)))
549 alSetError(context
.get(), AL_INVALID_VALUE
,
550 "Declaring persistently mapped storage without read or write access");
553 UserFmtType srctype
{UserFmtUByte
};
554 UserFmtChannels srcchannels
{UserFmtMono
};
557 std::tie(success
, srcchannels
, srctype
) = DecomposeUserFormat(format
);
558 if(UNLIKELY(!success
))
559 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid format 0x%04x", format
);
561 LoadData(context
.get(), albuf
, freq
, size
, srcchannels
, srctype
, data
, flags
);
565 AL_API
void* AL_APIENTRY
alMapBufferSOFT(ALuint buffer
, ALsizei offset
, ALsizei length
, ALbitfieldSOFT access
)
567 ContextRef context
{GetContextRef()};
568 if(UNLIKELY(!context
)) return nullptr;
570 ALCdevice
*device
= context
->Device
;
571 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
573 ALbuffer
*albuf
= LookupBuffer(device
, buffer
);
575 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
576 else if(UNLIKELY((access
&INVALID_MAP_FLAGS
) != 0))
577 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid map flags 0x%x", access
&INVALID_MAP_FLAGS
);
578 else if(UNLIKELY(!(access
&MAP_READ_WRITE_FLAGS
)))
579 alSetError(context
.get(), AL_INVALID_VALUE
, "Mapping buffer %u without read or write access",
583 ALbitfieldSOFT unavailable
= (albuf
->Access
^access
) & access
;
584 if(UNLIKELY(ReadRef(&albuf
->ref
) != 0 && !(access
&AL_MAP_PERSISTENT_BIT_SOFT
)))
585 alSetError(context
.get(), AL_INVALID_OPERATION
,
586 "Mapping in-use buffer %u without persistent mapping", buffer
);
587 else if(UNLIKELY(albuf
->MappedAccess
!= 0))
588 alSetError(context
.get(), AL_INVALID_OPERATION
, "Mapping already-mapped buffer %u", buffer
);
589 else if(UNLIKELY((unavailable
&AL_MAP_READ_BIT_SOFT
)))
590 alSetError(context
.get(), AL_INVALID_VALUE
,
591 "Mapping buffer %u for reading without read access", buffer
);
592 else if(UNLIKELY((unavailable
&AL_MAP_WRITE_BIT_SOFT
)))
593 alSetError(context
.get(), AL_INVALID_VALUE
,
594 "Mapping buffer %u for writing without write access", buffer
);
595 else if(UNLIKELY((unavailable
&AL_MAP_PERSISTENT_BIT_SOFT
)))
596 alSetError(context
.get(), AL_INVALID_VALUE
,
597 "Mapping buffer %u persistently without persistent access", buffer
);
598 else if(UNLIKELY(offset
< 0 || offset
>= albuf
->OriginalSize
||
599 length
<= 0 || length
> albuf
->OriginalSize
- offset
))
600 alSetError(context
.get(), AL_INVALID_VALUE
, "Mapping invalid range %d+%d for buffer %u",
601 offset
, length
, buffer
);
604 void *retval
= (ALbyte
*)albuf
->data
+ offset
;
605 albuf
->MappedAccess
= access
;
606 albuf
->MappedOffset
= offset
;
607 albuf
->MappedSize
= length
;
615 AL_API
void AL_APIENTRY
alUnmapBufferSOFT(ALuint buffer
)
617 ContextRef context
{GetContextRef()};
618 if(UNLIKELY(!context
)) return;
620 ALCdevice
*device
= context
->Device
;
621 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
623 ALbuffer
*albuf
= LookupBuffer(device
, buffer
);
625 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
626 else if(albuf
->MappedAccess
== 0)
627 alSetError(context
.get(), AL_INVALID_OPERATION
, "Unmapping unmapped buffer %u", buffer
);
630 albuf
->MappedAccess
= 0;
631 albuf
->MappedOffset
= 0;
632 albuf
->MappedSize
= 0;
636 AL_API
void AL_APIENTRY
alFlushMappedBufferSOFT(ALuint buffer
, ALsizei offset
, ALsizei length
)
638 ContextRef context
{GetContextRef()};
639 if(UNLIKELY(!context
)) return;
641 ALCdevice
*device
= context
->Device
;
642 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
644 ALbuffer
*albuf
= LookupBuffer(device
, buffer
);
646 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
647 else if(UNLIKELY(!(albuf
->MappedAccess
&AL_MAP_WRITE_BIT_SOFT
)))
648 alSetError(context
.get(), AL_INVALID_OPERATION
,
649 "Flushing buffer %u while not mapped for writing", buffer
);
650 else if(UNLIKELY(offset
< albuf
->MappedOffset
||
651 offset
>= albuf
->MappedOffset
+albuf
->MappedSize
||
652 length
<= 0 || length
> albuf
->MappedOffset
+albuf
->MappedSize
-offset
))
653 alSetError(context
.get(), AL_INVALID_VALUE
, "Flushing invalid range %d+%d on buffer %u",
654 offset
, length
, buffer
);
657 /* FIXME: Need to use some method of double-buffering for the mixer and
658 * app to hold separate memory, which can be safely transfered
659 * asynchronously. Currently we just say the app shouldn't write where
660 * OpenAL's reading, and hope for the best...
662 std::atomic_thread_fence(std::memory_order_seq_cst
);
666 AL_API ALvoid AL_APIENTRY
alBufferSubDataSOFT(ALuint buffer
, ALenum format
, const ALvoid
*data
, ALsizei offset
, ALsizei length
)
668 ContextRef context
{GetContextRef()};
669 if(UNLIKELY(!context
)) return;
671 ALCdevice
*device
= context
->Device
;
672 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
674 ALbuffer
*albuf
= LookupBuffer(device
, buffer
);
677 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
681 UserFmtType srctype
{UserFmtUByte
};
682 UserFmtChannels srcchannels
{UserFmtMono
};
684 std::tie(success
, srcchannels
, srctype
) = DecomposeUserFormat(format
);
685 if(UNLIKELY(!success
))
687 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid format 0x%04x", format
);
691 ALsizei unpack_align
{ATOMIC_LOAD_SEQ(&albuf
->UnpackAlign
)};
692 ALsizei align
{SanitizeAlignment(srctype
, unpack_align
)};
693 if(UNLIKELY(align
< 1))
694 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid unpack alignment %d", unpack_align
);
695 else if(UNLIKELY((long)srcchannels
!= (long)albuf
->FmtChannels
||
696 srctype
!= albuf
->OriginalType
))
697 alSetError(context
.get(), AL_INVALID_ENUM
, "Unpacking data with mismatched format");
698 else if(UNLIKELY(align
!= albuf
->OriginalAlign
))
699 alSetError(context
.get(), AL_INVALID_VALUE
,
700 "Unpacking data with alignment %u does not match original alignment %u",
701 align
, albuf
->OriginalAlign
);
702 else if(UNLIKELY(albuf
->MappedAccess
!= 0))
703 alSetError(context
.get(), AL_INVALID_OPERATION
, "Unpacking data into mapped buffer %u",
707 ALsizei num_chans
{ChannelsFromFmt(albuf
->FmtChannels
)};
708 ALsizei frame_size
{num_chans
* BytesFromFmt(albuf
->FmtType
)};
710 (albuf
->OriginalType
== UserFmtIMA4
) ? ((align
-1)/2 + 4) * num_chans
:
711 (albuf
->OriginalType
== UserFmtMSADPCM
) ? ((align
-2)/2 + 7) * num_chans
:
715 if(UNLIKELY(offset
< 0 || length
< 0 || offset
> albuf
->OriginalSize
||
716 length
> albuf
->OriginalSize
-offset
))
717 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid data sub-range %d+%d on buffer %u",
718 offset
, length
, buffer
);
719 else if(UNLIKELY((offset
%byte_align
) != 0))
720 alSetError(context
.get(), AL_INVALID_VALUE
,
721 "Sub-range offset %d is not a multiple of frame size %d (%d unpack alignment)",
722 offset
, byte_align
, align
);
723 else if(UNLIKELY((length
%byte_align
) != 0))
724 alSetError(context
.get(), AL_INVALID_VALUE
,
725 "Sub-range length %d is not a multiple of frame size %d (%d unpack alignment)",
726 length
, byte_align
, align
);
729 /* offset -> byte offset, length -> sample count */
730 offset
= offset
/byte_align
* align
* frame_size
;
731 length
= length
/byte_align
* align
;
733 void *dst
= static_cast<ALbyte
*>(albuf
->data
) + offset
;
734 if(srctype
== UserFmtIMA4
&& albuf
->FmtType
== FmtShort
)
735 Convert_ALshort_ALima4(static_cast<ALshort
*>(dst
),
736 static_cast<const ALubyte
*>(data
), num_chans
, length
, align
);
737 else if(srctype
== UserFmtMSADPCM
&& albuf
->FmtType
== FmtShort
)
738 Convert_ALshort_ALmsadpcm(static_cast<ALshort
*>(dst
),
739 static_cast<const ALubyte
*>(data
), num_chans
, length
, align
);
742 assert((long)srctype
== (long)albuf
->FmtType
);
743 memcpy(dst
, data
, length
*frame_size
);
750 AL_API
void AL_APIENTRY
alBufferSamplesSOFT(ALuint
UNUSED(buffer
),
751 ALuint
UNUSED(samplerate
), ALenum
UNUSED(internalformat
), ALsizei
UNUSED(samples
),
752 ALenum
UNUSED(channels
), ALenum
UNUSED(type
), const ALvoid
*UNUSED(data
))
754 ContextRef context
{GetContextRef()};
755 if(UNLIKELY(!context
)) return;
757 alSetError(context
.get(), AL_INVALID_OPERATION
, "alBufferSamplesSOFT not supported");
760 AL_API
void AL_APIENTRY
alBufferSubSamplesSOFT(ALuint
UNUSED(buffer
),
761 ALsizei
UNUSED(offset
), ALsizei
UNUSED(samples
),
762 ALenum
UNUSED(channels
), ALenum
UNUSED(type
), const ALvoid
*UNUSED(data
))
764 ContextRef context
{GetContextRef()};
765 if(UNLIKELY(!context
)) return;
767 alSetError(context
.get(), AL_INVALID_OPERATION
, "alBufferSubSamplesSOFT not supported");
770 AL_API
void AL_APIENTRY
alGetBufferSamplesSOFT(ALuint
UNUSED(buffer
),
771 ALsizei
UNUSED(offset
), ALsizei
UNUSED(samples
),
772 ALenum
UNUSED(channels
), ALenum
UNUSED(type
), ALvoid
*UNUSED(data
))
774 ContextRef context
{GetContextRef()};
775 if(UNLIKELY(!context
)) return;
777 alSetError(context
.get(), AL_INVALID_OPERATION
, "alGetBufferSamplesSOFT not supported");
780 AL_API ALboolean AL_APIENTRY
alIsBufferFormatSupportedSOFT(ALenum
UNUSED(format
))
782 ContextRef context
{GetContextRef()};
783 if(!context
) return AL_FALSE
;
785 alSetError(context
.get(), AL_INVALID_OPERATION
, "alIsBufferFormatSupportedSOFT not supported");
790 AL_API
void AL_APIENTRY
alBufferf(ALuint buffer
, ALenum param
, ALfloat
UNUSED(value
))
792 ContextRef context
{GetContextRef()};
793 if(UNLIKELY(!context
)) return;
795 ALCdevice
*device
= context
->Device
;
796 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
798 if(UNLIKELY(LookupBuffer(device
, buffer
) == nullptr))
799 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
803 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid buffer float property 0x%04x", param
);
808 AL_API
void AL_APIENTRY
alBuffer3f(ALuint buffer
, ALenum param
, ALfloat
UNUSED(value1
), ALfloat
UNUSED(value2
), ALfloat
UNUSED(value3
))
810 ContextRef context
{GetContextRef()};
811 if(UNLIKELY(!context
)) return;
813 ALCdevice
*device
= context
->Device
;
814 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
816 if(UNLIKELY(LookupBuffer(device
, buffer
) == nullptr))
817 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
821 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid buffer 3-float property 0x%04x", param
);
826 AL_API
void AL_APIENTRY
alBufferfv(ALuint buffer
, ALenum param
, const ALfloat
*values
)
828 ContextRef context
{GetContextRef()};
829 if(UNLIKELY(!context
)) return;
831 ALCdevice
*device
= context
->Device
;
832 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
834 if(UNLIKELY(LookupBuffer(device
, buffer
) == nullptr))
835 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
836 else if(UNLIKELY(!values
))
837 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
841 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid buffer float-vector property 0x%04x", param
);
846 AL_API
void AL_APIENTRY
alBufferi(ALuint buffer
, ALenum param
, ALint value
)
848 ContextRef context
{GetContextRef()};
849 if(UNLIKELY(!context
)) return;
851 ALCdevice
*device
= context
->Device
;
852 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
854 ALbuffer
*albuf
= LookupBuffer(device
, buffer
);
856 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
859 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT
:
860 if(UNLIKELY(value
< 0))
861 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid unpack block alignment %d", value
);
863 ATOMIC_STORE_SEQ(&albuf
->UnpackAlign
, value
);
866 case AL_PACK_BLOCK_ALIGNMENT_SOFT
:
867 if(UNLIKELY(value
< 0))
868 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid pack block alignment %d", value
);
870 ATOMIC_STORE_SEQ(&albuf
->PackAlign
, value
);
874 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid buffer integer property 0x%04x", param
);
879 AL_API
void AL_APIENTRY
alBuffer3i(ALuint buffer
, ALenum param
, ALint
UNUSED(value1
), ALint
UNUSED(value2
), ALint
UNUSED(value3
))
881 ContextRef context
{GetContextRef()};
882 if(UNLIKELY(!context
)) return;
884 ALCdevice
*device
= context
->Device
;
885 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
887 if(UNLIKELY(LookupBuffer(device
, buffer
) == nullptr))
888 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
892 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid buffer 3-integer property 0x%04x", param
);
897 AL_API
void AL_APIENTRY
alBufferiv(ALuint buffer
, ALenum param
, const ALint
*values
)
903 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT
:
904 case AL_PACK_BLOCK_ALIGNMENT_SOFT
:
905 alBufferi(buffer
, param
, values
[0]);
910 ContextRef context
{GetContextRef()};
911 if(UNLIKELY(!context
)) return;
913 ALCdevice
*device
= context
->Device
;
914 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
916 ALbuffer
*albuf
= LookupBuffer(device
, buffer
);
918 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
919 else if(UNLIKELY(!values
))
920 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
923 case AL_LOOP_POINTS_SOFT
:
924 if(UNLIKELY(ReadRef(&albuf
->ref
) != 0))
925 alSetError(context
.get(), AL_INVALID_OPERATION
, "Modifying in-use buffer %u's loop points",
927 else if(UNLIKELY(values
[0] >= values
[1] || values
[0] < 0 || values
[1] > albuf
->SampleLen
))
928 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid loop point range %d -> %d o buffer %u",
929 values
[0], values
[1], buffer
);
932 albuf
->LoopStart
= values
[0];
933 albuf
->LoopEnd
= values
[1];
938 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid buffer integer-vector property 0x%04x",
944 AL_API ALvoid AL_APIENTRY
alGetBufferf(ALuint buffer
, ALenum param
, ALfloat
*value
)
946 ContextRef context
{GetContextRef()};
947 if(UNLIKELY(!context
)) return;
949 ALCdevice
*device
= context
->Device
;
950 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
952 ALbuffer
*albuf
= LookupBuffer(device
, buffer
);
954 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
955 else if(UNLIKELY(!value
))
956 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
960 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid buffer float property 0x%04x", param
);
965 AL_API
void AL_APIENTRY
alGetBuffer3f(ALuint buffer
, ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
967 ContextRef context
{GetContextRef()};
968 if(UNLIKELY(!context
)) return;
970 ALCdevice
*device
= context
->Device
;
971 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
973 if(UNLIKELY(LookupBuffer(device
, buffer
) == nullptr))
974 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
975 else if(UNLIKELY(!value1
|| !value2
|| !value3
))
976 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
980 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid buffer 3-float property 0x%04x", param
);
985 AL_API
void AL_APIENTRY
alGetBufferfv(ALuint buffer
, ALenum param
, ALfloat
*values
)
989 case AL_SEC_LENGTH_SOFT
:
990 alGetBufferf(buffer
, param
, values
);
994 ContextRef context
{GetContextRef()};
995 if(UNLIKELY(!context
)) return;
997 ALCdevice
*device
= context
->Device
;
998 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
1000 if(UNLIKELY(LookupBuffer(device
, buffer
) == nullptr))
1001 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
1002 else if(UNLIKELY(!values
))
1003 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
1007 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid buffer float-vector property 0x%04x", param
);
1012 AL_API ALvoid AL_APIENTRY
alGetBufferi(ALuint buffer
, ALenum param
, ALint
*value
)
1014 ContextRef context
{GetContextRef()};
1015 if(UNLIKELY(!context
)) return;
1017 ALCdevice
*device
= context
->Device
;
1018 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
1020 ALbuffer
*albuf
= LookupBuffer(device
, buffer
);
1021 if(UNLIKELY(!albuf
))
1022 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
1023 else if(UNLIKELY(!value
))
1024 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
1028 *value
= albuf
->Frequency
;
1032 *value
= BytesFromFmt(albuf
->FmtType
) * 8;
1036 *value
= ChannelsFromFmt(albuf
->FmtChannels
);
1040 *value
= albuf
->SampleLen
* FrameSizeFromFmt(albuf
->FmtChannels
,
1044 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT
:
1045 *value
= ATOMIC_LOAD_SEQ(&albuf
->UnpackAlign
);
1048 case AL_PACK_BLOCK_ALIGNMENT_SOFT
:
1049 *value
= ATOMIC_LOAD_SEQ(&albuf
->PackAlign
);
1053 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid buffer integer property 0x%04x", param
);
1058 AL_API
void AL_APIENTRY
alGetBuffer3i(ALuint buffer
, ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
1060 ContextRef context
{GetContextRef()};
1061 if(UNLIKELY(!context
)) return;
1063 ALCdevice
*device
= context
->Device
;
1064 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
1066 if(UNLIKELY(LookupBuffer(device
, buffer
) == nullptr))
1067 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
1068 else if(UNLIKELY(!value1
|| !value2
|| !value3
))
1069 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
1073 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid buffer 3-integer property 0x%04x", param
);
1078 AL_API
void AL_APIENTRY
alGetBufferiv(ALuint buffer
, ALenum param
, ALint
*values
)
1086 case AL_INTERNAL_FORMAT_SOFT
:
1087 case AL_BYTE_LENGTH_SOFT
:
1088 case AL_SAMPLE_LENGTH_SOFT
:
1089 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT
:
1090 case AL_PACK_BLOCK_ALIGNMENT_SOFT
:
1091 alGetBufferi(buffer
, param
, values
);
1095 ContextRef context
{GetContextRef()};
1096 if(UNLIKELY(!context
)) return;
1098 ALCdevice
*device
= context
->Device
;
1099 std::lock_guard
<almtx_t
> _
{device
->BufferLock
};
1101 ALbuffer
*albuf
= LookupBuffer(device
, buffer
);
1102 if(UNLIKELY(!albuf
))
1103 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
1104 else if(UNLIKELY(!values
))
1105 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
1108 case AL_LOOP_POINTS_SOFT
:
1109 values
[0] = albuf
->LoopStart
;
1110 values
[1] = albuf
->LoopEnd
;
1114 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid buffer integer-vector property 0x%04x",
1120 ALsizei
BytesFromUserFmt(UserFmtType type
)
1124 case UserFmtUByte
: return sizeof(ALubyte
);
1125 case UserFmtShort
: return sizeof(ALshort
);
1126 case UserFmtFloat
: return sizeof(ALfloat
);
1127 case UserFmtDouble
: return sizeof(ALdouble
);
1128 case UserFmtMulaw
: return sizeof(ALubyte
);
1129 case UserFmtAlaw
: return sizeof(ALubyte
);
1130 case UserFmtIMA4
: break; /* not handled here */
1131 case UserFmtMSADPCM
: break; /* not handled here */
1135 ALsizei
ChannelsFromUserFmt(UserFmtChannels chans
)
1139 case UserFmtMono
: return 1;
1140 case UserFmtStereo
: return 2;
1141 case UserFmtRear
: return 2;
1142 case UserFmtQuad
: return 4;
1143 case UserFmtX51
: return 6;
1144 case UserFmtX61
: return 7;
1145 case UserFmtX71
: return 8;
1146 case UserFmtBFormat2D
: return 3;
1147 case UserFmtBFormat3D
: return 4;
1152 ALsizei
BytesFromFmt(FmtType type
)
1156 case FmtUByte
: return sizeof(ALubyte
);
1157 case FmtShort
: return sizeof(ALshort
);
1158 case FmtFloat
: return sizeof(ALfloat
);
1159 case FmtDouble
: return sizeof(ALdouble
);
1160 case FmtMulaw
: return sizeof(ALubyte
);
1161 case FmtAlaw
: return sizeof(ALubyte
);
1165 ALsizei
ChannelsFromFmt(FmtChannels chans
)
1169 case FmtMono
: return 1;
1170 case FmtStereo
: return 2;
1171 case FmtRear
: return 2;
1172 case FmtQuad
: return 4;
1173 case FmtX51
: return 6;
1174 case FmtX61
: return 7;
1175 case FmtX71
: return 8;
1176 case FmtBFormat2D
: return 3;
1177 case FmtBFormat3D
: return 4;
1184 * ReleaseALBuffers()
1186 * INTERNAL: Called to destroy any buffers that still exist on the device
1188 ALvoid
ReleaseALBuffers(ALCdevice
*device
)
1190 size_t leftover
= 0;
1191 for(auto &sublist
: device
->BufferList
)
1193 ALuint64 usemask
= ~sublist
.FreeMask
;
1196 ALsizei idx
= CTZ64(usemask
);
1197 ALbuffer
*buffer
= sublist
.Buffers
+ idx
;
1199 al_free(buffer
->data
);
1200 buffer
->data
= nullptr;
1201 buffer
->~ALbuffer();
1205 usemask
&= ~(U64(1) << idx
);
1207 sublist
.FreeMask
= ~usemask
;
1210 WARN("(%p) Deleted " SZFMT
" Buffer%s\n", device
, leftover
, (leftover
==1)?"":"s");