root/libmedia/AudioResampler.cpp

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. convert_raw_data

// AudioResampler.cpp -- custom audio resampler
// 
//   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
//   2011 Free Software Foundation, Inc
// 
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

#include "AudioResampler.h"

#include <cstring>
#include <cassert>

namespace gnash {
namespace media {

void 
AudioResampler::convert_raw_data(
    boost::int16_t** adjusted_data,
    int* adjusted_size,
    void* data,
    int sample_count,   // A stereo pair counts as one
    int sample_size,    // Should now always == 2
    // sample_rate and stereo are those of the incoming sample
    int sample_rate, 
    bool stereo,
    // m_sample_rate, m_stereo are the format we must convert to.
    int m_sample_rate,
    bool m_stereo)
{

    assert(sample_size == 2); // at least it seems the code relies on this...

    // simple hack to handle dup'ing mono to stereo
    if ( !stereo && m_stereo)
    {
        sample_rate >>= 1;
    }

    // simple hack to lose half the samples to get mono from stereo
    if ( stereo && !m_stereo)
    {
        sample_rate <<= 1;
    }

    // Brain-dead sample-rate conversion: duplicate or
    // skip input samples an integral number of times.
    int inc = 1;        // increment
    int dup = 1;        // duplicate
    if (sample_rate > m_sample_rate)
    {
        inc = sample_rate / m_sample_rate;
    }
    else if (sample_rate < m_sample_rate)
    {
        dup = m_sample_rate / sample_rate;
    }

    int output_sample_count = (sample_count * dup * (stereo ? 2 : 1)) / inc;
    boost::int16_t*     out_data = new boost::int16_t[output_sample_count];
    *adjusted_data = out_data;
    *adjusted_size = output_sample_count * sizeof(boost::int16_t); // in bytes

    // Either inc > 1 (decimate the audio)
    // or dup > 1 (repeat samples)
    // or both == 1 (no transformation required)
    if (inc == 1 && dup == 1)
    {
            // No tranformation required
            std::memcpy(out_data, data, output_sample_count * sizeof(boost::int16_t));
    }
    else if (inc > 1)
    {
        // Downsample by skipping samples from the input
        boost::int16_t* in = (boost::int16_t*) data;
        for (int i = output_sample_count; i > 0; i--)
        {
            *out_data++ = *in;
            in += inc;
        }
    }
    else if (dup > 1)
    {
        // Upsample by duplicating input samples in the output.

        // The straight sample-replication code handles mono-to-stereo (sort of)
        // and upsampling of mono but would make a botch of stereo-to-stereo
        // upsampling, giving the left sample in both channels
        // then the right sample in both channels alternately.
        // So for stereo-stereo transforms we have a stereo routine.

        boost::int16_t* in = (boost::int16_t*) data;

        if (stereo && m_stereo) {
            // Stereo-to-stereo upsampling: Replicate pairs of samples
            for (int i = output_sample_count / dup / 2; i > 0; i--)
            {
                for (int j = dup; j > 0; j--)
                {
                        out_data[0] = in[0];
                        out_data[1] = in[1];
                        out_data += 2;
                }
                in += 2;
            }
        } else {

            // Linear upsampling, either to increase a sample rate
            // or to convert a mono file to stereo or both:
            // replicate each sample several times.
            switch (dup)
            {
            case 2:
                for (int i = output_sample_count / dup; i > 0; i--)
                {
                    *out_data++ = *in;
                    *out_data++ = *in;
                    in++;
                }
                break;
            case 4:
                for (int i = output_sample_count / dup; i > 0; i--)
                {
                    *out_data++ = *in;
                    *out_data++ = *in;
                    *out_data++ = *in;
                    *out_data++ = *in;
                    in++;
                }
                break;
            default:
                for (int i = output_sample_count / dup; i > 0; i--)
                {
                    for (int j = dup; j > 0; j--)
                    {
                            *out_data++ = *in;
                    }
                    in++;
                }
                break;
            }
        }
    }
}

} // namespace media
} // namespace gnash 

// Local Variables:
// mode: C++
// indent-tabs-mode: t
// End:

/* [<][>][^][v][top][bottom][index][help] */