diff options
Diffstat (limited to 'extern/audaspace/src/sequence')
-rw-r--r-- | extern/audaspace/src/sequence/AnimateableProperty.cpp | 217 | ||||
-rw-r--r-- | extern/audaspace/src/sequence/Double.cpp | 35 | ||||
-rw-r--r-- | extern/audaspace/src/sequence/DoubleReader.cpp | 102 | ||||
-rw-r--r-- | extern/audaspace/src/sequence/PingPong.cpp | 36 | ||||
-rw-r--r-- | extern/audaspace/src/sequence/Sequence.cpp | 113 | ||||
-rw-r--r-- | extern/audaspace/src/sequence/SequenceData.cpp | 172 | ||||
-rw-r--r-- | extern/audaspace/src/sequence/SequenceEntry.cpp | 256 | ||||
-rw-r--r-- | extern/audaspace/src/sequence/SequenceHandle.cpp | 253 | ||||
-rw-r--r-- | extern/audaspace/src/sequence/SequenceHandle.h | 117 | ||||
-rw-r--r-- | extern/audaspace/src/sequence/SequenceReader.cpp | 198 | ||||
-rw-r--r-- | extern/audaspace/src/sequence/Superpose.cpp | 35 | ||||
-rw-r--r-- | extern/audaspace/src/sequence/SuperposeReader.cpp | 95 |
12 files changed, 1629 insertions, 0 deletions
diff --git a/extern/audaspace/src/sequence/AnimateableProperty.cpp b/extern/audaspace/src/sequence/AnimateableProperty.cpp new file mode 100644 index 00000000000..306ba8e07f5 --- /dev/null +++ b/extern/audaspace/src/sequence/AnimateableProperty.cpp @@ -0,0 +1,217 @@ +/******************************************************************************* + * 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 "sequence/AnimateableProperty.h" + +#include <cstring> +#include <cmath> +#include <mutex> + +AUD_NAMESPACE_BEGIN + +AnimateableProperty::AnimateableProperty(int count) : + Buffer(count * sizeof(float)), m_count(count), m_isAnimated(false) +{ + std::memset(getBuffer(), 0, count * sizeof(float)); +} + +AnimateableProperty::AnimateableProperty(int count, float value) : + Buffer(count * sizeof(float)), m_count(count), m_isAnimated(false) +{ + sample_t* buf = getBuffer(); + + for(int i = 0; i < count; i++) + buf[i] = value; +} + +void AnimateableProperty::updateUnknownCache(int start, int end) +{ + float* buf = getBuffer(); + + // we could do a better interpolation than zero order, but that doesn't work with Blender's animation system + // as frames are only written when changing, so to support jumps, we need zero order interpolation here. + for(int i = start; i <= end; i++) + std::memcpy(buf + i * m_count, buf + (start - 1) * m_count, m_count * sizeof(float)); +} + +AnimateableProperty::~AnimateableProperty() +{ +} + +int AnimateableProperty::getCount() const +{ + return m_count; +} + +void AnimateableProperty::write(const float* data) +{ + std::lock_guard<std::recursive_mutex> lock(m_mutex); + + m_isAnimated = false; + m_unknown.clear(); + std::memcpy(getBuffer(), data, m_count * sizeof(float)); +} + +void AnimateableProperty::write(const float* data, int position, int count) +{ + std::lock_guard<std::recursive_mutex> lock(m_mutex); + + int pos = getSize() / (sizeof(float) * m_count); + + if(!m_isAnimated) + pos = 0; + + m_isAnimated = true; + + assureSize((count + position) * m_count * sizeof(float), true); + + float* buf = getBuffer(); + + std::memcpy(buf + position * m_count, data, count * m_count * sizeof(float)); + + // have to fill up space between? + if(pos < position) + { + m_unknown.push_back(Unknown(pos, position - 1)); + + // if the buffer was not animated before, we copy the previous static value + if(pos == 0) + pos = 1; + + updateUnknownCache(pos, position - 1); + } + // otherwise it's not at the end, let's check if some unknown part got filled + else + { + bool erased = false; + + for(auto it = m_unknown.begin(); it != m_unknown.end(); erased ? it : it++) + { + erased = false; + + // unknown area before position + if(it->end < position) + continue; + + // we're after the new area, let's stop + if(it->start >= position + count) + break; + + // we have an intersection, now 4 cases: + // the start is included + if(position <= it->start) + { + // the end is included + if(position + count > it->end) + { + // simply delete + it = m_unknown.erase(it); + erased = true; + } + // the end is excluded, a second part remains + else + { + // update second part + it->start = position + count; + updateUnknownCache(it->start, it->end); + break; + } + } + // start is excluded, a first part remains + else + { + // the end is included + if(position + count > it->end) + { + // update first part + it->end = position - 1; + } + // the end is excluded, a second part remains + else + { + // add another item and update both parts + m_unknown.insert(it, Unknown(it->start, position - 1)); + it->start = position + count; + updateUnknownCache(it->start, it->end); + } + } + } + } +} + +void AnimateableProperty::read(float position, float* out) +{ + std::lock_guard<std::recursive_mutex> lock(m_mutex); + + if(!m_isAnimated) + { + std::memcpy(out, getBuffer(), m_count * sizeof(float)); + return; + } + + int last = getSize() / (sizeof(float) * m_count) - 1; + float t = position - std::floor(position); + + if(position >= last) + { + position = last; + t = 0; + } + + if(t == 0) + { + std::memcpy(out, getBuffer() + int(std::floor(position)) * m_count, m_count * sizeof(float)); + } + else + { + int pos = int(std::floor(position)) * m_count; + float t2 = t * t; + float t3 = t2 * t; + float m0, m1; + float* p0; + float* p1 = getBuffer() + pos; + float* p2; + float* p3; + last *= m_count; + + if(pos == 0) + p0 = p1; + else + p0 = p1 - m_count; + + p2 = p1 + m_count; + if(pos + m_count == last) + p3 = p2; + else + p3 = p2 + m_count; + + for(int i = 0; i < m_count; i++) + { + m0 = (p2[i] - p0[i]) / 2.0f; + m1 = (p3[i] - p1[i]) / 2.0f; + + out[i] = (2 * t3 - 3 * t2 + 1) * p0[i] + (-2 * t3 + 3 * t2) * p1[i] + + (t3 - 2 * t2 + t) * m0 + (t3 - t2) * m1; + } + } +} + +bool AnimateableProperty::isAnimated() const +{ + return m_isAnimated; +} + +AUD_NAMESPACE_END diff --git a/extern/audaspace/src/sequence/Double.cpp b/extern/audaspace/src/sequence/Double.cpp new file mode 100644 index 00000000000..1086be84a11 --- /dev/null +++ b/extern/audaspace/src/sequence/Double.cpp @@ -0,0 +1,35 @@ +/******************************************************************************* + * 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 "sequence/Double.h" +#include "sequence/DoubleReader.h" + +AUD_NAMESPACE_BEGIN + +Double::Double(std::shared_ptr<ISound> sound1, std::shared_ptr<ISound> sound2) : + m_sound1(sound1), m_sound2(sound2) +{ +} + +std::shared_ptr<IReader> Double::createReader() +{ + std::shared_ptr<IReader> reader1 = m_sound1->createReader(); + std::shared_ptr<IReader> reader2 = m_sound2->createReader(); + + return std::shared_ptr<IReader>(new DoubleReader(reader1, reader2)); +} + +AUD_NAMESPACE_END diff --git a/extern/audaspace/src/sequence/DoubleReader.cpp b/extern/audaspace/src/sequence/DoubleReader.cpp new file mode 100644 index 00000000000..33ab34ce366 --- /dev/null +++ b/extern/audaspace/src/sequence/DoubleReader.cpp @@ -0,0 +1,102 @@ +/******************************************************************************* + * 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 "sequence/DoubleReader.h" + +#include <cstring> + +AUD_NAMESPACE_BEGIN + +DoubleReader::DoubleReader(std::shared_ptr<IReader> reader1, std::shared_ptr<IReader> reader2) : + m_reader1(reader1), m_reader2(reader2), m_finished1(false) +{ + Specs s1, s2; + s1 = reader1->getSpecs(); + s2 = reader2->getSpecs(); +} + +DoubleReader::~DoubleReader() +{ +} + +bool DoubleReader::isSeekable() const +{ + return m_reader1->isSeekable() && m_reader2->isSeekable(); +} + +void DoubleReader::seek(int position) +{ + m_reader1->seek(position); + + int pos1 = m_reader1->getPosition(); + + if((m_finished1 = (pos1 < position))) + m_reader2->seek(position - pos1); + else + m_reader2->seek(0); +} + +int DoubleReader::getLength() const +{ + int len1 = m_reader1->getLength(); + int len2 = m_reader2->getLength(); + if(len1 < 0 || len2 < 0) + return -1; + return len1 + len2; +} + +int DoubleReader::getPosition() const +{ + return m_reader1->getPosition() + m_reader2->getPosition(); +} + +Specs DoubleReader::getSpecs() const +{ + return m_finished1 ? m_reader1->getSpecs() : m_reader2->getSpecs(); +} + +void DoubleReader::read(int& length, bool& eos, sample_t* buffer) +{ + eos = false; + + if(!m_finished1) + { + int len = length; + + m_reader1->read(len, m_finished1, buffer); + + if(len < length) + { + Specs specs1, specs2; + specs1 = m_reader1->getSpecs(); + specs2 = m_reader2->getSpecs(); + if(AUD_COMPARE_SPECS(specs1, specs2)) + { + int len2 = length - len; + m_reader2->read(len2, eos, buffer + specs1.channels * len); + length = len + len2; + } + else + length = len; + } + } + else + { + m_reader2->read(length, eos, buffer); + } +} + +AUD_NAMESPACE_END diff --git a/extern/audaspace/src/sequence/PingPong.cpp b/extern/audaspace/src/sequence/PingPong.cpp new file mode 100644 index 00000000000..19bfb10fc2d --- /dev/null +++ b/extern/audaspace/src/sequence/PingPong.cpp @@ -0,0 +1,36 @@ +/******************************************************************************* + * 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 "sequence/PingPong.h" +#include "sequence/DoubleReader.h" +#include "fx/ReverseReader.h" + +AUD_NAMESPACE_BEGIN + +PingPong::PingPong(std::shared_ptr<ISound> sound) : + Effect(sound) +{ +} + +std::shared_ptr<IReader> PingPong::createReader() +{ + std::shared_ptr<IReader> reader = getReader(); + std::shared_ptr<IReader> reader2 = std::shared_ptr<IReader>(new ReverseReader(getReader())); + + return std::shared_ptr<IReader>(new DoubleReader(reader, reader2)); +} + +AUD_NAMESPACE_END diff --git a/extern/audaspace/src/sequence/Sequence.cpp b/extern/audaspace/src/sequence/Sequence.cpp new file mode 100644 index 00000000000..eaec4d84ae1 --- /dev/null +++ b/extern/audaspace/src/sequence/Sequence.cpp @@ -0,0 +1,113 @@ +/******************************************************************************* + * 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 "sequence/Sequence.h" +#include "sequence/SequenceReader.h" +#include "sequence/SequenceData.h" + +AUD_NAMESPACE_BEGIN + +Sequence::Sequence(Specs specs, float fps, bool muted) +{ + m_sequence = std::shared_ptr<SequenceData>(new SequenceData(specs, fps, muted)); +} + +Specs Sequence::getSpecs() +{ + return m_sequence->getSpecs(); +} + +void Sequence::setSpecs(Specs specs) +{ + m_sequence->setSpecs(specs); +} + +float Sequence::getFPS() const +{ + return m_sequence->getFPS(); +} + +void Sequence::setFPS(float fps) +{ + m_sequence->setFPS(fps); +} + +void Sequence::mute(bool muted) +{ + m_sequence->mute(muted); +} + +bool Sequence::isMuted() const +{ + return m_sequence->isMuted(); +} + +float Sequence::getSpeedOfSound() const +{ + return m_sequence->getSpeedOfSound(); +} + +void Sequence::setSpeedOfSound(float speed) +{ + m_sequence->setSpeedOfSound(speed); +} + +float Sequence::getDopplerFactor() const +{ + return m_sequence->getDopplerFactor(); +} + +void Sequence::setDopplerFactor(float factor) +{ + m_sequence->setDopplerFactor(factor); +} + +DistanceModel Sequence::getDistanceModel() const +{ + return m_sequence->getDistanceModel(); +} + +void Sequence::setDistanceModel(DistanceModel model) +{ + m_sequence->setDistanceModel(model); +} + +AnimateableProperty* Sequence::getAnimProperty(AnimateablePropertyType type) +{ + return m_sequence->getAnimProperty(type); +} + +std::shared_ptr<SequenceEntry> Sequence::add(std::shared_ptr<ISound> sound, float begin, float end, float skip) +{ + return m_sequence->add(sound, begin, end, skip); +} + +void Sequence::remove(std::shared_ptr<SequenceEntry> entry) +{ + m_sequence->remove(entry); +} + +std::shared_ptr<IReader> Sequence::createQualityReader() +{ + return std::shared_ptr<IReader>(new SequenceReader(m_sequence, true)); +} + +std::shared_ptr<IReader> Sequence::createReader() +{ + return std::shared_ptr<IReader>(new SequenceReader(m_sequence)); +} + +AUD_NAMESPACE_END diff --git a/extern/audaspace/src/sequence/SequenceData.cpp b/extern/audaspace/src/sequence/SequenceData.cpp new file mode 100644 index 00000000000..fb920acc1a8 --- /dev/null +++ b/extern/audaspace/src/sequence/SequenceData.cpp @@ -0,0 +1,172 @@ +/******************************************************************************* + * 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 "sequence/SequenceData.h" +#include "sequence/SequenceReader.h" +#include "sequence/SequenceEntry.h" + +#include <mutex> + +AUD_NAMESPACE_BEGIN + +SequenceData::SequenceData(Specs specs, float fps, bool muted) : + m_specs(specs), + m_status(0), + m_entry_status(0), + m_id(0), + m_muted(muted), + m_fps(fps), + m_speed_of_sound(343.3f), + m_doppler_factor(1), + m_distance_model(DISTANCE_MODEL_INVERSE_CLAMPED), + m_volume(1, 1.0f), + m_location(3), + m_orientation(4) +{ + Quaternion q; + m_orientation.write(q.get()); + float f = 1; + m_volume.write(&f); +} + +SequenceData::~SequenceData() +{ +} + +void SequenceData::lock() +{ + m_mutex.lock(); +} + +void SequenceData::unlock() +{ + m_mutex.unlock(); +} + +Specs SequenceData::getSpecs() +{ + std::lock_guard<std::recursive_mutex> lock(m_mutex); + + return m_specs; +} + +void SequenceData::setSpecs(Specs specs) +{ + std::lock_guard<std::recursive_mutex> lock(m_mutex); + + m_specs = specs; + m_status++; +} + +float SequenceData::getFPS() const +{ + return m_fps; +} + +void SequenceData::setFPS(float fps) +{ + std::lock_guard<std::recursive_mutex> lock(m_mutex); + + m_fps = fps; +} + +void SequenceData::mute(bool muted) +{ + std::lock_guard<std::recursive_mutex> lock(m_mutex); + + m_muted = muted; +} + +bool SequenceData::isMuted() const +{ + return m_muted; +} + +float SequenceData::getSpeedOfSound() const +{ + return m_speed_of_sound; +} + +void SequenceData::setSpeedOfSound(float speed) +{ + std::lock_guard<std::recursive_mutex> lock(m_mutex); + + m_speed_of_sound = speed; + m_status++; +} + +float SequenceData::getDopplerFactor() const +{ + return m_doppler_factor; +} + +void SequenceData::setDopplerFactor(float factor) +{ + std::lock_guard<std::recursive_mutex> lock(m_mutex); + + m_doppler_factor = factor; + m_status++; +} + +DistanceModel SequenceData::getDistanceModel() const +{ + return m_distance_model; +} + +void SequenceData::setDistanceModel(DistanceModel model) +{ + std::lock_guard<std::recursive_mutex> lock(m_mutex); + + m_distance_model = model; + m_status++; +} + +AnimateableProperty* SequenceData::getAnimProperty(AnimateablePropertyType type) +{ + switch(type) + { + case AP_VOLUME: + return &m_volume; + case AP_LOCATION: + return &m_location; + case AP_ORIENTATION: + return &m_orientation; + default: + return nullptr; + } +} + +std::shared_ptr<SequenceEntry> SequenceData::add(std::shared_ptr<ISound> sound, float begin, float end, float skip) +{ + std::lock_guard<std::recursive_mutex> lock(m_mutex); + + std::shared_ptr<SequenceEntry> entry = std::shared_ptr<SequenceEntry>(new SequenceEntry(sound, begin, end, skip, m_id++)); + + m_entries.push_back(entry); + m_entry_status++; + + return entry; +} + +void SequenceData::remove(std::shared_ptr<SequenceEntry> entry) +{ + std::lock_guard<std::recursive_mutex> lock(m_mutex); + + m_entries.remove(entry); + m_entry_status++; +} + +AUD_NAMESPACE_END diff --git a/extern/audaspace/src/sequence/SequenceEntry.cpp b/extern/audaspace/src/sequence/SequenceEntry.cpp new file mode 100644 index 00000000000..de538199d7d --- /dev/null +++ b/extern/audaspace/src/sequence/SequenceEntry.cpp @@ -0,0 +1,256 @@ +/******************************************************************************* + * 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 "sequence/SequenceEntry.h" +#include "sequence/SequenceReader.h" + +#include <limits> +#include <mutex> + +AUD_NAMESPACE_BEGIN + +SequenceEntry::SequenceEntry(std::shared_ptr<ISound> sound, float begin, float end, float skip, int id) : + m_status(0), + m_pos_status(1), + m_sound_status(0), + m_id(id), + m_sound(sound), + m_begin(begin), + m_end(end), + m_skip(skip), + m_muted(false), + 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(360), + m_cone_angle_inner(360), + m_cone_volume_outer(0), + m_volume(1, 1.0f), + m_pitch(1, 1.0f), + m_location(3), + m_orientation(4) +{ + Quaternion q; + m_orientation.write(q.get()); + float f = 1; + m_volume.write(&f); + m_pitch.write(&f); +} + +SequenceEntry::~SequenceEntry() +{ +} + +void SequenceEntry::lock() +{ + m_mutex.lock(); +} + +void SequenceEntry::unlock() +{ + m_mutex.unlock(); +} + +std::shared_ptr<ISound> SequenceEntry::getSound() +{ + std::lock_guard<std::recursive_mutex> lock(m_mutex); + return m_sound; +} + +void SequenceEntry::setSound(std::shared_ptr<ISound> sound) +{ + std::lock_guard<std::recursive_mutex> lock(m_mutex); + + if(m_sound.get() != sound.get()) + { + m_sound = sound; + m_sound_status++; + } +} + +void SequenceEntry::move(float begin, float end, float skip) +{ + std::lock_guard<std::recursive_mutex> lock(m_mutex); + + if(m_begin != begin || m_skip != skip || m_end != end) + { + m_begin = begin; + m_skip = skip; + m_end = end; + m_pos_status++; + } +} + +bool SequenceEntry::isMuted() +{ + return m_muted; +} + +void SequenceEntry::mute(bool mute) +{ + std::lock_guard<std::recursive_mutex> lock(m_mutex); + + m_muted = mute; +} + +int SequenceEntry::getID() const +{ + return m_id; +} + +AnimateableProperty* SequenceEntry::getAnimProperty(AnimateablePropertyType type) +{ + switch(type) + { + case AP_VOLUME: + return &m_volume; + case AP_PITCH: + return &m_pitch; + case AP_PANNING: + return &m_panning; + case AP_LOCATION: + return &m_location; + case AP_ORIENTATION: + return &m_orientation; + default: + return nullptr; + } +} + +bool SequenceEntry::isRelative() +{ + return m_relative; +} + +void SequenceEntry::setRelative(bool relative) +{ + std::lock_guard<std::recursive_mutex> lock(m_mutex); + + if(m_relative != relative) + { + m_relative = relative; + m_status++; + } +} + +float SequenceEntry::getVolumeMaximum() +{ + return m_volume_max; +} + +void SequenceEntry::setVolumeMaximum(float volume) +{ + std::lock_guard<std::recursive_mutex> lock(m_mutex); + + m_volume_max = volume; + m_status++; +} + +float SequenceEntry::getVolumeMinimum() +{ + return m_volume_min; +} + +void SequenceEntry::setVolumeMinimum(float volume) +{ + std::lock_guard<std::recursive_mutex> lock(m_mutex); + + m_volume_min = volume; + m_status++; +} + +float SequenceEntry::getDistanceMaximum() +{ + return m_distance_max; +} + +void SequenceEntry::setDistanceMaximum(float distance) +{ + std::lock_guard<std::recursive_mutex> lock(m_mutex); + + m_distance_max = distance; + m_status++; +} + +float SequenceEntry::getDistanceReference() +{ + return m_distance_reference; +} + +void SequenceEntry::setDistanceReference(float distance) +{ + std::lock_guard<std::recursive_mutex> lock(m_mutex); + + m_distance_reference = distance; + m_status++; +} + +float SequenceEntry::getAttenuation() +{ + return m_attenuation; +} + +void SequenceEntry::setAttenuation(float factor) +{ + std::lock_guard<std::recursive_mutex> lock(m_mutex); + + m_attenuation = factor; + m_status++; +} + +float SequenceEntry::getConeAngleOuter() +{ + return m_cone_angle_outer; +} + +void SequenceEntry::setConeAngleOuter(float angle) +{ + std::lock_guard<std::recursive_mutex> lock(m_mutex); + + m_cone_angle_outer = angle; + m_status++; +} + +float SequenceEntry::getConeAngleInner() +{ + return m_cone_angle_inner; +} + +void SequenceEntry::setConeAngleInner(float angle) +{ + std::lock_guard<std::recursive_mutex> lock(m_mutex); + + m_cone_angle_inner = angle; + m_status++; +} + +float SequenceEntry::getConeVolumeOuter() +{ + return m_cone_volume_outer; +} + +void SequenceEntry::setConeVolumeOuter(float volume) +{ + std::lock_guard<std::recursive_mutex> lock(m_mutex); + + m_cone_volume_outer = volume; + m_status++; +} + +AUD_NAMESPACE_END diff --git a/extern/audaspace/src/sequence/SequenceHandle.cpp b/extern/audaspace/src/sequence/SequenceHandle.cpp new file mode 100644 index 00000000000..140b1fbd94a --- /dev/null +++ b/extern/audaspace/src/sequence/SequenceHandle.cpp @@ -0,0 +1,253 @@ +/******************************************************************************* + * 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 "SequenceHandle.h" +#include "sequence/SequenceEntry.h" +#include "devices/ReadDevice.h" +#include "Exception.h" + +#include <mutex> + +#define KEEP_TIME 10 + +AUD_NAMESPACE_BEGIN + +void SequenceHandle::start() +{ + // we already tried to start, aborting + if(!m_valid) + return; + + // in case the sound is playing, we need to stop first + stop(); + + std::lock_guard<ILockable> lock(*m_entry); + + // let's try playing + if(m_entry->m_sound.get()) + { + try + { + m_handle = m_device.play(m_entry->m_sound, true); + m_3dhandle = std::dynamic_pointer_cast<I3DHandle>(m_handle); + } + catch(Exception&) + { + // handle stays invalid in case we get an exception + } + + // after starting we have to set the properties, so let's ensure that + m_status--; + } + + // if the sound could not be played, we invalidate + m_valid = m_handle.get(); +} + +bool SequenceHandle::updatePosition(float position) +{ + std::lock_guard<ILockable> lock(*m_entry); + + if(m_handle.get()) + { + // we currently have a handle, let's check where we are + if(position >= m_entry->m_end) + { + if(position >= m_entry->m_end + KEEP_TIME) + // far end, stopping + stop(); + else + { + // close end, just pausing + m_handle->pause(); + return true; + } + } + else if(position >= m_entry->m_begin) + { + // inside, resuming + m_handle->resume(); + return true; + } + else + { + if(position < m_entry->m_begin - KEEP_TIME) + // far beginning, stopping + stop(); + else + { + // close beginning, just pausing + m_handle->pause(); + return true; + } + } + } + else + { + // we don't have a handle, let's start if we should be playing + if(position >= m_entry->m_begin && position <= m_entry->m_end) + { + start(); + return m_valid; + } + } + + return false; +} + +SequenceHandle::SequenceHandle(std::shared_ptr<SequenceEntry> entry, ReadDevice& device) : + m_entry(entry), + m_valid(true), + m_status(0), + m_pos_status(0), + m_sound_status(0), + m_device(device) +{ +} + +SequenceHandle::~SequenceHandle() +{ + stop(); +} + +int SequenceHandle::compare(std::shared_ptr<SequenceEntry> entry) const +{ + if(m_entry->getID() < entry->getID()) + return -1; + else if(m_entry->getID() == entry->getID()) + return 0; + return 1; +} + +void SequenceHandle::stop() +{ + if(m_handle.get()) + m_handle->stop(); + m_handle = nullptr; + m_3dhandle = nullptr; +} + +void SequenceHandle::update(float position, float frame, float fps) +{ + if(m_sound_status != m_entry->m_sound_status) + { + // if a new sound has been set, it's possible to get valid again! + m_sound_status = m_entry->m_sound_status; + m_valid = true; + + // stop whatever sound has been playing + stop(); + + // seek starts and seeks to the correct position + if(!seek(position)) + // no handle, aborting + return; + } + else + { + if(!m_valid) + // invalid, aborting + return; + + if(m_handle.get()) + { + // we have a handle, let's update the position + if(!updatePosition(position)) + // lost handle, aborting + return; + } + else + { + // we don't have a handle, let's see if we can start + if(!seek(position)) + return; + } + } + + std::lock_guard<ILockable> lock(*m_entry); + if(m_pos_status != m_entry->m_pos_status) + { + m_pos_status = m_entry->m_pos_status; + + // position changed, need to seek + if(!seek(position)) + // lost handle, aborting + return; + } + + // so far everything alright and handle is there, let's keep going + + if(m_status != m_entry->m_status) + { + m_3dhandle->setRelative(m_entry->m_relative); + m_3dhandle->setVolumeMaximum(m_entry->m_volume_max); + m_3dhandle->setVolumeMinimum(m_entry->m_volume_min); + m_3dhandle->setDistanceMaximum(m_entry->m_distance_max); + m_3dhandle->setDistanceReference(m_entry->m_distance_reference); + m_3dhandle->setAttenuation(m_entry->m_attenuation); + m_3dhandle->setConeAngleOuter(m_entry->m_cone_angle_outer); + m_3dhandle->setConeAngleInner(m_entry->m_cone_angle_inner); + m_3dhandle->setConeVolumeOuter(m_entry->m_cone_volume_outer); + + m_status = m_entry->m_status; + } + + float value; + + m_entry->m_volume.read(frame, &value); + m_handle->setVolume(value); + m_entry->m_pitch.read(frame, &value); + m_handle->setPitch(value); + m_entry->m_panning.read(frame, &value); + SoftwareDevice::setPanning(m_handle.get(), value); + + Vector3 v, v2; + Quaternion q; + + m_entry->m_orientation.read(frame, q.get()); + m_3dhandle->setOrientation(q); + m_entry->m_location.read(frame, v.get()); + m_3dhandle->setLocation(v); + m_entry->m_location.read(frame + 1, v2.get()); + v2 -= v; + m_3dhandle->setVelocity(v2 * fps); + + if(m_entry->m_muted) + m_handle->setVolume(0); +} + +bool SequenceHandle::seek(float position) +{ + if(!m_valid) + // sound not valid, aborting + return false; + + if(!updatePosition(position)) + // no handle, aborting + return false; + + std::lock_guard<ILockable> lock(*m_entry); + float seekpos = position - m_entry->m_begin; + if(seekpos < 0) + seekpos = 0; + seekpos += m_entry->m_skip; + m_handle->setPitch(1.0f); + m_handle->seek(seekpos); + + return true; +} + +AUD_NAMESPACE_END diff --git a/extern/audaspace/src/sequence/SequenceHandle.h b/extern/audaspace/src/sequence/SequenceHandle.h new file mode 100644 index 00000000000..9a77489a8f8 --- /dev/null +++ b/extern/audaspace/src/sequence/SequenceHandle.h @@ -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. + ******************************************************************************/ + +#pragma once + +#include "Audaspace.h" + +#include <memory> + +AUD_NAMESPACE_BEGIN + +class ReadDevice; +class IHandle; +class I3DHandle; +class SequenceEntry; + +/** + * Represents a playing sequenced entry. + */ +class SequenceHandle +{ +private: + /// The entry this handle belongs to. + std::shared_ptr<SequenceEntry> m_entry; + + /// The handle in the read device. + std::shared_ptr<IHandle> m_handle; + + /// The 3D handle in the read device. + std::shared_ptr<I3DHandle> m_3dhandle; + + /// Whether the sound is playable. + bool m_valid; + + /// The last read status from the entry. + int m_status; + + /// The last position status from the entry. + int m_pos_status; + + /// The last sound status from the entry. + int m_sound_status; + + /// The read device this handle is played on. + ReadDevice& m_device; + + // delete copy constructor and operator= + SequenceHandle(const SequenceHandle&) = delete; + SequenceHandle& operator=(const SequenceHandle&) = delete; + + /** + * Starts playing back the handle. + */ + void start(); + + /** + * Updates the handle state depending on position. + * \param position Current playback position in seconds. + * \return Whether the handle is valid. + */ + bool updatePosition(float position); + +public: + /** + * Creates a new sequenced handle. + * \param entry The entry this handle plays. + * \param device The read device to play on. + */ + SequenceHandle(std::shared_ptr<SequenceEntry> entry, ReadDevice& device); + + /** + * Destroys the handle. + */ + ~SequenceHandle(); + + /** + * Compares whether this handle is playing the same entry as supplied. + * \param entry The entry to compare to. + * \return Whether the entries ID is smaller, equal or bigger. + */ + int compare(std::shared_ptr<SequenceEntry> entry) const; + + /** + * Stops playing back the handle. + */ + void stop(); + + /** + * Updates the handle for playback. + * \param position The current time during playback. + * \param frame The current frame during playback. + * \param fps The animation frames per second. + */ + void update(float position, float frame, float fps); + + /** + * Seeks the handle to a specific time position. + * \param position The time to seek to. + * \return Whether the handle is valid. + */ + bool seek(float position); +}; + +AUD_NAMESPACE_END diff --git a/extern/audaspace/src/sequence/SequenceReader.cpp b/extern/audaspace/src/sequence/SequenceReader.cpp new file mode 100644 index 00000000000..38647aaeadf --- /dev/null +++ b/extern/audaspace/src/sequence/SequenceReader.cpp @@ -0,0 +1,198 @@ +/******************************************************************************* + * 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 "sequence/SequenceReader.h" +#include "sequence/SequenceData.h" +#include "Exception.h" +#include "SequenceHandle.h" + +#include <algorithm> +#include <mutex> +#include <cmath> + +AUD_NAMESPACE_BEGIN + +SequenceReader::SequenceReader(std::shared_ptr<SequenceData> sequence, bool quality) : + m_position(0), m_device(sequence->m_specs), m_sequence(sequence), m_status(0), m_entry_status(0) +{ + m_device.setQuality(quality); +} + +SequenceReader::~SequenceReader() +{ +} + +bool SequenceReader::isSeekable() const +{ + return true; +} + +void SequenceReader::seek(int position) +{ + if(position < 0) + return; + + m_position = position; + + for(auto& handle : m_handles) + { + handle->seek(position / m_sequence->m_specs.rate); + } +} + +int SequenceReader::getLength() const +{ + return -1; +} + +int SequenceReader::getPosition() const +{ + return m_position; +} + +Specs SequenceReader::getSpecs() const +{ + return m_sequence->m_specs; +} + +void SequenceReader::read(int& length, bool& eos, sample_t* buffer) +{ + std::lock_guard<ILockable> lock(*m_sequence); + + if(m_sequence->m_status != m_status) + { + m_device.changeSpecs(m_sequence->m_specs); + m_device.setSpeedOfSound(m_sequence->m_speed_of_sound); + m_device.setDistanceModel(m_sequence->m_distance_model); + m_device.setDopplerFactor(m_sequence->m_doppler_factor); + + m_status = m_sequence->m_status; + } + + if(m_sequence->m_entry_status != m_entry_status) + { + std::list<std::shared_ptr<SequenceHandle> > handles; + + auto hit = m_handles.begin(); + auto eit = m_sequence->m_entries.begin(); + + int result; + std::shared_ptr<SequenceHandle> handle; + + while(hit != m_handles.end() && eit != m_sequence->m_entries.end()) + { + handle = *hit; + std::shared_ptr<SequenceEntry> entry = *eit; + + result = handle->compare(entry); + + if(result < 0) + { + try + { + handle = std::shared_ptr<SequenceHandle>(new SequenceHandle(entry, m_device)); + handles.push_back(handle); + } + catch(Exception&) + { + } + eit++; + } + else if(result == 0) + { + handles.push_back(handle); + hit++; + eit++; + } + else + { + handle->stop(); + hit++; + } + } + + while(hit != m_handles.end()) + { + (*hit)->stop(); + hit++; + } + + while(eit != m_sequence->m_entries.end()) + { + try + { + handle = std::shared_ptr<SequenceHandle>(new SequenceHandle(*eit, m_device)); + handles.push_back(handle); + } + catch(Exception&) + { + } + eit++; + } + + m_handles = handles; + + m_entry_status = m_sequence->m_entry_status; + } + + Specs specs = m_sequence->m_specs; + int pos = 0; + float time = float(m_position) / float(specs.rate); + float volume, frame; + int len, cfra; + Vector3 v, v2; + Quaternion q; + + + while(pos < length) + { + frame = time * m_sequence->m_fps; + cfra = int(std::floor(frame)); + + len = int(std::ceil((cfra + 1) / m_sequence->m_fps * specs.rate)) - m_position; + len = std::min(length - pos, len); + len = std::max(len, 1); + + for(auto& handle : m_handles) + { + handle->update(time, frame, m_sequence->m_fps); + } + + m_sequence->m_volume.read(frame, &volume); + if(m_sequence->m_muted) + volume = 0.0f; + m_device.setVolume(volume); + + m_sequence->m_orientation.read(frame, q.get()); + m_device.setListenerOrientation(q); + m_sequence->m_location.read(frame, v.get()); + m_device.setListenerLocation(v); + m_sequence->m_location.read(frame + 1, v2.get()); + v2 -= v; + m_device.setListenerVelocity(v2 * m_sequence->m_fps); + + m_device.read(reinterpret_cast<data_t*>(buffer + specs.channels * pos), len); + + pos += len; + time += float(len) / float(specs.rate); + } + + m_position += length; + + eos = false; +} + +AUD_NAMESPACE_END diff --git a/extern/audaspace/src/sequence/Superpose.cpp b/extern/audaspace/src/sequence/Superpose.cpp new file mode 100644 index 00000000000..3d13f7db627 --- /dev/null +++ b/extern/audaspace/src/sequence/Superpose.cpp @@ -0,0 +1,35 @@ +/******************************************************************************* + * 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 "sequence/Superpose.h" +#include "sequence/SuperposeReader.h" + +AUD_NAMESPACE_BEGIN + +Superpose::Superpose(std::shared_ptr<ISound> sound1, std::shared_ptr<ISound> sound2) : + m_sound1(sound1), m_sound2(sound2) +{ +} + +std::shared_ptr<IReader> Superpose::createReader() +{ + std::shared_ptr<IReader> reader1 = m_sound1->createReader(); + std::shared_ptr<IReader> reader2 = m_sound2->createReader(); + + return std::shared_ptr<IReader>(new SuperposeReader(reader1, reader2)); +} + +AUD_NAMESPACE_END diff --git a/extern/audaspace/src/sequence/SuperposeReader.cpp b/extern/audaspace/src/sequence/SuperposeReader.cpp new file mode 100644 index 00000000000..9206a7a96ef --- /dev/null +++ b/extern/audaspace/src/sequence/SuperposeReader.cpp @@ -0,0 +1,95 @@ +/******************************************************************************* + * 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 "sequence/SuperposeReader.h" +#include "Exception.h" + +#include <algorithm> +#include <cstring> + +AUD_NAMESPACE_BEGIN + +SuperposeReader::SuperposeReader(std::shared_ptr<IReader> reader1, std::shared_ptr<IReader> reader2) : + m_reader1(reader1), m_reader2(reader2) +{ +} + +SuperposeReader::~SuperposeReader() +{ +} + +bool SuperposeReader::isSeekable() const +{ + return m_reader1->isSeekable() && m_reader2->isSeekable(); +} + +void SuperposeReader::seek(int position) +{ + m_reader1->seek(position); + m_reader2->seek(position); +} + +int SuperposeReader::getLength() const +{ + int len1 = m_reader1->getLength(); + int len2 = m_reader2->getLength(); + if((len1 < 0) || (len2 < 0)) + return -1; + return std::min(len1, len2); +} + +int SuperposeReader::getPosition() const +{ + int pos1 = m_reader1->getPosition(); + int pos2 = m_reader2->getPosition(); + return std::max(pos1, pos2); +} + +Specs SuperposeReader::getSpecs() const +{ + return m_reader1->getSpecs(); +} + +void SuperposeReader::read(int& length, bool& eos, sample_t* buffer) +{ + Specs specs = m_reader1->getSpecs(); + Specs s2 = m_reader2->getSpecs(); + if(!AUD_COMPARE_SPECS(specs, s2)) + AUD_THROW(StateException, "Two readers with different specifiactions cannot be superposed."); + + int samplesize = AUD_SAMPLE_SIZE(specs); + + m_buffer.assureSize(length * samplesize); + + int len1 = length; + m_reader1->read(len1, eos, buffer); + + if(len1 < length) + std::memset(buffer + len1 * specs.channels, 0, (length - len1) * samplesize); + + int len2 = length; + bool eos2; + sample_t* buf = m_buffer.getBuffer(); + m_reader2->read(len2, eos2, buf); + + for(int i = 0; i < len2 * specs.channels; i++) + buffer[i] += buf[i]; + + length = std::max(len1, len2); + eos &= eos2; +} + +AUD_NAMESPACE_END |