18 void ALBuffer::cleanup()
20 while(!mIsLoaded
.load(std::memory_order_acquire
))
21 std::this_thread::yield();
23 throw std::runtime_error("Buffer is in use");
26 alDeleteBuffers(1, &mId
);
27 if(alGetError() != AL_NO_ERROR
)
28 throw std::runtime_error("Buffer failed to delete");
33 void ALBuffer::load(ALuint frames
, ALenum format
, SharedPtr
<Decoder
> decoder
, const String
&name
, ALContext
*ctx
)
35 Vector
<ALbyte
> data(FramesToBytes(frames
, mChannelConfig
, mSampleType
));
37 ALuint got
= decoder
->read(data
.data(), frames
);
41 data
.resize(FramesToBytes(frames
, mChannelConfig
, mSampleType
));
46 if(mSampleType
== SampleType::UInt8
) silence
= 0x80;
47 else if(mSampleType
== SampleType::Mulaw
) silence
= 0x7f;
48 std::fill(data
.begin(), data
.end(), silence
);
51 std::pair
<uint64_t,uint64_t> loop_pts
= decoder
->getLoopPoints();
52 if(loop_pts
.first
>= loop_pts
.second
)
53 loop_pts
= std::make_pair(0, frames
);
56 loop_pts
.second
= std::min
<uint64_t>(loop_pts
.second
, frames
);
57 loop_pts
.first
= std::min
<uint64_t>(loop_pts
.first
, loop_pts
.second
-1);
60 ctx
->send(&MessageHandler::bufferLoading
,
61 name
, mChannelConfig
, mSampleType
, mFrequency
, data
64 alBufferData(mId
, format
, data
.data(), data
.size(), mFrequency
);
65 if(ctx
->hasExtension(SOFT_loop_points
))
67 ALint pts
[2]{(ALint
)loop_pts
.first
, (ALint
)loop_pts
.second
};
68 alBufferiv(mId
, AL_LOOP_POINTS_SOFT
, pts
);
71 mIsLoaded
.store(true, std::memory_order_release
);
75 ALuint
ALBuffer::getLength() const
77 CheckContext(mContext
);
78 if(mLoadStatus
!= BufferLoadStatus::Ready
)
79 throw std::runtime_error("Buffer not loaded");
81 ALint size
=-1, bits
=-1, chans
=-1;
82 alGetBufferi(mId
, AL_SIZE
, &size
);
83 alGetBufferi(mId
, AL_BITS
, &bits
);
84 alGetBufferi(mId
, AL_CHANNELS
, &chans
);
85 if(size
< 0 || bits
< 0 || chans
< 0)
86 throw std::runtime_error("Buffer format error");
87 return size
/ chans
* 8 / bits
;
90 ALuint
ALBuffer::getSize() const
92 CheckContext(mContext
);
93 if(mLoadStatus
!= BufferLoadStatus::Ready
)
94 throw std::runtime_error("Buffer not loaded");
97 alGetBufferi(mId
, AL_SIZE
, &size
);
99 throw std::runtime_error("Buffer size error");
103 void ALBuffer::setLoopPoints(ALuint start
, ALuint end
)
105 ALuint length
= getLength();
108 throw std::runtime_error("Buffer is in use");
110 if(!mContext
->hasExtension(SOFT_loop_points
))
112 if(start
!= 0 || end
!= length
)
113 throw std::runtime_error("Loop points not supported");
117 if(start
>= end
|| end
> length
)
118 throw std::runtime_error("Loop points out of range");
120 ALint pts
[2]{(ALint
)start
, (ALint
)end
};
122 alBufferiv(mId
, AL_LOOP_POINTS_SOFT
, pts
);
123 if(alGetError() != AL_NO_ERROR
)
124 throw std::runtime_error("Failed to set loop points");
127 std::pair
<ALuint
,ALuint
> ALBuffer::getLoopPoints() const
129 CheckContext(mContext
);
130 if(mLoadStatus
!= BufferLoadStatus::Ready
)
131 throw std::runtime_error("Buffer not loaded");
133 if(!mContext
->hasExtension(SOFT_loop_points
))
134 return std::make_pair(0, getLength());
137 alGetBufferiv(mId
, AL_LOOP_POINTS_SOFT
, pts
);
138 if(pts
[0] == -1 || pts
[1] == -1)
139 throw std::runtime_error("Failed to get loop points");
141 return std::make_pair(pts
[0], pts
[1]);
145 BufferLoadStatus
ALBuffer::getLoadStatus()
147 /* NOTE: LoadStatus is separate from IsLoaded to force the app to receive
148 * acknowledgement that the buffer is ready before using it. Otherwise, if
149 * the app decides to simply use it after a short wait there's no guarantee
150 * it'll be ready in a consistent manner. It may work some times and fail
153 if(mLoadStatus
== BufferLoadStatus::Pending
&& mIsLoaded
.load(std::memory_order_acquire
))
154 mLoadStatus
= BufferLoadStatus::Ready
;
158 using ALuintPair
= std::pair
<ALuint
,ALuint
>;
159 DECL_THUNK0(ALuint
, Buffer
, getLength
, const)
160 DECL_THUNK0(ALuint
, Buffer
, getFrequency
, const)
161 DECL_THUNK0(ChannelConfig
, Buffer
, getChannelConfig
, const)
162 DECL_THUNK0(SampleType
, Buffer
, getSampleType
, const)
163 DECL_THUNK0(ALuint
, Buffer
, getSize
, const)
164 DECL_THUNK2(void, Buffer
, setLoopPoints
,, ALuint
, ALuint
)
165 DECL_THUNK0(ALuintPair
, Buffer
, getLoopPoints
, const)
166 DECL_THUNK0(Vector
<Source
*>, Buffer
, getSources
, const)
167 DECL_THUNK0(BufferLoadStatus
, Buffer
, getLoadStatus
,)
168 DECL_THUNK0(const String
&, Buffer
, getName
, const)
169 DECL_THUNK0(bool, Buffer
, isInUse
, const)
172 ALURE_API
const char *GetSampleTypeName(SampleType type
)
176 case SampleType::UInt8
: return "Unsigned 8-bit";
177 case SampleType::Int16
: return "Signed 16-bit";
178 case SampleType::Float32
: return "32-bit float";
179 case SampleType::Mulaw
: return "Mulaw";
181 throw std::runtime_error("Invalid type");
184 ALURE_API
const char *GetChannelConfigName(ChannelConfig cfg
)
188 case ChannelConfig::Mono
: return "Mono";
189 case ChannelConfig::Stereo
: return "Stereo";
190 case ChannelConfig::Rear
: return "Rear";
191 case ChannelConfig::Quad
: return "Quadrophonic";
192 case ChannelConfig::X51
: return "5.1 Surround";
193 case ChannelConfig::X61
: return "6.1 Surround";
194 case ChannelConfig::X71
: return "7.1 Surround";
195 case ChannelConfig::BFormat2D
: return "B-Format 2D";
196 case ChannelConfig::BFormat3D
: return "B-Format 3D";
198 throw std::runtime_error("Invalid config");
202 ALURE_API ALuint
FramesToBytes(ALuint frames
, ChannelConfig chans
, SampleType type
)
204 ALuint size
= frames
;
207 case ChannelConfig::Mono
: size
*= 1; break;
208 case ChannelConfig::Stereo
: size
*= 2; break;
209 case ChannelConfig::Rear
: size
*= 2; break;
210 case ChannelConfig::Quad
: size
*= 4; break;
211 case ChannelConfig::X51
: size
*= 6; break;
212 case ChannelConfig::X61
: size
*= 7; break;
213 case ChannelConfig::X71
: size
*= 8; break;
214 case ChannelConfig::BFormat2D
: size
*= 3; break;
215 case ChannelConfig::BFormat3D
: size
*= 4; break;
219 case SampleType::UInt8
: size
*= 1; break;
220 case SampleType::Int16
: size
*= 2; break;
221 case SampleType::Float32
: size
*= 4; break;
222 case SampleType::Mulaw
: size
*= 1; break;
228 ALURE_API ALuint
BytesToFrames(ALuint bytes
, ChannelConfig chans
, SampleType type
)
230 return bytes
/ FramesToBytes(1, chans
, type
);
234 ALenum
GetFormat(ChannelConfig chans
, SampleType type
)
236 #define RETURN_FMT(x) do { \
237 ALenum fmt = alGetEnumValue(x); \
238 if(fmt != AL_NONE && fmt != -1) \
241 if(type
== SampleType::UInt8
)
243 if(chans
== ChannelConfig::Mono
) return AL_FORMAT_MONO8
;
244 if(chans
== ChannelConfig::Stereo
) return AL_FORMAT_STEREO8
;
245 if(ALContext::GetCurrent()->hasExtension(EXT_MCFORMATS
))
247 if(chans
== ChannelConfig::Rear
) RETURN_FMT("AL_FORMAT_REAR8");
248 if(chans
== ChannelConfig::Quad
) RETURN_FMT("AL_FORMAT_QUAD8");
249 if(chans
== ChannelConfig::X51
) RETURN_FMT("AL_FORMAT_51CHN8");
250 if(chans
== ChannelConfig::X61
) RETURN_FMT("AL_FORMAT_61CHN8");
251 if(chans
== ChannelConfig::X71
) RETURN_FMT("AL_FORMAT_71CHN8");
253 if(ALContext::GetCurrent()->hasExtension(EXT_BFORMAT
))
255 if(chans
== ChannelConfig::BFormat2D
) RETURN_FMT("AL_FORMAT_BFORMAT2D_8");
256 if(chans
== ChannelConfig::BFormat3D
) RETURN_FMT("AL_FORMAT_BFORMAT3D_8");
259 else if(type
== SampleType::Int16
)
261 if(chans
== ChannelConfig::Mono
) return AL_FORMAT_MONO16
;
262 if(chans
== ChannelConfig::Stereo
) return AL_FORMAT_STEREO16
;
263 if(ALContext::GetCurrent()->hasExtension(EXT_MCFORMATS
))
265 if(chans
== ChannelConfig::Rear
) RETURN_FMT("AL_FORMAT_REAR16");
266 if(chans
== ChannelConfig::Quad
) RETURN_FMT("AL_FORMAT_QUAD16");
267 if(chans
== ChannelConfig::X51
) RETURN_FMT("AL_FORMAT_51CHN16");
268 if(chans
== ChannelConfig::X61
) RETURN_FMT("AL_FORMAT_61CHN16");
269 if(chans
== ChannelConfig::X71
) RETURN_FMT("AL_FORMAT_71CHN16");
271 if(ALContext::GetCurrent()->hasExtension(EXT_BFORMAT
))
273 if(chans
== ChannelConfig::BFormat2D
) RETURN_FMT("AL_FORMAT_BFORMAT2D_16");
274 if(chans
== ChannelConfig::BFormat3D
) RETURN_FMT("AL_FORMAT_BFORMAT3D_16");
277 else if(type
== SampleType::Float32
&& ALContext::GetCurrent()->hasExtension(EXT_FLOAT32
))
279 if(chans
== ChannelConfig::Mono
) return AL_FORMAT_MONO_FLOAT32
;
280 if(chans
== ChannelConfig::Stereo
) return AL_FORMAT_STEREO_FLOAT32
;
281 if(ALContext::GetCurrent()->hasExtension(EXT_MCFORMATS
))
283 if(chans
== ChannelConfig::Rear
) RETURN_FMT("AL_FORMAT_REAR32");
284 if(chans
== ChannelConfig::Quad
) RETURN_FMT("AL_FORMAT_QUAD32");
285 if(chans
== ChannelConfig::X51
) RETURN_FMT("AL_FORMAT_51CHN32");
286 if(chans
== ChannelConfig::X61
) RETURN_FMT("AL_FORMAT_61CHN32");
287 if(chans
== ChannelConfig::X71
) RETURN_FMT("AL_FORMAT_71CHN32");
289 if(ALContext::GetCurrent()->hasExtension(EXT_BFORMAT
))
291 if(chans
== ChannelConfig::BFormat2D
) RETURN_FMT("AL_FORMAT_BFORMAT2D_FLOAT32");
292 if(chans
== ChannelConfig::BFormat3D
) RETURN_FMT("AL_FORMAT_BFORMAT3D_FLOAT32");
295 else if(type
== SampleType::Mulaw
&& ALContext::GetCurrent()->hasExtension(EXT_MULAW
))
297 if(chans
== ChannelConfig::Mono
) return AL_FORMAT_MONO_MULAW
;
298 if(chans
== ChannelConfig::Stereo
) return AL_FORMAT_STEREO_MULAW
;
299 if(ALContext::GetCurrent()->hasExtension(EXT_MULAW_MCFORMATS
))
301 if(chans
== ChannelConfig::Rear
) RETURN_FMT("AL_FORMAT_REAR_MULAW");
302 if(chans
== ChannelConfig::Quad
) RETURN_FMT("AL_FORMAT_QUAD_MULAW");
303 if(chans
== ChannelConfig::X51
) RETURN_FMT("AL_FORMAT_51CHN_MULAW");
304 if(chans
== ChannelConfig::X61
) RETURN_FMT("AL_FORMAT_61CHN_MULAW");
305 if(chans
== ChannelConfig::X71
) RETURN_FMT("AL_FORMAT_71CHN_MULAW");
307 if(ALContext::GetCurrent()->hasExtension(EXT_MULAW_BFORMAT
))
309 if(chans
== ChannelConfig::BFormat2D
) RETURN_FMT("AL_FORMAT_BFORMAT2D_MULAW");
310 if(chans
== ChannelConfig::BFormat3D
) RETURN_FMT("AL_FORMAT_BFORMAT3D_MULAW");