Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'extern/audaspace/src/devices/SoftwareDevice.cpp')
-rw-r--r--extern/audaspace/src/devices/SoftwareDevice.cpp989
1 files changed, 989 insertions, 0 deletions
diff --git a/extern/audaspace/src/devices/SoftwareDevice.cpp b/extern/audaspace/src/devices/SoftwareDevice.cpp
new file mode 100644
index 00000000000..c944b9ed12d
--- /dev/null
+++ b/extern/audaspace/src/devices/SoftwareDevice.cpp
@@ -0,0 +1,989 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "devices/SoftwareDevice.h"
+#include "fx/PitchReader.h"
+#include "respec/ChannelMapperReader.h"
+#include "respec/JOSResampleReader.h"
+#include "respec/LinearResampleReader.h"
+#include "respec/Mixer.h"
+#include "Exception.h"
+#include "ISound.h"
+
+#include <algorithm>
+#include <cmath>
+#include <cstring>
+#include <iostream>
+#include <limits>
+#include <mutex>
+
+AUD_NAMESPACE_BEGIN
+
+enum RenderFlags
+{
+ RENDER_DISTANCE = 0x01,
+ RENDER_DOPPLER = 0x02,
+ RENDER_CONE = 0x04,
+ RENDER_VOLUME = 0x08
+};
+
+#define PITCH_MAX 10
+
+/******************************************************************************/
+/********************** SoftwareHandle Handle Code ************************/
+/******************************************************************************/
+
+bool SoftwareDevice::SoftwareHandle::pause(bool keep)
+{
+ if(m_status)
+ {
+ std::lock_guard<ILockable> lock(*m_device);
+
+ if(m_status == STATUS_PLAYING)
+ {
+ for(auto it = m_device->m_playingSounds.begin(); it != m_device->m_playingSounds.end(); it++)
+ {
+ if(it->get() == this)
+ {
+ std::shared_ptr<SoftwareHandle> This = *it;
+
+ m_device->m_playingSounds.erase(it);
+ m_device->m_pausedSounds.push_back(This);
+
+ if(m_device->m_playingSounds.empty())
+ m_device->playing(m_device->m_playback = false);
+
+ m_status = keep ? STATUS_STOPPED : STATUS_PAUSED;
+
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+SoftwareDevice::SoftwareHandle::SoftwareHandle(SoftwareDevice* device, std::shared_ptr<IReader> reader, std::shared_ptr<PitchReader> pitch, std::shared_ptr<ResampleReader> resampler, std::shared_ptr<ChannelMapperReader> mapper, bool keep) :
+ m_reader(reader), m_pitch(pitch), m_resampler(resampler), m_mapper(mapper), m_keep(keep), m_user_pitch(1.0f), m_user_volume(1.0f), m_user_pan(0.0f), m_volume(1.0f), m_old_volume(0), m_loopcount(0),
+ m_relative(true), m_volume_max(1.0f), m_volume_min(0), m_distance_max(std::numeric_limits<float>::max()),
+ m_distance_reference(1.0f), m_attenuation(1.0f), m_cone_angle_outer(M_PI), m_cone_angle_inner(M_PI), m_cone_volume_outer(0),
+ m_flags(RENDER_CONE), m_stop(nullptr), m_stop_data(nullptr), m_status(STATUS_PLAYING), m_device(device)
+{
+}
+
+void SoftwareDevice::SoftwareHandle::update()
+{
+ int flags = 0;
+
+ m_old_volume = m_volume;
+
+ Vector3 SL;
+ if(m_relative)
+ SL = -m_location;
+ else
+ SL = m_device->m_location - m_location;
+ float distance = SL * SL;
+
+ if(distance > 0)
+ distance = sqrt(distance);
+ else
+ flags |= RENDER_DOPPLER | RENDER_DISTANCE;
+
+ if(m_pitch->getSpecs().channels != CHANNELS_MONO)
+ {
+ m_volume = m_user_volume;
+ m_pitch->setPitch(m_user_pitch);
+ return;
+ }
+
+ flags = ~(flags | m_flags | m_device->m_flags);
+
+ // Doppler and Pitch
+
+ if(flags & RENDER_DOPPLER)
+ {
+ float vls;
+ if(m_relative)
+ vls = 0;
+ else
+ vls = SL * m_device->m_velocity / distance;
+ float vss = SL * m_velocity / distance;
+ float max = m_device->m_speed_of_sound / m_device->m_doppler_factor;
+ if(vss >= max)
+ {
+ m_pitch->setPitch(PITCH_MAX);
+ }
+ else
+ {
+ if(vls > max)
+ vls = max;
+
+ m_pitch->setPitch((m_device->m_speed_of_sound - m_device->m_doppler_factor * vls) / (m_device->m_speed_of_sound - m_device->m_doppler_factor * vss) * m_user_pitch);
+ }
+ }
+ else
+ m_pitch->setPitch(m_user_pitch);
+
+ if(flags & RENDER_VOLUME)
+ {
+ // Distance
+
+ if(flags & RENDER_DISTANCE)
+ {
+ if(m_device->m_distance_model == DISTANCE_MODEL_INVERSE_CLAMPED ||
+ m_device->m_distance_model == DISTANCE_MODEL_LINEAR_CLAMPED ||
+ m_device->m_distance_model == DISTANCE_MODEL_EXPONENT_CLAMPED)
+ {
+ distance = std::max(std::min(m_distance_max, distance), m_distance_reference);
+ }
+
+ switch(m_device->m_distance_model)
+ {
+ case DISTANCE_MODEL_INVERSE:
+ case DISTANCE_MODEL_INVERSE_CLAMPED:
+ m_volume = m_distance_reference / (m_distance_reference + m_attenuation * (distance - m_distance_reference));
+ break;
+ case DISTANCE_MODEL_LINEAR:
+ case DISTANCE_MODEL_LINEAR_CLAMPED:
+ {
+ float temp = m_distance_max - m_distance_reference;
+ if(temp == 0)
+ {
+ if(distance > m_distance_reference)
+ m_volume = 0.0f;
+ else
+ m_volume = 1.0f;
+ }
+ else
+ m_volume = 1.0f - m_attenuation * (distance - m_distance_reference) / (m_distance_max - m_distance_reference);
+ break;
+ }
+ case DISTANCE_MODEL_EXPONENT:
+ case DISTANCE_MODEL_EXPONENT_CLAMPED:
+ if(m_distance_reference == 0)
+ m_volume = 0;
+ else
+ m_volume = std::pow(distance / m_distance_reference, -m_attenuation);
+ break;
+ default:
+ m_volume = 1.0f;
+ }
+ }
+ else
+ m_volume = 1.0f;
+
+ // Cone
+
+ if(flags & RENDER_CONE)
+ {
+ Vector3 SZ = m_orientation.getLookAt();
+
+ float phi = std::acos(float(SZ * SL / (SZ.length() * SL.length())));
+ float t = (phi - m_cone_angle_inner)/(m_cone_angle_outer - m_cone_angle_inner);
+
+ if(t > 0)
+ {
+ if(t > 1)
+ m_volume *= m_cone_volume_outer;
+ else
+ m_volume *= 1 + t * (m_cone_volume_outer - 1);
+ }
+ }
+
+ if(m_volume > m_volume_max)
+ m_volume = m_volume_max;
+ else if(m_volume < m_volume_min)
+ m_volume = m_volume_min;
+
+ // Volume
+
+ m_volume *= m_user_volume;
+ }
+
+ // 3D Cue
+
+ Quaternion orientation;
+
+ if(!m_relative)
+ orientation = m_device->m_orientation;
+
+ Vector3 Z = orientation.getLookAt();
+ Vector3 N = orientation.getUp();
+ Vector3 A = N * ((SL * N) / (N * N)) - SL;
+
+ float Asquare = A * A;
+
+ if(Asquare > 0)
+ {
+ float phi = std::acos(float(Z * A / (Z.length() * std::sqrt(Asquare))));
+ if(N.cross(Z) * A > 0)
+ phi = -phi;
+
+ m_mapper->setMonoAngle(phi);
+ }
+ else
+ m_mapper->setMonoAngle(m_relative ? m_user_pan * M_PI / 2.0 : 0);
+}
+
+void SoftwareDevice::SoftwareHandle::setSpecs(Specs specs)
+{
+ m_mapper->setChannels(specs.channels);
+ m_resampler->setRate(specs.rate);
+}
+
+bool SoftwareDevice::SoftwareHandle::pause()
+{
+ return pause(false);
+}
+
+bool SoftwareDevice::SoftwareHandle::resume()
+{
+ if(m_status)
+ {
+ std::lock_guard<ILockable> lock(*m_device);
+
+ if(m_status == STATUS_PAUSED)
+ {
+ for(auto it = m_device->m_pausedSounds.begin(); it != m_device->m_pausedSounds.end(); it++)
+ {
+ if(it->get() == this)
+ {
+ std::shared_ptr<SoftwareHandle> This = *it;
+
+ m_device->m_pausedSounds.erase(it);
+
+ m_device->m_playingSounds.push_back(This);
+
+ if(!m_device->m_playback)
+ m_device->playing(m_device->m_playback = true);
+ m_status = STATUS_PLAYING;
+
+ return true;
+ }
+ }
+ }
+
+ }
+
+ return false;
+}
+
+bool SoftwareDevice::SoftwareHandle::stop()
+{
+ if(!m_status)
+ return false;
+
+ std::lock_guard<ILockable> lock(*m_device);
+
+ if(!m_status)
+ return false;
+
+ m_status = STATUS_INVALID;
+
+ for(auto it = m_device->m_playingSounds.begin(); it != m_device->m_playingSounds.end(); it++)
+ {
+ if(it->get() == this)
+ {
+ std::shared_ptr<SoftwareHandle> This = *it;
+
+ m_device->m_playingSounds.erase(it);
+
+ if(m_device->m_playingSounds.empty())
+ m_device->playing(m_device->m_playback = false);
+
+ return true;
+ }
+ }
+
+ for(auto it = m_device->m_pausedSounds.begin(); it != m_device->m_pausedSounds.end(); it++)
+ {
+ if(it->get() == this)
+ {
+ std::shared_ptr<SoftwareHandle> This = *it;
+
+ m_device->m_pausedSounds.erase(it);
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool SoftwareDevice::SoftwareHandle::getKeep()
+{
+ if(m_status)
+ return m_keep;
+
+ return false;
+}
+
+bool SoftwareDevice::SoftwareHandle::setKeep(bool keep)
+{
+ if(!m_status)
+ return false;
+
+ std::lock_guard<ILockable> lock(*m_device);
+
+ if(!m_status)
+ return false;
+
+ m_keep = keep;
+
+ return true;
+}
+
+bool SoftwareDevice::SoftwareHandle::seek(float position)
+{
+ if(!m_status)
+ return false;
+
+ std::lock_guard<ILockable> lock(*m_device);
+
+ if(!m_status)
+ return false;
+
+ m_pitch->setPitch(m_user_pitch);
+ m_reader->seek((int)(position * m_reader->getSpecs().rate));
+
+ if(m_status == STATUS_STOPPED)
+ m_status = STATUS_PAUSED;
+
+ return true;
+}
+
+float SoftwareDevice::SoftwareHandle::getPosition()
+{
+ if(!m_status)
+ return false;
+
+ std::lock_guard<ILockable> lock(*m_device);
+
+ if(!m_status)
+ return 0.0f;
+
+ float position = m_reader->getPosition() / (float)m_device->m_specs.rate;
+
+ return position;
+}
+
+Status SoftwareDevice::SoftwareHandle::getStatus()
+{
+ return m_status;
+}
+
+float SoftwareDevice::SoftwareHandle::getVolume()
+{
+ return m_user_volume;
+}
+
+bool SoftwareDevice::SoftwareHandle::setVolume(float volume)
+{
+ if(!m_status)
+ return false;
+ m_user_volume = volume;
+
+ if(volume == 0)
+ {
+ m_old_volume = m_volume = volume;
+ m_flags |= RENDER_VOLUME;
+ }
+ else
+ m_flags &= ~RENDER_VOLUME;
+
+ return true;
+}
+
+float SoftwareDevice::SoftwareHandle::getPitch()
+{
+ return m_user_pitch;
+}
+
+bool SoftwareDevice::SoftwareHandle::setPitch(float pitch)
+{
+ if(!m_status)
+ return false;
+ if(pitch > 0.0f)
+ m_user_pitch = pitch;
+ return true;
+}
+
+int SoftwareDevice::SoftwareHandle::getLoopCount()
+{
+ if(!m_status)
+ return 0;
+ return m_loopcount;
+}
+
+bool SoftwareDevice::SoftwareHandle::setLoopCount(int count)
+{
+ if(!m_status)
+ return false;
+
+ if(m_status == STATUS_STOPPED && (count > m_loopcount || count < 0))
+ m_status = STATUS_PAUSED;
+
+ m_loopcount = count;
+
+ return true;
+}
+
+bool SoftwareDevice::SoftwareHandle::setStopCallback(stopCallback callback, void* data)
+{
+ if(!m_status)
+ return false;
+
+ std::lock_guard<ILockable> lock(*m_device);
+
+ if(!m_status)
+ return false;
+
+ m_stop = callback;
+ m_stop_data = data;
+
+ return true;
+}
+
+
+
+/******************************************************************************/
+/******************** SoftwareHandle 3DHandle Code ************************/
+/******************************************************************************/
+
+Vector3 SoftwareDevice::SoftwareHandle::getLocation()
+{
+ if(!m_status)
+ return Vector3();
+
+ return m_location;
+}
+
+bool SoftwareDevice::SoftwareHandle::setLocation(const Vector3& location)
+{
+ if(!m_status)
+ return false;
+
+ m_location = location;
+
+ return true;
+}
+
+Vector3 SoftwareDevice::SoftwareHandle::getVelocity()
+{
+ if(!m_status)
+ return Vector3();
+
+ return m_velocity;
+}
+
+bool SoftwareDevice::SoftwareHandle::setVelocity(const Vector3& velocity)
+{
+ if(!m_status)
+ return false;
+
+ m_velocity = velocity;
+
+ return true;
+}
+
+Quaternion SoftwareDevice::SoftwareHandle::getOrientation()
+{
+ if(!m_status)
+ return Quaternion();
+
+ return m_orientation;
+}
+
+bool SoftwareDevice::SoftwareHandle::setOrientation(const Quaternion& orientation)
+{
+ if(!m_status)
+ return false;
+
+ m_orientation = orientation;
+
+ return true;
+}
+
+bool SoftwareDevice::SoftwareHandle::isRelative()
+{
+ if(!m_status)
+ return false;
+
+ return m_relative;
+}
+
+bool SoftwareDevice::SoftwareHandle::setRelative(bool relative)
+{
+ if(!m_status)
+ return false;
+
+ m_relative = relative;
+
+ return true;
+}
+
+float SoftwareDevice::SoftwareHandle::getVolumeMaximum()
+{
+ if(!m_status)
+ return std::numeric_limits<float>::quiet_NaN();
+
+ return m_volume_max;
+}
+
+bool SoftwareDevice::SoftwareHandle::setVolumeMaximum(float volume)
+{
+ if(!m_status)
+ return false;
+
+ m_volume_max = volume;
+
+ return true;
+}
+
+float SoftwareDevice::SoftwareHandle::getVolumeMinimum()
+{
+ if(!m_status)
+ return std::numeric_limits<float>::quiet_NaN();
+
+ return m_volume_min;
+}
+
+bool SoftwareDevice::SoftwareHandle::setVolumeMinimum(float volume)
+{
+ if(!m_status)
+ return false;
+
+ m_volume_min = volume;
+
+ return true;
+}
+
+float SoftwareDevice::SoftwareHandle::getDistanceMaximum()
+{
+ if(!m_status)
+ return std::numeric_limits<float>::quiet_NaN();
+
+ return m_distance_max;
+}
+
+bool SoftwareDevice::SoftwareHandle::setDistanceMaximum(float distance)
+{
+ if(!m_status)
+ return false;
+
+ m_distance_max = distance;
+
+ return true;
+}
+
+float SoftwareDevice::SoftwareHandle::getDistanceReference()
+{
+ if(!m_status)
+ return std::numeric_limits<float>::quiet_NaN();
+
+ return m_distance_reference;
+}
+
+bool SoftwareDevice::SoftwareHandle::setDistanceReference(float distance)
+{
+ if(!m_status)
+ return false;
+
+ m_distance_reference = distance;
+
+ return true;
+}
+
+float SoftwareDevice::SoftwareHandle::getAttenuation()
+{
+ if(!m_status)
+ return std::numeric_limits<float>::quiet_NaN();
+
+ return m_attenuation;
+}
+
+bool SoftwareDevice::SoftwareHandle::setAttenuation(float factor)
+{
+ if(!m_status)
+ return false;
+
+ m_attenuation = factor;
+
+ if(factor == 0)
+ m_flags |= RENDER_DISTANCE;
+ else
+ m_flags &= ~RENDER_DISTANCE;
+
+ return true;
+}
+
+float SoftwareDevice::SoftwareHandle::getConeAngleOuter()
+{
+ if(!m_status)
+ return std::numeric_limits<float>::quiet_NaN();
+
+ return m_cone_angle_outer * 360.0f / M_PI;
+}
+
+bool SoftwareDevice::SoftwareHandle::setConeAngleOuter(float angle)
+{
+ if(!m_status)
+ return false;
+
+ m_cone_angle_outer = angle * M_PI / 360.0f;
+
+ return true;
+}
+
+float SoftwareDevice::SoftwareHandle::getConeAngleInner()
+{
+ if(!m_status)
+ return std::numeric_limits<float>::quiet_NaN();
+
+ return m_cone_angle_inner * 360.0f / M_PI;
+}
+
+bool SoftwareDevice::SoftwareHandle::setConeAngleInner(float angle)
+{
+ if(!m_status)
+ return false;
+
+ if(angle >= 360)
+ m_flags |= RENDER_CONE;
+ else
+ m_flags &= ~RENDER_CONE;
+
+ m_cone_angle_inner = angle * M_PI / 360.0f;
+
+ return true;
+}
+
+float SoftwareDevice::SoftwareHandle::getConeVolumeOuter()
+{
+ if(!m_status)
+ return std::numeric_limits<float>::quiet_NaN();
+
+ return m_cone_volume_outer;
+}
+
+bool SoftwareDevice::SoftwareHandle::setConeVolumeOuter(float volume)
+{
+ if(!m_status)
+ return false;
+
+ m_cone_volume_outer = volume;
+
+ return true;
+}
+
+/******************************************************************************/
+/**************************** IDevice Code ************************************/
+/******************************************************************************/
+
+void SoftwareDevice::create()
+{
+ m_playback = false;
+ m_volume = 1.0f;
+ m_mixer = std::shared_ptr<Mixer>(new Mixer(m_specs));
+ m_speed_of_sound = 343.3f;
+ m_doppler_factor = 1.0f;
+ m_distance_model = DISTANCE_MODEL_INVERSE_CLAMPED;
+ m_flags = 0;
+ m_quality = false;
+}
+
+void SoftwareDevice::destroy()
+{
+ if(m_playback)
+ playing(m_playback = false);
+
+ while(!m_playingSounds.empty())
+ m_playingSounds.front()->stop();
+
+ while(!m_pausedSounds.empty())
+ m_pausedSounds.front()->stop();
+}
+
+void SoftwareDevice::mix(data_t* buffer, int length)
+{
+ m_buffer.assureSize(length * AUD_SAMPLE_SIZE(m_specs));
+
+ std::lock_guard<std::recursive_mutex> lock(m_mutex);
+
+ {
+ std::shared_ptr<SoftwareDevice::SoftwareHandle> sound;
+ int len;
+ int pos;
+ bool eos;
+ std::list<std::shared_ptr<SoftwareDevice::SoftwareHandle> > stopSounds;
+ std::list<std::shared_ptr<SoftwareDevice::SoftwareHandle> > pauseSounds;
+ sample_t* buf = m_buffer.getBuffer();
+
+ m_mixer->clear(length);
+
+ // for all sounds
+ for(auto& sound : m_playingSounds)
+ {
+ // get the buffer from the source
+ pos = 0;
+ len = length;
+
+ // update 3D Info
+ sound->update();
+
+ try
+ {
+ sound->m_reader->read(len, eos, buf);
+
+ // in case of looping
+ while(pos + len < length && sound->m_loopcount && eos)
+ {
+ m_mixer->mix(buf, pos, len, sound->m_volume, sound->m_old_volume);
+
+ pos += len;
+
+ if(sound->m_loopcount > 0)
+ sound->m_loopcount--;
+
+ sound->m_reader->seek(0);
+
+ len = length - pos;
+ sound->m_reader->read(len, eos, buf);
+
+ // prevent endless loop
+ if(!len)
+ break;
+ }
+ }
+ catch(Exception& e)
+ {
+ len = 0;
+ std::cerr << "Caught exception while reading sound data during playback with software mixing: " << e.getMessage() << std::endl;
+ }
+
+ m_mixer->mix(buf, pos, len, sound->m_volume, sound->m_old_volume);
+
+ // in case the end of the sound is reached
+ if(eos && !sound->m_loopcount)
+ {
+ if(sound->m_stop)
+ sound->m_stop(sound->m_stop_data);
+
+ if(sound->m_keep)
+ pauseSounds.push_back(sound);
+ else
+ stopSounds.push_back(sound);
+ }
+ }
+
+ // superpose
+ m_mixer->read(buffer, m_volume);
+
+ // cleanup
+ for(auto& sound : pauseSounds)
+ sound->pause(true);
+
+ for(auto& sound : stopSounds)
+ sound->stop();
+
+ pauseSounds.clear();
+ stopSounds.clear();
+ }
+}
+
+void SoftwareDevice::setPanning(IHandle* handle, float pan)
+{
+ SoftwareDevice::SoftwareHandle* h = dynamic_cast<SoftwareDevice::SoftwareHandle*>(handle);
+ h->m_user_pan = pan;
+}
+
+void SoftwareDevice::setQuality(bool quality)
+{
+ m_quality = quality;
+}
+
+void SoftwareDevice::setSpecs(Specs specs)
+{
+ m_specs.specs = specs;
+ m_mixer->setSpecs(specs);
+
+ for(auto& sound : m_playingSounds)
+ {
+ sound->setSpecs(specs);
+ }
+}
+
+SoftwareDevice::SoftwareDevice()
+{
+}
+
+DeviceSpecs SoftwareDevice::getSpecs() const
+{
+ return m_specs;
+}
+
+std::shared_ptr<IHandle> SoftwareDevice::play(std::shared_ptr<IReader> reader, bool keep)
+{
+ // prepare the reader
+ // pitch
+
+ std::shared_ptr<PitchReader> pitch = std::shared_ptr<PitchReader>(new PitchReader(reader, 1));
+ reader = std::shared_ptr<IReader>(pitch);
+
+ std::shared_ptr<ResampleReader> resampler;
+
+ // resample
+ if(m_quality)
+ resampler = std::shared_ptr<ResampleReader>(new JOSResampleReader(reader, m_specs.rate));
+ else
+ resampler = std::shared_ptr<ResampleReader>(new LinearResampleReader(reader, m_specs.rate));
+ reader = std::shared_ptr<IReader>(resampler);
+
+ // rechannel
+ std::shared_ptr<ChannelMapperReader> mapper = std::shared_ptr<ChannelMapperReader>(new ChannelMapperReader(reader, m_specs.channels));
+ reader = std::shared_ptr<IReader>(mapper);
+
+ if(!reader.get())
+ return std::shared_ptr<IHandle>();
+
+ // play sound
+ std::shared_ptr<SoftwareDevice::SoftwareHandle> sound = std::shared_ptr<SoftwareDevice::SoftwareHandle>(new SoftwareDevice::SoftwareHandle(this, reader, pitch, resampler, mapper, keep));
+
+ std::lock_guard<std::recursive_mutex> lock(m_mutex);
+
+ m_playingSounds.push_back(sound);
+
+ if(!m_playback)
+ playing(m_playback = true);
+
+ return std::shared_ptr<IHandle>(sound);
+}
+
+std::shared_ptr<IHandle> SoftwareDevice::play(std::shared_ptr<ISound> sound, bool keep)
+{
+ return play(sound->createReader(), keep);
+}
+
+void SoftwareDevice::stopAll()
+{
+ std::lock_guard<std::recursive_mutex> lock(m_mutex);
+
+ while(!m_playingSounds.empty())
+ m_playingSounds.front()->stop();
+
+ while(!m_pausedSounds.empty())
+ m_pausedSounds.front()->stop();
+}
+
+void SoftwareDevice::lock()
+{
+ m_mutex.lock();
+}
+
+void SoftwareDevice::unlock()
+{
+ m_mutex.unlock();
+}
+
+float SoftwareDevice::getVolume() const
+{
+ return m_volume;
+}
+
+void SoftwareDevice::setVolume(float volume)
+{
+ m_volume = volume;
+}
+
+ISynchronizer* SoftwareDevice::getSynchronizer()
+{
+ return &m_synchronizer;
+}
+
+/******************************************************************************/
+/**************************** 3D Device Code **********************************/
+/******************************************************************************/
+
+Vector3 SoftwareDevice::getListenerLocation() const
+{
+ return m_location;
+}
+
+void SoftwareDevice::setListenerLocation(const Vector3& location)
+{
+ m_location = location;
+}
+
+Vector3 SoftwareDevice::getListenerVelocity() const
+{
+ return m_velocity;
+}
+
+void SoftwareDevice::setListenerVelocity(const Vector3& velocity)
+{
+ m_velocity = velocity;
+}
+
+Quaternion SoftwareDevice::getListenerOrientation() const
+{
+ return m_orientation;
+}
+
+void SoftwareDevice::setListenerOrientation(const Quaternion& orientation)
+{
+ m_orientation = orientation;
+}
+
+float SoftwareDevice::getSpeedOfSound() const
+{
+ return m_speed_of_sound;
+}
+
+void SoftwareDevice::setSpeedOfSound(float speed)
+{
+ m_speed_of_sound = speed;
+}
+
+float SoftwareDevice::getDopplerFactor() const
+{
+ return m_doppler_factor;
+}
+
+void SoftwareDevice::setDopplerFactor(float factor)
+{
+ m_doppler_factor = factor;
+ if(factor == 0)
+ m_flags |= RENDER_DOPPLER;
+ else
+ m_flags &= ~RENDER_DOPPLER;
+}
+
+DistanceModel SoftwareDevice::getDistanceModel() const
+{
+ return m_distance_model;
+}
+
+void SoftwareDevice::setDistanceModel(DistanceModel model)
+{
+ m_distance_model = model;
+ if(model == DISTANCE_MODEL_INVALID)
+ m_flags |= RENDER_DISTANCE;
+ else
+ m_flags &= ~RENDER_DISTANCE;
+}
+
+AUD_NAMESPACE_END