2016-05-17 03:04:11 +12:00
|
|
|
#pragma once
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
#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>
|
2016-06-29 18:17:12 +12:00
|
|
|
class DVAPI TSoundTrackT final : public TSoundTrack {
|
2016-03-19 06:57:51 +13:00
|
|
|
public:
|
2016-06-15 18:43:10 +12:00
|
|
|
typedef T SampleType;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
//----------------------------------------------------------------------------
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
TSoundTrackT(TUINT32 sampleRate, int channelCount, TINT32 sampleCount)
|
|
|
|
: TSoundTrack(sampleRate, T::getBitPerSample(), channelCount, sizeof(T),
|
|
|
|
sampleCount, T::isSampleSigned()) {}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
//----------------------------------------------------------------------------
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
TSoundTrackT(TUINT32 sampleRate, int channelCount, TINT32 sampleCount,
|
|
|
|
T *buffer, TSoundTrackT<T> *parent)
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
: TSoundTrack(sampleRate, T::getBitPerSample(), channelCount, sizeof(T),
|
|
|
|
sampleCount, reinterpret_cast<UCHAR *>(buffer), parent) {}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
//----------------------------------------------------------------------------
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
~TSoundTrackT(){};
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
//----------------------------------------------------------------------------
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-19 20:06:29 +12:00
|
|
|
bool isSampleSigned() const override { return T::isSampleSigned(); }
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
//----------------------------------------------------------------------------
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
//! Returns the const samples array
|
|
|
|
const T *samples() const { return reinterpret_cast<T *>(m_buffer); }
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
//----------------------------------------------------------------------------
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
//! Returns the samples array
|
|
|
|
T *samples() { return reinterpret_cast<T *>(m_buffer); }
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
//----------------------------------------------------------------------------
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
//! Returns a soundtrack whom is a clone of the object
|
2016-06-19 20:06:29 +12:00
|
|
|
TSoundTrackP clone() const override {
|
2016-06-15 18:43:10 +12:00
|
|
|
TSoundTrackP dst = TSoundTrack::create(getFormat(), m_sampleCount);
|
|
|
|
TSoundTrackP src(const_cast<TSoundTrack *>((const TSoundTrack *)this));
|
|
|
|
dst->copy(src, (TINT32)0);
|
|
|
|
return dst;
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
//----------------------------------------------------------------------------
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
//! Extract the subtrack in the samples range [s0,s1] given in samples
|
2016-06-19 20:06:29 +12:00
|
|
|
TSoundTrackP extract(TINT32 s0, TINT32 s1) override {
|
2016-06-15 18:43:10 +12:00
|
|
|
if (!m_buffer || s0 > s1) return TSoundTrackP();
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
// addRef();
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
TINT32 ss0, ss1;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
ss0 = tcrop<TINT32>(s0, (TINT32)0, getSampleCount() - 1);
|
|
|
|
ss1 = tcrop<TINT32>(s1, (TINT32)0, getSampleCount() - 1);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
return TSoundTrackP(new TSoundTrackT<T>(
|
|
|
|
getSampleRate(), getChannelCount(), ss1 - ss0 + 1,
|
|
|
|
(T *)(m_buffer + (long)(ss0 * getSampleSize())), this));
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
//----------------------------------------------------------------------------
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
/*!
|
|
|
|
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.
|
|
|
|
*/
|
2016-06-19 20:06:29 +12:00
|
|
|
TSoundTrackP clone(TSound::Channel chan) const override {
|
2016-06-15 18:43:10 +12:00
|
|
|
if (getChannelCount() == 1)
|
|
|
|
return clone();
|
|
|
|
else {
|
|
|
|
typedef typename T::ChannelSampleType TCST;
|
|
|
|
TSoundTrackT<TCST> *dst =
|
|
|
|
new TSoundTrackT<TCST>(m_sampleRate, 1, getSampleCount());
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
const T *sample = samples();
|
|
|
|
const T *endSample = sample + getSampleCount();
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
TCST *dstSample = dst->samples();
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
while (sample < endSample) {
|
|
|
|
*dstSample++ = sample->getValue(chan);
|
|
|
|
sample++;
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
//----------------------------------------------------------------------------
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
//! Copies from sample dst_s0 of object the samples of the soundtrack src
|
2016-06-19 20:06:29 +12:00
|
|
|
void copy(const TSoundTrackP &src, TINT32 dst_s0) override {
|
2016-06-15 18:43:10 +12:00
|
|
|
TSoundTrackT<T> *srcT = dynamic_cast<TSoundTrackT<T> *>(src.getPointer());
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
if (!srcT)
|
|
|
|
throw(
|
|
|
|
TException("Unable to copy from a track whose format is different"));
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
T *srcSample = srcT->samples();
|
|
|
|
T *srcEndSample = srcT->samples() + srcT->getSampleCount();
|
|
|
|
T *dstEndSample = samples() + getSampleCount();
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
TINT32 ss0 = tcrop<TINT32>(dst_s0, (TINT32)0, getSampleCount() - (TINT32)1);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
T *dstSample = samples() + ss0;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
while (srcSample < srcEndSample && dstSample < dstEndSample)
|
|
|
|
*dstSample++ = *srcSample++;
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2017-06-07 00:19:00 +12:00
|
|
|
//----------------------------------------------------------------------------
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2017-06-07 00:19:00 +12:00
|
|
|
//! Applies a trasformation (echo, reverb, ect) to the object and returns the
|
|
|
|
//! transformed soundtrack
|
2016-06-23 22:02:33 +12:00
|
|
|
TSoundTrackP apply(TSoundTransform *transform) override;
|
2016-06-15 18:43:10 +12:00
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
//! Returns the pressure of the sample s about the channel chan
|
2016-06-19 20:06:29 +12:00
|
|
|
double getPressure(TINT32 s, TSound::Channel chan) const override {
|
2016-06-15 18:43:10 +12:00
|
|
|
assert(s >= 0 && s < getSampleCount());
|
|
|
|
assert(m_buffer);
|
|
|
|
const T *sample = samples() + s;
|
|
|
|
assert(sample);
|
|
|
|
return sample->getPressure(chan);
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
//! Returns the soundtrack pressure max and min values in the given sample
|
|
|
|
//! range and channel
|
|
|
|
void getMinMaxPressure(TINT32 s0, TINT32 s1, TSound::Channel chan,
|
2016-06-19 20:06:29 +12:00
|
|
|
double &min, double &max) const override {
|
2016-06-15 18:43:10 +12:00
|
|
|
TINT32 sampleCount = getSampleCount();
|
|
|
|
if (sampleCount <= 0) {
|
|
|
|
min = 0;
|
|
|
|
max = -1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(s1 >= s0);
|
|
|
|
TINT32 ss0, ss1;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
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
|
2016-06-20 14:23:05 +12:00
|
|
|
double getMaxPressure(TINT32 s0, TINT32 s1,
|
|
|
|
TSound::Channel chan) const override {
|
2016-06-15 18:43:10 +12:00
|
|
|
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
|
2016-06-20 14:23:05 +12:00
|
|
|
double getMinPressure(TINT32 s0, TINT32 s1,
|
|
|
|
TSound::Channel chan) const override {
|
2016-06-15 18:43:10 +12:00
|
|
|
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
|
2016-06-19 20:06:29 +12:00
|
|
|
void blank(TINT32 s0, TINT32 s1) override {
|
2016-06-15 18:43:10 +12:00
|
|
|
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);
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
};
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
|
2016-04-15 17:11:23 +12:00
|
|
|
#ifdef _WIN32
|
2016-03-19 06:57:51 +13:00
|
|
|
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;
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
class TSoundTransform {
|
2016-03-19 06:57:51 +13:00
|
|
|
public:
|
2016-06-15 18:43:10 +12:00
|
|
|
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; };
|
2016-03-19 06:57:51 +13:00
|
|
|
};
|
|
|
|
|
|
|
|
//==============================================================================
|
2017-05-09 00:13:29 +12:00
|
|
|
|
|
|
|
#if !defined(_MSC_VER) || defined(TSOUND_EXPORTS)
|
2016-03-19 06:57:51 +13:00
|
|
|
template <class T>
|
2017-05-09 00:13:29 +12:00
|
|
|
TSoundTrackP TSoundTrackT<T>::apply(TSoundTransform *transform) {
|
2016-06-15 18:43:10 +12:00
|
|
|
assert(transform);
|
|
|
|
return transform->compute(*this);
|
2016-03-19 06:57:51 +13:00
|
|
|
}
|
|
|
|
#endif
|
2017-05-09 00:13:29 +12:00
|
|
|
|
2016-03-19 06:57:51 +13:00
|
|
|
#endif
|