//=========================================================================
// Name:            ResampeStep.cpp
// Purpose:         Describes a resampling step in the audio pipeline.
//
// Authors:         Mooneer Salem
// License:
//
//  All rights reserved.
//
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License version 2.1,
//  as published by the Free Software Foundation.  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, see <http://www.gnu.org/licenses/>.
//
//=========================================================================

#include "ResampleStep.h"

#include <algorithm>
#include <assert.h>
#include <cstdio>

// returns number of output samples generated by resampling
// TBD -- remove identical version from util.cpp.
static int resample_step(SRC_STATE *src,
            short      output_short[],
            short      input_short[],
            int        output_sample_rate,
            int        input_sample_rate,
            int        length_output_short, // maximum output array length in samples
            int        length_input_short
            )
{
    SRC_DATA src_data;
    float    input[length_input_short];
    float    output[length_output_short];
    int      ret;

    assert(src != NULL);

    src_short_to_float_array(input_short, input, length_input_short);

    src_data.data_in = input;
    src_data.data_out = output;
    src_data.input_frames = length_input_short;
    src_data.output_frames = length_output_short;
    src_data.end_of_input = 0;
    src_data.src_ratio = (float)output_sample_rate/input_sample_rate;

    ret = src_process(src, &src_data);
    if (ret != 0)
    {
        fprintf(stderr, "WARNING: resampling failed: %s\n", src_strerror(ret));
    }
    assert(ret == 0);

    assert(src_data.output_frames_gen <= length_output_short);
    src_float_to_short_array(output, output_short, src_data.output_frames_gen);

    return src_data.output_frames_gen;
}

ResampleStep::ResampleStep(int inputSampleRate, int outputSampleRate)
    : inputSampleRate_(inputSampleRate)
    , outputSampleRate_(outputSampleRate)
{
    int src_error;
    resampleState_ = src_new(SRC_SINC_FASTEST, 1, &src_error);
    assert(resampleState_ != nullptr);
}

ResampleStep::~ResampleStep()
{
    src_delete(resampleState_);
}

int ResampleStep::getInputSampleRate() const
{
    return inputSampleRate_;
}

int ResampleStep::getOutputSampleRate() const
{
    return outputSampleRate_;
}

std::shared_ptr<short> ResampleStep::execute(std::shared_ptr<short> inputSamples, int numInputSamples, int* numOutputSamples)
{
    short* outputSamples = nullptr;
    if (numInputSamples > 0)
    {
        double scaleFactor = ((double)outputSampleRate_)/((double)inputSampleRate_);
        int outputArraySize = std::max(numInputSamples, (int)(scaleFactor*numInputSamples));
        assert(outputArraySize > 0);

        outputSamples = new short[outputArraySize];
        assert(outputSamples != nullptr);
 
        *numOutputSamples = resample_step(
            resampleState_, outputSamples, inputSamples.get(), outputSampleRate_, 
            inputSampleRate_, outputArraySize, numInputSamples);
    }
    else
    {
        *numOutputSamples = 0;
    }
 
    return std::shared_ptr<short>(outputSamples, std::default_delete<short[]>());
}
