//
// Class which should minimalize effect of
// changed sound signal by interpolating through the zero
//

#include "AudioCleaner.h"
#include <iostream>

using namespace std;

template <class T>
size_t AudioCleanerStereo<T>::soundOff(void* out, const void* in)
{
    T* OUT = (T*) out;
    const T* IN = (const T*) in;

    //cout << "sound off" << endl;
    unsigned i = 1;
    while (i < CLEARED_SAMPLES)
    {
	float f = (CLEARED_SAMPLES - i) / (float)CLEARED_SAMPLES;
	*OUT++ = (T) (f * *IN++);
	*OUT++ = (T) (f * *IN++);
        i++;
    }

    while (i < 2 * CLEARED_SAMPLES)
    {
	*OUT++ = (T) 0;
	*OUT++ = (T) 0;
	i++;
    }
    return 2 * CLEARED_SAMPLES;
}

template <class T>
size_t AudioCleanerStereo<T>::soundOn(void* out, size_t n)
{

    T* OUT = (T*) out;
    size_t clear = (n < clearSize && (n > 0)) ? n : clearSize;
    //cout << "sound on " << clearSize << "   " << n << endl;
    size_t sub = CLEARED_SAMPLES * 2 * sizeof(T);
    if (clear < sub)
        sub = clear;

    memset(OUT, 0, clear - sub + 4);

    OUT += clear / sizeof(T);
    T* IN = OUT;

    for (unsigned i = 1; i <= CLEARED_SAMPLES; i++)
    {
	float f = (CLEARED_SAMPLES - i) / (float)CLEARED_SAMPLES;
        f *= f;
	//cout << i << "  " << *OUT << "   " << f << endl;
        OUT--;
	*OUT = (T) (f * *OUT);
        OUT--;
	*OUT = (T) (f * *OUT);
    }

    return 0;
}

template <class T>
size_t AudioCleanerMono<T>::soundOff(void* out, const void* in)
{
    T* OUT = (T*) out;
    const T* IN = (const T*) in;

    for (unsigned i = 0; i < CLEARED_SAMPLES; i++)
    {
	float f = (CLEARED_SAMPLES - i) / (double)CLEARED_SAMPLES;
	*OUT++ = (T) (IN[0] * f);
    }
    return 0;
}

template <class T>
size_t AudioCleanerMono<T>::soundOn(void* out, size_t n)
{
    T* OUT = (T*) out;
    size_t clear = (n < clearSize && (n > 0)) ? n : clearSize;
    size_t sub = CLEARED_SAMPLES * sizeof(T);
    if (clear < sub)
        sub = clear;
    //cout << "sound on " << clearSize << "   " << n << endl;

    memset(OUT, 0, clear - sub + 2);

    return 0;
}

IAudioCleaner* CreateAudioCleaner(unsigned int channels, unsigned int bitsPerSample,
				  size_t clearsz)
{
    IAudioCleaner* r = 0;

    //cout << "AudioCleaner(): ch: " << channels << " bps: " << bitsPerSample << "  size: " << clearsz << endl;
    switch (channels)
    {
    case 1:
	if (bitsPerSample <= 8)
	    r = new AudioCleanerMono<unsigned char>(clearsz);
        else if (bitsPerSample <= 16)
	    r = new AudioCleanerMono<short>(clearsz);
        else if (bitsPerSample <= 32)
	    r = new AudioCleanerMono<int>(clearsz);
        break;
    case 2:
	if (bitsPerSample <= 8)
	    r = new AudioCleanerStereo<unsigned char>(clearsz);
        else if (bitsPerSample <= 16)
	    r = new AudioCleanerStereo<short>(clearsz);
        else if (bitsPerSample <= 32)
	    r = new AudioCleanerStereo<int>(clearsz);
        break;
    }

    return r;
}
