3D Audio GSoC:
authorJoerg Mueller <nexyon@gmail.com>
Tue, 21 Jun 2011 20:25:48 +0000 (20:25 +0000)
committerJoerg Mueller <nexyon@gmail.com>
Tue, 21 Jun 2011 20:25:48 +0000 (20:25 +0000)
Dynamic resampling for libsamplerate and linear resampling.

CMakeLists.txt
intern/audaspace/FX/AUD_ReverseReader.cpp
intern/audaspace/SRC/AUD_SRCResampleFactory.cpp
intern/audaspace/SRC/AUD_SRCResampleReader.cpp
intern/audaspace/SRC/AUD_SRCResampleReader.h
intern/audaspace/intern/AUD_LinearResampleFactory.cpp
intern/audaspace/intern/AUD_LinearResampleReader.cpp
intern/audaspace/intern/AUD_LinearResampleReader.h

index 52773a40ce351100731cdf4b54549c37d96c13b5..ebf255f06a30dcf1b9f81bf9003e79215aaaba0b 100644 (file)
@@ -200,10 +200,6 @@ if(NOT WITH_GAMEENGINE AND WITH_PLAYER)
        message(FATAL_ERROR "WITH_PLAYER requires WITH_GAMEENGINE")
 endif()
 
-if(NOT WITH_SAMPLERATE AND (WITH_OPENAL OR WITH_SDL OR WITH_JACK))
-       message(FATAL_ERROR "WITH_OPENAL/WITH_SDL/WITH_JACK require WITH_SAMPLERATE")
-endif()
-
 if(NOT WITH_IMAGE_OPENJPEG AND WITH_IMAGE_REDCODE)
        message(FATAL_ERROR "WITH_IMAGE_REDCODE requires WITH_IMAGE_OPENJPEG")
 endif()
index 1a5083d3eb4d3a4d91b6a0968d6fe87e7a2d4eae..73f6830f3fa6a495e56b811d7515383adc3ba66c 100644 (file)
@@ -76,7 +76,7 @@ void AUD_ReverseReader::read(int& length, bool& eos, sample_t* buffer)
        const AUD_Specs specs = getSpecs();
        const int samplesize = AUD_SAMPLE_SIZE(specs);
 
-       sample_t temp[10];
+       sample_t temp[AUD_CHANNEL_MAX];
 
        int len = length;
 
index 15e96f6ff1d31bc21a73f5e43b6b351bae017684..3ae2c4fbd06b6aa6944d8714071bf425ddd4b95a 100644 (file)
@@ -40,10 +40,5 @@ AUD_SRCResampleFactory::AUD_SRCResampleFactory(AUD_Reference<AUD_IFactory> facto
 
 AUD_Reference<AUD_IReader> AUD_SRCResampleFactory::createReader()
 {
-       AUD_Reference<AUD_IReader> reader = getReader();
-
-       if(reader->getSpecs().rate != m_specs.rate)
-               reader = new AUD_SRCResampleReader(reader, m_specs.specs);
-
-       return reader;
+       return new AUD_SRCResampleReader(getReader(), m_specs.specs);
 }
index 59854a7a2c439a68687da353eba1d8ca00773dea..cd6b0ef8c502a5068335e730ef074ced3780a557 100644 (file)
@@ -46,17 +46,14 @@ static const char* state_error = "AUD_SRCResampleReader: SRC State couldn't be "
 AUD_SRCResampleReader::AUD_SRCResampleReader(AUD_Reference<AUD_IReader> reader,
                                                                                         AUD_Specs specs) :
                AUD_EffectReader(reader),
-               m_sspecs(reader->getSpecs()),
-               m_factor(double(specs.rate) / double(m_sspecs.rate)),
-               m_tspecs(specs),
+               m_rate(specs.rate),
+               m_channels(reader->getSpecs().channels),
                m_position(0)
 {
-       m_tspecs.channels = m_sspecs.channels;
-
        int error;
        m_src = src_callback_new(src_callback,
                                                         SRC_SINC_MEDIUM_QUALITY,
-                                                        m_sspecs.channels,
+                                                        m_channels,
                                                         &error,
                                                         this);
 
@@ -74,7 +71,11 @@ AUD_SRCResampleReader::~AUD_SRCResampleReader()
 
 long AUD_SRCResampleReader::doCallback(float** data)
 {
-       int length = m_buffer.getSize() / AUD_SAMPLE_SIZE(m_tspecs);
+       AUD_Specs specs;
+       specs.channels = m_channels;
+       specs.rate = m_rate;
+
+       int length = m_buffer.getSize() / AUD_SAMPLE_SIZE(specs);
 
        *data = m_buffer.getBuffer();
        m_reader->read(length, m_eos, *data);
@@ -84,14 +85,18 @@ long AUD_SRCResampleReader::doCallback(float** data)
 
 void AUD_SRCResampleReader::seek(int position)
 {
-       m_reader->seek(position / m_factor);
+       AUD_Specs specs = m_reader->getSpecs();
+       double factor = double(m_rate) / double(specs.rate);
+       m_reader->seek(position / factor);
        src_reset(m_src);
        m_position = position;
 }
 
 int AUD_SRCResampleReader::getLength() const
 {
-       return m_reader->getLength() * m_factor;
+       AUD_Specs specs = m_reader->getSpecs();
+       double factor = double(m_rate) / double(specs.rate);
+       return m_reader->getLength() * factor;
 }
 
 int AUD_SRCResampleReader::getPosition() const
@@ -101,18 +106,46 @@ int AUD_SRCResampleReader::getPosition() const
 
 AUD_Specs AUD_SRCResampleReader::getSpecs() const
 {
-       return m_tspecs;
+       AUD_Specs specs = m_reader->getSpecs();
+       specs.rate = m_rate;
+       return specs;
 }
 
 void AUD_SRCResampleReader::read(int& length, bool& eos, sample_t* buffer)
 {
+       AUD_Specs specs = m_reader->getSpecs();
+
+       double factor = double(m_rate) / double(specs.rate);
+
+       specs.rate = m_rate;
+
        int size = length;
 
-       m_buffer.assureSize(length * AUD_SAMPLE_SIZE(m_tspecs));
+       m_buffer.assureSize(length * AUD_SAMPLE_SIZE(specs));
+
+       if(specs.channels != m_channels)
+       {
+               src_delete(m_src);
+
+               m_channels = specs.channels;
+
+               int error;
+               m_src = src_callback_new(src_callback,
+                                                                SRC_SINC_MEDIUM_QUALITY,
+                                                                m_channels,
+                                                                &error,
+                                                                this);
+
+               if(!m_src)
+               {
+                       // XXX printf("%s\n", src_strerror(error));
+                       AUD_THROW(AUD_ERROR_SRC, state_error);
+               }
+       }
 
        m_eos = false;
 
-       length = src_callback_read(m_src, m_factor, length, buffer);
+       length = src_callback_read(m_src, factor, length, buffer);
 
        m_position += length;
 
index 5b210a61e70294cce26520a14eceba78045ddac9..896a742356b94d392a2d92a7efa6674118d0324a 100644 (file)
@@ -44,24 +44,19 @@ class AUD_SRCResampleReader : public AUD_EffectReader
 {
 private:
        /**
-        * The sample specification of the source.
-        */
-       const AUD_Specs m_sspecs;
-
-       /**
-        * The resampling factor.
+        * The sound output buffer.
         */
-       const double m_factor;
+       AUD_Buffer m_buffer;
 
        /**
-        * The sound output buffer.
+        * The target sampling rate.
         */
-       AUD_Buffer m_buffer;
+       AUD_SampleRate m_rate;
 
        /**
-        * The target specification.
+        * The reader channels.
         */
-       AUD_Specs m_tspecs;
+       AUD_Channels m_channels;
 
        /**
         * The src state structure.
index 404281a33bb4e664addd5989d31ac4d6b4186908..de23869441f7cb23cd9d5b02f14bea772783af16 100644 (file)
@@ -40,10 +40,5 @@ AUD_LinearResampleFactory::AUD_LinearResampleFactory(AUD_Reference<AUD_IFactory>
 
 AUD_Reference<AUD_IReader> AUD_LinearResampleFactory::createReader()
 {
-       AUD_Reference<AUD_IReader> reader = getReader();
-
-       if(reader->getSpecs().rate != m_specs.rate)
-               reader = new AUD_LinearResampleReader(reader, m_specs.specs);
-
-       return reader;
+       return new AUD_LinearResampleReader(getReader(), m_specs.specs);
 }
index 7e4f7a5b45d132bc92b466fcfa1c367ca1018035..c227baad73b4dc4b4e7639a7d805274938199949 100644 (file)
 #include <cmath>
 #include <cstring>
 
-#define CC channels + channel
+#define CC m_channels + channel
 
 AUD_LinearResampleReader::AUD_LinearResampleReader(AUD_Reference<AUD_IReader> reader,
                                                                                                   AUD_Specs specs) :
        AUD_EffectReader(reader),
-       m_sspecs(reader->getSpecs()),
-       m_factor(float(specs.rate) / float(m_sspecs.rate)),
-       m_tspecs(specs),
+       m_rate(specs.rate),
+       m_channels(reader->getSpecs().channels),
        m_position(0),
-       m_sposition(0)
+       m_cache_pos(0),
+       m_cache_ok(false)
 {
-       m_tspecs.channels = m_sspecs.channels;
-       m_cache.resize(2 * AUD_SAMPLE_SIZE(m_tspecs));
+       specs.channels = m_channels;
+       m_cache.resize(2 * AUD_SAMPLE_SIZE(specs));
 }
 
 void AUD_LinearResampleReader::seek(int position)
 {
-       m_position = position;
-       m_sposition = floor(position / m_factor);
-       m_reader->seek(m_sposition);
+       position = floor(position * double(m_reader->getSpecs().rate) / double(m_rate));
+       m_reader->seek(position);
+       m_cache_ok = false;
+       m_cache_pos = 0;
 }
 
 int AUD_LinearResampleReader::getLength() const
 {
-       return m_reader->getLength() * m_factor;
+       return floor(m_reader->getLength() * double(m_rate) / double(m_reader->getSpecs().rate));
 }
 
 int AUD_LinearResampleReader::getPosition() const
 {
-       return m_position;
+       return floor((m_reader->getPosition() + (m_cache_ok ? m_cache_pos - 2 : 0))
+                                * m_rate / m_reader->getSpecs().rate);
 }
 
 AUD_Specs AUD_LinearResampleReader::getSpecs() const
 {
-       return m_tspecs;
+       AUD_Specs specs = m_reader->getSpecs();
+       specs.rate = m_rate;
+       return specs;
 }
 
 void AUD_LinearResampleReader::read(int& length, bool& eos, sample_t* buffer)
 {
-       int samplesize = AUD_SAMPLE_SIZE(m_tspecs);
+       AUD_Specs specs = m_reader->getSpecs();
+
+       int samplesize = AUD_SAMPLE_SIZE(specs);
        int size = length;
+       float factor = float(m_rate) / float(m_reader->getSpecs().rate);
+       float spos;
+       sample_t low, high;
+       eos = false;
 
-       m_buffer.assureSize(size * AUD_SAMPLE_SIZE(m_sspecs));
+       if(factor == 1 && (!m_cache_ok || m_cache_pos == 0))
+       {
+               // can read directly!
+               m_reader->read(length, eos, buffer);
+               return;
+       }
 
-       int need = ceil((m_position + length) / m_factor) + 1 - m_sposition;
-       int len = need;
-       sample_t* buf = m_buffer.getBuffer();
+       // check for channels changed
 
-       m_reader->read(len, eos, buf);
+       if(specs.channels != m_channels)
+       {
+               m_cache.resize(2 * samplesize);
+               m_channels = specs.channels;
+               m_cache_ok = false;
+       }
 
-       if(len < need)
-               length = floor((m_sposition + len - 1) * m_factor) - m_position;
+       int len;
+       sample_t* buf;
 
-       float spos;
-       sample_t low, high;
-       int channels = m_sspecs.channels;
+       if(m_cache_ok)
+       {
+               int need = ceil(length / factor - (1 - m_cache_pos));
+
+               len = need;
+
+               m_buffer.assureSize((len + 3) * samplesize);
+               buf = m_buffer.getBuffer();
+
+               memcpy(buf, m_cache.getBuffer(), 2 * samplesize);
+               m_reader->read(len, eos, buf + 2 * m_channels);
 
-       for(int channel = 0; channel < channels; channel++)
+               if(len < need)
+                       length = floor((len + (1 - m_cache_pos)) * factor);
+       }
+       else
        {
-               for(int i = 0; i < length; i++)
-               {
-                       spos = (m_position + i) / m_factor - m_sposition;
+               int need = ceil(length / factor) + 1;
+
+               len = need;
 
-                       if(floor(spos) < 0)
+               m_buffer.assureSize((len + 1) * samplesize);
+               buf = m_buffer.getBuffer();
+
+               m_reader->read(len, eos, buf);
+
+               if(len < need)
+               {
+                       if(eos)
                        {
-                               low = m_cache.getBuffer()[(int)(floor(spos) + 2) * CC];
-                               if(ceil(spos) < 0)
-                                       high = m_cache.getBuffer()[(int)(ceil(spos) + 2) * CC];
-                               else
-                                       high = buf[(int)ceil(spos) * CC];
+                               length = floor(len * factor);
+                               memset(buf + len * m_channels, 0, samplesize);
                        }
                        else
-                       {
-                                       low = buf[(int)floor(spos) * CC];
-                                       high = buf[(int)ceil(spos) * CC];
-                       }
+                               length = ceil((len - 1) * factor);
+               }
+               m_cache_ok = true;
+               m_cache_pos = 0;
+       }
+
+       for(int channel = 0; channel < m_channels; channel++)
+       {
+               for(int i = 0; i < length; i++)
+               {
+                       spos = (i + 1) / factor + m_cache_pos;
+
+                       low = buf[(int)floor(spos) * CC];
+                       high = buf[(int)ceil(spos) * CC];
+
                        buffer[i * CC] = low + (spos - floor(spos)) * (high - low);
                }
        }
 
-       if(len > 1)
-               memcpy(m_cache.getBuffer(),
-                          buf + (len - 2) * channels,
-                          2 * samplesize);
-       else if(len == 1)
-               memcpy(m_cache.getBuffer() + 1 * channels, buf, samplesize);
+       if(floor(spos) == spos)
+       {
+               memcpy(m_cache.getBuffer(), buf + int(floor(spos - 1)) * m_channels, 2 * samplesize);
+               m_cache_pos = 1;
+       }
+       else
+       {
+               memcpy(m_cache.getBuffer(), buf + int(floor(spos)) * m_channels, 2 * samplesize);
+               m_cache_pos = spos - floor(spos);
+       }
 
-       m_sposition += len;
-       m_position += length;
        eos &= length < size;
 }
index f7dd0e96aa6a93b113d024810d072619ae65a814..8e0eac612fa151a7c67fe495f1657ff5161581d0 100644 (file)
@@ -42,19 +42,14 @@ class AUD_LinearResampleReader : public AUD_EffectReader
 {
 private:
        /**
-        * The sample specification of the source.
-        */
-       const AUD_Specs m_sspecs;
-
-       /**
-        * The resampling factor.
+        * The target specification.
         */
-       const float m_factor;
+       AUD_SampleRate m_rate;
 
        /**
-        * The target specification.
+        * The reader channels.
         */
-       AUD_Specs m_tspecs;
+       AUD_Channels m_channels;
 
        /**
         * The current position.
@@ -62,9 +57,9 @@ private:
        int m_position;
 
        /**
-        * The current reading source position.
+        * The position in the cache.
         */
-       int m_sposition;
+       float m_cache_pos;
 
        /**
         * The sound output buffer.
@@ -76,6 +71,11 @@ private:
         */
        AUD_Buffer m_cache;
 
+       /**
+        * Whether the cache contains valid data.
+        */
+       bool m_cache_ok;
+
        // hide copy constructor and operator=
        AUD_LinearResampleReader(const AUD_LinearResampleReader&);
        AUD_LinearResampleReader& operator=(const AUD_LinearResampleReader&);