16 #ifdef HAVE_LIBSNDFILE
17 #include "decoders/sndfile1.h"
20 #include "decoders/mpg123-1.h"
23 #include "devicemanager.h"
27 #include "auxeffectslot.h"
33 template<typename T
, size_t N
>
34 static inline size_t countof(const T(&)[N
])
38 typedef std::pair
<std::string
,SharedPtr
<DecoderFactory
>> FactoryPair
;
39 typedef std::vector
<FactoryPair
> FactoryMap
;
41 static FactoryPair sDefaultDecoders
[] = {
43 { "_alure_int_mpg123", SharedPtr
<DecoderFactory
>(new Mpg123DecoderFactory
) },
45 #ifdef HAVE_LIBSNDFILE
46 { "_alure_int_sndfile", SharedPtr
<DecoderFactory
>(new SndFileDecoderFactory
) },
49 static FactoryMap sDecoders
{ std::make_move_iterator(std::begin(sDefaultDecoders
)),
50 std::make_move_iterator(std::end(sDefaultDecoders
)) };
52 void RegisterDecoder(const std::string
&name
, SharedPtr
<DecoderFactory
> factory
)
54 FactoryMap::iterator iter
= sDecoders
.begin();
55 while(iter
!= sDecoders
.end())
57 if(iter
->first
== name
)
58 throw std::runtime_error("Decoder factory \""+name
+"\" already registered");
59 if(iter
->second
.get() == factory
.get())
61 std::stringstream sstr
;
62 sstr
<< "Decoder factory instance "<<factory
<<" already registered";
63 throw std::runtime_error(sstr
.str());
67 sDecoders
.push_back(std::make_pair(name
, factory
));
70 SharedPtr
<DecoderFactory
> UnregisterDecoder(const std::string
&name
)
72 FactoryMap::iterator iter
= sDecoders
.begin();
73 while(iter
!= sDecoders
.end())
75 if(iter
->first
== name
)
77 SharedPtr
<DecoderFactory
> factory
= iter
->second
;
78 sDecoders
.erase(iter
);
83 return SharedPtr
<DecoderFactory
>(nullptr);
87 class DefaultFileIOFactory
: public FileIOFactory
{
88 virtual SharedPtr
<std::istream
> openFile(const std::string
&name
)
90 SharedPtr
<std::ifstream
> file(new std::ifstream(name
.c_str(), std::ios::binary
));
91 if(!file
->is_open()) file
.reset();
95 static DefaultFileIOFactory sDefaultFileFactory
;
97 static SharedPtr
<FileIOFactory
> sFileFactory
;
98 SharedPtr
<FileIOFactory
> FileIOFactory::set(SharedPtr
<FileIOFactory
> factory
)
100 SharedPtr
<FileIOFactory
> old
= sFileFactory
;
101 sFileFactory
= factory
;
105 FileIOFactory
&FileIOFactory::get()
107 FileIOFactory
*factory
= sFileFactory
.get();
108 if(factory
) return *factory
;
109 return sDefaultFileFactory
;
114 static inline void LoadALFunc(T
**func
, const char *name
)
115 { *func
= reinterpret_cast<T
*>(alGetProcAddress(name
)); }
118 static void LoadNothing(ALContext
*) { }
120 static void LoadEFX(ALContext
*ctx
)
122 LoadALFunc(&ctx
->alGenEffects
, "alGenEffects");
123 LoadALFunc(&ctx
->alDeleteEffects
, "alDeleteEffects");
124 LoadALFunc(&ctx
->alIsEffect
, "alIsEffect");
125 LoadALFunc(&ctx
->alEffecti
, "alEffecti");
126 LoadALFunc(&ctx
->alEffectiv
, "alEffectiv");
127 LoadALFunc(&ctx
->alEffectf
, "alEffectf");
128 LoadALFunc(&ctx
->alEffectfv
, "alEffectfv");
129 LoadALFunc(&ctx
->alGetEffecti
, "alGetEffecti");
130 LoadALFunc(&ctx
->alGetEffectiv
, "alGetEffectiv");
131 LoadALFunc(&ctx
->alGetEffectf
, "alGetEffectf");
132 LoadALFunc(&ctx
->alGetEffectfv
, "alGetEffectfv");
134 LoadALFunc(&ctx
->alGenFilters
, "alGenFilters");
135 LoadALFunc(&ctx
->alDeleteFilters
, "alDeleteFilters");
136 LoadALFunc(&ctx
->alIsFilter
, "alIsFilter");
137 LoadALFunc(&ctx
->alFilteri
, "alFilteri");
138 LoadALFunc(&ctx
->alFilteriv
, "alFilteriv");
139 LoadALFunc(&ctx
->alFilterf
, "alFilterf");
140 LoadALFunc(&ctx
->alFilterfv
, "alFilterfv");
141 LoadALFunc(&ctx
->alGetFilteri
, "alGetFilteri");
142 LoadALFunc(&ctx
->alGetFilteriv
, "alGetFilteriv");
143 LoadALFunc(&ctx
->alGetFilterf
, "alGetFilterf");
144 LoadALFunc(&ctx
->alGetFilterfv
, "alGetFilterfv");
146 LoadALFunc(&ctx
->alGenAuxiliaryEffectSlots
, "alGenAuxiliaryEffectSlots");
147 LoadALFunc(&ctx
->alDeleteAuxiliaryEffectSlots
, "alDeleteAuxiliaryEffectSlots");
148 LoadALFunc(&ctx
->alIsAuxiliaryEffectSlot
, "alIsAuxiliaryEffectSlot");
149 LoadALFunc(&ctx
->alAuxiliaryEffectSloti
, "alAuxiliaryEffectSloti");
150 LoadALFunc(&ctx
->alAuxiliaryEffectSlotiv
, "alAuxiliaryEffectSlotiv");
151 LoadALFunc(&ctx
->alAuxiliaryEffectSlotf
, "alAuxiliaryEffectSlotf");
152 LoadALFunc(&ctx
->alAuxiliaryEffectSlotfv
, "alAuxiliaryEffectSlotfv");
153 LoadALFunc(&ctx
->alGetAuxiliaryEffectSloti
, "alGetAuxiliaryEffectSloti");
154 LoadALFunc(&ctx
->alGetAuxiliaryEffectSlotiv
, "alGetAuxiliaryEffectSlotiv");
155 LoadALFunc(&ctx
->alGetAuxiliaryEffectSlotf
, "alGetAuxiliaryEffectSlotf");
156 LoadALFunc(&ctx
->alGetAuxiliaryEffectSlotfv
, "alGetAuxiliaryEffectSlotfv");
159 static void LoadSourceLatency(ALContext
*ctx
)
161 LoadALFunc(&ctx
->alGetSourcei64vSOFT
, "alGetSourcei64vSOFT");
164 static const struct {
165 enum ALExtension extension
;
167 void (*loader
)(ALContext
*);
168 } ALExtensionList
[] = {
169 { EXT_EFX
, "ALC_EXT_EFX", LoadEFX
},
171 { EXT_FLOAT32
, "AL_EXT_FLOAT32", LoadNothing
},
172 { EXT_MCFORMATS
, "AL_EXT_MCFORMATS", LoadNothing
},
173 { EXT_BFORMAT
, "AL_EXT_BFORMAT", LoadNothing
},
175 { EXT_MULAW
, "AL_EXT_MULAW", LoadNothing
},
176 { EXT_MULAW_MCFORMATS
, "AL_EXT_MULAW_MCFORMATS", LoadNothing
},
177 { EXT_MULAW_BFORMAT
, "AL_EXT_MULAW_BFORMAT", LoadNothing
},
179 { SOFT_source_latency
, "AL_SOFT_source_latency", LoadSourceLatency
},
183 ALContext
*ALContext::sCurrentCtx
= 0;
184 thread_local ALContext
*ALContext::sThreadCurrentCtx
;
186 void ALContext::MakeCurrent(ALContext
*context
)
188 if(alcMakeContextCurrent(context
? context
->getContext() : 0) == ALC_FALSE
)
189 throw std::runtime_error("Call to alcMakeContextCurrent failed");
193 std::call_once(context
->mSetExts
, std::mem_fn(&ALContext::setupExts
), context
);
196 sCurrentCtx
->decRef();
197 sCurrentCtx
= context
;
198 if(sThreadCurrentCtx
)
199 sThreadCurrentCtx
->decRef();
200 sThreadCurrentCtx
= 0;
203 void ALContext::MakeThreadCurrent(ALContext
*context
)
205 if(!ALDeviceManager::SetThreadContext
)
206 throw std::runtime_error("Thread-local contexts unsupported");
207 if(ALDeviceManager::SetThreadContext(context
? context
->getContext() : 0) == ALC_FALSE
)
208 throw std::runtime_error("Call to alcSetThreadContext failed");
212 std::call_once(context
->mSetExts
, std::mem_fn(&ALContext::setupExts
), context
);
214 if(sThreadCurrentCtx
)
215 sThreadCurrentCtx
->decRef();
216 sThreadCurrentCtx
= context
;
219 void ALContext::setupExts()
221 ALCdevice
*device
= mDevice
->getDevice();
222 for(size_t i
= 0;i
< countof(ALExtensionList
);i
++)
224 mHasExt
[ALExtensionList
[i
].extension
] = false;
225 if(strncmp(ALExtensionList
[i
].name
, "ALC", 3) == 0)
226 mHasExt
[ALExtensionList
[i
].extension
] = alcIsExtensionPresent(device
, ALExtensionList
[i
].name
);
228 mHasExt
[ALExtensionList
[i
].extension
] = alIsExtensionPresent(ALExtensionList
[i
].name
);
230 if(mHasExt
[ALExtensionList
[i
].extension
])
231 ALExtensionList
[i
].loader(this);
236 ALContext::ALContext(ALCcontext
*context
, ALDevice
*device
)
237 : mContext(context
), mDevice(device
), mRefs(0),
239 alGetSourcei64vSOFT(0),
240 alGenEffects(0), alDeleteEffects(0), alIsEffect(0),
241 alEffecti(0), alEffectiv(0), alEffectf(0), alEffectfv(0),
242 alGetEffecti(0), alGetEffectiv(0), alGetEffectf(0), alGetEffectfv(0),
243 alGenFilters(0), alDeleteFilters(0), alIsFilter(0),
244 alFilteri(0), alFilteriv(0), alFilterf(0), alFilterfv(0),
245 alGetFilteri(0), alGetFilteriv(0), alGetFilterf(0), alGetFilterfv(0),
246 alGenAuxiliaryEffectSlots(0), alDeleteAuxiliaryEffectSlots(0), alIsAuxiliaryEffectSlot(0),
247 alAuxiliaryEffectSloti(0), alAuxiliaryEffectSlotiv(0), alAuxiliaryEffectSlotf(0), alAuxiliaryEffectSlotfv(0),
248 alGetAuxiliaryEffectSloti(0), alGetAuxiliaryEffectSlotiv(0), alGetAuxiliaryEffectSlotf(0), alGetAuxiliaryEffectSlotfv(0)
252 ALContext::~ALContext()
254 mDevice
->removeContext(this);
258 Device
*ALContext::getDevice()
263 void ALContext::destroy()
265 if(mRefs
.load() != 0)
266 throw std::runtime_error("Context is in use");
268 alcDestroyContext(mContext
);
274 void ALContext::startBatch()
276 alcSuspendContext(mContext
);
279 void ALContext::endBatch()
281 alcProcessContext(mContext
);
285 Listener
*ALContext::getListener()
291 SharedPtr
<Decoder
> ALContext::createDecoder(const std::string
&name
)
293 SharedPtr
<std::istream
> file(FileIOFactory::get().openFile(name
));
294 if(!file
.get()) throw std::runtime_error("Failed to open "+name
);
296 FactoryMap::const_reverse_iterator iter
= sDecoders
.rbegin();
297 while(iter
!= sDecoders
.rend())
299 DecoderFactory
*factory
= iter
->second
.get();
300 SharedPtr
<Decoder
> decoder
= factory
->createDecoder(file
);
301 if(decoder
.get()) return decoder
;
305 throw std::runtime_error("Failed to rewind "+name
+" for the next decoder factory");
309 throw std::runtime_error("No decoder for "+name
);
313 Buffer
*ALContext::getBuffer(const std::string
&name
)
317 Buffer
*buffer
= mDevice
->getBuffer(name
);
318 if(buffer
) return buffer
;
320 SharedPtr
<Decoder
> decoder(createDecoder(name
));
322 ALuint srate
= decoder
->getFrequency();
323 SampleConfig chans
= decoder
->getSampleConfig();
324 SampleType type
= decoder
->getSampleType();
325 ALuint frames
= decoder
->getLength();
327 std::vector
<ALbyte
> data(FramesToBytes(frames
, chans
, type
));
328 frames
= decoder
->read(&data
[0], frames
);
329 if(!frames
) throw std::runtime_error("No samples for buffer");
330 data
.resize(FramesToBytes(frames
, chans
, type
));
335 alGenBuffers(1, &bid
);
336 alBufferData(bid
, GetFormat(chans
, type
), &data
[0], data
.size(), srate
);
337 if(alGetError() != AL_NO_ERROR
)
338 throw std::runtime_error("Failed to buffer data");
340 return mDevice
->addBuffer(name
, new ALBuffer(mDevice
, bid
, srate
, chans
, type
));
343 alDeleteBuffers(1, &bid
);
349 void ALContext::removeBuffer(const std::string
&name
)
352 mDevice
->removeBuffer(name
);
355 void ALContext::removeBuffer(Buffer
*buffer
)
358 mDevice
->removeBuffer(buffer
);
362 ALuint
ALContext::getSourceId(ALuint maxprio
)
367 if(mSourceIds
.empty())
370 alGenSources(1, &id
);
371 if(alGetError() == AL_NO_ERROR
)
374 ALSource
*lowest
= 0;
375 for(ALSource
*src
: mUsedSources
)
377 if(src
->getId() != 0 && (!lowest
|| src
->getPriority() < lowest
->getPriority()))
380 if(lowest
&& lowest
->getPriority() < maxprio
)
383 if(mSourceIds
.empty())
384 throw std::runtime_error("No available sources");
386 id
= mSourceIds
.top();
392 Source
*ALContext::getSource()
396 ALSource
*source
= 0;
397 if(mFreeSources
.empty())
398 source
= new ALSource(this);
401 source
= mFreeSources
.back();
404 mUsedSources
.insert(source
);
408 void ALContext::freeSource(ALSource
*source
)
410 mUsedSources
.erase(source
);
411 mFreeSources
.push(source
);
415 AuxiliaryEffectSlot
*ALContext::createAuxiliaryEffectSlot()
417 if(!hasExtension(EXT_EFX
) || !alGenAuxiliaryEffectSlots
)
418 throw std::runtime_error("AuxiliaryEffectSlots not supported");
423 alGenAuxiliaryEffectSlots(1, &id
);
424 if(alGetError() != AL_NO_ERROR
)
425 throw std::runtime_error("Failed to create AuxiliaryEffectSlot");
427 return new ALAuxiliaryEffectSlot(this, id
);
430 alDeleteAuxiliaryEffectSlots(1, &id
);
436 Effect
*ALContext::createEffect()
438 if(!hasExtension(EXT_EFX
))
439 throw std::runtime_error("Effects not supported");
444 alGenEffects(1, &id
);
445 if(alGetError() != AL_NO_ERROR
)
446 throw std::runtime_error("Failed to create Effect");
448 return new ALEffect(this, id
);
451 alDeleteEffects(1, &id
);
457 void ALContext::setDopplerFactor(ALfloat factor
)
459 if(!(factor
>= 0.0f
))
460 throw std::runtime_error("Doppler factor out of range");
462 alDopplerFactor(factor
);
466 void ALContext::setSpeedOfSound(ALfloat speed
)
469 throw std::runtime_error("Speed of sound out of range");
471 alSpeedOfSound(speed
);
475 void ALContext::setDistanceModel(DistanceModel model
)
478 alDistanceModel(model
);
482 void ALContext::update()
485 std::for_each(mUsedSources
.begin(), mUsedSources
.end(), std::mem_fun(&ALSource::updateNoCtxCheck
));
489 void ALContext::setGain(ALfloat gain
)
492 throw std::runtime_error("Gain out of range");
494 alListenerf(AL_GAIN
, gain
);
498 void ALContext::setPosition(ALfloat x
, ALfloat y
, ALfloat z
)
501 alListener3f(AL_POSITION
, x
, y
, z
);
504 void ALContext::setPosition(const ALfloat
*pos
)
507 alListenerfv(AL_POSITION
, pos
);
510 void ALContext::setVelocity(ALfloat x
, ALfloat y
, ALfloat z
)
513 alListener3f(AL_VELOCITY
, x
, y
, z
);
516 void ALContext::setVelocity(const ALfloat
*vel
)
519 alListenerfv(AL_VELOCITY
, vel
);
522 void ALContext::setOrientation(ALfloat x1
, ALfloat y1
, ALfloat z1
, ALfloat x2
, ALfloat y2
, ALfloat z2
)
525 ALfloat ori
[6] = { x1
, y1
, z1
, x2
, y2
, z2
};
526 alListenerfv(AL_ORIENTATION
, ori
);
529 void ALContext::setOrientation(const ALfloat
*at
, const ALfloat
*up
)
532 ALfloat ori
[6] = { at
[0], at
[1], at
[2], up
[0], up
[1], up
[2] };
533 alListenerfv(AL_ORIENTATION
, ori
);
536 void ALContext::setOrientation(const ALfloat
*ori
)
539 alListenerfv(AL_ORIENTATION
, ori
);
543 void Context::MakeCurrent(Context
*context
)
548 ctx
= cast
<ALContext
*>(context
);
549 if(!ctx
) throw std::runtime_error("Invalid context pointer");
551 ALContext::MakeCurrent(ctx
);
554 Context
*Context::GetCurrent()
556 return ALContext::GetCurrent();
559 void Context::MakeThreadCurrent(Context
*context
)
564 ctx
= cast
<ALContext
*>(context
);
565 if(!ctx
) throw std::runtime_error("Invalid context pointer");
567 ALContext::MakeThreadCurrent(ctx
);
570 Context
*Context::GetThreadCurrent()
572 return ALContext::GetThreadCurrent();