Add Chromium-only Blender WebEngine parity work

This commit is contained in:
mes123456
2026-08-12 04:47:48 -04:00
commit 9fd26010f6
18225 changed files with 11622124 additions and 0 deletions

View File

@@ -0,0 +1,266 @@
/*******************************************************************************
* 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 <cassert>
#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(Buffer::getBuffer(), 0, count * sizeof(float));
}
AnimateableProperty::AnimateableProperty(int count, float value) :
Buffer(count * sizeof(float)), m_count(count), m_isAnimated(false)
{
sample_t* buf = Buffer::getBuffer();
for(int i = 0; i < count; i++)
buf[i] = value;
}
void AnimateableProperty::updateUnknownCache(int start, int end)
{
float* buf = Buffer::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(Buffer::getBuffer(), data, m_count * sizeof(float));
}
void AnimateableProperty::writeConstantRange(const float* data, int position_start, int position_end)
{
int pos = getSize() / (sizeof(float) * m_count);
assureSize(position_end * m_count * sizeof(float), true);
float* buffer = Buffer::getBuffer();
// if we were not animated yet, use the new constant value as the
// first/default value to fill in the unknown parts
if (!m_isAnimated)
{
std::memcpy(buffer, data, m_count * sizeof(float));
pos = 0;
}
for(int i = position_start; i < position_end; i++)
{
std::memcpy(buffer + i * m_count, data, m_count * sizeof(float));
}
m_isAnimated = true;
updateUnknownAfterWrite(pos, position_start, position_end - position_start);
}
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 = Buffer::getBuffer();
std::memcpy(buf + position * m_count, data, count * m_count * sizeof(float));
updateUnknownAfterWrite(pos, position, count);
}
void AnimateableProperty::updateUnknownAfterWrite(int pos, int position, int count)
{
// 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, Buffer::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(position < 0)
{
position = 0;
t = 0;
}
if(t == 0)
{
std::memcpy(out, Buffer::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 = Buffer::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) * p1[i] + (-2 * t3 + 3 * t2) * p2[i] + (t3 - 2 * t2 + t) * m0 + (t3 - t2) * m1;
}
}
}
float AnimateableProperty::readSingle(float position)
{
assert(m_count == 1);
float value;
read(position, &value);
return value;
}
bool AnimateableProperty::isAnimated() const
{
return m_isAnimated;
}
const Buffer& AnimateableProperty::getBuffer()
{
return *this;
}
AUD_NAMESPACE_END

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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, double begin, double end, double skip)
{
return m_sequence->add(sound, m_sequence, begin, end, skip);
}
void Sequence::remove(std::shared_ptr<SequenceEntry> entry)
{
m_sequence->remove(entry);
}
std::shared_ptr<IReader> Sequence::createQualityReader(ResampleQuality quality)
{
return std::shared_ptr<IReader>(new SequenceReader(m_sequence, quality));
}
std::shared_ptr<IReader> Sequence::createReader()
{
return std::shared_ptr<IReader>(new SequenceReader(m_sequence));
}
AUD_NAMESPACE_END

View File

@@ -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, std::shared_ptr<SequenceData> sequence_data, double begin, double end, double 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, sequence_data, 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

View File

@@ -0,0 +1,257 @@
/*******************************************************************************
* 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, double begin, double end, double skip, std::shared_ptr<SequenceData> sequence_data, 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_sequence_data(sequence_data),
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(double begin, double end, double 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

View File

@@ -0,0 +1,282 @@
/*******************************************************************************
* 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
#define POSITION_EPSILON (1.0 / static_cast<double>(RATE_48000))
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(double 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 - POSITION_EPSILON >= 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 + POSITION_EPSILON >= 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 + POSITION_EPSILON >= m_entry->m_begin && position - POSITION_EPSILON <= 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(double 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(double 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);
double seek_frame = (position - m_entry->m_begin) * m_entry->m_sequence_data->getFPS();
if(seek_frame < 0)
seek_frame = 0;
seek_frame += m_entry->m_skip * m_entry->m_sequence_data->getFPS();
AnimateableProperty* pitch_property = m_entry->getAnimProperty(AP_PITCH);
double target_frame = 0;
if(pitch_property != nullptr)
{
int frame_start = (m_entry->m_begin - m_entry->m_skip) * m_entry->m_sequence_data->getFPS();
for(int i = 0; seek_frame > 0; i++)
{
float pitch;
pitch_property->read(frame_start + i, &pitch);
const double factor = seek_frame > 1.0 ? 1.0 : seek_frame;
target_frame += pitch * factor;
seek_frame--;
}
}
else
{
target_frame = seek_frame;
}
double seekpos = target_frame / m_entry->m_sequence_data->getFPS();
m_handle->setPitch(1.0f);
m_handle->seek(seekpos);
return true;
}
AUD_NAMESPACE_END

View File

@@ -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(double 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(double 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(double position);
};
AUD_NAMESPACE_END

View File

@@ -0,0 +1,197 @@
/*******************************************************************************
* 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, ResampleQuality 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 / (double)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;
double time = double(m_position) / double(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 - pos;
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 += double(len) / double(specs.rate);
}
m_position += length;
eos = false;
}
AUD_NAMESPACE_END

View File

@@ -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

View File

@@ -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::max(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