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')
-rw-r--r--extern/audaspace/src/devices/DefaultSynchronizer.cpp49
-rw-r--r--extern/audaspace/src/devices/DeviceManager.cpp117
-rw-r--r--extern/audaspace/src/devices/NULLDevice.cpp193
-rw-r--r--extern/audaspace/src/devices/ReadDevice.cpp69
-rw-r--r--extern/audaspace/src/devices/SoftwareDevice.cpp989
5 files changed, 1417 insertions, 0 deletions
diff --git a/extern/audaspace/src/devices/DefaultSynchronizer.cpp b/extern/audaspace/src/devices/DefaultSynchronizer.cpp
new file mode 100644
index 00000000000..aa8945dadaa
--- /dev/null
+++ b/extern/audaspace/src/devices/DefaultSynchronizer.cpp
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * 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/DefaultSynchronizer.h"
+#include "devices/IHandle.h"
+
+AUD_NAMESPACE_BEGIN
+
+void DefaultSynchronizer::seek(std::shared_ptr<IHandle> handle, float time)
+{
+ handle->seek(time);
+}
+
+float DefaultSynchronizer::getPosition(std::shared_ptr<IHandle> handle)
+{
+ return handle->getPosition();
+}
+
+void DefaultSynchronizer::play()
+{
+}
+
+void DefaultSynchronizer::stop()
+{
+}
+
+void DefaultSynchronizer::setSyncCallback(ISynchronizer::syncFunction function, void* data)
+{
+}
+
+int DefaultSynchronizer::isPlaying()
+{
+ return -1;
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/devices/DeviceManager.cpp b/extern/audaspace/src/devices/DeviceManager.cpp
new file mode 100644
index 00000000000..2ebc3d58c86
--- /dev/null
+++ b/extern/audaspace/src/devices/DeviceManager.cpp
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * 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/DeviceManager.h"
+#include "devices/IDeviceFactory.h"
+#include "devices/IDevice.h"
+#include "devices/I3DDevice.h"
+
+#include <limits>
+#include <string>
+#include <algorithm>
+
+AUD_NAMESPACE_BEGIN
+
+std::unordered_map<std::string, std::shared_ptr<IDeviceFactory>> DeviceManager::m_factories;
+std::shared_ptr<IDevice> DeviceManager::m_device;
+
+void DeviceManager::registerDevice(std::string name, std::shared_ptr<IDeviceFactory> factory)
+{
+ m_factories[name] = factory;
+}
+
+std::shared_ptr<IDeviceFactory> DeviceManager::getDeviceFactory(std::string name)
+{
+ return m_factories[name];
+}
+
+std::shared_ptr<IDeviceFactory> DeviceManager::getDefaultDeviceFactory()
+{
+ int min = std::numeric_limits<int>::min();
+
+ std::shared_ptr<IDeviceFactory> result;
+
+ for(auto factory : m_factories)
+ {
+ if(factory.second->getPriority() >= min)
+ {
+ result = factory.second;
+ min = result->getPriority();
+ }
+ }
+
+ return result;
+}
+
+void DeviceManager::setDevice(std::shared_ptr<IDevice> device)
+{
+ m_device = device;
+}
+
+void DeviceManager::openDevice(std::string name)
+{
+ setDevice(getDeviceFactory(name)->openDevice());
+}
+
+void DeviceManager::openDefaultDevice()
+{
+ setDevice(getDefaultDeviceFactory()->openDevice());
+}
+
+void DeviceManager::releaseDevice()
+{
+ m_device = nullptr;
+}
+
+std::shared_ptr<IDevice> DeviceManager::getDevice()
+{
+ return m_device;
+}
+
+std::shared_ptr<I3DDevice> DeviceManager::get3DDevice()
+{
+ return std::dynamic_pointer_cast<I3DDevice>(m_device);
+}
+
+std::vector<std::string> DeviceManager::getAvailableDeviceNames()
+{
+ struct DeviceNamePriority {
+ std::string name;
+ int priority;
+ };
+
+ std::vector<DeviceNamePriority> devices;
+ devices.reserve(m_factories.size());
+
+ for(const auto& pair : m_factories)
+ devices.push_back({pair.first, pair.second->getPriority()});
+
+ auto sort = [](const DeviceNamePriority& lhs, const DeviceNamePriority& rhs){
+ return lhs.priority > rhs.priority;
+ };
+
+ std::sort(devices.begin(), devices.end(), sort);
+
+ std::vector<std::string> names;
+ names.reserve(devices.size());
+
+ for(const auto& device : devices)
+ names.push_back(device.name);
+
+ return names;
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/devices/NULLDevice.cpp b/extern/audaspace/src/devices/NULLDevice.cpp
new file mode 100644
index 00000000000..a82537f43b2
--- /dev/null
+++ b/extern/audaspace/src/devices/NULLDevice.cpp
@@ -0,0 +1,193 @@
+/*******************************************************************************
+ * 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/NULLDevice.h"
+#include "devices/DeviceManager.h"
+#include "devices/IDeviceFactory.h"
+
+#include <limits>
+#include <string>
+
+AUD_NAMESPACE_BEGIN
+
+NULLDevice::NULLHandle::NULLHandle()
+{
+}
+
+bool NULLDevice::NULLHandle::pause()
+{
+ return false;
+}
+
+bool NULLDevice::NULLHandle::resume()
+{
+ return false;
+}
+
+bool NULLDevice::NULLHandle::stop()
+{
+ return false;
+}
+
+bool NULLDevice::NULLHandle::getKeep()
+{
+ return false;
+}
+
+bool NULLDevice::NULLHandle::setKeep(bool keep)
+{
+ return false;
+}
+
+bool NULLDevice::NULLHandle::seek(float position)
+{
+ return false;
+}
+
+float NULLDevice::NULLHandle::getPosition()
+{
+ return std::numeric_limits<float>::quiet_NaN();
+}
+
+Status NULLDevice::NULLHandle::getStatus()
+{
+ return STATUS_INVALID;
+}
+
+float NULLDevice::NULLHandle::getVolume()
+{
+ return std::numeric_limits<float>::quiet_NaN();
+}
+
+bool NULLDevice::NULLHandle::setVolume(float volume)
+{
+ return false;
+}
+
+float NULLDevice::NULLHandle::getPitch()
+{
+ return std::numeric_limits<float>::quiet_NaN();
+}
+
+bool NULLDevice::NULLHandle::setPitch(float pitch)
+{
+ return false;
+}
+
+int NULLDevice::NULLHandle::getLoopCount()
+{
+ return 0;
+}
+
+bool NULLDevice::NULLHandle::setLoopCount(int count)
+{
+ return false;
+}
+
+bool NULLDevice::NULLHandle::setStopCallback(stopCallback callback, void* data)
+{
+ return false;
+}
+
+NULLDevice::NULLDevice()
+{
+}
+
+NULLDevice::~NULLDevice()
+{
+}
+
+DeviceSpecs NULLDevice::getSpecs() const
+{
+ DeviceSpecs specs;
+ specs.channels = CHANNELS_INVALID;
+ specs.format = FORMAT_INVALID;
+ specs.rate = RATE_INVALID;
+ return specs;
+}
+
+std::shared_ptr<IHandle> NULLDevice::play(std::shared_ptr<IReader> reader, bool keep)
+{
+ return std::shared_ptr<IHandle>(new NULLHandle());
+}
+
+std::shared_ptr<IHandle> NULLDevice::play(std::shared_ptr<ISound> sound, bool keep)
+{
+ return std::shared_ptr<IHandle>(new NULLHandle());
+}
+
+void NULLDevice::stopAll()
+{
+}
+
+void NULLDevice::lock()
+{
+}
+
+void NULLDevice::unlock()
+{
+}
+
+float NULLDevice::getVolume() const
+{
+ return std::numeric_limits<float>::quiet_NaN();
+}
+
+void NULLDevice::setVolume(float volume)
+{
+}
+
+ISynchronizer* NULLDevice::getSynchronizer()
+{
+ return nullptr;
+}
+
+class NULLDeviceFactory : public IDeviceFactory
+{
+public:
+ NULLDeviceFactory()
+ {
+ }
+
+ virtual std::shared_ptr<IDevice> openDevice()
+ {
+ return std::shared_ptr<IDevice>(new NULLDevice());
+ }
+
+ virtual int getPriority()
+ {
+ return std::numeric_limits<int>::min();
+ }
+
+ virtual void setSpecs(DeviceSpecs specs)
+ {
+ }
+
+ virtual void setBufferSize(int buffersize)
+ {
+ }
+
+ virtual void setName(std::string name)
+ {
+ }
+};
+
+void NULLDevice::registerPlugin()
+{
+ DeviceManager::registerDevice("Null", std::shared_ptr<IDeviceFactory>(new NULLDeviceFactory));
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/devices/ReadDevice.cpp b/extern/audaspace/src/devices/ReadDevice.cpp
new file mode 100644
index 00000000000..487fee1f59a
--- /dev/null
+++ b/extern/audaspace/src/devices/ReadDevice.cpp
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * 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/ReadDevice.h"
+#include "IReader.h"
+
+#include <cstring>
+
+AUD_NAMESPACE_BEGIN
+
+ReadDevice::ReadDevice(DeviceSpecs specs) :
+ m_playing(false)
+{
+ m_specs = specs;
+
+ create();
+}
+
+ReadDevice::ReadDevice(Specs specs) :
+ m_playing(false)
+{
+ m_specs.specs = specs;
+ m_specs.format = FORMAT_FLOAT32;
+
+ create();
+}
+
+ReadDevice::~ReadDevice()
+{
+ destroy();
+}
+
+bool ReadDevice::read(data_t* buffer, int length)
+{
+ if(m_playing)
+ mix(buffer, length);
+ else
+ if(m_specs.format == FORMAT_U8)
+ std::memset(buffer, 0x80, length * AUD_DEVICE_SAMPLE_SIZE(m_specs));
+ else
+ std::memset(buffer, 0, length * AUD_DEVICE_SAMPLE_SIZE(m_specs));
+ return m_playing;
+}
+
+void ReadDevice::changeSpecs(Specs specs)
+{
+ if(!AUD_COMPARE_SPECS(specs, m_specs.specs))
+ setSpecs(specs);
+}
+
+void ReadDevice::playing(bool playing)
+{
+ m_playing = playing;
+}
+
+AUD_NAMESPACE_END
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