3D Audio GSoC:

High quality resampling on mixdown, linear for playback.

* Lots of improvements and fixes for the JOS resampler, now it works fine!
* High quality filter coefficients for the JOS resampler (sorry for the 5 MB source file).
* Fix for GE orientation bug. Note: moto uses x,y,z,w quaternion storage, while rest of blender uses w,x,y,z.
* Minor changes/fixes.
This commit is contained in:
Joerg Mueller 2011-08-15 21:50:09 +00:00
parent cbbbf31315
commit a458de88b6
18 changed files with 29580 additions and 3471 deletions

@ -1182,7 +1182,7 @@ const char* AUD_mixdown(AUD_Sound* sound, unsigned int start, unsigned int lengt
AUD_SequencerFactory* f = dynamic_cast<AUD_SequencerFactory*>(sound->get());
f->setSpecs(specs.specs);
AUD_Reference<AUD_IReader> reader = f->createReader();
AUD_Reference<AUD_IReader> reader = f->createQualityReader();
reader->seek(start);
AUD_Reference<AUD_IWriter> writer = AUD_FileWriter::createWriter(filename, specs, format, codec, bitrate);
AUD_FileWriter::writeReader(reader, writer, length, buffersize);
@ -1195,6 +1195,28 @@ const char* AUD_mixdown(AUD_Sound* sound, unsigned int start, unsigned int lengt
}
}
AUD_Device* AUD_openMixdownDevice(AUD_DeviceSpecs specs, AUD_Sound* sequencer, float volume, float start)
{
try
{
AUD_ReadDevice* device = new AUD_ReadDevice(specs);
device->setQuality(true);
device->setVolume(volume);
dynamic_cast<AUD_SequencerFactory*>(sequencer->get())->setSpecs(specs.specs);
AUD_Handle handle = device->play(*sequencer);
if(!handle.isNull())
handle->seek(start);
return new AUD_Device(device);
}
catch(AUD_Exception&)
{
return NULL;
}
}
AUD_Reference<AUD_IDevice> AUD_getDevice()
{
return AUD_device;

@ -527,6 +527,8 @@ extern void* AUD_getSet(void* set);
extern const char* AUD_mixdown(AUD_Sound* sound, unsigned int start, unsigned int length, unsigned int buffersize, const char* filename, AUD_DeviceSpecs specs, AUD_Container format, AUD_Codec codec, unsigned int bitrate);
extern AUD_Device* AUD_openMixdownDevice(AUD_DeviceSpecs specs, AUD_Sound* sequencer, float volume, float start);
#ifdef WITH_PYTHON
extern PyObject* AUD_getPythonFactory(AUD_Sound* sound);

@ -38,7 +38,6 @@
#endif
#include "AUD_FileFactory.h"
#include "AUD_Buffer.h"
#include <cstring>

@ -34,7 +34,7 @@
#include "AUD_IFactory.h"
#include "AUD_Reference.h"
class AUD_Buffer;
#include "AUD_Buffer.h"
#include <string>

File diff suppressed because it is too large Load Diff

@ -41,13 +41,11 @@
class AUD_JOSResampleReader : public AUD_ResampleReader
{
private:
static const unsigned int m_nL = 9;
static const unsigned int m_nN = 23;
static const unsigned int m_Nz = 32;
static const unsigned int m_L = 1 << m_nL;
static const unsigned int m_NN = 1 << m_nN;
typedef void (AUD_JOSResampleReader::*AUD_resample_f)(double target_factor, int length, sample_t* buffer);
static const int m_len = 292874;
static const int m_L = 2048;
static const float m_coeff[];
static const float m_diff[];
/**
* The reader channels.
@ -62,25 +60,44 @@ private:
/**
* The subsample position in the cache.
*/
unsigned int m_P;
double m_P;
/**
* The input data buffer.
*/
AUD_Buffer m_buffer;
/**
* Double buffer for the sums.
*/
AUD_Buffer m_sums;
/**
* How many samples in the cache are valid.
*/
int m_cache_valid;
/**
* Resample function.
*/
AUD_resample_f m_resample;
/**
* Last resampling factor.
*/
double m_last_factor;
// hide copy constructor and operator=
AUD_JOSResampleReader(const AUD_JOSResampleReader&);
AUD_JOSResampleReader& operator=(const AUD_JOSResampleReader&);
void reset();
void updateBuffer(int size, float factor, int samplesize);
void updateBuffer(int size, double factor, int samplesize);
void resample(double target_factor, int length, sample_t* buffer);
void resample_mono(double target_factor, int length, sample_t* buffer);
void resample_stereo(double target_factor, int length, sample_t* buffer);
public:
/**

File diff suppressed because it is too large Load Diff

@ -196,3 +196,8 @@ AUD_Reference<AUD_IReader> AUD_SequencerFactory::createReader()
{
return new AUD_SequencerReader(this);
}
AUD_Reference<AUD_IReader> AUD_SequencerFactory::createQualityReader()
{
return new AUD_SequencerReader(this, true);
}

@ -110,6 +110,8 @@ public:
void remove(AUD_Reference<AUD_SequencerEntry> entry);
virtual AUD_Reference<AUD_IReader> createReader();
AUD_Reference<AUD_IReader> createQualityReader();
};
#endif //AUD_SEQUENCERFACTORY

@ -34,9 +34,10 @@
typedef std::list<AUD_Reference<AUD_SequencerHandle> >::iterator AUD_HandleIterator;
typedef std::list<AUD_Reference<AUD_SequencerEntry> >::iterator AUD_EntryIterator;
AUD_SequencerReader::AUD_SequencerReader(AUD_Reference<AUD_SequencerFactory> factory) :
AUD_SequencerReader::AUD_SequencerReader(AUD_Reference<AUD_SequencerFactory> factory, bool quality) :
m_position(0), m_device(factory->m_specs), m_factory(factory), m_status(0), m_entry_status(0)
{
m_device.setQuality(quality);
}
AUD_SequencerReader::~AUD_SequencerReader()

@ -73,7 +73,7 @@ public:
* \param reader The reader to mix.
* \param specs The target specification.
*/
AUD_SequencerReader(AUD_Reference<AUD_SequencerFactory> factory);
AUD_SequencerReader(AUD_Reference<AUD_SequencerFactory> factory, bool quality = false);
/**
* Destroys the reader.

@ -33,11 +33,8 @@
#include "AUD_IReader.h"
#include "AUD_Mixer.h"
#include "AUD_IFactory.h"
#ifdef WITH_SAMPLERATE
#include "AUD_SRCResampleReader.h"
#else
#include "AUD_JOSResampleReader.h"
#include "AUD_LinearResampleReader.h"
#endif
#include <cstring>
#include <cmath>
@ -665,6 +662,7 @@ void AUD_SoftwareDevice::create()
m_doppler_factor = 1.0f;
m_distance_model = AUD_DISTANCE_MODEL_INVERSE_CLAMPED;
m_flags = 0;
m_quality = false;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
@ -701,6 +699,7 @@ void AUD_SoftwareDevice::mix(data_t* buffer, int length)
int pos;
bool eos;
std::list<AUD_Reference<AUD_SoftwareDevice::AUD_SoftwareHandle> > stopSounds;
std::list<AUD_Reference<AUD_SoftwareDevice::AUD_SoftwareHandle> > pauseSounds;
sample_t* buf = m_buffer.getBuffer();
m_mixer->clear(length);
@ -752,7 +751,7 @@ void AUD_SoftwareDevice::mix(data_t* buffer, int length)
sound->m_stop(sound->m_stop_data);
if(sound->m_keep)
sound->pause();
pauseSounds.push_back(sound);
else
stopSounds.push_back(sound);
}
@ -768,6 +767,13 @@ void AUD_SoftwareDevice::mix(data_t* buffer, int length)
stopSounds.pop_front();
sound->stop();
}
while(!pauseSounds.empty())
{
sound = pauseSounds.front();
pauseSounds.pop_front();
sound->pause();
}
}
unlock();
@ -779,6 +785,11 @@ void AUD_SoftwareDevice::setPanning(AUD_IHandle* handle, float pan)
h->m_user_pan = pan;
}
void AUD_SoftwareDevice::setQuality(bool quality)
{
m_quality = quality;
}
void AUD_SoftwareDevice::setSpecs(AUD_Specs specs)
{
m_specs.specs = specs;
@ -806,11 +817,10 @@ AUD_Reference<AUD_IHandle> AUD_SoftwareDevice::play(AUD_Reference<AUD_IReader> r
AUD_Reference<AUD_ResampleReader> resampler;
// resample
#ifdef WITH_SAMPLERATE
resampler = new AUD_SRCResampleReader(reader, m_specs.specs);
#else
if(m_quality)
resampler = new AUD_JOSResampleReader(reader, m_specs.specs);
else
resampler = new AUD_LinearResampleReader(reader, m_specs.specs);
#endif
reader = AUD_Reference<AUD_IReader>(resampler);
// rechannel

@ -203,6 +203,11 @@ protected:
*/
AUD_Reference<AUD_Mixer> m_mixer;
/**
* Whether to do high or low quality resampling.
*/
bool m_quality;
/**
* Initializes member variables.
*/
@ -283,6 +288,7 @@ private:
public:
static void setPanning(AUD_IHandle* handle, float pan);
void setQuality(bool quality);
virtual AUD_DeviceSpecs getSpecs() const;
virtual AUD_Reference<AUD_IHandle> play(AUD_Reference<AUD_IReader> reader, bool keep = false);

@ -31,7 +31,6 @@
#include "AUD_SndFileFactory.h"
#include "AUD_SndFileReader.h"
#include "AUD_Buffer.h"
#include <cstring>

@ -34,7 +34,7 @@
#include "AUD_IFactory.h"
#include "AUD_Reference.h"
class AUD_Buffer;
#include "AUD_Buffer.h"
#include <string>

@ -372,14 +372,7 @@ void sound_load(struct Main *bmain, struct bSound* sound)
AUD_Device* sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, float volume)
{
AUD_Device* mixdown = AUD_openReadDevice(specs);
AUD_setDeviceVolume(mixdown, volume);
AUD_setSequencerSpecs(scene->sound_scene, specs.specs);
AUD_freeHandle(AUD_playDevice(mixdown, scene->sound_scene, start / FPS));
return mixdown;
return AUD_openMixdownDevice(specs, scene->sound_scene, volume, start / FPS);
}
void sound_create_scene(struct Scene *scene)

@ -1016,15 +1016,15 @@ void KX_KetsjiEngine::DoSound(KX_Scene* scene)
if(dev)
{
AUD_Vector3 v;
AUD_Quaternion q;
float q[4];
cam->NodeGetWorldPosition().getValue(v.get());
dev->setListenerLocation(v);
cam->GetLinearVelocity().getValue(v.get());
dev->setListenerVelocity(v);
cam->NodeGetWorldOrientation().getRotation().getValue(q.get());
dev->setListenerOrientation(q);
cam->NodeGetWorldOrientation().getRotation().getValue(q);
dev->setListenerOrientation(AUD_Quaternion(q[3], q[0], q[1], q[2]));
}
}

@ -224,14 +224,14 @@ bool KX_SoundActuator::Update(double curtime, bool frame)
{
KX_GameObject* obj = (KX_GameObject*)this->GetParent();
AUD_Vector3 v;
AUD_Quaternion q;
float q[4];
obj->NodeGetWorldPosition().getValue(v.get());
handle3d->setSourceLocation(v);
obj->GetLinearVelocity().getValue(v.get());
handle3d->setSourceVelocity(v);
obj->NodeGetWorldOrientation().getRotation().getValue(q.get());
handle3d->setSourceOrientation(q);
obj->NodeGetWorldOrientation().getRotation().getValue(q);
handle3d->setSourceOrientation(AUD_Quaternion(q[3], q[0], q[1], q[2]));
}
result = true;
}