Revision: 39427 http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=39427 Author: nexyon Date: 2011-08-15 21:50:09 +0000 (Mon, 15 Aug 2011) Log Message: ----------- 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. Modified Paths: -------------- branches/soc-2011-pepper/intern/audaspace/intern/AUD_C-API.cpp branches/soc-2011-pepper/intern/audaspace/intern/AUD_C-API.h branches/soc-2011-pepper/intern/audaspace/intern/AUD_FileFactory.cpp branches/soc-2011-pepper/intern/audaspace/intern/AUD_FileFactory.h branches/soc-2011-pepper/intern/audaspace/intern/AUD_JOSResampleReader.cpp branches/soc-2011-pepper/intern/audaspace/intern/AUD_JOSResampleReader.h branches/soc-2011-pepper/intern/audaspace/intern/AUD_SequencerFactory.cpp branches/soc-2011-pepper/intern/audaspace/intern/AUD_SequencerFactory.h branches/soc-2011-pepper/intern/audaspace/intern/AUD_SequencerReader.cpp branches/soc-2011-pepper/intern/audaspace/intern/AUD_SequencerReader.h branches/soc-2011-pepper/intern/audaspace/intern/AUD_SoftwareDevice.cpp branches/soc-2011-pepper/intern/audaspace/intern/AUD_SoftwareDevice.h branches/soc-2011-pepper/intern/audaspace/sndfile/AUD_SndFileFactory.cpp branches/soc-2011-pepper/intern/audaspace/sndfile/AUD_SndFileFactory.h branches/soc-2011-pepper/source/blender/blenkernel/intern/sound.c branches/soc-2011-pepper/source/gameengine/Ketsji/KX_KetsjiEngine.cpp branches/soc-2011-pepper/source/gameengine/Ketsji/KX_SoundActuator.cpp Added Paths: ----------- branches/soc-2011-pepper/intern/audaspace/intern/AUD_JOSResampleReaderCoeff.cpp Modified: branches/soc-2011-pepper/intern/audaspace/intern/AUD_C-API.cpp =================================================================== --- branches/soc-2011-pepper/intern/audaspace/intern/AUD_C-API.cpp 2011-08-15 19:30:24 UTC (rev 39426) +++ branches/soc-2011-pepper/intern/audaspace/intern/AUD_C-API.cpp 2011-08-15 21:50:09 UTC (rev 39427) @@ -1182,7 +1182,7 @@ 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 @@ } } +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; Modified: branches/soc-2011-pepper/intern/audaspace/intern/AUD_C-API.h =================================================================== --- branches/soc-2011-pepper/intern/audaspace/intern/AUD_C-API.h 2011-08-15 19:30:24 UTC (rev 39426) +++ branches/soc-2011-pepper/intern/audaspace/intern/AUD_C-API.h 2011-08-15 21:50:09 UTC (rev 39427) @@ -527,6 +527,8 @@ 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); Modified: branches/soc-2011-pepper/intern/audaspace/intern/AUD_FileFactory.cpp =================================================================== --- branches/soc-2011-pepper/intern/audaspace/intern/AUD_FileFactory.cpp 2011-08-15 19:30:24 UTC (rev 39426) +++ branches/soc-2011-pepper/intern/audaspace/intern/AUD_FileFactory.cpp 2011-08-15 21:50:09 UTC (rev 39427) @@ -38,7 +38,6 @@ #endif #include "AUD_FileFactory.h" -#include "AUD_Buffer.h" #include <cstring> Modified: branches/soc-2011-pepper/intern/audaspace/intern/AUD_FileFactory.h =================================================================== --- branches/soc-2011-pepper/intern/audaspace/intern/AUD_FileFactory.h 2011-08-15 19:30:24 UTC (rev 39426) +++ branches/soc-2011-pepper/intern/audaspace/intern/AUD_FileFactory.h 2011-08-15 21:50:09 UTC (rev 39427) @@ -34,7 +34,7 @@ #include "AUD_IFactory.h" #include "AUD_Reference.h" -class AUD_Buffer; +#include "AUD_Buffer.h" #include <string> Modified: branches/soc-2011-pepper/intern/audaspace/intern/AUD_JOSResampleReader.cpp =================================================================== --- branches/soc-2011-pepper/intern/audaspace/intern/AUD_JOSResampleReader.cpp 2011-08-15 19:30:24 UTC (rev 39426) +++ branches/soc-2011-pepper/intern/audaspace/intern/AUD_JOSResampleReader.cpp 2011-08-15 21:50:09 UTC (rev 39427) @@ -30,20 +30,30 @@ #include "AUD_JOSResampleReader.h" +#include "AUD_JOSResampleReaderCoeff.cpp" + #include <cmath> #include <cstring> +#include <iostream> #define CC m_channels + channel -#define AUD_RATE_MAX 10 +#define AUD_RATE_MAX 256 +#define SHIFT_BITS 12 +#define double_to_fp(x) (lrint(x * double(1 << SHIFT_BITS))) +#define int_to_fp(x) (x << SHIFT_BITS) +#define fp_to_int(x) (x >> SHIFT_BITS) +#define fp_to_double(x) (x * 1.0/(1 << SHIFT_BITS)) +#define fp_rest(x) (x & ((1 << SHIFT_BITS) - 1)) +#define fp_rest_to_double(x) fp_to_double(fp_rest(x)) -AUD_JOSResampleReader::AUD_JOSResampleReader(AUD_Reference<AUD_IReader> reader, - AUD_Specs specs) : +AUD_JOSResampleReader::AUD_JOSResampleReader(AUD_Reference<AUD_IReader> reader, AUD_Specs specs) : AUD_ResampleReader(reader, specs.rate), - m_channels(reader->getSpecs().channels), + m_channels(AUD_CHANNELS_INVALID), m_n(0), m_P(0), - m_cache_valid(0) + m_cache_valid(0), + m_last_factor(0) { } @@ -52,20 +62,22 @@ m_cache_valid = 0; m_n = 0; m_P = 0; + m_last_factor = 0; } -void AUD_JOSResampleReader::updateBuffer(int size, float factor, int samplesize) +void AUD_JOSResampleReader::updateBuffer(int size, double factor, int samplesize) { unsigned int len; + double num_samples = double(m_len) / double(m_L); // first calculate what length we need right now if(factor >= 1) - len = m_Nz; + len = ceil(num_samples); else - len = (unsigned int)(ceil(m_Nz / factor)); + len = (unsigned int)(ceil(num_samples / factor)); // then check if afterwards the length is enough for the maximum rate - if(len + size < m_Nz * AUD_RATE_MAX) - len = size - m_Nz * AUD_RATE_MAX; + if(len + size < num_samples * AUD_RATE_MAX) + len = size - num_samples * AUD_RATE_MAX; if(m_n > len) { @@ -79,6 +91,125 @@ m_buffer.assureSize((m_cache_valid + size) * samplesize, true); } +#define RESAMPLE_METHOD(name, left, right) void AUD_JOSResampleReader::name(double target_factor, int length, sample_t* buffer)\ +{\ + sample_t* buf = m_buffer.getBuffer();\ +\ + int P, l, end, channel, i;\ + double eta, v, f_increment, factor;\ +\ + m_sums.assureSize(m_channels * sizeof(double));\ + double* sums = reinterpret_cast<double*>(m_sums.getBuffer());\ + sample_t* data;\ + const float* coeff = m_coeff;\ +\ + unsigned int P_increment;\ +\ + for(unsigned int t = 0; t < length; t++)\ + {\ + factor = (m_last_factor * (length - t) + target_factor * t) / length;\ +\ + if(factor >= 1)\ + f_increment = m_L;\ + else\ + f_increment = factor * m_L;\ +\ + P_increment = double_to_fp(f_increment);\ + P = double_to_fp(m_P * f_increment);\ +\ + end = (int_to_fp(m_len) - P) / P_increment - 1;\ + if(m_n < end)\ + end = m_n;\ +\ + memset(sums, 0, sizeof(double) * m_channels);\ +\ + P += P_increment * end;\ + data = buf + (m_n - end) * m_channels;\ + l = fp_to_int(P);\ +\ + for(i = 0; i <= end; i++)\ + {\ + eta = fp_rest_to_double(P);\ + v = coeff[l] + eta * (coeff[l+1] - coeff[l]);\ + P -= P_increment;\ + l = fp_to_int(P);\ + left\ + }\ +\ + P = -P;\ +\ + end = (int_to_fp(m_len) - P) / P_increment - 1;\ + if(m_cache_valid - m_n - 2 < end)\ + end = m_cache_valid - m_n - 2;\ +\ + P += P_increment * end;\ + data = buf + (m_n + 2 + end) * m_channels - 1;\ + l = fp_to_int(P);\ +\ + for(i = 0; i <= end; i++)\ + {\ + eta = fp_rest_to_double(P);\ + v = coeff[l] + eta * (coeff[l+1] - coeff[l]);\ + P -= P_increment;\ + l = fp_to_int(P);\ + right\ + }\ +\ + for(channel = 0; channel < m_channels; channel++)\ + {\ + *buffer = f_increment / m_L * sums[channel];\ + buffer++;\ + }\ +\ + m_P += fmod(1.0 / factor, 1.0);\ + m_n += floor(1.0 / factor);\ +\ + if(m_P >= 1.0)\ + {\ + m_P -= 1.0;\ + m_n++;\ + }\ + }\ +} + +RESAMPLE_METHOD(resample, { + channel = 0; + do + { + sums[channel] += *data * v; + channel++; + data++; + } + while(channel < m_channels); +}, { + channel = m_channels; + do + { + channel--; + sums[channel] += *data * v; + data--; + } + while(channel); +}) + +RESAMPLE_METHOD(resample_mono, { + *sums += *data * v; + data++; +}, { + *sums += *data * v; + data--; +}) + +RESAMPLE_METHOD(resample_stereo, { + sums[0] += data[0] * v; + sums[1] += data[1] * v; + data+=2; +}, { + data-=2; + sums[0] += data[1] * v; + sums[1] += data[2] * v; +}) + void AUD_JOSResampleReader::seek(int position) { position = floor(position * double(m_reader->getSpecs().rate) / double(m_rate)); @@ -93,7 +224,7 @@ int AUD_JOSResampleReader::getPosition() const { - return floor((m_reader->getPosition() + double(m_P) / 4294967296.0) // 2^32 + return floor((m_reader->getPosition() + double(m_P)) * m_rate / m_reader->getSpecs().rate); } @@ -112,27 +243,42 @@ AUD_Specs specs = m_reader->getSpecs(); int samplesize = AUD_SAMPLE_SIZE(specs); - float factor = float(m_rate) / float(m_reader->getSpecs().rate); + double target_factor = double(m_rate) / double(specs.rate); eos = false; int len; - sample_t* buf; + double num_samples = double(m_len) / double(m_L); // check for channels changed - if(specs.channels != m_channels) { m_channels = specs.channels; reset(); + + switch(m_channels) + { + case AUD_CHANNELS_MONO: + m_resample = &AUD_JOSResampleReader::resample_mono; + break; + case AUD_CHANNELS_STEREO: + m_resample = &AUD_JOSResampleReader::resample_stereo; + break; + default: + m_resample = &AUD_JOSResampleReader::resample; + break; + } } - if(factor == 1 && (m_P == 1)) + if(m_last_factor == 0) + m_last_factor = target_factor; + + if(target_factor == 1 && m_last_factor == 1 && (m_P == 0)) { // can read directly! len = length - (m_cache_valid - m_n); - updateBuffer(len, factor, samplesize); - buf = m_buffer.getBuffer(); + updateBuffer(len, target_factor, samplesize); + sample_t* buf = m_buffer.getBuffer(); m_reader->read(len, eos, buf + m_cache_valid * m_channels); m_cache_valid += len; @@ -148,159 +294,57 @@ return; } + // use minimum for the following calculations + double factor = AUD_MIN(target_factor, m_last_factor); if(factor >= 1) - len = (m_n - m_cache_valid) + int(ceil(length / factor)) + m_Nz; + len = (m_n - m_cache_valid) + int(ceil(length / factor)) + ceil(num_samples); else - len = (m_n - m_cache_valid) + int(ceil(length / factor) + ceil(m_Nz / factor)); + len = (m_n - m_cache_valid) + int(ceil(length / factor) + ceil(num_samples / factor)); if(len > 0) { int should = len; updateBuffer(len, factor, samplesize); - buf = m_buffer.getBuffer(); - m_reader->read(len, eos, buf + m_cache_valid * m_channels); + m_reader->read(len, eos, m_buffer.getBuffer() + m_cache_valid * m_channels); m_cache_valid += len; if(len < should) { - if(eos) - { - // end of stream, let's check how many more samples we can produce - if(factor >= 1) - len = floor((len - (m_n - m_cache_valid)) * factor); - else @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org http://lists.blender.org/mailman/listinfo/bf-blender-cvs