Blob Blame Raw
#pragma once

#ifndef TSOUND_T__INCLUDED
#define TSOUND_T__INCLUDED

#include "tsoundsample.h"

#undef DVAPI
#undef DVVAR
#ifdef TSOUND_EXPORTS
#define DVAPI DV_EXPORT_API
#define DVVAR DV_EXPORT_VAR
#else
#define DVAPI DV_IMPORT_API
#define DVVAR DV_IMPORT_VAR
#endif

//=========================================================

template <class T>
class DVAPI TSoundTrackT : public TSoundTrack
{
public:
	typedef T SampleType;

	//----------------------------------------------------------------------------

	TSoundTrackT(TUINT32 sampleRate, int channelCount, TINT32 sampleCount)
		: TSoundTrack(
			  sampleRate, T::getBitPerSample(),
			  channelCount, sizeof(T), sampleCount, T::isSampleSigned()) {}

	//----------------------------------------------------------------------------

	TSoundTrackT(TUINT32 sampleRate,
				 int channelCount,
				 TINT32 sampleCount,
				 T *buffer,
				 TSoundTrackT<T> *parent)

		: TSoundTrack(
			  sampleRate, T::getBitPerSample(),
			  channelCount, sizeof(T), sampleCount,
			  reinterpret_cast<UCHAR *>(buffer), parent)
	{
	}

	//----------------------------------------------------------------------------

	~TSoundTrackT(){};

	//----------------------------------------------------------------------------

	bool isSampleSigned() const
	{
		return T::isSampleSigned();
	}

	//----------------------------------------------------------------------------

	//!Returns the const samples array
	const T *samples() const
	{
		return reinterpret_cast<T *>(m_buffer);
	}

	//----------------------------------------------------------------------------

	//!Returns the samples array
	T *samples()
	{
		return reinterpret_cast<T *>(m_buffer);
	}

	//----------------------------------------------------------------------------

	//!Returns a soundtrack whom is a clone of the object
	TSoundTrackP clone() const
	{

		TSoundTrackP dst = TSoundTrack::create(getFormat(), m_sampleCount);
		TSoundTrackP src(const_cast<TSoundTrack *>((const TSoundTrack *)this));
		dst->copy(src, (TINT32)0);
		return dst;
	}

	//----------------------------------------------------------------------------

	//!Extract the subtrack in the samples range [s0,s1] given in samples
	TSoundTrackP extract(TINT32 s0, TINT32 s1)
	{

		if (!m_buffer || s0 > s1)
			return TSoundTrackP();

		//addRef();

		TINT32 ss0, ss1;

		ss0 = tcrop<TINT32>(s0, (TINT32)0, getSampleCount() - 1);
		ss1 = tcrop<TINT32>(s1, (TINT32)0, getSampleCount() - 1);

		return TSoundTrackP(
			new TSoundTrackT<T>(
				getSampleRate(), getChannelCount(), ss1 - ss0 + 1,
				(T *)(m_buffer + (long)(ss0 * getSampleSize())), this));
	}

	//----------------------------------------------------------------------------

	/*!
    Returns a soundtrack whom is a clone of the object for the spicified channel
    A clone means that it's an object who lives indipendently from the other
    from which it's created.It hasn't reference to the object.
  */
	TSoundTrackP clone(TSound::Channel chan) const
	{
		if (getChannelCount() == 1)
			return clone();
		else {
			typedef typename T::ChannelSampleType TCST;
			TSoundTrackT<TCST> *dst =
				new TSoundTrackT<TCST>(m_sampleRate, 1, getSampleCount());

			const T *sample = samples();
			const T *endSample = sample + getSampleCount();

			TCST *dstSample = dst->samples();

			while (sample < endSample) {
				*dstSample++ = sample->getValue(chan);
				sample++;
			}

			return dst;
		}
	}

	//----------------------------------------------------------------------------

	//!Copies from sample dst_s0 of object the samples of the soundtrack src
	void copy(const TSoundTrackP &src, TINT32 dst_s0)
	{

		TSoundTrackT<T> *srcT = dynamic_cast<TSoundTrackT<T> *>(src.getPointer());

		if (!srcT)
			throw(TException("Unable to copy from a track whose format is different"));

		T *srcSample = srcT->samples();
		T *srcEndSample = srcT->samples() + srcT->getSampleCount();
		T *dstEndSample = samples() + getSampleCount();

		TINT32 ss0 = tcrop<TINT32>(dst_s0, (TINT32)0, getSampleCount() - (TINT32)1);

		T *dstSample = samples() + ss0;

		while (srcSample < srcEndSample && dstSample < dstEndSample)
			*dstSample++ = *srcSample++;
	}

//----------------------------------------------------------------------------

//!Applies a trasformation (echo, reverb, ect) to the object and returns the transformed soundtrack
#if defined(MACOSX) || defined(LINUX)
	TSoundTrackP apply(TSoundTransform *transform);
#else // _WIN32
	TSoundTrackP apply(TSoundTransform *transform)
	{
		assert(transform);
		return transform->compute(*this);
	}
#endif
	//----------------------------------------------------------------------------

	//! Returns the pressure of the sample s about the channel chan
	double getPressure(TINT32 s, TSound::Channel chan) const
	{
		assert(s >= 0 && s < getSampleCount());
		assert(m_buffer);
		const T *sample = samples() + s;
		assert(sample);
		return sample->getPressure(chan);
	}

	//----------------------------------------------------------------------------

	//!Returns the soundtrack pressure max and min values in the given sample range and channel
	void getMinMaxPressure(
		TINT32 s0, TINT32 s1, TSound::Channel chan,
		double &min, double &max) const
	{

		TINT32 sampleCount = getSampleCount();
		if (sampleCount <= 0) {
			min = 0;
			max = -1;
			return;
		}

		assert(s1 >= s0);
		TINT32 ss0, ss1;

		ss0 = tcrop<TINT32>(s0, (TINT32)0, sampleCount - (TINT32)1);
		ss1 = tcrop<TINT32>(s1, (TINT32)0, sampleCount - (TINT32)1);

		assert(ss1 >= ss0);

		if (s0 == s1) {
			min = max = getPressure(s0, chan);
			return;
		}

		const T *sample = samples() + ss0;
		assert(sample);
		min = max = sample->getPressure(chan);

		const T *endSample = sample + (ss1 - ss0 + 1);
		++sample;

		while (sample < endSample) {
			double value = sample->getPressure(chan);

			if (max < value)
				max = value;
			if (min > value)
				min = value;

			++sample;
		}
	}

	//----------------------------------------------------------------------------

	//!Returns the soundtrack pressure max value in the given sample range and channel
	double getMaxPressure(TINT32 s0, TINT32 s1, TSound::Channel chan) const
	{

		TINT32 sampleCount = getSampleCount();
		if (sampleCount <= 0) {
			return -1;
		}

		assert(s1 >= s0);
		TINT32 ss0, ss1;

		ss0 = tcrop<TINT32>(s0, (TINT32)0, sampleCount - (TINT32)1);
		ss1 = tcrop<TINT32>(s1, (TINT32)0, sampleCount - (TINT32)1);
		assert(ss1 >= ss0);

		if (s0 == s1)
			return (getPressure(s0, chan));

		const T *sample = samples() + ss0;
		assert(sample);
		double maxPressure = sample->getPressure(chan);
		const T *endSample = sample + (ss1 - ss0 + 1);
		++sample;

		while (sample < endSample) {
			if (maxPressure < sample->getPressure(chan))
				maxPressure = sample->getPressure(chan);
			++sample;
		}

		return ((double)maxPressure);
	}

	//----------------------------------------------------------------------------

	//!Returns the soundtrack pressure min value in the given sample range and channel
	double getMinPressure(TINT32 s0, TINT32 s1, TSound::Channel chan) const
	{

		TINT32 sampleCount = getSampleCount();
		if (sampleCount <= 0) {
			return 0;
		}

		assert(s1 >= s0);
		TINT32 ss0, ss1;

		ss0 = tcrop<TINT32>(s0, (TINT32)0, (TINT32)(getSampleCount() - (TINT32)1));
		ss1 = tcrop<TINT32>(s1, (TINT32)0, (TINT32)(getSampleCount() - (TINT32)1));

		assert(ss1 >= ss0);

		if (s0 == s1)
			return (getPressure(s0, chan));

		const T *sample = samples() + ss0;
		assert(sample);
		double minPressure = sample->getPressure(chan);
		const T *endSample = sample + (ss1 - ss0 + 1);
		++sample;

		while (sample < endSample) {
			if (minPressure > sample->getPressure(chan))
				minPressure = sample->getPressure(chan);
			++sample;
		}

		return ((double)minPressure);
	}

	//----------------------------------------------------------------------------

	/*!
    Copies the samples in the given sample range and channel
    inside the dstChan channel from sample dst_s0
  */
	void copyChannel(
		const TSoundTrackT<T> &src, TINT32 src_s0, TINT32 src_s1,
		TSound::Channel srcChan, TINT32 dst_s0,
		TSound::Channel dstChan)
	{

		TINT32 ss0, ss1;
		//se i valori sono nel range ed uguali => voglio copiare il
		//canale di un solo campione
		if (src_s1 == src_s0 && src_s1 >= 0 && src_s1 < src.getSampleCount())
			ss0 = ss1 = src_s1;
		else {
			assert(src_s1 >= src_s0);
			ss0 = tcrop(src_s0, (TINT32)0, (TINT32)(src.getSampleCount() - 1));
			ss1 = tcrop(src_s1, (TINT32)0, (TINT32)(src.getSampleCount() - 1));
			assert(ss1 >= ss0);
			//esco perche' non ha senso copiare indiscriminatamente il primo
			//o l'ultimo campione della sorgente
			if (ss1 == ss0)
				return;
		}

		assert(dst_s0 >= 0L && dst_s0 < getSampleCount());

		const T *srcSample = src.samples() + ss0;

		const T *srcEndSample =
			srcSample + std::min((TINT32)(ss1 - ss0 + 1), (TINT32)(getSampleCount() - dst_s0));

		T *dstSample = samples() + dst_s0;

		for (; srcSample < srcEndSample; srcSample++, dstSample++)
			dstSample->setValue(srcChan, srcSample->getValue(dstChan));
	}

	//----------------------------------------------------------------------------

	//!Makes blank the samples in the given sample range
	void blank(TINT32 s0, TINT32 s1)
	{

		TINT32 ss0, ss1;
		//se i valori sono nel range ed uguali => voglio pulire
		//un solo campione
		if (s1 == s0 && s1 >= 0 && s1 < getSampleCount())
			ss0 = ss1 = s1;
		else {
			assert(s1 >= s0);

			ss0 = tcrop<TINT32>(s0, (TINT32)0, (TINT32)(getSampleCount() - 1));
			ss1 = tcrop<TINT32>(s1, (TINT32)0, (TINT32)(getSampleCount() - 1));

			assert(ss1 >= ss0);
			//esco perche' non ha senso pulire indiscriminatamente
			//il primo o l'ultimo campione
			if (ss1 == ss0)
				return;
		}

		T *sample = samples() + ss0;
		assert(sample);

		T blankSample;
		const T *endSample = sample + (ss1 - ss0 + 1);
		while (sample < endSample)
			*sample++ = blankSample;
	}

	//----------------------------------------------------------------------------

	//!Makes blank the samples in the given sample range and channel
	void blankChannel(TINT32 s0, TINT32 s1, TSound::Channel chan)
	{

		if (s0 > s1)
			return;
		// ....
		assert(false);
	}
};

//==============================================================================

#ifdef _WIN32
template class DVAPI TSoundTrackT<TMono8SignedSample>;
template class DVAPI TSoundTrackT<TMono8UnsignedSample>;
template class DVAPI TSoundTrackT<TStereo8SignedSample>;
template class DVAPI TSoundTrackT<TStereo8UnsignedSample>;
template class DVAPI TSoundTrackT<TMono16Sample>;
template class DVAPI TSoundTrackT<TStereo16Sample>;
template class DVAPI TSoundTrackT<TMono24Sample>;
template class DVAPI TSoundTrackT<TStereo24Sample>;
#endif

typedef TSoundTrackT<TMono8SignedSample> TSoundTrackMono8Signed;
typedef TSoundTrackT<TMono8UnsignedSample> TSoundTrackMono8Unsigned;
typedef TSoundTrackT<TStereo8SignedSample> TSoundTrackStereo8Signed;
typedef TSoundTrackT<TStereo8UnsignedSample> TSoundTrackStereo8Unsigned;
typedef TSoundTrackT<TMono16Sample> TSoundTrackMono16;
typedef TSoundTrackT<TStereo16Sample> TSoundTrackStereo16;
typedef TSoundTrackT<TMono24Sample> TSoundTrackMono24;
typedef TSoundTrackT<TStereo24Sample> TSoundTrackStereo24;

//==============================================================================

class TSoundTransform
{
public:
	TSoundTransform() {}
	virtual ~TSoundTransform() {}

	virtual TSoundTrackP compute(const TSoundTrackMono8Signed &) { return 0; };
	virtual TSoundTrackP compute(const TSoundTrackMono8Unsigned &) { return 0; };
	virtual TSoundTrackP compute(const TSoundTrackStereo8Signed &) { return 0; };
	virtual TSoundTrackP compute(const TSoundTrackStereo8Unsigned &) { return 0; };
	virtual TSoundTrackP compute(const TSoundTrackMono16 &) { return 0; };
	virtual TSoundTrackP compute(const TSoundTrackStereo16 &) { return 0; };
	virtual TSoundTrackP compute(const TSoundTrackMono24 &) { return 0; };
	virtual TSoundTrackP compute(const TSoundTrackStereo24 &) { return 0; };
};

//==============================================================================
#if defined(MACOSX) || defined(LINUX)
template <class T>
DVAPI TSoundTrackP TSoundTrackT<T>::apply(TSoundTransform *transform)
{
	assert(transform);
	return transform->compute(*this);
}
#endif
#endif