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
;
159 ALURE_API
const char *GetSampleTypeName(SampleType type
)
163 case SampleType::UInt8
: return "Unsigned 8-bit";
164 case SampleType::Int16
: return "Signed 16-bit";
165 case SampleType::Float32
: return "32-bit float";
166 case SampleType::Mulaw
: return "Mulaw";
168 throw std::runtime_error("Invalid type");
171 ALURE_API
const char *GetChannelConfigName(ChannelConfig cfg
)
175 case ChannelConfig::Mono
: return "Mono";
176 case ChannelConfig::Stereo
: return "Stereo";
177 case ChannelConfig::Rear
: return "Rear";
178 case ChannelConfig::Quad
: return "Quadrophonic";
179 case ChannelConfig::X51
: return "5.1 Surround";
180 case ChannelConfig::X61
: return "6.1 Surround";
181 case ChannelConfig::X71
: return "7.1 Surround";
182 case ChannelConfig::BFormat2D
: return "B-Format 2D";
183 case ChannelConfig::BFormat3D
: return "B-Format 3D";
185 throw std::runtime_error("Invalid config");
189 ALURE_API ALuint
FramesToBytes(ALuint frames
, ChannelConfig chans
, SampleType type
)
191 ALuint size
= frames
;
194 case ChannelConfig::Mono
: size
*= 1; break;
195 case ChannelConfig::Stereo
: size
*= 2; break;
196 case ChannelConfig::Rear
: size
*= 2; break;
197 case ChannelConfig::Quad
: size
*= 4; break;
198 case ChannelConfig::X51
: size
*= 6; break;
199 case ChannelConfig::X61
: size
*= 7; break;
200 case ChannelConfig::X71
: size
*= 8; break;
201 case ChannelConfig::BFormat2D
: size
*= 3; break;
202 case ChannelConfig::BFormat3D
: size
*= 4; break;
206 case SampleType::UInt8
: size
*= 1; break;
207 case SampleType::Int16
: size
*= 2; break;
208 case SampleType::Float32
: size
*= 4; break;
209 case SampleType::Mulaw
: size
*= 1; break;
215 ALURE_API ALuint
BytesToFrames(ALuint bytes
, ChannelConfig chans
, SampleType type
)
217 return bytes
/ FramesToBytes(1, chans
, type
);
221 ALenum
GetFormat(ChannelConfig chans
, SampleType type
)
223 #define RETURN_FMT(x) do { \
224 ALenum fmt = alGetEnumValue(x); \
225 if(fmt != AL_NONE && fmt != -1) \
228 if(type
== SampleType::UInt8
)
230 if(chans
== ChannelConfig::Mono
) return AL_FORMAT_MONO8
;
231 if(chans
== ChannelConfig::Stereo
) return AL_FORMAT_STEREO8
;
232 if(ALContext::GetCurrent()->hasExtension(EXT_MCFORMATS
))
234 if(chans
== ChannelConfig::Rear
) RETURN_FMT("AL_FORMAT_REAR8");
235 if(chans
== ChannelConfig::Quad
) RETURN_FMT("AL_FORMAT_QUAD8");
236 if(chans
== ChannelConfig::X51
) RETURN_FMT("AL_FORMAT_51CHN8");
237 if(chans
== ChannelConfig::X61
) RETURN_FMT("AL_FORMAT_61CHN8");
238 if(chans
== ChannelConfig::X71
) RETURN_FMT("AL_FORMAT_71CHN8");
240 if(ALContext::GetCurrent()->hasExtension(EXT_BFORMAT
))
242 if(chans
== ChannelConfig::BFormat2D
) RETURN_FMT("AL_FORMAT_BFORMAT2D_8");
243 if(chans
== ChannelConfig::BFormat3D
) RETURN_FMT("AL_FORMAT_BFORMAT3D_8");
246 else if(type
== SampleType::Int16
)
248 if(chans
== ChannelConfig::Mono
) return AL_FORMAT_MONO16
;
249 if(chans
== ChannelConfig::Stereo
) return AL_FORMAT_STEREO16
;
250 if(ALContext::GetCurrent()->hasExtension(EXT_MCFORMATS
))
252 if(chans
== ChannelConfig::Rear
) RETURN_FMT("AL_FORMAT_REAR16");
253 if(chans
== ChannelConfig::Quad
) RETURN_FMT("AL_FORMAT_QUAD16");
254 if(chans
== ChannelConfig::X51
) RETURN_FMT("AL_FORMAT_51CHN16");
255 if(chans
== ChannelConfig::X61
) RETURN_FMT("AL_FORMAT_61CHN16");
256 if(chans
== ChannelConfig::X71
) RETURN_FMT("AL_FORMAT_71CHN16");
258 if(ALContext::GetCurrent()->hasExtension(EXT_BFORMAT
))
260 if(chans
== ChannelConfig::BFormat2D
) RETURN_FMT("AL_FORMAT_BFORMAT2D_16");
261 if(chans
== ChannelConfig::BFormat3D
) RETURN_FMT("AL_FORMAT_BFORMAT3D_16");
264 else if(type
== SampleType::Float32
&& ALContext::GetCurrent()->hasExtension(EXT_FLOAT32
))
266 if(chans
== ChannelConfig::Mono
) return AL_FORMAT_MONO_FLOAT32
;
267 if(chans
== ChannelConfig::Stereo
) return AL_FORMAT_STEREO_FLOAT32
;
268 if(ALContext::GetCurrent()->hasExtension(EXT_MCFORMATS
))
270 if(chans
== ChannelConfig::Rear
) RETURN_FMT("AL_FORMAT_REAR32");
271 if(chans
== ChannelConfig::Quad
) RETURN_FMT("AL_FORMAT_QUAD32");
272 if(chans
== ChannelConfig::X51
) RETURN_FMT("AL_FORMAT_51CHN32");
273 if(chans
== ChannelConfig::X61
) RETURN_FMT("AL_FORMAT_61CHN32");
274 if(chans
== ChannelConfig::X71
) RETURN_FMT("AL_FORMAT_71CHN32");
276 if(ALContext::GetCurrent()->hasExtension(EXT_BFORMAT
))
278 if(chans
== ChannelConfig::BFormat2D
) RETURN_FMT("AL_FORMAT_BFORMAT2D_FLOAT32");
279 if(chans
== ChannelConfig::BFormat3D
) RETURN_FMT("AL_FORMAT_BFORMAT3D_FLOAT32");
282 else if(type
== SampleType::Mulaw
&& ALContext::GetCurrent()->hasExtension(EXT_MULAW
))
284 if(chans
== ChannelConfig::Mono
) return AL_FORMAT_MONO_MULAW
;
285 if(chans
== ChannelConfig::Stereo
) return AL_FORMAT_STEREO_MULAW
;
286 if(ALContext::GetCurrent()->hasExtension(EXT_MULAW_MCFORMATS
))
288 if(chans
== ChannelConfig::Rear
) RETURN_FMT("AL_FORMAT_REAR_MULAW");
289 if(chans
== ChannelConfig::Quad
) RETURN_FMT("AL_FORMAT_QUAD_MULAW");
290 if(chans
== ChannelConfig::X51
) RETURN_FMT("AL_FORMAT_51CHN_MULAW");
291 if(chans
== ChannelConfig::X61
) RETURN_FMT("AL_FORMAT_61CHN_MULAW");
292 if(chans
== ChannelConfig::X71
) RETURN_FMT("AL_FORMAT_71CHN_MULAW");
294 if(ALContext::GetCurrent()->hasExtension(EXT_MULAW_BFORMAT
))
296 if(chans
== ChannelConfig::BFormat2D
) RETURN_FMT("AL_FORMAT_BFORMAT2D_MULAW");
297 if(chans
== ChannelConfig::BFormat3D
) RETURN_FMT("AL_FORMAT_BFORMAT3D_MULAW");