Use a sorted vector for the source send properties
[alure.git] / src / buffer.cpp
blob0fec23a2df28b497be6c92f931d36cbe738f9c18
2 #include "config.h"
4 #include "buffer.h"
6 #include <stdexcept>
7 #include <sstream>
8 #include <cstring>
10 #include "al.h"
11 #include "alext.h"
13 #include "context.h"
15 namespace alure
18 void BufferImpl::cleanup()
20 if(isInUse())
21 throw std::runtime_error("Buffer is in use");
23 alGetError();
24 alDeleteBuffers(1, &mId);
25 if(alGetError() != AL_NO_ERROR)
26 throw std::runtime_error("Buffer failed to delete");
27 mId = 0;
31 void BufferImpl::load(ALuint frames, ALenum format, SharedPtr<Decoder> decoder, ContextImpl *ctx)
33 Vector<ALbyte> data(FramesToBytes(frames, mChannelConfig, mSampleType));
35 ALuint got = decoder->read(data.data(), frames);
36 if(got > 0)
38 frames = got;
39 data.resize(FramesToBytes(frames, mChannelConfig, mSampleType));
41 else
43 ALbyte silence = 0;
44 if(mSampleType == SampleType::UInt8) silence = 0x80;
45 else if(mSampleType == SampleType::Mulaw) silence = 0x7f;
46 std::fill(data.begin(), data.end(), silence);
49 std::pair<uint64_t,uint64_t> loop_pts = decoder->getLoopPoints();
50 if(loop_pts.first >= loop_pts.second)
51 loop_pts = std::make_pair(0, frames);
52 else
54 loop_pts.second = std::min<uint64_t>(loop_pts.second, frames);
55 loop_pts.first = std::min<uint64_t>(loop_pts.first, loop_pts.second-1);
58 ctx->send(&MessageHandler::bufferLoading,
59 mName, mChannelConfig, mSampleType, mFrequency, data
62 alBufferData(mId, format, data.data(), data.size(), mFrequency);
63 if(ctx->hasExtension(AL::SOFT_loop_points))
65 ALint pts[2]{(ALint)loop_pts.first, (ALint)loop_pts.second};
66 alBufferiv(mId, AL_LOOP_POINTS_SOFT, pts);
71 ALuint BufferImpl::getLength() const
73 CheckContext(mContext);
75 ALint size=-1, bits=-1, chans=-1;
76 alGetBufferi(mId, AL_SIZE, &size);
77 alGetBufferi(mId, AL_BITS, &bits);
78 alGetBufferi(mId, AL_CHANNELS, &chans);
79 if(size < 0 || bits < 0 || chans < 0)
80 throw std::runtime_error("Buffer format error");
81 return size / chans * 8 / bits;
84 ALuint BufferImpl::getSize() const
86 CheckContext(mContext);
88 ALint size = -1;
89 alGetBufferi(mId, AL_SIZE, &size);
90 if(size < 0)
91 throw std::runtime_error("Buffer size error");
92 return size;
95 void BufferImpl::setLoopPoints(ALuint start, ALuint end)
97 ALuint length = getLength();
99 if(isInUse())
100 throw std::runtime_error("Buffer is in use");
102 if(!mContext->hasExtension(AL::SOFT_loop_points))
104 if(start != 0 || end != length)
105 throw std::runtime_error("Loop points not supported");
106 return;
109 if(start >= end || end > length)
110 throw std::runtime_error("Loop points out of range");
112 ALint pts[2]{(ALint)start, (ALint)end};
113 alGetError();
114 alBufferiv(mId, AL_LOOP_POINTS_SOFT, pts);
115 if(alGetError() != AL_NO_ERROR)
116 throw std::runtime_error("Failed to set loop points");
119 std::pair<ALuint,ALuint> BufferImpl::getLoopPoints() const
121 CheckContext(mContext);
123 if(!mContext->hasExtension(AL::SOFT_loop_points))
124 return std::make_pair(0, getLength());
126 ALint pts[2]{-1,-1};
127 alGetBufferiv(mId, AL_LOOP_POINTS_SOFT, pts);
128 if(pts[0] == -1 || pts[1] == -1)
129 throw std::runtime_error("Failed to get loop points");
131 return std::make_pair(pts[0], pts[1]);
135 using ALuintPair = std::pair<ALuint,ALuint>;
136 DECL_THUNK0(ALuint, Buffer, getLength, const)
137 DECL_THUNK0(ALuint, Buffer, getFrequency, const)
138 DECL_THUNK0(ChannelConfig, Buffer, getChannelConfig, const)
139 DECL_THUNK0(SampleType, Buffer, getSampleType, const)
140 DECL_THUNK0(ALuint, Buffer, getSize, const)
141 DECL_THUNK2(void, Buffer, setLoopPoints,, ALuint, ALuint)
142 DECL_THUNK0(ALuintPair, Buffer, getLoopPoints, const)
143 DECL_THUNK0(Vector<Source>, Buffer, getSources, const)
144 DECL_THUNK0(StringView, Buffer, getName, const)
145 DECL_THUNK0(bool, Buffer, isInUse, const)
148 ALURE_API const char *GetSampleTypeName(SampleType type)
150 switch(type)
152 case SampleType::UInt8: return "Unsigned 8-bit";
153 case SampleType::Int16: return "Signed 16-bit";
154 case SampleType::Float32: return "32-bit float";
155 case SampleType::Mulaw: return "Mulaw";
157 throw std::runtime_error("Invalid type");
160 ALURE_API const char *GetChannelConfigName(ChannelConfig cfg)
162 switch(cfg)
164 case ChannelConfig::Mono: return "Mono";
165 case ChannelConfig::Stereo: return "Stereo";
166 case ChannelConfig::Rear: return "Rear";
167 case ChannelConfig::Quad: return "Quadrophonic";
168 case ChannelConfig::X51: return "5.1 Surround";
169 case ChannelConfig::X61: return "6.1 Surround";
170 case ChannelConfig::X71: return "7.1 Surround";
171 case ChannelConfig::BFormat2D: return "B-Format 2D";
172 case ChannelConfig::BFormat3D: return "B-Format 3D";
174 throw std::runtime_error("Invalid config");
178 ALURE_API ALuint FramesToBytes(ALuint frames, ChannelConfig chans, SampleType type)
180 ALuint size = frames;
181 switch(chans)
183 case ChannelConfig::Mono: size *= 1; break;
184 case ChannelConfig::Stereo: size *= 2; break;
185 case ChannelConfig::Rear: size *= 2; break;
186 case ChannelConfig::Quad: size *= 4; break;
187 case ChannelConfig::X51: size *= 6; break;
188 case ChannelConfig::X61: size *= 7; break;
189 case ChannelConfig::X71: size *= 8; break;
190 case ChannelConfig::BFormat2D: size *= 3; break;
191 case ChannelConfig::BFormat3D: size *= 4; break;
193 switch(type)
195 case SampleType::UInt8: size *= 1; break;
196 case SampleType::Int16: size *= 2; break;
197 case SampleType::Float32: size *= 4; break;
198 case SampleType::Mulaw: size *= 1; break;
201 return size;
204 ALURE_API ALuint BytesToFrames(ALuint bytes, ChannelConfig chans, SampleType type)
206 return bytes / FramesToBytes(1, chans, type);
210 ALenum GetFormat(ChannelConfig chans, SampleType type)
212 #define RETURN_FMT(x) do { \
213 ALenum fmt = alGetEnumValue(x); \
214 if(fmt != AL_NONE && fmt != -1) \
215 return fmt; \
216 } while(0)
217 if(type == SampleType::UInt8)
219 if(chans == ChannelConfig::Mono) return AL_FORMAT_MONO8;
220 if(chans == ChannelConfig::Stereo) return AL_FORMAT_STEREO8;
221 if(ContextImpl::GetCurrent()->hasExtension(AL::EXT_MCFORMATS))
223 if(chans == ChannelConfig::Rear) RETURN_FMT("AL_FORMAT_REAR8");
224 if(chans == ChannelConfig::Quad) RETURN_FMT("AL_FORMAT_QUAD8");
225 if(chans == ChannelConfig::X51) RETURN_FMT("AL_FORMAT_51CHN8");
226 if(chans == ChannelConfig::X61) RETURN_FMT("AL_FORMAT_61CHN8");
227 if(chans == ChannelConfig::X71) RETURN_FMT("AL_FORMAT_71CHN8");
229 if(ContextImpl::GetCurrent()->hasExtension(AL::EXT_BFORMAT))
231 if(chans == ChannelConfig::BFormat2D) RETURN_FMT("AL_FORMAT_BFORMAT2D_8");
232 if(chans == ChannelConfig::BFormat3D) RETURN_FMT("AL_FORMAT_BFORMAT3D_8");
235 else if(type == SampleType::Int16)
237 if(chans == ChannelConfig::Mono) return AL_FORMAT_MONO16;
238 if(chans == ChannelConfig::Stereo) return AL_FORMAT_STEREO16;
239 if(ContextImpl::GetCurrent()->hasExtension(AL::EXT_MCFORMATS))
241 if(chans == ChannelConfig::Rear) RETURN_FMT("AL_FORMAT_REAR16");
242 if(chans == ChannelConfig::Quad) RETURN_FMT("AL_FORMAT_QUAD16");
243 if(chans == ChannelConfig::X51) RETURN_FMT("AL_FORMAT_51CHN16");
244 if(chans == ChannelConfig::X61) RETURN_FMT("AL_FORMAT_61CHN16");
245 if(chans == ChannelConfig::X71) RETURN_FMT("AL_FORMAT_71CHN16");
247 if(ContextImpl::GetCurrent()->hasExtension(AL::EXT_BFORMAT))
249 if(chans == ChannelConfig::BFormat2D) RETURN_FMT("AL_FORMAT_BFORMAT2D_16");
250 if(chans == ChannelConfig::BFormat3D) RETURN_FMT("AL_FORMAT_BFORMAT3D_16");
253 else if(type == SampleType::Float32 && ContextImpl::GetCurrent()->hasExtension(AL::EXT_FLOAT32))
255 if(chans == ChannelConfig::Mono) return AL_FORMAT_MONO_FLOAT32;
256 if(chans == ChannelConfig::Stereo) return AL_FORMAT_STEREO_FLOAT32;
257 if(ContextImpl::GetCurrent()->hasExtension(AL::EXT_MCFORMATS))
259 if(chans == ChannelConfig::Rear) RETURN_FMT("AL_FORMAT_REAR32");
260 if(chans == ChannelConfig::Quad) RETURN_FMT("AL_FORMAT_QUAD32");
261 if(chans == ChannelConfig::X51) RETURN_FMT("AL_FORMAT_51CHN32");
262 if(chans == ChannelConfig::X61) RETURN_FMT("AL_FORMAT_61CHN32");
263 if(chans == ChannelConfig::X71) RETURN_FMT("AL_FORMAT_71CHN32");
265 if(ContextImpl::GetCurrent()->hasExtension(AL::EXT_BFORMAT))
267 if(chans == ChannelConfig::BFormat2D) RETURN_FMT("AL_FORMAT_BFORMAT2D_FLOAT32");
268 if(chans == ChannelConfig::BFormat3D) RETURN_FMT("AL_FORMAT_BFORMAT3D_FLOAT32");
271 else if(type == SampleType::Mulaw && ContextImpl::GetCurrent()->hasExtension(AL::EXT_MULAW))
273 if(chans == ChannelConfig::Mono) return AL_FORMAT_MONO_MULAW;
274 if(chans == ChannelConfig::Stereo) return AL_FORMAT_STEREO_MULAW;
275 if(ContextImpl::GetCurrent()->hasExtension(AL::EXT_MULAW_MCFORMATS))
277 if(chans == ChannelConfig::Rear) RETURN_FMT("AL_FORMAT_REAR_MULAW");
278 if(chans == ChannelConfig::Quad) RETURN_FMT("AL_FORMAT_QUAD_MULAW");
279 if(chans == ChannelConfig::X51) RETURN_FMT("AL_FORMAT_51CHN_MULAW");
280 if(chans == ChannelConfig::X61) RETURN_FMT("AL_FORMAT_61CHN_MULAW");
281 if(chans == ChannelConfig::X71) RETURN_FMT("AL_FORMAT_71CHN_MULAW");
283 if(ContextImpl::GetCurrent()->hasExtension(AL::EXT_MULAW_BFORMAT))
285 if(chans == ChannelConfig::BFormat2D) RETURN_FMT("AL_FORMAT_BFORMAT2D_MULAW");
286 if(chans == ChannelConfig::BFormat3D) RETURN_FMT("AL_FORMAT_BFORMAT3D_MULAW");
289 #undef RETURN_FMT
291 return AL_NONE;