3D Audio GSoC:
Implemented basic audio animation. * AnimatableProperty: Propper cache writing and spline interpolation for reading (the solution for stair steps in audio animation) * Animatable properties so far are: volume, pitch, panning * Users note: Changing the pitch of a sound results in wrong seeking, due to the resulting playback length difference. * Users note: Panning only works for mono sources, values are in the range [-2..2], this basically controls the angle of the sound, 0 is front, -1 left, 1 right and 2 and -2 are back. Typical stereo panning only supports [-1..1]. * Disabled animation of audio related ffmpeg output parameters. * Scene Audio Panel: 3D Listener settings also for Renderer, new Volume property (animatable!), Update/Bake buttons for animation problems, moved sampling rate and channel count here
This commit is contained in:
@@ -32,6 +32,7 @@
|
||||
#include "AUD_AnimateableProperty.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
|
||||
AUD_AnimateableProperty::AUD_AnimateableProperty(int count) :
|
||||
AUD_Buffer(count * sizeof(float)), m_count(count), m_isAnimated(false), m_changed(false)
|
||||
@@ -78,16 +79,85 @@ void AUD_AnimateableProperty::write(const float* data, int position, int count)
|
||||
lock();
|
||||
|
||||
m_isAnimated = true;
|
||||
m_changed = true;
|
||||
|
||||
int pos = getSize() / (sizeof(float) * m_count);
|
||||
|
||||
assureSize((count + position) * m_count * sizeof(float), true);
|
||||
memcpy(getBuffer() + position * m_count, data, count * m_count * sizeof(float));
|
||||
|
||||
float* buf = getBuffer();
|
||||
|
||||
memcpy(buf + position * m_count, data, count * m_count * sizeof(float));
|
||||
|
||||
for(int i = pos; i < position; i++)
|
||||
memcpy(buf + i * m_count, buf + (pos - 1) * m_count, m_count * sizeof(float));
|
||||
|
||||
unlock();
|
||||
}
|
||||
|
||||
const float* AUD_AnimateableProperty::read(int position) const
|
||||
void AUD_AnimateableProperty::read(float position, float* out)
|
||||
{
|
||||
return getBuffer() + position * m_count;
|
||||
lock();
|
||||
|
||||
if(!m_isAnimated)
|
||||
{
|
||||
memcpy(out, getBuffer(), m_count * sizeof(float));
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
float last = (getSize() / (sizeof(float) * m_count) - 1);
|
||||
float t = position - floor(position);
|
||||
|
||||
if(position > last)
|
||||
{
|
||||
position = last;
|
||||
t = 0;
|
||||
}
|
||||
|
||||
if(t == 0)
|
||||
{
|
||||
memcpy(out, getBuffer() + int(floor(position)) * m_count, m_count * sizeof(float));
|
||||
}
|
||||
else
|
||||
{
|
||||
int pos = int(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;
|
||||
|
||||
if(pos == 0)
|
||||
p0 = p1;
|
||||
else
|
||||
p0 = p1 - m_count;
|
||||
|
||||
if(pos > last)
|
||||
{
|
||||
p3 = p2 = p1;
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
unlock();
|
||||
}
|
||||
|
||||
bool AUD_AnimateableProperty::isAnimated() const
|
||||
@@ -97,6 +167,9 @@ bool AUD_AnimateableProperty::isAnimated() const
|
||||
|
||||
bool AUD_AnimateableProperty::hasChanged()
|
||||
{
|
||||
if(m_isAnimated)
|
||||
return true;
|
||||
|
||||
bool result = m_changed;
|
||||
m_changed = false;
|
||||
return result;
|
||||
|
||||
@@ -84,7 +84,7 @@ public:
|
||||
|
||||
void write(const float* data, int position, int count);
|
||||
|
||||
const float* read(int position) const;
|
||||
void read(float position, float* out);
|
||||
|
||||
bool isAnimated() const;
|
||||
|
||||
|
||||
@@ -938,6 +938,24 @@ void AUD_updateSequenceSound(AUD_SEntry* entry, AUD_Sound* sound)
|
||||
(*entry)->setSound(AUD_Sound());
|
||||
}
|
||||
|
||||
void AUD_setSequenceAnimData(AUD_SEntry* entry, AUD_AnimateablePropertyType type, int frame, float* data, char animated)
|
||||
{
|
||||
AUD_AnimateableProperty* prop = (*entry)->getAnimProperty(type);
|
||||
if(animated)
|
||||
prop->write(data, frame, 1);
|
||||
else
|
||||
prop->write(data);
|
||||
}
|
||||
|
||||
void AUD_setSequencerAnimData(AUD_Sound* sequencer, AUD_AnimateablePropertyType type, int frame, float* data, char animated)
|
||||
{
|
||||
AUD_AnimateableProperty* prop = ((AUD_SequencerFactory*)sequencer->get())->getAnimProperty(type);
|
||||
if(animated)
|
||||
prop->write(data, frame, 1);
|
||||
else
|
||||
prop->write(data);
|
||||
}
|
||||
|
||||
void AUD_setSequencerDeviceSpecs(AUD_Sound* sequencer)
|
||||
{
|
||||
((AUD_SequencerFactory*)sequencer->get())->setSpecs(AUD_device->getSpecs().specs);
|
||||
|
||||
@@ -471,6 +471,10 @@ extern void AUD_muteSequence(AUD_SEntry* entry, char mute);
|
||||
|
||||
extern void AUD_updateSequenceSound(AUD_SEntry* entry, AUD_Sound* sound);
|
||||
|
||||
extern void AUD_setSequenceAnimData(AUD_SEntry* entry, AUD_AnimateablePropertyType type, int frame, float* data, char animated);
|
||||
|
||||
extern void AUD_setSequencerAnimData(AUD_Sound* sequencer, AUD_AnimateablePropertyType type, int frame, float* data, char animated);
|
||||
|
||||
extern void AUD_setSequencerDeviceSpecs(AUD_Sound* sequencer);
|
||||
|
||||
extern void AUD_setSequencerSpecs(AUD_Sound* sequencer, AUD_Specs specs);
|
||||
|
||||
@@ -45,7 +45,7 @@ AUD_SequencerEntry::AUD_SequencerEntry(AUD_Reference<AUD_IFactory> sound, float
|
||||
m_end(end),
|
||||
m_skip(skip),
|
||||
m_muted(false),
|
||||
m_relative(false),
|
||||
m_relative(true),
|
||||
m_volume_max(1.0f),
|
||||
m_volume_min(0),
|
||||
m_distance_max(std::numeric_limits<float>::max()),
|
||||
@@ -72,10 +72,13 @@ void AUD_SequencerEntry::setSound(AUD_Reference<AUD_IFactory> sound)
|
||||
|
||||
void AUD_SequencerEntry::move(float begin, float end, float skip)
|
||||
{
|
||||
m_begin = begin;
|
||||
m_skip = skip;
|
||||
m_end = end;
|
||||
m_pos_status++;
|
||||
if(m_begin != begin || m_skip != skip || m_end != end)
|
||||
{
|
||||
m_begin = begin;
|
||||
m_skip = skip;
|
||||
m_end = end;
|
||||
m_pos_status++;
|
||||
}
|
||||
}
|
||||
|
||||
void AUD_SequencerEntry::mute(bool mute)
|
||||
@@ -88,6 +91,25 @@ int AUD_SequencerEntry::getID() const
|
||||
return m_id;
|
||||
}
|
||||
|
||||
AUD_AnimateableProperty* AUD_SequencerEntry::getAnimProperty(AUD_AnimateablePropertyType type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case AUD_AP_VOLUME:
|
||||
return &m_volume;
|
||||
case AUD_AP_PITCH:
|
||||
return &m_pitch;
|
||||
case AUD_AP_PANNING:
|
||||
return &m_panning;
|
||||
case AUD_AP_LOCATION:
|
||||
return &m_location;
|
||||
case AUD_AP_ORIENTATION:
|
||||
return &m_orientation;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool AUD_SequencerEntry::isRelative()
|
||||
{
|
||||
return m_relative;
|
||||
|
||||
@@ -76,6 +76,8 @@ public:
|
||||
|
||||
int getID() const;
|
||||
|
||||
AUD_AnimateableProperty* getAnimProperty(AUD_AnimateablePropertyType type);
|
||||
|
||||
/**
|
||||
* Checks whether the source location, velocity and orientation are relative
|
||||
* to the listener.
|
||||
|
||||
@@ -48,6 +48,8 @@ AUD_SequencerFactory::AUD_SequencerFactory(AUD_Specs specs, float fps, bool mute
|
||||
{
|
||||
AUD_Quaternion q;
|
||||
m_orientation.write(q.get());
|
||||
float f = 1;
|
||||
m_volume.write(&f);
|
||||
}
|
||||
|
||||
AUD_SequencerFactory::~AUD_SequencerFactory()
|
||||
|
||||
@@ -66,7 +66,7 @@ void AUD_SequencerHandle::stop()
|
||||
m_handle->stop();
|
||||
}
|
||||
|
||||
void AUD_SequencerHandle::update(float position)
|
||||
void AUD_SequencerHandle::update(float position, float frame)
|
||||
{
|
||||
if(!m_handle.isNull())
|
||||
{
|
||||
@@ -111,7 +111,16 @@ void AUD_SequencerHandle::update(float position)
|
||||
m_status = m_entry->m_status;
|
||||
}
|
||||
|
||||
// AUD_XXX TODO: Animation data
|
||||
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);
|
||||
AUD_SoftwareDevice::setPanning(m_handle.get(), value);
|
||||
|
||||
// AUD_XXX: TODO: animation data
|
||||
|
||||
if(m_entry->m_muted)
|
||||
m_handle->setVolume(0);
|
||||
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
~AUD_SequencerHandle();
|
||||
int compare(AUD_Reference<AUD_SequencerEntry> entry) const;
|
||||
void stop();
|
||||
void update(float position);
|
||||
void update(float position, float frame);
|
||||
void seek(float position);
|
||||
};
|
||||
|
||||
|
||||
@@ -144,19 +144,27 @@ void AUD_SequencerReader::read(int& length, bool& eos, sample_t* buffer)
|
||||
AUD_Specs specs = m_factory->m_specs;
|
||||
int pos = 0;
|
||||
float time = float(m_position) / float(specs.rate);
|
||||
int len;
|
||||
float value, frame;
|
||||
int len, cfra;
|
||||
|
||||
while(pos < length)
|
||||
{
|
||||
len = int(ceil((int(floor(time * m_factory->m_fps)) + 1) / m_factory->m_fps * specs.rate)) - m_position;
|
||||
frame = time * m_factory->m_fps;
|
||||
cfra = int(floor(frame));
|
||||
|
||||
len = int(ceil((cfra + 1) / m_factory->m_fps * specs.rate)) - m_position;
|
||||
len = AUD_MIN(length - pos, len);
|
||||
len = AUD_MAX(len, 1);
|
||||
|
||||
for(AUD_HandleIterator it = m_handles.begin(); it != m_handles.end(); it++)
|
||||
{
|
||||
(*it)->update(time);
|
||||
(*it)->update(time, frame);
|
||||
}
|
||||
|
||||
m_factory->m_volume.read(frame, &value);
|
||||
|
||||
m_device.setVolume(value);
|
||||
|
||||
m_device.read(reinterpret_cast<data_t*>(buffer + specs.channels * pos), len);
|
||||
|
||||
pos += len;
|
||||
|
||||
@@ -62,8 +62,8 @@ typedef enum
|
||||
/******************************************************************************/
|
||||
|
||||
AUD_SoftwareDevice::AUD_SoftwareHandle::AUD_SoftwareHandle(AUD_SoftwareDevice* device, AUD_Reference<AUD_IReader> reader, AUD_Reference<AUD_PitchReader> pitch, AUD_Reference<AUD_ResampleReader> resampler, AUD_Reference<AUD_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_volume(1.0f), m_loopcount(0),
|
||||
m_relative(false), m_volume_max(1.0f), m_volume_min(0), m_distance_max(std::numeric_limits<float>::max()),
|
||||
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_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(AUD_RENDER_CONE), m_stop(NULL), m_stop_data(NULL), m_status(AUD_STATUS_PLAYING), m_device(device)
|
||||
{
|
||||
@@ -211,7 +211,7 @@ void AUD_SoftwareDevice::AUD_SoftwareHandle::update()
|
||||
m_mapper->setMonoAngle(phi);
|
||||
}
|
||||
else
|
||||
m_mapper->setMonoAngle(0);
|
||||
m_mapper->setMonoAngle(m_relative ? m_user_pan * M_PI / 2.0 : 0);
|
||||
}
|
||||
|
||||
void AUD_SoftwareDevice::AUD_SoftwareHandle::setSpecs(AUD_Specs specs)
|
||||
@@ -768,6 +768,12 @@ void AUD_SoftwareDevice::mix(data_t* buffer, int length)
|
||||
unlock();
|
||||
}
|
||||
|
||||
void AUD_SoftwareDevice::setPanning(AUD_IHandle* handle, float pan)
|
||||
{
|
||||
AUD_SoftwareDevice::AUD_SoftwareHandle* h = dynamic_cast<AUD_SoftwareDevice::AUD_SoftwareHandle*>(handle);
|
||||
h->m_user_pan = pan;
|
||||
}
|
||||
|
||||
void AUD_SoftwareDevice::setSpecs(AUD_Specs specs)
|
||||
{
|
||||
m_specs.specs = specs;
|
||||
|
||||
@@ -81,6 +81,9 @@ protected:
|
||||
/// The user set volume of the source.
|
||||
float m_user_volume;
|
||||
|
||||
/// The user set panning for non-3D sources
|
||||
float m_user_pan;
|
||||
|
||||
/// The calculated final volume of the source.
|
||||
float m_volume;
|
||||
|
||||
@@ -278,6 +281,9 @@ private:
|
||||
int m_flags;
|
||||
|
||||
public:
|
||||
|
||||
static void setPanning(AUD_IHandle* handle, float pan);
|
||||
|
||||
virtual AUD_DeviceSpecs getSpecs() const;
|
||||
virtual AUD_Reference<AUD_IHandle> play(AUD_Reference<AUD_IReader> reader, bool keep = false);
|
||||
virtual AUD_Reference<AUD_IHandle> play(AUD_Reference<AUD_IFactory> factory, bool keep = false);
|
||||
|
||||
Reference in New Issue
Block a user