A non-async stream is dead, don't try refilling it
[alure.git] / src / context.cpp
blobccff8b99f578a30e42a251f2637a8b2206e97ec5
2 #include "config.h"
4 #include "context.h"
6 #include <stdexcept>
7 #include <algorithm>
8 #include <memory>
9 #include <iostream>
10 #include <sstream>
11 #include <fstream>
12 #include <cstring>
13 #include <map>
15 #include "alc.h"
17 #ifdef HAVE_VORBISFILE
18 #include "decoders/vorbisfile.hpp"
19 #endif
20 #ifdef HAVE_LIBFLAC
21 #include "decoders/flac.hpp"
22 #endif
23 #ifdef HAVE_OPUSFILE
24 #include "decoders/opusfile.hpp"
25 #endif
26 #ifdef HAVE_LIBSNDFILE
27 #include "decoders/sndfile.hpp"
28 #endif
29 #ifdef HAVE_MPG123
30 #include "decoders/mpg123.hpp"
31 #endif
32 #include "decoders/wave.hpp"
34 #include "devicemanager.h"
35 #include "device.h"
36 #include "buffer.h"
37 #include "source.h"
38 #include "auxeffectslot.h"
39 #include "effect.h"
41 namespace alure
44 template<typename T, size_t N>
45 static inline size_t countof(const T(&)[N])
46 { return N; }
49 typedef std::pair<std::string,SharedPtr<DecoderFactory>> FactoryPair;
50 static const FactoryPair sDefaultDecoders[] = {
51 #ifdef HAVE_VORBISFILE
52 { "_alure_int_vorbis", SharedPtr<DecoderFactory>(new VorbisFileDecoderFactory) },
53 #endif
54 #ifdef HAVE_LIBFLAC
55 { "_alure_int_flac", SharedPtr<DecoderFactory>(new FlacDecoderFactory) },
56 #endif
57 #ifdef HAVE_OPUSFILE
58 { "_alure_int_opus", SharedPtr<DecoderFactory>(new OpusFileDecoderFactory) },
59 #endif
61 { "_alure_int_wave", SharedPtr<DecoderFactory>(new WaveDecoderFactory) },
63 #ifdef HAVE_LIBSNDFILE
64 { "_alure_int_sndfile", SharedPtr<DecoderFactory>(new SndFileDecoderFactory) },
65 #endif
66 #ifdef HAVE_MPG123
67 { "_alure_int_mpg123", SharedPtr<DecoderFactory>(new Mpg123DecoderFactory) },
68 #endif
71 typedef std::map<std::string,SharedPtr<DecoderFactory>> FactoryMap;
72 static FactoryMap sDecoders;
74 template<typename T>
75 static SharedPtr<Decoder> GetDecoder(const std::string &name, SharedPtr<std::istream> file, T start, T end)
77 while(start != end)
79 DecoderFactory *factory = start->second.get();
80 SharedPtr<Decoder> decoder = factory->createDecoder(file);
81 if(decoder) return decoder;
83 file->clear();
84 if(!file->seekg(0))
85 throw std::runtime_error("Failed to rewind "+name+" for the next decoder factory");
87 ++start;
90 return SharedPtr<Decoder>(nullptr);
93 static SharedPtr<Decoder> GetDecoder(const std::string &name, SharedPtr<std::istream> file)
95 SharedPtr<Decoder> decoder = GetDecoder(name, file, sDecoders.begin(), sDecoders.end());
96 if(!decoder) decoder = GetDecoder(name, file, std::begin(sDefaultDecoders), std::end(sDefaultDecoders));
97 if(!decoder) throw std::runtime_error("No decoder for "+name);
98 return decoder;
101 void RegisterDecoder(const std::string &name, SharedPtr<DecoderFactory> factory)
103 FactoryMap::iterator iter = sDecoders.begin();
104 while(iter != sDecoders.end())
106 if(iter->first == name)
107 throw std::runtime_error("Decoder factory \""+name+"\" already registered");
108 if(iter->second.get() == factory.get())
110 std::stringstream sstr;
111 sstr<< "Decoder factory instance "<<factory<<" already registered";
112 throw std::runtime_error(sstr.str());
114 iter++;
116 sDecoders.insert(std::make_pair(name, factory));
119 SharedPtr<DecoderFactory> UnregisterDecoder(const std::string &name)
121 FactoryMap::iterator iter = sDecoders.find(name);
122 if(iter != sDecoders.end())
124 SharedPtr<DecoderFactory> factory = iter->second;
125 sDecoders.erase(iter);
126 return factory;
128 return SharedPtr<DecoderFactory>(nullptr);
132 class DefaultFileIOFactory : public FileIOFactory {
133 virtual SharedPtr<std::istream> openFile(const std::string &name)
135 SharedPtr<std::ifstream> file(new std::ifstream(name.c_str(), std::ios::binary));
136 if(!file->is_open()) file.reset();
137 return file;
140 static DefaultFileIOFactory sDefaultFileFactory;
142 static SharedPtr<FileIOFactory> sFileFactory;
143 SharedPtr<FileIOFactory> FileIOFactory::set(SharedPtr<FileIOFactory> factory)
145 sFileFactory.swap(factory);
146 return factory;
149 FileIOFactory &FileIOFactory::get()
151 FileIOFactory *factory = sFileFactory.get();
152 if(factory) return *factory;
153 return sDefaultFileFactory;
157 template<typename T>
158 static inline void LoadALFunc(T **func, const char *name)
159 { *func = reinterpret_cast<T*>(alGetProcAddress(name)); }
162 static void LoadNothing(ALContext*) { }
164 static void LoadEFX(ALContext *ctx)
166 LoadALFunc(&ctx->alGenEffects, "alGenEffects");
167 LoadALFunc(&ctx->alDeleteEffects, "alDeleteEffects");
168 LoadALFunc(&ctx->alIsEffect, "alIsEffect");
169 LoadALFunc(&ctx->alEffecti, "alEffecti");
170 LoadALFunc(&ctx->alEffectiv, "alEffectiv");
171 LoadALFunc(&ctx->alEffectf, "alEffectf");
172 LoadALFunc(&ctx->alEffectfv, "alEffectfv");
173 LoadALFunc(&ctx->alGetEffecti, "alGetEffecti");
174 LoadALFunc(&ctx->alGetEffectiv, "alGetEffectiv");
175 LoadALFunc(&ctx->alGetEffectf, "alGetEffectf");
176 LoadALFunc(&ctx->alGetEffectfv, "alGetEffectfv");
178 LoadALFunc(&ctx->alGenFilters, "alGenFilters");
179 LoadALFunc(&ctx->alDeleteFilters, "alDeleteFilters");
180 LoadALFunc(&ctx->alIsFilter, "alIsFilter");
181 LoadALFunc(&ctx->alFilteri, "alFilteri");
182 LoadALFunc(&ctx->alFilteriv, "alFilteriv");
183 LoadALFunc(&ctx->alFilterf, "alFilterf");
184 LoadALFunc(&ctx->alFilterfv, "alFilterfv");
185 LoadALFunc(&ctx->alGetFilteri, "alGetFilteri");
186 LoadALFunc(&ctx->alGetFilteriv, "alGetFilteriv");
187 LoadALFunc(&ctx->alGetFilterf, "alGetFilterf");
188 LoadALFunc(&ctx->alGetFilterfv, "alGetFilterfv");
190 LoadALFunc(&ctx->alGenAuxiliaryEffectSlots, "alGenAuxiliaryEffectSlots");
191 LoadALFunc(&ctx->alDeleteAuxiliaryEffectSlots, "alDeleteAuxiliaryEffectSlots");
192 LoadALFunc(&ctx->alIsAuxiliaryEffectSlot, "alIsAuxiliaryEffectSlot");
193 LoadALFunc(&ctx->alAuxiliaryEffectSloti, "alAuxiliaryEffectSloti");
194 LoadALFunc(&ctx->alAuxiliaryEffectSlotiv, "alAuxiliaryEffectSlotiv");
195 LoadALFunc(&ctx->alAuxiliaryEffectSlotf, "alAuxiliaryEffectSlotf");
196 LoadALFunc(&ctx->alAuxiliaryEffectSlotfv, "alAuxiliaryEffectSlotfv");
197 LoadALFunc(&ctx->alGetAuxiliaryEffectSloti, "alGetAuxiliaryEffectSloti");
198 LoadALFunc(&ctx->alGetAuxiliaryEffectSlotiv, "alGetAuxiliaryEffectSlotiv");
199 LoadALFunc(&ctx->alGetAuxiliaryEffectSlotf, "alGetAuxiliaryEffectSlotf");
200 LoadALFunc(&ctx->alGetAuxiliaryEffectSlotfv, "alGetAuxiliaryEffectSlotfv");
203 static void LoadSourceLatency(ALContext *ctx)
205 LoadALFunc(&ctx->alGetSourcei64vSOFT, "alGetSourcei64vSOFT");
208 static const struct {
209 enum ALExtension extension;
210 const char name[32];
211 void (*loader)(ALContext*);
212 } ALExtensionList[] = {
213 { EXT_EFX, "ALC_EXT_EFX", LoadEFX },
215 { EXT_FLOAT32, "AL_EXT_FLOAT32", LoadNothing },
216 { EXT_MCFORMATS, "AL_EXT_MCFORMATS", LoadNothing },
217 { EXT_BFORMAT, "AL_EXT_BFORMAT", LoadNothing },
219 { EXT_MULAW, "AL_EXT_MULAW", LoadNothing },
220 { EXT_MULAW_MCFORMATS, "AL_EXT_MULAW_MCFORMATS", LoadNothing },
221 { EXT_MULAW_BFORMAT, "AL_EXT_MULAW_BFORMAT", LoadNothing },
223 { SOFT_loop_points, "AL_SOFT_loop_points", LoadNothing },
224 { SOFT_source_latency, "AL_SOFT_source_latency", LoadSourceLatency },
228 ALContext *ALContext::sCurrentCtx = 0;
229 thread_local ALContext *ALContext::sThreadCurrentCtx;
231 void ALContext::MakeCurrent(ALContext *context)
233 std::unique_lock<std::mutex> lock1, lock2;
234 if(sCurrentCtx)
235 lock1 = std::unique_lock<std::mutex>(sCurrentCtx->mMutex);
236 if(context && context != sCurrentCtx)
237 lock2 = std::unique_lock<std::mutex>(context->mMutex);
239 if(alcMakeContextCurrent(context ? context->getContext() : 0) == ALC_FALSE)
240 throw std::runtime_error("Call to alcMakeContextCurrent failed");
241 if(context)
243 context->addRef();
244 std::call_once(context->mSetExts, std::mem_fn(&ALContext::setupExts), context);
246 std::swap(sCurrentCtx, context);
247 if(context) context->decRef();
249 if(sThreadCurrentCtx)
250 sThreadCurrentCtx->decRef();
251 sThreadCurrentCtx = 0;
253 if(sCurrentCtx && sCurrentCtx != context)
255 lock2.unlock();
256 sCurrentCtx->mWakeThread.notify_all();
260 void ALContext::MakeThreadCurrent(ALContext *context)
262 if(!ALDeviceManager::SetThreadContext)
263 throw std::runtime_error("Thread-local contexts unsupported");
264 if(ALDeviceManager::SetThreadContext(context ? context->getContext() : 0) == ALC_FALSE)
265 throw std::runtime_error("Call to alcSetThreadContext failed");
266 if(context)
268 context->addRef();
269 std::call_once(context->mSetExts, std::mem_fn(&ALContext::setupExts), context);
271 if(sThreadCurrentCtx)
272 sThreadCurrentCtx->decRef();
273 sThreadCurrentCtx = context;
276 void ALContext::setupExts()
278 ALCdevice *device = mDevice->getDevice();
279 for(size_t i = 0;i < countof(ALExtensionList);i++)
281 mHasExt[ALExtensionList[i].extension] = false;
282 if(strncmp(ALExtensionList[i].name, "ALC", 3) == 0)
283 mHasExt[ALExtensionList[i].extension] = alcIsExtensionPresent(device, ALExtensionList[i].name);
284 else
285 mHasExt[ALExtensionList[i].extension] = alIsExtensionPresent(ALExtensionList[i].name);
287 if(mHasExt[ALExtensionList[i].extension])
288 ALExtensionList[i].loader(this);
293 void ALContext::backgroundProc()
295 if(ALDeviceManager::SetThreadContext && mDevice->hasExtension(EXT_thread_local_context))
296 ALDeviceManager::SetThreadContext(getContext());
298 std::unique_lock<std::mutex> lock(mMutex);
299 while(!mQuitThread)
301 for(PendingBuffer &pendbuf : mPendingBuffers)
302 pendbuf.mBuffer->load(pendbuf.mFrames, pendbuf.mFormat,
303 pendbuf.mDecoder, pendbuf.mName, this);
304 mPendingBuffers.clear();
306 auto source = mStreamingSources.begin();
307 while(source != mStreamingSources.end())
309 if(!(*source)->updateAsync())
310 source = mStreamingSources.erase(source);
311 else
312 ++source;
315 do {
316 mWakeThread.wait(lock);
317 } while(!mQuitThread && alcGetCurrentContext() != getContext());
319 lock.unlock();
321 if(ALDeviceManager::SetThreadContext)
322 ALDeviceManager::SetThreadContext(0);
326 ALContext::ALContext(ALCcontext *context, ALDevice *device)
327 : mContext(context), mDevice(device), mRefs(0),
328 mHasExt{false}, mQuitThread(false),
329 alGetSourcei64vSOFT(0),
330 alGenEffects(0), alDeleteEffects(0), alIsEffect(0),
331 alEffecti(0), alEffectiv(0), alEffectf(0), alEffectfv(0),
332 alGetEffecti(0), alGetEffectiv(0), alGetEffectf(0), alGetEffectfv(0),
333 alGenFilters(0), alDeleteFilters(0), alIsFilter(0),
334 alFilteri(0), alFilteriv(0), alFilterf(0), alFilterfv(0),
335 alGetFilteri(0), alGetFilteriv(0), alGetFilterf(0), alGetFilterfv(0),
336 alGenAuxiliaryEffectSlots(0), alDeleteAuxiliaryEffectSlots(0), alIsAuxiliaryEffectSlot(0),
337 alAuxiliaryEffectSloti(0), alAuxiliaryEffectSlotiv(0), alAuxiliaryEffectSlotf(0), alAuxiliaryEffectSlotfv(0),
338 alGetAuxiliaryEffectSloti(0), alGetAuxiliaryEffectSlotiv(0), alGetAuxiliaryEffectSlotf(0), alGetAuxiliaryEffectSlotfv(0)
342 ALContext::~ALContext()
344 mDevice->removeContext(this);
348 Device *ALContext::getDevice()
350 return mDevice;
353 void ALContext::destroy()
355 if(mRefs.load() != 0)
356 throw std::runtime_error("Context is in use");
357 if(!mBuffers.empty())
358 throw std::runtime_error("Trying to destroy a context with buffers");
360 if(mThread.joinable())
362 std::unique_lock<std::mutex> lock(mMutex);
363 mQuitThread = true;
364 lock.unlock();
365 mWakeThread.notify_all();
366 mThread.join();
369 alcDestroyContext(mContext);
370 mContext = 0;
371 delete this;
375 void ALContext::startBatch()
377 alcSuspendContext(mContext);
380 void ALContext::endBatch()
382 alcProcessContext(mContext);
386 Listener *ALContext::getListener()
388 return this;
392 SharedPtr<MessageHandler> ALContext::setMessageHandler(SharedPtr<MessageHandler> handler)
394 std::lock_guard<std::mutex> lock(mMutex);
395 mMessage.swap(handler);
396 return handler;
399 SharedPtr<MessageHandler> ALContext::getMessageHandler() const
401 return mMessage;
405 SharedPtr<Decoder> ALContext::createDecoder(const std::string &name)
407 SharedPtr<std::istream> file(FileIOFactory::get().openFile(name));
408 if(file.get()) return GetDecoder(name, file);
410 // Resource not found. Try to find a substitute.
411 if(!mMessage.get()) throw std::runtime_error("Failed to open "+name);
412 std::string oldname = name;
413 do {
414 std::string newname;
415 if(!mMessage->resourceNotFound(oldname, newname))
416 throw std::runtime_error("Failed to open "+oldname);
417 file = FileIOFactory::get().openFile(newname);
418 oldname = std::move(newname);
419 } while(!file.get());
421 return GetDecoder(oldname, file);
425 Buffer *ALContext::getBuffer(const std::string &name)
427 CheckContext(this);
429 BufferMap::const_iterator iter = mBuffers.find(name);
430 if(iter != mBuffers.end())
432 // Ensure the buffer is loaded before returning. getBuffer guarantees
433 // the returned buffer is loaded.
434 ALBuffer *buffer = iter->second;
435 while(buffer->getLoadStatus() == BufferLoad_Pending)
436 std::this_thread::yield();
437 return buffer;
440 SharedPtr<Decoder> decoder(createDecoder(name));
442 ALuint srate = decoder->getFrequency();
443 ChannelConfig chans = decoder->getChannelConfig();
444 SampleType type = decoder->getSampleType();
445 ALuint frames = decoder->getLength();
447 std::vector<ALbyte> data(FramesToBytes(frames, chans, type));
448 frames = decoder->read(&data[0], frames);
449 if(!frames) throw std::runtime_error("No samples for buffer");
450 data.resize(FramesToBytes(frames, chans, type));
452 std::pair<uint64_t,uint64_t> loop_pts = decoder->getLoopPoints();
453 if(loop_pts.first >= loop_pts.second)
454 loop_pts = std::make_pair(0, frames);
455 else
457 loop_pts.second = std::min<uint64_t>(loop_pts.second, frames);
458 loop_pts.first = std::min<uint64_t>(loop_pts.first, loop_pts.second-1);
461 // Get the format before calling the bufferLoading message handler, to
462 // ensure it's something OpenAL can handle.
463 ALenum format = GetFormat(chans, type);
465 if(mMessage.get())
466 mMessage->bufferLoading(name, chans, type, srate, data);
468 alGetError();
469 ALuint bid = 0;
470 try {
471 alGenBuffers(1, &bid);
472 alBufferData(bid, format, &data[0], data.size(), srate);
473 if(hasExtension(SOFT_loop_points))
475 ALint pts[2]{(ALint)loop_pts.first, (ALint)loop_pts.second};
476 alBufferiv(bid, AL_LOOP_POINTS_SOFT, pts);
478 if(alGetError() != AL_NO_ERROR)
479 throw std::runtime_error("Failed to buffer data");
481 ALBuffer *buffer = new ALBuffer(mDevice, bid, srate, chans, type, true);
482 return mBuffers.insert(std::make_pair(name, buffer)).first->second;
484 catch(...) {
485 alDeleteBuffers(1, &bid);
486 throw;
490 Buffer *ALContext::getBufferAsync(const std::string &name)
492 CheckContext(this);
494 BufferMap::const_iterator iter = mBuffers.find(name);
495 if(iter != mBuffers.end()) return iter->second;
497 SharedPtr<Decoder> decoder(createDecoder(name));
499 ALuint srate = decoder->getFrequency();
500 ChannelConfig chans = decoder->getChannelConfig();
501 SampleType type = decoder->getSampleType();
502 ALuint frames = decoder->getLength();
503 if(!frames) throw std::runtime_error("No samples for buffer");
505 ALenum format = GetFormat(chans, type);
507 alGetError();
508 ALuint bid = 0;
509 alGenBuffers(1, &bid);
510 if(alGetError() != AL_NO_ERROR)
511 throw std::runtime_error("Failed to buffer data");
513 ALBuffer *buffer = new ALBuffer(mDevice, bid, srate, chans, type, false);
515 std::unique_lock<std::mutex> lock(mMutex);
516 if(mThread.get_id() == std::thread::id())
517 mThread = std::thread(std::mem_fn(&ALContext::backgroundProc), this);
518 mPendingBuffers.push_back(PendingBuffer{name, buffer, decoder, format, frames});
519 lock.unlock();
520 mWakeThread.notify_all();
522 return mBuffers.insert(std::make_pair(name, buffer)).first->second;
526 void ALContext::removeBuffer(const std::string &name)
528 CheckContext(this);
529 BufferMap::iterator iter = mBuffers.find(name);
530 if(iter != mBuffers.end())
532 ALBuffer *albuf = iter->second;
533 albuf->cleanup();
534 mBuffers.erase(iter);
538 void ALContext::removeBuffer(Buffer *buffer)
540 CheckContext(this);
541 BufferMap::iterator iter = mBuffers.begin();
542 while(iter != mBuffers.end())
544 ALBuffer *albuf = iter->second;
545 if(albuf == buffer)
547 albuf->cleanup();
548 mBuffers.erase(iter);
549 break;
551 ++iter;
556 ALuint ALContext::getSourceId(ALuint maxprio)
558 CheckContext(this);
560 ALuint id = 0;
561 if(mSourceIds.empty())
563 alGetError();
564 alGenSources(1, &id);
565 if(alGetError() == AL_NO_ERROR)
566 return id;
568 ALSource *lowest = 0;
569 for(ALSource *src : mUsedSources)
571 if(src->getId() != 0 && (!lowest || src->getPriority() < lowest->getPriority()))
572 lowest = src;
574 if(lowest && lowest->getPriority() < maxprio)
575 lowest->stop();
577 if(mSourceIds.empty())
578 throw std::runtime_error("No available sources");
580 id = mSourceIds.top();
581 mSourceIds.pop();
582 return id;
586 Source *ALContext::getSource()
588 CheckContext(this);
590 ALSource *source = 0;
591 if(mFreeSources.empty())
592 source = new ALSource(this);
593 else
595 source = mFreeSources.back();
596 mFreeSources.pop();
598 mUsedSources.insert(source);
599 return source;
602 void ALContext::freeSource(ALSource *source)
604 mUsedSources.erase(source);
605 mFreeSources.push(source);
609 void ALContext::addStream(ALSource *source)
611 std::lock_guard<std::mutex> lock(mMutex);
612 if(mThread.get_id() == std::thread::id())
613 mThread = std::thread(std::mem_fn(&ALContext::backgroundProc), this);
614 mStreamingSources.insert(source);
617 void ALContext::removeStream(ALSource *source)
619 std::lock_guard<std::mutex> lock(mMutex);
620 mStreamingSources.erase(source);
624 AuxiliaryEffectSlot *ALContext::createAuxiliaryEffectSlot()
626 if(!hasExtension(EXT_EFX) || !alGenAuxiliaryEffectSlots)
627 throw std::runtime_error("AuxiliaryEffectSlots not supported");
628 CheckContext(this);
630 alGetError();
631 ALuint id = 0;
632 alGenAuxiliaryEffectSlots(1, &id);
633 if(alGetError() != AL_NO_ERROR)
634 throw std::runtime_error("Failed to create AuxiliaryEffectSlot");
635 try {
636 return new ALAuxiliaryEffectSlot(this, id);
638 catch(...) {
639 alDeleteAuxiliaryEffectSlots(1, &id);
640 throw;
645 Effect *ALContext::createEffect()
647 if(!hasExtension(EXT_EFX))
648 throw std::runtime_error("Effects not supported");
649 CheckContext(this);
651 alGetError();
652 ALuint id = 0;
653 alGenEffects(1, &id);
654 if(alGetError() != AL_NO_ERROR)
655 throw std::runtime_error("Failed to create Effect");
656 try {
657 return new ALEffect(this, id);
659 catch(...) {
660 alDeleteEffects(1, &id);
661 throw;
666 void ALContext::setDopplerFactor(ALfloat factor)
668 if(!(factor >= 0.0f))
669 throw std::runtime_error("Doppler factor out of range");
670 CheckContext(this);
671 alDopplerFactor(factor);
675 void ALContext::setSpeedOfSound(ALfloat speed)
677 if(!(speed > 0.0f))
678 throw std::runtime_error("Speed of sound out of range");
679 CheckContext(this);
680 alSpeedOfSound(speed);
684 void ALContext::setDistanceModel(DistanceModel model)
686 CheckContext(this);
687 alDistanceModel(model);
691 void ALContext::update()
693 CheckContext(this);
694 std::for_each(mUsedSources.begin(), mUsedSources.end(), std::mem_fun(&ALSource::updateNoCtxCheck));
695 // For performance reasons, don't wait for the thread's mutex. This should
696 // be called often enough to keep up with any and all streams regardless.
697 wakeThread();
701 void ALContext::setGain(ALfloat gain)
703 if(!(gain >= 0.0f))
704 throw std::runtime_error("Gain out of range");
705 CheckContext(this);
706 alListenerf(AL_GAIN, gain);
710 void ALContext::setPosition(ALfloat x, ALfloat y, ALfloat z)
712 CheckContext(this);
713 alListener3f(AL_POSITION, x, y, z);
716 void ALContext::setPosition(const ALfloat *pos)
718 CheckContext(this);
719 alListenerfv(AL_POSITION, pos);
722 void ALContext::setVelocity(ALfloat x, ALfloat y, ALfloat z)
724 CheckContext(this);
725 alListener3f(AL_VELOCITY, x, y, z);
728 void ALContext::setVelocity(const ALfloat *vel)
730 CheckContext(this);
731 alListenerfv(AL_VELOCITY, vel);
734 void ALContext::setOrientation(ALfloat x1, ALfloat y1, ALfloat z1, ALfloat x2, ALfloat y2, ALfloat z2)
736 CheckContext(this);
737 ALfloat ori[6] = { x1, y1, z1, x2, y2, z2 };
738 alListenerfv(AL_ORIENTATION, ori);
741 void ALContext::setOrientation(const ALfloat *at, const ALfloat *up)
743 CheckContext(this);
744 ALfloat ori[6] = { at[0], at[1], at[2], up[0], up[1], up[2] };
745 alListenerfv(AL_ORIENTATION, ori);
748 void ALContext::setOrientation(const ALfloat *ori)
750 CheckContext(this);
751 alListenerfv(AL_ORIENTATION, ori);
754 void ALContext::setMetersPerUnit(ALfloat m_u)
756 if(!(m_u > 0.0f))
757 throw std::runtime_error("Invalid meters per unit");
758 CheckContext(this);
759 if(hasExtension(EXT_EFX))
760 alListenerf(AL_METERS_PER_UNIT, m_u);
764 void Context::MakeCurrent(Context *context)
766 ALContext *ctx = 0;
767 if(context)
769 ctx = cast<ALContext*>(context);
770 if(!ctx) throw std::runtime_error("Invalid context pointer");
772 ALContext::MakeCurrent(ctx);
775 Context *Context::GetCurrent()
777 return ALContext::GetCurrent();
780 void Context::MakeThreadCurrent(Context *context)
782 ALContext *ctx = 0;
783 if(context)
785 ctx = cast<ALContext*>(context);
786 if(!ctx) throw std::runtime_error("Invalid context pointer");
788 ALContext::MakeThreadCurrent(ctx);
791 Context *Context::GetThreadCurrent()
793 return ALContext::GetThreadCurrent();