Merging pepper to trunk at revision 39791.

Important note: I used rsync to do the local merge, as "svn merge --reintegrate ^/branches/soc-2011-pepper" doesn't work with our svn server right now!
This commit is contained in:
Joerg Mueller 2011-08-30 09:15:55 +00:00
commit 9424b1ceff
438 changed files with 68102 additions and 23866 deletions

@ -1539,6 +1539,63 @@ Game Types (bge.types)
Return the value matching key, or the default value if its not found. Return the value matching key, or the default value if its not found.
:return: The key value or a default. :return: The key value or a default.
.. method:: playAction(name, start_frame, end_frame, layer=0, priority=0 blendin=0, play_mode=ACT_MODE_PLAY, layer_weight=0.0, ipo_flags=0, speed=1.0)
Plays an action.
:arg name: the name of the action
:type name: string
:arg start: the start frame of the action
:type start: float
:arg end: the end frame of the action
:type end: float
:arg layer: the layer the action will play in (actions in different layers are added/blended together)
:type layer: integer
:arg priority: only play this action if there isn't an action currently playing in this layer with a higher (lower number) priority
:type priority: integer
:arg blendin: the amount of blending between this animation and the previous one on this layer
:type blendin: float
:arg play_mode: the play mode
:type play_mode: KX_ACTION_PLAY, KX_ACTION_LOOP, or KX_ACTION_PING_PONG
:arg layer_weight: how much of the previous layer to use for blending (0 = add)
:type layer_weight: float
:arg ipo_flags: flags for the old IPO behaviors (force, etc)
:type ipo_flags: int bitfield
:arg speed: the playback speed of the action as a factor (1.0 = normal speed, 2.0 = 2x speed, etc)
:type speed: float
.. method:: stopAction(layer=0)
Stop playing the action on the given layer.
:arg layer: The layer to stop playing.
:type layer: integer
.. method:: getActionFrame(layer=0)
Gets the current frame of the action playing in the supplied layer.
:arg layer: The layer that you want to get the frame from.
:type layer: integer
:return: The current frame of the action
.. method:: setActionFrame(frame, layer=0)
Set the current frame of the action playing in the supplied layer.
:arg layer: The layer where you want to set the frame
:type layer: integer
:arg frame: The frame to set the action to
:type frame: float
.. method:: isPlayingAction(layer=0)
Checks to see if there is an action playing in the given layer.
:arg layer: The layer to check for a playing action.
:type layer: integer
.. class:: KX_IpoActuator(SCA_IActuator) .. class:: KX_IpoActuator(SCA_IActuator)
IPO actuator activates an animation. IPO actuator activates an animation.

@ -41,6 +41,8 @@ set(SRC
FX/AUD_DelayReader.cpp FX/AUD_DelayReader.cpp
FX/AUD_DoubleFactory.cpp FX/AUD_DoubleFactory.cpp
FX/AUD_DoubleReader.cpp FX/AUD_DoubleReader.cpp
FX/AUD_DynamicIIRFilterFactory.cpp
FX/AUD_DynamicIIRFilterReader.cpp
FX/AUD_EffectFactory.cpp FX/AUD_EffectFactory.cpp
FX/AUD_EffectReader.cpp FX/AUD_EffectReader.cpp
FX/AUD_EnvelopeFactory.cpp FX/AUD_EnvelopeFactory.cpp
@ -66,6 +68,8 @@ set(SRC
FX/AUD_SuperposeReader.cpp FX/AUD_SuperposeReader.cpp
FX/AUD_VolumeFactory.cpp FX/AUD_VolumeFactory.cpp
intern/AUD_3DMath.h intern/AUD_3DMath.h
intern/AUD_AnimateableProperty.cpp
intern/AUD_AnimateableProperty.h
intern/AUD_Buffer.cpp intern/AUD_Buffer.cpp
intern/AUD_Buffer.h intern/AUD_Buffer.h
intern/AUD_BufferReader.cpp intern/AUD_BufferReader.cpp
@ -82,14 +86,21 @@ set(SRC
intern/AUD_ConverterFunctions.h intern/AUD_ConverterFunctions.h
intern/AUD_ConverterReader.cpp intern/AUD_ConverterReader.cpp
intern/AUD_ConverterReader.h intern/AUD_ConverterReader.h
intern/AUD_DefaultMixer.cpp
intern/AUD_DefaultMixer.h
intern/AUD_FileFactory.cpp intern/AUD_FileFactory.cpp
intern/AUD_FileFactory.h intern/AUD_FileFactory.h
intern/AUD_FileWriter.cpp
intern/AUD_FileWriter.h
intern/AUD_I3DDevice.h intern/AUD_I3DDevice.h
intern/AUD_I3DHandle.h
intern/AUD_IDevice.h intern/AUD_IDevice.h
intern/AUD_IFactory.h intern/AUD_IFactory.h
intern/AUD_IHandle.h
intern/AUD_IReader.h intern/AUD_IReader.h
intern/AUD_IWriter.h
intern/AUD_JOSResampleFactory.cpp
intern/AUD_JOSResampleFactory.h
intern/AUD_JOSResampleReader.cpp
intern/AUD_JOSResampleReader.h
intern/AUD_LinearResampleFactory.cpp intern/AUD_LinearResampleFactory.cpp
intern/AUD_LinearResampleFactory.h intern/AUD_LinearResampleFactory.h
intern/AUD_LinearResampleReader.cpp intern/AUD_LinearResampleReader.cpp
@ -104,9 +115,15 @@ set(SRC
intern/AUD_ReadDevice.cpp intern/AUD_ReadDevice.cpp
intern/AUD_ReadDevice.h intern/AUD_ReadDevice.h
intern/AUD_Reference.h intern/AUD_Reference.h
intern/AUD_ResampleFactory.h intern/AUD_ReferenceHandler.cpp
intern/AUD_ResampleReader.cpp
intern/AUD_ResampleReader.h
intern/AUD_SequencerEntry.cpp
intern/AUD_SequencerEntry.h
intern/AUD_SequencerFactory.cpp intern/AUD_SequencerFactory.cpp
intern/AUD_SequencerFactory.h intern/AUD_SequencerFactory.h
intern/AUD_SequencerHandle.cpp
intern/AUD_SequencerHandle.h
intern/AUD_SequencerReader.cpp intern/AUD_SequencerReader.cpp
intern/AUD_SequencerReader.h intern/AUD_SequencerReader.h
intern/AUD_SilenceFactory.cpp intern/AUD_SilenceFactory.cpp
@ -131,6 +148,8 @@ set(SRC
FX/AUD_DelayReader.h FX/AUD_DelayReader.h
FX/AUD_DoubleFactory.h FX/AUD_DoubleFactory.h
FX/AUD_DoubleReader.h FX/AUD_DoubleReader.h
FX/AUD_DynamicIIRFilterFactory.h
FX/AUD_DynamicIIRFilterReader.h
FX/AUD_EffectFactory.h FX/AUD_EffectFactory.h
FX/AUD_EffectReader.h FX/AUD_EffectReader.h
FX/AUD_EnvelopeFactory.h FX/AUD_EnvelopeFactory.h
@ -168,9 +187,11 @@ if(WITH_CODEC_FFMPEG)
list(APPEND SRC list(APPEND SRC
ffmpeg/AUD_FFMPEGFactory.cpp ffmpeg/AUD_FFMPEGFactory.cpp
ffmpeg/AUD_FFMPEGReader.cpp ffmpeg/AUD_FFMPEGReader.cpp
ffmpeg/AUD_FFMPEGWriter.cpp
ffmpeg/AUD_FFMPEGFactory.h ffmpeg/AUD_FFMPEGFactory.h
ffmpeg/AUD_FFMPEGReader.h ffmpeg/AUD_FFMPEGReader.h
ffmpeg/AUD_FFMPEGWriter.h
) )
endif() endif()
@ -230,9 +251,11 @@ if(WITH_CODEC_SNDFILE)
list(APPEND SRC list(APPEND SRC
sndfile/AUD_SndFileFactory.cpp sndfile/AUD_SndFileFactory.cpp
sndfile/AUD_SndFileReader.cpp sndfile/AUD_SndFileReader.cpp
sndfile/AUD_SndFileWriter.cpp
sndfile/AUD_SndFileFactory.h sndfile/AUD_SndFileFactory.h
sndfile/AUD_SndFileReader.h sndfile/AUD_SndFileReader.h
sndfile/AUD_SndFileWriter.h
) )
endif() endif()

@ -32,7 +32,7 @@
#include "AUD_AccumulatorFactory.h" #include "AUD_AccumulatorFactory.h"
#include "AUD_CallbackIIRFilterReader.h" #include "AUD_CallbackIIRFilterReader.h"
sample_t accumulatorFilterAdditive(AUD_CallbackIIRFilterReader* reader, void* useless) sample_t AUD_AccumulatorFactory::accumulatorFilterAdditive(AUD_CallbackIIRFilterReader* reader, void* useless)
{ {
float in = reader->x(0); float in = reader->x(0);
float lastin = reader->x(-1); float lastin = reader->x(-1);
@ -42,7 +42,7 @@ sample_t accumulatorFilterAdditive(AUD_CallbackIIRFilterReader* reader, void* us
return out; return out;
} }
sample_t accumulatorFilter(AUD_CallbackIIRFilterReader* reader, void* useless) sample_t AUD_AccumulatorFactory::accumulatorFilter(AUD_CallbackIIRFilterReader* reader, void* useless)
{ {
float in = reader->x(0); float in = reader->x(0);
float lastin = reader->x(-1); float lastin = reader->x(-1);
@ -52,14 +52,14 @@ sample_t accumulatorFilter(AUD_CallbackIIRFilterReader* reader, void* useless)
return out; return out;
} }
AUD_AccumulatorFactory::AUD_AccumulatorFactory(AUD_IFactory* factory, AUD_AccumulatorFactory::AUD_AccumulatorFactory(AUD_Reference<AUD_IFactory> factory,
bool additive) : bool additive) :
AUD_EffectFactory(factory), AUD_EffectFactory(factory),
m_additive(additive) m_additive(additive)
{ {
} }
AUD_IReader* AUD_AccumulatorFactory::createReader() const AUD_Reference<AUD_IReader> AUD_AccumulatorFactory::createReader()
{ {
return new AUD_CallbackIIRFilterReader(getReader(), 2, 2, return new AUD_CallbackIIRFilterReader(getReader(), 2, 2,
m_additive ? accumulatorFilterAdditive : accumulatorFilter); m_additive ? accumulatorFilterAdditive : accumulatorFilter);

@ -33,9 +33,14 @@
#define AUD_ACCUMULATORFACTORY #define AUD_ACCUMULATORFACTORY
#include "AUD_EffectFactory.h" #include "AUD_EffectFactory.h"
class AUD_CallbackIIRFilterReader;
/** /**
* This factory creates an accumulator reader. * This factory creates an accumulator reader.
*
* The accumulator adds the difference at the input to the last output in case
* it's positive. In additive mode it additionaly adds the difference always.
* So in case the difference is positive, it's added twice.
*/ */
class AUD_AccumulatorFactory : public AUD_EffectFactory class AUD_AccumulatorFactory : public AUD_EffectFactory
{ {
@ -55,9 +60,12 @@ public:
* \param factory The input factory. * \param factory The input factory.
* \param additive Whether the accumulator is additive. * \param additive Whether the accumulator is additive.
*/ */
AUD_AccumulatorFactory(AUD_IFactory* factory, bool additive = false); AUD_AccumulatorFactory(AUD_Reference<AUD_IFactory> factory, bool additive = false);
virtual AUD_IReader* createReader() const; virtual AUD_Reference<AUD_IReader> createReader();
static sample_t accumulatorFilterAdditive(AUD_CallbackIIRFilterReader* reader, void* useless);
static sample_t accumulatorFilter(AUD_CallbackIIRFilterReader* reader, void* useless);
}; };
#endif //AUD_ACCUMULATORFACTORY #endif //AUD_ACCUMULATORFACTORY

@ -33,20 +33,20 @@
#include <cstring> #include <cstring>
#define CC m_channels + m_channel #define CC m_specs.channels + m_channel
AUD_BaseIIRFilterReader::AUD_BaseIIRFilterReader(AUD_IReader* reader, int in, AUD_BaseIIRFilterReader::AUD_BaseIIRFilterReader(AUD_Reference<AUD_IReader> reader, int in,
int out) : int out) :
AUD_EffectReader(reader), AUD_EffectReader(reader),
m_channels(reader->getSpecs().channels), m_specs(reader->getSpecs()),
m_xlen(in), m_ylen(out), m_xlen(in), m_ylen(out),
m_xpos(0), m_ypos(0), m_channel(0) m_xpos(0), m_ypos(0), m_channel(0)
{ {
m_x = new sample_t[in * m_channels]; m_x = new sample_t[m_xlen * m_specs.channels];
m_y = new sample_t[out * m_channels]; m_y = new sample_t[m_ylen * m_specs.channels];
memset(m_x, 0, sizeof(sample_t) * in * m_channels); memset(m_x, 0, sizeof(sample_t) * m_xlen * m_specs.channels);
memset(m_y, 0, sizeof(sample_t) * out * m_channels); memset(m_y, 0, sizeof(sample_t) * m_ylen * m_specs.channels);
} }
AUD_BaseIIRFilterReader::~AUD_BaseIIRFilterReader() AUD_BaseIIRFilterReader::~AUD_BaseIIRFilterReader()
@ -55,24 +55,77 @@ AUD_BaseIIRFilterReader::~AUD_BaseIIRFilterReader()
delete[] m_y; delete[] m_y;
} }
void AUD_BaseIIRFilterReader::read(int & length, sample_t* & buffer) void AUD_BaseIIRFilterReader::setLengths(int in, int out)
{ {
sample_t* buf; if(in != m_xlen)
{
sample_t* xn = new sample_t[in * m_specs.channels];
memset(xn, 0, sizeof(sample_t) * in * m_specs.channels);
int samplesize = AUD_SAMPLE_SIZE(m_reader->getSpecs()); for(m_channel = 0; m_channel < m_specs.channels; m_channel++)
{
for(int i = 1; i <= in && i <= m_xlen; i++)
{
xn[(in - i) * CC] = x(-i);
}
}
m_reader->read(length, buf); delete[] m_x;
m_x = xn;
m_xpos = 0;
m_xlen = in;
}
if(m_buffer.getSize() < length * samplesize) if(out != m_ylen)
m_buffer.resize(length * samplesize); {
sample_t* yn = new sample_t[out * m_specs.channels];
memset(yn, 0, sizeof(sample_t) * out * m_specs.channels);
buffer = m_buffer.getBuffer(); for(m_channel = 0; m_channel < m_specs.channels; m_channel++)
{
for(int i = 1; i <= out && i <= m_ylen; i++)
{
yn[(out - i) * CC] = y(-i);
}
}
for(m_channel = 0; m_channel < m_channels; m_channel++) delete[] m_y;
m_y = yn;
m_ypos = 0;
m_ylen = out;
}
}
void AUD_BaseIIRFilterReader::read(int& length, bool& eos, sample_t* buffer)
{
AUD_Specs specs = m_reader->getSpecs();
if(specs.channels != m_specs.channels)
{
m_specs.channels = specs.channels;
delete[] m_x;
delete[] m_y;
m_x = new sample_t[m_xlen * m_specs.channels];
m_y = new sample_t[m_ylen * m_specs.channels];
memset(m_x, 0, sizeof(sample_t) * m_xlen * m_specs.channels);
memset(m_y, 0, sizeof(sample_t) * m_ylen * m_specs.channels);
}
if(specs.rate != m_specs.rate)
{
m_specs = specs;
sampleRateChanged(m_specs.rate);
}
m_reader->read(length, eos, buffer);
for(m_channel = 0; m_channel < m_specs.channels; m_channel++)
{ {
for(int i = 0; i < length; i++) for(int i = 0; i < length; i++)
{ {
m_x[m_xpos * CC] = buf[i * CC]; m_x[m_xpos * CC] = buffer[i * CC];
m_y[m_ypos * CC] = buffer[i * CC] = filter(); m_y[m_ypos * CC] = buffer[i * CC] = filter();
m_xpos = (m_xpos + 1) % m_xlen; m_xpos = (m_xpos + 1) % m_xlen;
@ -80,3 +133,7 @@ void AUD_BaseIIRFilterReader::read(int & length, sample_t* & buffer)
} }
} }
} }
void AUD_BaseIIRFilterReader::sampleRateChanged(AUD_SampleRate rate)
{
}

@ -42,24 +42,19 @@ class AUD_BaseIIRFilterReader : public AUD_EffectReader
{ {
private: private:
/** /**
* Channel count. * Specs.
*/ */
const int m_channels; AUD_Specs m_specs;
/** /**
* Length of input samples needed. * Length of input samples needed.
*/ */
const int m_xlen; int m_xlen;
/** /**
* Length of output samples needed. * Length of output samples needed.
*/ */
const int m_ylen; int m_ylen;
/**
* The playback buffer.
*/
AUD_Buffer m_buffer;
/** /**
* The last in samples array. * The last in samples array.
@ -97,24 +92,46 @@ protected:
* \param in The count of past input samples needed. * \param in The count of past input samples needed.
* \param out The count of past output samples needed. * \param out The count of past output samples needed.
*/ */
AUD_BaseIIRFilterReader(AUD_IReader* reader, int in, int out); AUD_BaseIIRFilterReader(AUD_Reference<AUD_IReader> reader, int in, int out);
void setLengths(int in, int out);
public: public:
/**
* Retrieves the last input samples.
* \param pos The position, valid are 0 (current) or negative values.
* \return The sample value.
*/
inline sample_t x(int pos) inline sample_t x(int pos)
{ {
return m_x[(m_xpos + pos + m_xlen) % m_xlen * m_channels + m_channel]; return m_x[(m_xpos + pos + m_xlen) % m_xlen * m_specs.channels + m_channel];
} }
/**
* Retrieves the last output samples.
* \param pos The position, valid are negative values.
* \return The sample value.
*/
inline sample_t y(int pos) inline sample_t y(int pos)
{ {
return m_y[(m_ypos + pos + m_ylen) % m_ylen * m_channels + m_channel]; return m_y[(m_ypos + pos + m_ylen) % m_ylen * m_specs.channels + m_channel];
} }
virtual ~AUD_BaseIIRFilterReader(); virtual ~AUD_BaseIIRFilterReader();
virtual void read(int & length, sample_t* & buffer); virtual void read(int& length, bool& eos, sample_t* buffer);
/**
* Runs the filtering function.
* \return The current output sample value.
*/
virtual sample_t filter()=0; virtual sample_t filter()=0;
/**
* Notifies the filter about a sample rate change.
* \param rate The new sample rate.
*/
virtual void sampleRateChanged(AUD_SampleRate rate);
}; };
#endif //AUD_BASEIIRFILTERREADER #endif //AUD_BASEIIRFILTERREADER

@ -41,19 +41,18 @@
#define BWPB41 0.76536686473 #define BWPB41 0.76536686473
#define BWPB42 1.84775906502 #define BWPB42 1.84775906502
AUD_ButterworthFactory::AUD_ButterworthFactory(AUD_IFactory* factory, AUD_ButterworthFactory::AUD_ButterworthFactory(AUD_Reference<AUD_IFactory> factory,
float frequency) : float frequency) :
AUD_EffectFactory(factory), AUD_DynamicIIRFilterFactory(factory),
m_frequency(frequency) m_frequency(frequency)
{ {
} }
AUD_IReader* AUD_ButterworthFactory::createReader() const void AUD_ButterworthFactory::recalculateCoefficients(AUD_SampleRate rate,
std::vector<float> &b,
std::vector<float> &a)
{ {
AUD_IReader* reader = getReader(); float omega = 2 * tan(m_frequency * M_PI / rate);
// calculate coefficients
float omega = 2 * tan(m_frequency * M_PI / reader->getSpecs().rate);
float o2 = omega * omega; float o2 = omega * omega;
float o4 = o2 * o2; float o4 = o2 * o2;
float x1 = o2 + 2 * BWPB41 * omega + 4; float x1 = o2 + 2 * BWPB41 * omega + 4;
@ -62,7 +61,6 @@ AUD_IReader* AUD_ButterworthFactory::createReader() const
float y2 = o2 - 2 * BWPB42 * omega + 4; float y2 = o2 - 2 * BWPB42 * omega + 4;
float o228 = 2 * o2 - 8; float o228 = 2 * o2 - 8;
float norm = x1 * x2; float norm = x1 * x2;
std::vector<float> a, b;
a.push_back(1); a.push_back(1);
a.push_back((x1 + x2) * o228 / norm); a.push_back((x1 + x2) * o228 / norm);
a.push_back((x1 * y2 + x2 * y1 + o228 * o228) / norm); a.push_back((x1 * y2 + x2 * y1 + o228 * o228) / norm);
@ -73,6 +71,4 @@ AUD_IReader* AUD_ButterworthFactory::createReader() const
b.push_back(6 * o4 / norm); b.push_back(6 * o4 / norm);
b.push_back(b[1]); b.push_back(b[1]);
b.push_back(b[0]); b.push_back(b[0]);
return new AUD_IIRFilterReader(reader, b, a);
} }

@ -32,12 +32,12 @@
#ifndef AUD_BUTTERWORTHFACTORY #ifndef AUD_BUTTERWORTHFACTORY
#define AUD_BUTTERWORTHFACTORY #define AUD_BUTTERWORTHFACTORY
#include "AUD_EffectFactory.h" #include "AUD_DynamicIIRFilterFactory.h"
/** /**
* This factory creates a butterworth filter reader. * This factory creates a butterworth lowpass filter reader.
*/ */
class AUD_ButterworthFactory : public AUD_EffectFactory class AUD_ButterworthFactory : public AUD_DynamicIIRFilterFactory
{ {
private: private:
/** /**
@ -55,9 +55,11 @@ public:
* \param factory The input factory. * \param factory The input factory.
* \param frequency The cutoff frequency. * \param frequency The cutoff frequency.
*/ */
AUD_ButterworthFactory(AUD_IFactory* factory, float frequency); AUD_ButterworthFactory(AUD_Reference<AUD_IFactory> factory, float frequency);
virtual AUD_IReader* createReader() const; virtual void recalculateCoefficients(AUD_SampleRate rate,
std::vector<float>& b,
std::vector<float>& a);
}; };
#endif //AUD_BUTTERWORTHFACTORY #endif //AUD_BUTTERWORTHFACTORY

@ -31,7 +31,7 @@
#include "AUD_CallbackIIRFilterReader.h" #include "AUD_CallbackIIRFilterReader.h"
AUD_CallbackIIRFilterReader::AUD_CallbackIIRFilterReader(AUD_IReader* reader, AUD_CallbackIIRFilterReader::AUD_CallbackIIRFilterReader(AUD_Reference<AUD_IReader> reader,
int in, int out, int in, int out,
doFilterIIR doFilter, doFilterIIR doFilter,
endFilterIIR endFilter, endFilterIIR endFilter,

@ -76,7 +76,7 @@ public:
* \param endFilter The finishing callback. * \param endFilter The finishing callback.
* \param data Data pointer for the callbacks. * \param data Data pointer for the callbacks.
*/ */
AUD_CallbackIIRFilterReader(AUD_IReader* reader, int in, int out, AUD_CallbackIIRFilterReader(AUD_Reference<AUD_IReader> reader, int in, int out,
doFilterIIR doFilter, doFilterIIR doFilter,
endFilterIIR endFilter = 0, endFilterIIR endFilter = 0,
void* data = 0); void* data = 0);

@ -33,7 +33,7 @@
#include "AUD_DelayReader.h" #include "AUD_DelayReader.h"
#include "AUD_Space.h" #include "AUD_Space.h"
AUD_DelayFactory::AUD_DelayFactory(AUD_IFactory* factory, float delay) : AUD_DelayFactory::AUD_DelayFactory(AUD_Reference<AUD_IFactory> factory, float delay) :
AUD_EffectFactory(factory), AUD_EffectFactory(factory),
m_delay(delay) m_delay(delay)
{ {
@ -44,7 +44,7 @@ float AUD_DelayFactory::getDelay() const
return m_delay; return m_delay;
} }
AUD_IReader* AUD_DelayFactory::createReader() const AUD_Reference<AUD_IReader> AUD_DelayFactory::createReader()
{ {
return new AUD_DelayReader(getReader(), m_delay); return new AUD_DelayReader(getReader(), m_delay);
} }

@ -55,14 +55,14 @@ public:
* \param factory The input factory. * \param factory The input factory.
* \param delay The desired delay in seconds. * \param delay The desired delay in seconds.
*/ */
AUD_DelayFactory(AUD_IFactory* factory, float delay = 0); AUD_DelayFactory(AUD_Reference<AUD_IFactory> factory, float delay = 0);
/** /**
* Returns the delay in seconds. * Returns the delay in seconds.
*/ */
float getDelay() const; float getDelay() const;
virtual AUD_IReader* createReader() const; virtual AUD_Reference<AUD_IReader> createReader();
}; };
#endif //AUD_DELAYFACTORY #endif //AUD_DELAYFACTORY

@ -33,11 +33,10 @@
#include <cstring> #include <cstring>
AUD_DelayReader::AUD_DelayReader(AUD_IReader* reader, float delay) : AUD_DelayReader::AUD_DelayReader(AUD_Reference<AUD_IReader> reader, float delay) :
AUD_EffectReader(reader), AUD_EffectReader(reader),
m_delay(int(delay * reader->getSpecs().rate)), m_delay(int(delay * reader->getSpecs().rate)),
m_remdelay(int(delay * reader->getSpecs().rate)), m_remdelay(int(delay * reader->getSpecs().rate))
m_empty(true)
{ {
} }
@ -70,49 +69,30 @@ int AUD_DelayReader::getPosition() const
return m_reader->getPosition() + m_delay; return m_reader->getPosition() + m_delay;
} }
void AUD_DelayReader::read(int & length, sample_t* & buffer) void AUD_DelayReader::read(int& length, bool& eos, sample_t* buffer)
{ {
if(m_remdelay > 0) if(m_remdelay > 0)
{ {
AUD_Specs specs = m_reader->getSpecs(); AUD_Specs specs = m_reader->getSpecs();
int samplesize = AUD_SAMPLE_SIZE(specs); int samplesize = AUD_SAMPLE_SIZE(specs);
if(m_buffer.getSize() < length * samplesize)
{
m_buffer.resize(length * samplesize);
m_empty = false;
}
buffer = m_buffer.getBuffer();
if(length > m_remdelay) if(length > m_remdelay)
{ {
if(!m_empty)
memset(buffer, 0, m_remdelay * samplesize); memset(buffer, 0, m_remdelay * samplesize);
int len = length - m_remdelay; int len = length - m_remdelay;
sample_t* buf; m_reader->read(len, eos, buffer + m_remdelay * specs.channels);
m_reader->read(len, buf);
memcpy(buffer + m_remdelay * specs.channels,
buf, len * samplesize);
if(len < length-m_remdelay)
length = m_remdelay + len; length = m_remdelay + len;
m_remdelay = 0; m_remdelay = 0;
m_empty = false;
} }
else else
{
if(!m_empty)
{ {
memset(buffer, 0, length * samplesize); memset(buffer, 0, length * samplesize);
m_empty = true;
}
m_remdelay -= length; m_remdelay -= length;
} }
} }
else else
m_reader->read(length, buffer); m_reader->read(length, eos, buffer);
} }

@ -36,16 +36,11 @@
#include "AUD_Buffer.h" #include "AUD_Buffer.h"
/** /**
* This class reads another reader and changes it's delay. * This class reads another reader and delays it.
*/ */
class AUD_DelayReader : public AUD_EffectReader class AUD_DelayReader : public AUD_EffectReader
{ {
private: private:
/**
* The playback buffer.
*/
AUD_Buffer m_buffer;
/** /**
* The delay level. * The delay level.
*/ */
@ -56,11 +51,6 @@ private:
*/ */
int m_remdelay; int m_remdelay;
/**
* Whether the buffer is currently filled with zeros.
*/
bool m_empty;
// hide copy constructor and operator= // hide copy constructor and operator=
AUD_DelayReader(const AUD_DelayReader&); AUD_DelayReader(const AUD_DelayReader&);
AUD_DelayReader& operator=(const AUD_DelayReader&); AUD_DelayReader& operator=(const AUD_DelayReader&);
@ -71,12 +61,12 @@ public:
* \param reader The reader to read from. * \param reader The reader to read from.
* \param delay The delay in seconds. * \param delay The delay in seconds.
*/ */
AUD_DelayReader(AUD_IReader* reader, float delay); AUD_DelayReader(AUD_Reference<AUD_IReader> reader, float delay);
virtual void seek(int position); virtual void seek(int position);
virtual int getLength() const; virtual int getLength() const;
virtual int getPosition() const; virtual int getPosition() const;
virtual void read(int & length, sample_t* & buffer); virtual void read(int& length, bool& eos, sample_t* buffer);
}; };
#endif //AUD_DELAYREADER #endif //AUD_DELAYREADER

@ -32,25 +32,15 @@
#include "AUD_DoubleFactory.h" #include "AUD_DoubleFactory.h"
#include "AUD_DoubleReader.h" #include "AUD_DoubleReader.h"
AUD_DoubleFactory::AUD_DoubleFactory(AUD_IFactory* factory1, AUD_IFactory* factory2) : AUD_DoubleFactory::AUD_DoubleFactory(AUD_Reference<AUD_IFactory> factory1, AUD_Reference<AUD_IFactory> factory2) :
m_factory1(factory1), m_factory2(factory2) m_factory1(factory1), m_factory2(factory2)
{ {
} }
AUD_IReader* AUD_DoubleFactory::createReader() const AUD_Reference<AUD_IReader> AUD_DoubleFactory::createReader()
{ {
AUD_IReader* reader1 = m_factory1->createReader(); AUD_Reference<AUD_IReader> reader1 = m_factory1->createReader();
AUD_IReader* reader2; AUD_Reference<AUD_IReader> reader2 = m_factory2->createReader();
try
{
reader2 = m_factory2->createReader();
}
catch(AUD_Exception&)
{
delete reader1;
throw;
}
return new AUD_DoubleReader(reader1, reader2); return new AUD_DoubleReader(reader1, reader2);
} }

@ -36,7 +36,6 @@
/** /**
* This factory plays two other factories behind each other. * This factory plays two other factories behind each other.
* \note Readers from the underlying factories must have the same sample rate and channel count.
*/ */
class AUD_DoubleFactory : public AUD_IFactory class AUD_DoubleFactory : public AUD_IFactory
{ {
@ -44,12 +43,12 @@ private:
/** /**
* First played factory. * First played factory.
*/ */
AUD_IFactory* m_factory1; AUD_Reference<AUD_IFactory> m_factory1;
/** /**
* Second played factory. * Second played factory.
*/ */
AUD_IFactory* m_factory2; AUD_Reference<AUD_IFactory> m_factory2;
// hide copy constructor and operator= // hide copy constructor and operator=
AUD_DoubleFactory(const AUD_DoubleFactory&); AUD_DoubleFactory(const AUD_DoubleFactory&);
@ -61,9 +60,9 @@ public:
* \param factory1 The first input factory. * \param factory1 The first input factory.
* \param factory2 The second input factory. * \param factory2 The second input factory.
*/ */
AUD_DoubleFactory(AUD_IFactory* factory1, AUD_IFactory* factory2); AUD_DoubleFactory(AUD_Reference<AUD_IFactory> factory1, AUD_Reference<AUD_IFactory> factory2);
virtual AUD_IReader* createReader() const; virtual AUD_Reference<AUD_IReader> createReader();
}; };
#endif //AUD_DOUBLEFACTORY #endif //AUD_DOUBLEFACTORY

@ -33,28 +33,17 @@
#include <cstring> #include <cstring>
static const char* specs_error = "AUD_DoubleReader: Both readers have to have " AUD_DoubleReader::AUD_DoubleReader(AUD_Reference<AUD_IReader> reader1,
"the same specs."; AUD_Reference<AUD_IReader> reader2) :
AUD_DoubleReader::AUD_DoubleReader(AUD_IReader* reader1,
AUD_IReader* reader2) :
m_reader1(reader1), m_reader2(reader2), m_finished1(false) m_reader1(reader1), m_reader2(reader2), m_finished1(false)
{ {
AUD_Specs s1, s2; AUD_Specs s1, s2;
s1 = reader1->getSpecs(); s1 = reader1->getSpecs();
s2 = reader2->getSpecs(); s2 = reader2->getSpecs();
if(memcmp(&s1, &s2, sizeof(AUD_Specs)) != 0)
{
delete reader1;
delete reader2;
AUD_THROW(AUD_ERROR_SPECS, specs_error);
}
} }
AUD_DoubleReader::~AUD_DoubleReader() AUD_DoubleReader::~AUD_DoubleReader()
{ {
delete m_reader1;
delete m_reader2;
} }
bool AUD_DoubleReader::isSeekable() const bool AUD_DoubleReader::isSeekable() const
@ -90,43 +79,36 @@ int AUD_DoubleReader::getPosition() const
AUD_Specs AUD_DoubleReader::getSpecs() const AUD_Specs AUD_DoubleReader::getSpecs() const
{ {
return m_reader1->getSpecs(); return m_finished1 ? m_reader1->getSpecs() : m_reader2->getSpecs();
} }
void AUD_DoubleReader::read(int & length, sample_t* & buffer) void AUD_DoubleReader::read(int& length, bool& eos, sample_t* buffer)
{ {
eos = false;
if(!m_finished1) if(!m_finished1)
{ {
int len = length; int len = length;
m_reader1->read(len, buffer);
m_reader1->read(len, m_finished1, buffer);
if(len < length) if(len < length)
{ {
AUD_Specs specs = m_reader1->getSpecs(); AUD_Specs specs1, specs2;
int samplesize = AUD_SAMPLE_SIZE(specs); specs1 = m_reader1->getSpecs();
specs2 = m_reader2->getSpecs();
if(m_buffer.getSize() < length * samplesize) if(AUD_COMPARE_SPECS(specs1, specs2))
m_buffer.resize(length * samplesize); {
int len2 = length - len;
sample_t* buf = buffer; m_reader2->read(len2, eos, buffer + specs1.channels * len);
buffer = m_buffer.getBuffer(); length = len + len2;
}
memcpy(buffer, buf, len * samplesize); else
length = len;
len = length - len;
length -= len;
m_reader2->read(len, buf);
memcpy(buffer + length * specs.channels, buf,
len * samplesize);
length += len;
m_finished1 = true;
} }
} }
else else
{ {
m_reader2->read(length, buffer); m_reader2->read(length, eos, buffer);
} }
} }

@ -34,9 +34,10 @@
#include "AUD_IReader.h" #include "AUD_IReader.h"
#include "AUD_Buffer.h" #include "AUD_Buffer.h"
#include "AUD_Reference.h"
/** /**
* This reader plays two readers with the same specs sequently. * This reader plays two readers sequently.
*/ */
class AUD_DoubleReader : public AUD_IReader class AUD_DoubleReader : public AUD_IReader
{ {
@ -44,35 +45,29 @@ private:
/** /**
* The first reader. * The first reader.
*/ */
AUD_IReader* m_reader1; AUD_Reference<AUD_IReader> m_reader1;
/** /**
* The second reader. * The second reader.
*/ */
AUD_IReader* m_reader2; AUD_Reference<AUD_IReader> m_reader2;
/** /**
* Whether we've reached the end of the first reader. * Whether we've reached the end of the first reader.
*/ */
bool m_finished1; bool m_finished1;
/**
* The playback buffer for the intersecting part.
*/
AUD_Buffer m_buffer;
// hide copy constructor and operator= // hide copy constructor and operator=
AUD_DoubleReader(const AUD_DoubleReader&); AUD_DoubleReader(const AUD_DoubleReader&);
AUD_DoubleReader& operator=(const AUD_DoubleReader&); AUD_DoubleReader& operator=(const AUD_DoubleReader&);
public: public:
/** /**
* Creates a new ping pong reader. * Creates a new double reader.
* \param reader1 The first reader to read from. * \param reader1 The first reader to read from.
* \param reader2 The second reader to read from. * \param reader2 The second reader to read from.
* \exception AUD_Exception Thrown if the specs from the readers differ.
*/ */
AUD_DoubleReader(AUD_IReader* reader1, AUD_IReader* reader2); AUD_DoubleReader(AUD_Reference<AUD_IReader> reader1, AUD_Reference<AUD_IReader> reader2);
/** /**
* Destroys the reader. * Destroys the reader.
@ -84,7 +79,7 @@ public:
virtual int getLength() const; virtual int getLength() const;
virtual int getPosition() const; virtual int getPosition() const;
virtual AUD_Specs getSpecs() const; virtual AUD_Specs getSpecs() const;
virtual void read(int & length, sample_t* & buffer); virtual void read(int& length, bool& eos, sample_t* buffer);
}; };
#endif //AUD_DOUBLEREADER #endif //AUD_DOUBLEREADER

@ -0,0 +1,42 @@
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* Copyright 2009-2011 Jörg Hermann Müller
*
* This file is part of AudaSpace.
*
* Audaspace 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 2 of the License, or
* (at your option) any later version.
*
* AudaSpace 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 Audaspace; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file audaspace/FX/AUD_DynamicIIRFilterFactory.cpp
* \ingroup audfx
*/
#include "AUD_DynamicIIRFilterFactory.h"
#include "AUD_DynamicIIRFilterReader.h"
AUD_DynamicIIRFilterFactory::AUD_DynamicIIRFilterFactory(AUD_Reference<AUD_IFactory> factory) :
AUD_EffectFactory(factory)
{
}
AUD_Reference<AUD_IReader> AUD_DynamicIIRFilterFactory::createReader()
{
return new AUD_DynamicIIRFilterReader(getReader(), this);
}

@ -0,0 +1,65 @@
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* Copyright 2009-2011 Jörg Hermann Müller
*
* This file is part of AudaSpace.
*
* Audaspace 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 2 of the License, or
* (at your option) any later version.
*
* AudaSpace 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 Audaspace; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file audaspace/FX/AUD_DynamicIIRFilterFactory.h
* \ingroup audfx
*/
#ifndef AUD_DYNAMICIIRFILTERFACTORY
#define AUD_DYNAMICIIRFILTERFACTORY
#include "AUD_EffectFactory.h"
#include <vector>
/**
* This factory creates a IIR filter reader.
*
* This means that on sample rate change the filter recalculates its
* coefficients.
*/
class AUD_DynamicIIRFilterFactory : public AUD_EffectFactory
{
public:
/**
* Creates a new Dynmic IIR filter factory.
* \param factory The input factory.
*/
AUD_DynamicIIRFilterFactory(AUD_Reference<AUD_IFactory> factory);
virtual AUD_Reference<AUD_IReader> createReader();
/**
* Recalculates the filter coefficients.
* \param rate The sample rate of the audio data.
* \param[out] b The input filter coefficients.
* \param[out] a The output filter coefficients.
*/
virtual void recalculateCoefficients(AUD_SampleRate rate,
std::vector<float>& b,
std::vector<float>& a)=0;
};
#endif // AUD_DYNAMICIIRFILTERFACTORY

@ -0,0 +1,45 @@
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* Copyright 2009-2011 Jörg Hermann Müller
*
* This file is part of AudaSpace.
*
* Audaspace 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 2 of the License, or
* (at your option) any later version.
*
* AudaSpace 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 Audaspace; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file audaspace/FX/AUD_DynamicIIRFilterReader.cpp
* \ingroup audfx
*/
#include "AUD_DynamicIIRFilterReader.h"
AUD_DynamicIIRFilterReader::AUD_DynamicIIRFilterReader(AUD_Reference<AUD_IReader> reader,
AUD_Reference<AUD_DynamicIIRFilterFactory> factory) :
AUD_IIRFilterReader(reader, std::vector<float>(), std::vector<float>())
{
sampleRateChanged(reader->getSpecs().rate);
}
void AUD_DynamicIIRFilterReader::sampleRateChanged(AUD_SampleRate rate)
{
std::vector<float> a, b;
m_factory->recalculateCoefficients(rate, b, a);
setCoefficients(b, a);
}

@ -0,0 +1,56 @@
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* Copyright 2009-2011 Jörg Hermann Müller
*
* This file is part of AudaSpace.
*
* Audaspace 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 2 of the License, or
* (at your option) any later version.
*
* AudaSpace 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 Audaspace; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file audaspace/FX/AUD_DynamicIIRFilterReader.h
* \ingroup audfx
*/
#ifndef AUD_DYNAMICIIRFILTERREADER
#define AUD_DYNAMICIIRFILTERREADER
#include "AUD_IIRFilterReader.h"
#include "AUD_DynamicIIRFilterFactory.h"
/**
* This class is for dynamic infinite impulse response filters with simple
* coefficients that change depending on the sample rate.
*/
class AUD_DynamicIIRFilterReader : public AUD_IIRFilterReader
{
private:
/**
* The factory for dynamically recalculating filter coefficients.
*/
AUD_Reference<AUD_DynamicIIRFilterFactory> m_factory;
public:
AUD_DynamicIIRFilterReader(AUD_Reference<AUD_IReader> reader,
AUD_Reference<AUD_DynamicIIRFilterFactory> factory);
virtual void sampleRateChanged(AUD_SampleRate rate);
};
#endif // AUD_DYNAMICIIRFILTERREADER

@ -32,7 +32,7 @@
#include "AUD_EffectFactory.h" #include "AUD_EffectFactory.h"
#include "AUD_IReader.h" #include "AUD_IReader.h"
AUD_EffectFactory::AUD_EffectFactory(AUD_IFactory* factory) AUD_EffectFactory::AUD_EffectFactory(AUD_Reference<AUD_IFactory> factory)
{ {
m_factory = factory; m_factory = factory;
} }
@ -41,7 +41,7 @@ AUD_EffectFactory::~AUD_EffectFactory()
{ {
} }
AUD_IFactory* AUD_EffectFactory::getFactory() const AUD_Reference<AUD_IFactory> AUD_EffectFactory::getFactory() const
{ {
return m_factory; return m_factory;
} }

@ -49,7 +49,7 @@ protected:
/** /**
* If there is no reader it is created out of this factory. * If there is no reader it is created out of this factory.
*/ */
AUD_IFactory* m_factory; AUD_Reference<AUD_IFactory> m_factory;
/** /**
* Returns the reader created out of the factory. * Returns the reader created out of the factory.
@ -57,7 +57,7 @@ protected:
* classes. * classes.
* \return The reader created out of the factory. * \return The reader created out of the factory.
*/ */
inline AUD_IReader* getReader() const inline AUD_Reference<AUD_IReader> getReader() const
{ {
return m_factory->createReader(); return m_factory->createReader();
} }
@ -67,7 +67,7 @@ public:
* Creates a new factory. * Creates a new factory.
* \param factory The input factory. * \param factory The input factory.
*/ */
AUD_EffectFactory(AUD_IFactory* factory); AUD_EffectFactory(AUD_Reference<AUD_IFactory> factory);
/** /**
* Destroys the factory. * Destroys the factory.
@ -78,7 +78,7 @@ public:
* Returns the saved factory. * Returns the saved factory.
* \return The factory or NULL if there has no factory been saved. * \return The factory or NULL if there has no factory been saved.
*/ */
AUD_IFactory* getFactory() const; AUD_Reference<AUD_IFactory> getFactory() const;
}; };
#endif //AUD_EFFECTFACTORY #endif //AUD_EFFECTFACTORY

@ -31,14 +31,13 @@
#include "AUD_EffectReader.h" #include "AUD_EffectReader.h"
AUD_EffectReader::AUD_EffectReader(AUD_IReader* reader) AUD_EffectReader::AUD_EffectReader(AUD_Reference<AUD_IReader> reader)
{ {
m_reader = reader; m_reader = reader;
} }
AUD_EffectReader::~AUD_EffectReader() AUD_EffectReader::~AUD_EffectReader()
{ {
delete m_reader;
} }
bool AUD_EffectReader::isSeekable() const bool AUD_EffectReader::isSeekable() const
@ -66,7 +65,7 @@ AUD_Specs AUD_EffectReader::getSpecs() const
return m_reader->getSpecs(); return m_reader->getSpecs();
} }
void AUD_EffectReader::read(int & length, sample_t* & buffer) void AUD_EffectReader::read(int& length, bool& eos, sample_t* buffer)
{ {
m_reader->read(length, buffer); m_reader->read(length, eos, buffer);
} }

@ -33,6 +33,7 @@
#define AUD_EFFECTREADER #define AUD_EFFECTREADER
#include "AUD_IReader.h" #include "AUD_IReader.h"
#include "AUD_Reference.h"
/** /**
* This reader is a base class for all effect readers that take one other reader * This reader is a base class for all effect readers that take one other reader
@ -49,14 +50,14 @@ protected:
/** /**
* The reader to read from. * The reader to read from.
*/ */
AUD_IReader* m_reader; AUD_Reference<AUD_IReader> m_reader;
public: public:
/** /**
* Creates a new effect reader. * Creates a new effect reader.
* \param reader The reader to read from. * \param reader The reader to read from.
*/ */
AUD_EffectReader(AUD_IReader* reader); AUD_EffectReader(AUD_Reference<AUD_IReader> reader);
/** /**
* Destroys the reader. * Destroys the reader.
@ -68,7 +69,7 @@ public:
virtual int getLength() const; virtual int getLength() const;
virtual int getPosition() const; virtual int getPosition() const;
virtual AUD_Specs getSpecs() const; virtual AUD_Specs getSpecs() const;
virtual void read(int & length, sample_t* & buffer); virtual void read(int& length, bool& eos, sample_t* buffer);
}; };
#endif //AUD_EFFECTREADER #endif //AUD_EFFECTREADER

@ -42,7 +42,7 @@ struct EnvelopeParameters
float arthreshold; float arthreshold;
}; };
sample_t envelopeFilter(AUD_CallbackIIRFilterReader* reader, EnvelopeParameters* param) sample_t AUD_EnvelopeFactory::envelopeFilter(AUD_CallbackIIRFilterReader* reader, EnvelopeParameters* param)
{ {
float in = fabs(reader->x(0)); float in = fabs(reader->x(0));
float out = reader->y(-1); float out = reader->y(-1);
@ -51,12 +51,12 @@ sample_t envelopeFilter(AUD_CallbackIIRFilterReader* reader, EnvelopeParameters*
return (in > out ? param->attack : param->release) * (out - in) + in; return (in > out ? param->attack : param->release) * (out - in) + in;
} }
void endEnvelopeFilter(EnvelopeParameters* param) void AUD_EnvelopeFactory::endEnvelopeFilter(EnvelopeParameters* param)
{ {
delete param; delete param;
} }
AUD_EnvelopeFactory::AUD_EnvelopeFactory(AUD_IFactory* factory, float attack, AUD_EnvelopeFactory::AUD_EnvelopeFactory(AUD_Reference<AUD_IFactory> factory, float attack,
float release, float threshold, float release, float threshold,
float arthreshold) : float arthreshold) :
AUD_EffectFactory(factory), AUD_EffectFactory(factory),
@ -67,14 +67,14 @@ AUD_EnvelopeFactory::AUD_EnvelopeFactory(AUD_IFactory* factory, float attack,
{ {
} }
AUD_IReader* AUD_EnvelopeFactory::createReader() const AUD_Reference<AUD_IReader> AUD_EnvelopeFactory::createReader()
{ {
AUD_IReader* reader = getReader(); AUD_Reference<AUD_IReader> reader = getReader();
EnvelopeParameters* param = new EnvelopeParameters(); EnvelopeParameters* param = new EnvelopeParameters();
param->arthreshold = m_arthreshold; param->arthreshold = m_arthreshold;
param->attack = pow(m_arthreshold, 1.0f/(reader->getSpecs().rate * m_attack)); param->attack = pow(m_arthreshold, 1.0f/(static_cast<float>(reader->getSpecs().rate) * m_attack));
param->release = pow(m_arthreshold, 1.0f/(reader->getSpecs().rate * m_release)); param->release = pow(m_arthreshold, 1.0f/(static_cast<float>(reader->getSpecs().rate) * m_release));
param->threshold = m_threshold; param->threshold = m_threshold;
return new AUD_CallbackIIRFilterReader(reader, 1, 2, return new AUD_CallbackIIRFilterReader(reader, 1, 2,

@ -33,6 +33,8 @@
#define AUD_ENVELOPEFACTORY #define AUD_ENVELOPEFACTORY
#include "AUD_EffectFactory.h" #include "AUD_EffectFactory.h"
class AUD_CallbackIIRFilterReader;
struct EnvelopeParameters;
/** /**
* This factory creates an envelope follower reader. * This factory creates an envelope follower reader.
@ -73,10 +75,13 @@ public:
* \param threshold The threshold value. * \param threshold The threshold value.
* \param arthreshold The attack/release threshold value. * \param arthreshold The attack/release threshold value.
*/ */
AUD_EnvelopeFactory(AUD_IFactory* factory, float attack, float release, AUD_EnvelopeFactory(AUD_Reference<AUD_IFactory> factory, float attack, float release,
float threshold, float arthreshold); float threshold, float arthreshold);
virtual AUD_IReader* createReader() const; virtual AUD_Reference<AUD_IReader> createReader();
static sample_t envelopeFilter(AUD_CallbackIIRFilterReader* reader, EnvelopeParameters* param);
static void endEnvelopeFilter(EnvelopeParameters* param);
}; };
#endif //AUD_ENVELOPEFACTORY #endif //AUD_ENVELOPEFACTORY

@ -32,7 +32,7 @@
#include "AUD_FaderFactory.h" #include "AUD_FaderFactory.h"
#include "AUD_FaderReader.h" #include "AUD_FaderReader.h"
AUD_FaderFactory::AUD_FaderFactory(AUD_IFactory* factory, AUD_FadeType type, AUD_FaderFactory::AUD_FaderFactory(AUD_Reference<AUD_IFactory> factory, AUD_FadeType type,
float start, float length) : float start, float length) :
AUD_EffectFactory(factory), AUD_EffectFactory(factory),
m_type(type), m_type(type),
@ -56,7 +56,7 @@ float AUD_FaderFactory::getLength() const
return m_length; return m_length;
} }
AUD_IReader* AUD_FaderFactory::createReader() const AUD_Reference<AUD_IReader> AUD_FaderFactory::createReader()
{ {
return new AUD_FaderReader(getReader(), m_type, m_start, m_length); return new AUD_FaderReader(getReader(), m_type, m_start, m_length);
} }

@ -69,7 +69,7 @@ public:
* \param start The time where fading should start in seconds. * \param start The time where fading should start in seconds.
* \param length How long fading should last in seconds. * \param length How long fading should last in seconds.
*/ */
AUD_FaderFactory(AUD_IFactory* factory, AUD_FaderFactory(AUD_Reference<AUD_IFactory> factory,
AUD_FadeType type = AUD_FADE_IN, AUD_FadeType type = AUD_FADE_IN,
float start = 0.0f, float length = 1.0f); float start = 0.0f, float length = 1.0f);
@ -88,7 +88,7 @@ public:
*/ */
float getLength() const; float getLength() const;
virtual AUD_IReader* createReader() const; virtual AUD_Reference<AUD_IReader> createReader();
}; };
#endif //AUD_FADERFACTORY #endif //AUD_FADERFACTORY

@ -33,68 +33,39 @@
#include <cstring> #include <cstring>
AUD_FaderReader::AUD_FaderReader(AUD_IReader* reader, AUD_FadeType type, AUD_FaderReader::AUD_FaderReader(AUD_Reference<AUD_IReader> reader, AUD_FadeType type,
float start,float length) : float start,float length) :
AUD_EffectReader(reader), AUD_EffectReader(reader),
m_type(type), m_type(type),
m_start(start), m_start(start),
m_length(length), m_length(length)
m_empty(true)
{ {
} }
void AUD_FaderReader::read(int & length, sample_t* & buffer) void AUD_FaderReader::read(int& length, bool& eos, sample_t* buffer)
{ {
int position = m_reader->getPosition(); int position = m_reader->getPosition();
AUD_Specs specs = m_reader->getSpecs(); AUD_Specs specs = m_reader->getSpecs();
int samplesize = AUD_SAMPLE_SIZE(specs); int samplesize = AUD_SAMPLE_SIZE(specs);
m_reader->read(length, buffer); m_reader->read(length, eos, buffer);
if((position + length) / (float)specs.rate <= m_start) if((position + length) / (float)specs.rate <= m_start)
{ {
if(m_type != AUD_FADE_OUT) if(m_type != AUD_FADE_OUT)
{
if(m_buffer.getSize() < length * samplesize)
{
m_buffer.resize(length * samplesize);
m_empty = false;
}
buffer = m_buffer.getBuffer();
if(!m_empty)
{ {
memset(buffer, 0, length * samplesize); memset(buffer, 0, length * samplesize);
m_empty = true;
}
} }
} }
else if(position / (float)specs.rate >= m_start+m_length) else if(position / (float)specs.rate >= m_start+m_length)
{ {
if(m_type == AUD_FADE_OUT) if(m_type == AUD_FADE_OUT)
{
if(m_buffer.getSize() < length * samplesize)
{
m_buffer.resize(length * samplesize);
m_empty = false;
}
buffer = m_buffer.getBuffer();
if(!m_empty)
{ {
memset(buffer, 0, length * samplesize); memset(buffer, 0, length * samplesize);
m_empty = true;
}
} }
} }
else else
{ {
if(m_buffer.getSize() < length * samplesize)
m_buffer.resize(length * samplesize);
sample_t* buf = m_buffer.getBuffer();
float volume = 1.0f; float volume = 1.0f;
for(int i = 0; i < length * specs.channels; i++) for(int i = 0; i < length * specs.channels; i++)
@ -111,10 +82,7 @@ void AUD_FaderReader::read(int & length, sample_t* & buffer)
volume = 1.0f - volume; volume = 1.0f - volume;
} }
buf[i] = buffer[i] * volume; buffer[i] = buffer[i] * volume;
} }
buffer = buf;
m_empty = false;
} }
} }

@ -58,16 +58,6 @@ private:
*/ */
const float m_length; const float m_length;
/**
* The playback buffer.
*/
AUD_Buffer m_buffer;
/**
* Whether the buffer is empty.
*/
bool m_empty;
// hide copy constructor and operator= // hide copy constructor and operator=
AUD_FaderReader(const AUD_FaderReader&); AUD_FaderReader(const AUD_FaderReader&);
AUD_FaderReader& operator=(const AUD_FaderReader&); AUD_FaderReader& operator=(const AUD_FaderReader&);
@ -79,10 +69,10 @@ public:
* \param start The time where fading should start in seconds. * \param start The time where fading should start in seconds.
* \param length How long fading should last in seconds. * \param length How long fading should last in seconds.
*/ */
AUD_FaderReader(AUD_IReader* reader, AUD_FadeType type, AUD_FaderReader(AUD_Reference<AUD_IReader> reader, AUD_FadeType type,
float start,float length); float start,float length);
virtual void read(int & length, sample_t* & buffer); virtual void read(int& length, bool& eos, sample_t* buffer);
}; };
#endif //AUD_FADERREADER #endif //AUD_FADERREADER

@ -38,30 +38,26 @@
#define M_PI 3.14159265358979323846 #define M_PI 3.14159265358979323846
#endif #endif
AUD_HighpassFactory::AUD_HighpassFactory(AUD_IFactory* factory, float frequency, AUD_HighpassFactory::AUD_HighpassFactory(AUD_Reference<AUD_IFactory> factory, float frequency,
float Q) : float Q) :
AUD_EffectFactory(factory), AUD_DynamicIIRFilterFactory(factory),
m_frequency(frequency), m_frequency(frequency),
m_Q(Q) m_Q(Q)
{ {
} }
AUD_IReader* AUD_HighpassFactory::createReader() const void AUD_HighpassFactory::recalculateCoefficients(AUD_SampleRate rate,
std::vector<float> &b,
std::vector<float> &a)
{ {
AUD_IReader* reader = getReader(); float w0 = 2 * M_PI * m_frequency / rate;
// calculate coefficients
float w0 = 2 * M_PI * m_frequency / reader->getSpecs().rate;
float alpha = sin(w0) / (2 * m_Q); float alpha = sin(w0) / (2 * m_Q);
float norm = 1 + alpha; float norm = 1 + alpha;
float c = cos(w0); float c = cos(w0);
std::vector<float> a, b;
a.push_back(1); a.push_back(1);
a.push_back(-2 * c / norm); a.push_back(-2 * c / norm);
a.push_back((1 - alpha) / norm); a.push_back((1 - alpha) / norm);
b.push_back((1 + c) / (2 * norm)); b.push_back((1 + c) / (2 * norm));
b.push_back((-1 - c) / norm); b.push_back((-1 - c) / norm);
b.push_back(b[0]); b.push_back(b[0]);
return new AUD_IIRFilterReader(reader, b, a);
} }

@ -32,16 +32,16 @@
#ifndef AUD_HIGHPASSFACTORY #ifndef AUD_HIGHPASSFACTORY
#define AUD_HIGHPASSFACTORY #define AUD_HIGHPASSFACTORY
#include "AUD_EffectFactory.h" #include "AUD_DynamicIIRFilterFactory.h"
/** /**
* This factory creates a highpass filter reader. * This factory creates a highpass filter reader.
*/ */
class AUD_HighpassFactory : public AUD_EffectFactory class AUD_HighpassFactory : public AUD_DynamicIIRFilterFactory
{ {
private: private:
/** /**
* The attack value in seconds. * The cutoff frequency.
*/ */
const float m_frequency; const float m_frequency;
@ -61,9 +61,9 @@ public:
* \param frequency The cutoff frequency. * \param frequency The cutoff frequency.
* \param Q The Q factor. * \param Q The Q factor.
*/ */
AUD_HighpassFactory(AUD_IFactory* factory, float frequency, float Q = 1.0f); AUD_HighpassFactory(AUD_Reference<AUD_IFactory> factory, float frequency, float Q = 1.0f);
virtual AUD_IReader* createReader() const; virtual void recalculateCoefficients(AUD_SampleRate rate, std::vector<float> &b, std::vector<float> &a);
}; };
#endif //AUD_HIGHPASSFACTORY #endif //AUD_HIGHPASSFACTORY

@ -32,14 +32,14 @@
#include "AUD_IIRFilterFactory.h" #include "AUD_IIRFilterFactory.h"
#include "AUD_IIRFilterReader.h" #include "AUD_IIRFilterReader.h"
AUD_IIRFilterFactory::AUD_IIRFilterFactory(AUD_IFactory* factory, AUD_IIRFilterFactory::AUD_IIRFilterFactory(AUD_Reference<AUD_IFactory> factory,
std::vector<float> b, std::vector<float> b,
std::vector<float> a) : std::vector<float> a) :
AUD_EffectFactory(factory), m_a(a), m_b(b) AUD_EffectFactory(factory), m_a(a), m_b(b)
{ {
} }
AUD_IReader* AUD_IIRFilterFactory::createReader() const AUD_Reference<AUD_IReader> AUD_IIRFilterFactory::createReader()
{ {
return new AUD_IIRFilterReader(getReader(), m_b, m_a); return new AUD_IIRFilterReader(getReader(), m_b, m_a);
} }

@ -63,10 +63,10 @@ public:
* \param b The input filter coefficients. * \param b The input filter coefficients.
* \param a The output filter coefficients. * \param a The output filter coefficients.
*/ */
AUD_IIRFilterFactory(AUD_IFactory* factory, std::vector<float> b, AUD_IIRFilterFactory(AUD_Reference<AUD_IFactory> factory, std::vector<float> b,
std::vector<float> a); std::vector<float> a);
virtual AUD_IReader* createReader() const; virtual AUD_Reference<AUD_IReader> createReader();
}; };
#endif //AUD_IIRFILTERFACTORY #endif //AUD_IIRFILTERFACTORY

@ -31,9 +31,9 @@
#include "AUD_IIRFilterReader.h" #include "AUD_IIRFilterReader.h"
AUD_IIRFilterReader::AUD_IIRFilterReader(AUD_IReader* reader, AUD_IIRFilterReader::AUD_IIRFilterReader(AUD_Reference<AUD_IReader> reader,
std::vector<float> b, const std::vector<float>& b,
std::vector<float> a) : const std::vector<float>& a) :
AUD_BaseIIRFilterReader(reader, b.size(), a.size()), m_a(a), m_b(b) AUD_BaseIIRFilterReader(reader, b.size(), a.size()), m_a(a), m_b(b)
{ {
for(int i = 1; i < m_a.size(); i++) for(int i = 1; i < m_a.size(); i++)
@ -54,3 +54,11 @@ sample_t AUD_IIRFilterReader::filter()
return out; return out;
} }
void AUD_IIRFilterReader::setCoefficients(const std::vector<float>& b,
const std::vector<float>& a)
{
setLengths(m_b.size(), m_a.size());
m_a = a;
m_b = b;
}

@ -63,10 +63,13 @@ public:
* \param b The input filter coefficients. * \param b The input filter coefficients.
* \param a The output filter coefficients. * \param a The output filter coefficients.
*/ */
AUD_IIRFilterReader(AUD_IReader* reader, std::vector<float> b, AUD_IIRFilterReader(AUD_Reference<AUD_IReader> reader, const std::vector<float>& b,
std::vector<float> a); const std::vector<float>& a);
virtual sample_t filter(); virtual sample_t filter();
void setCoefficients(const std::vector<float>& b,
const std::vector<float>& a);
}; };
#endif //AUD_IIRFILTERREADER #endif //AUD_IIRFILTERREADER

@ -33,7 +33,7 @@
#include "AUD_LimiterReader.h" #include "AUD_LimiterReader.h"
#include "AUD_Space.h" #include "AUD_Space.h"
AUD_LimiterFactory::AUD_LimiterFactory(AUD_IFactory* factory, AUD_LimiterFactory::AUD_LimiterFactory(AUD_Reference<AUD_IFactory> factory,
float start, float end) : float start, float end) :
AUD_EffectFactory(factory), AUD_EffectFactory(factory),
m_start(start), m_start(start),
@ -51,7 +51,7 @@ float AUD_LimiterFactory::getEnd() const
return m_end; return m_end;
} }
AUD_IReader* AUD_LimiterFactory::createReader() const AUD_Reference<AUD_IReader> AUD_LimiterFactory::createReader()
{ {
return new AUD_LimiterReader(getReader(), m_start, m_end); return new AUD_LimiterReader(getReader(), m_start, m_end);
} }

@ -62,7 +62,7 @@ public:
* \param end The desired end time, a negative value signals that it should * \param end The desired end time, a negative value signals that it should
* play to the end. * play to the end.
*/ */
AUD_LimiterFactory(AUD_IFactory* factory, AUD_LimiterFactory(AUD_Reference<AUD_IFactory> factory,
float start = 0, float end = -1); float start = 0, float end = -1);
/** /**
@ -75,7 +75,7 @@ public:
*/ */
float getEnd() const; float getEnd() const;
virtual AUD_IReader* createReader() const; virtual AUD_Reference<AUD_IReader> createReader();
}; };
#endif //AUD_LIMITERFACTORY #endif //AUD_LIMITERFACTORY

@ -32,30 +32,46 @@
#include "AUD_LimiterReader.h" #include "AUD_LimiterReader.h"
#include "AUD_Buffer.h" #include "AUD_Buffer.h"
#include <iostream> AUD_LimiterReader::AUD_LimiterReader(AUD_Reference<AUD_IReader> reader,
AUD_LimiterReader::AUD_LimiterReader(AUD_IReader* reader,
float start, float end) : float start, float end) :
AUD_EffectReader(reader), AUD_EffectReader(reader),
m_start(int(start * reader->getSpecs().rate)), m_start(start),
m_end(int(end * reader->getSpecs().rate)) m_end(end)
{ {
if(m_start > 0) if(m_start > 0)
{ {
AUD_Specs specs = m_reader->getSpecs();
AUD_Specs specs2;
if(m_reader->isSeekable()) if(m_reader->isSeekable())
m_reader->seek(m_start); m_reader->seek(m_start * specs.rate);
else else
{ {
// skip first m_start samples by reading them // skip first m_start samples by reading them
int length = AUD_DEFAULT_BUFFER_SIZE; int length = AUD_DEFAULT_BUFFER_SIZE;
sample_t* buffer; AUD_Buffer buffer(AUD_DEFAULT_BUFFER_SIZE * AUD_SAMPLE_SIZE(specs));
for(int len = m_start; bool eos = false;
length == AUD_DEFAULT_BUFFER_SIZE; for(int len = m_start * specs.rate;
len -= AUD_DEFAULT_BUFFER_SIZE) length > 0 && !eos;
len -= length)
{ {
if(len < AUD_DEFAULT_BUFFER_SIZE) if(len < AUD_DEFAULT_BUFFER_SIZE)
length = len; length = len;
m_reader->read(length, buffer);
m_reader->read(length, eos, buffer.getBuffer());
specs2 = m_reader->getSpecs();
if(specs2.rate != specs.rate)
{
len = len * specs2.rate / specs.rate;
specs.rate = specs2.rate;
}
if(specs2.channels != specs.channels)
{
specs = specs2;
buffer.assureSize(AUD_DEFAULT_BUFFER_SIZE * AUD_SAMPLE_SIZE(specs));
}
} }
} }
} }
@ -63,35 +79,71 @@ AUD_LimiterReader::AUD_LimiterReader(AUD_IReader* reader,
void AUD_LimiterReader::seek(int position) void AUD_LimiterReader::seek(int position)
{ {
m_reader->seek(position + m_start); m_reader->seek(position + m_start * m_reader->getSpecs().rate);
} }
int AUD_LimiterReader::getLength() const int AUD_LimiterReader::getLength() const
{ {
int len = m_reader->getLength(); int len = m_reader->getLength();
if(len < 0 || (len > m_end && m_end >= 0)) AUD_SampleRate rate = m_reader->getSpecs().rate;
len = m_end; if(len < 0 || (len > m_end * rate && m_end >= 0))
return len - m_start; len = m_end * rate;
return len - m_start * rate;
} }
int AUD_LimiterReader::getPosition() const int AUD_LimiterReader::getPosition() const
{ {
int pos = m_reader->getPosition(); int pos = m_reader->getPosition();
return AUD_MIN(pos, m_end) - m_start; AUD_SampleRate rate = m_reader->getSpecs().rate;
return AUD_MIN(pos, m_end * rate) - m_start * rate;
} }
void AUD_LimiterReader::read(int & length, sample_t* & buffer) void AUD_LimiterReader::read(int& length, bool& eos, sample_t* buffer)
{ {
eos = false;
if(m_end >= 0) if(m_end >= 0)
{ {
int position = m_reader->getPosition(); int position = m_reader->getPosition();
if(position + length > m_end) AUD_SampleRate rate = m_reader->getSpecs().rate;
length = m_end - position;
if(position + length > m_end * rate)
{
length = m_end * rate - position;
eos = true;
}
if(position < m_start * rate)
{
int len2 = length;
for(int len = m_start * rate - position;
len2 == length && !eos;
len -= length)
{
if(len < length)
len2 = len;
m_reader->read(len2, eos, buffer);
position += len2;
}
if(position < m_start * rate)
{
length = 0;
return;
}
}
if(length < 0) if(length < 0)
{ {
length = 0; length = 0;
return; return;
} }
} }
m_reader->read(length, buffer); if(eos)
{
m_reader->read(length, eos, buffer);
eos = true;
}
else
m_reader->read(length, eos, buffer);
} }

@ -35,7 +35,7 @@
#include "AUD_EffectReader.h" #include "AUD_EffectReader.h"
/** /**
* This reader limits another reader in start and end sample. * This reader limits another reader in start and end times.
*/ */
class AUD_LimiterReader : public AUD_EffectReader class AUD_LimiterReader : public AUD_EffectReader
{ {
@ -43,12 +43,12 @@ private:
/** /**
* The start sample: inclusive. * The start sample: inclusive.
*/ */
const int m_start; const float m_start;
/** /**
* The end sample: exlusive. * The end sample: exlusive.
*/ */
const int m_end; const float m_end;
// hide copy constructor and operator= // hide copy constructor and operator=
AUD_LimiterReader(const AUD_LimiterReader&); AUD_LimiterReader(const AUD_LimiterReader&);
@ -58,16 +58,16 @@ public:
/** /**
* Creates a new limiter reader. * Creates a new limiter reader.
* \param reader The reader to read from. * \param reader The reader to read from.
* \param start The desired start sample (inclusive). * \param start The desired start time (inclusive).
* \param end The desired end sample (exklusive), a negative value signals * \param end The desired end time (sample exklusive), a negative value
* that it should play to the end. * signals that it should play to the end.
*/ */
AUD_LimiterReader(AUD_IReader* reader, float start = 0, float end = -1); AUD_LimiterReader(AUD_Reference<AUD_IReader> reader, float start = 0, float end = -1);
virtual void seek(int position); virtual void seek(int position);
virtual int getLength() const; virtual int getLength() const;
virtual int getPosition() const; virtual int getPosition() const;
virtual void read(int & length, sample_t* & buffer); virtual void read(int& length, bool& eos, sample_t* buffer);
}; };
#endif //AUD_LIMITERREADER #endif //AUD_LIMITERREADER

@ -32,7 +32,7 @@
#include "AUD_LoopFactory.h" #include "AUD_LoopFactory.h"
#include "AUD_LoopReader.h" #include "AUD_LoopReader.h"
AUD_LoopFactory::AUD_LoopFactory(AUD_IFactory* factory, int loop) : AUD_LoopFactory::AUD_LoopFactory(AUD_Reference<AUD_IFactory> factory, int loop) :
AUD_EffectFactory(factory), AUD_EffectFactory(factory),
m_loop(loop) m_loop(loop)
{ {
@ -43,7 +43,7 @@ int AUD_LoopFactory::getLoop() const
return m_loop; return m_loop;
} }
AUD_IReader* AUD_LoopFactory::createReader() const AUD_Reference<AUD_IReader> AUD_LoopFactory::createReader()
{ {
return new AUD_LoopReader(getReader(), m_loop); return new AUD_LoopReader(getReader(), m_loop);
} }

@ -57,14 +57,14 @@ public:
* \param loop The desired loop count, negative values result in endless * \param loop The desired loop count, negative values result in endless
* looping. * looping.
*/ */
AUD_LoopFactory(AUD_IFactory* factory, int loop = -1); AUD_LoopFactory(AUD_Reference<AUD_IFactory> factory, int loop = -1);
/** /**
* Returns the loop count. * Returns the loop count.
*/ */
int getLoop() const; int getLoop() const;
virtual AUD_IReader* createReader() const; virtual AUD_Reference<AUD_IReader> createReader();
}; };
#endif //AUD_LOOPFACTORY #endif //AUD_LOOPFACTORY

@ -34,7 +34,7 @@
#include <cstring> #include <cstring>
AUD_LoopReader::AUD_LoopReader(AUD_IReader* reader, int loop) : AUD_LoopReader::AUD_LoopReader(AUD_Reference<AUD_IReader> reader, int loop) :
AUD_EffectReader(reader), m_count(loop), m_left(loop) AUD_EffectReader(reader), m_count(loop), m_left(loop)
{ {
} }
@ -68,29 +68,20 @@ int AUD_LoopReader::getPosition() const
return m_reader->getPosition() * (m_count < 0 ? 1 : m_count); return m_reader->getPosition() * (m_count < 0 ? 1 : m_count);
} }
void AUD_LoopReader::read(int & length, sample_t* & buffer) void AUD_LoopReader::read(int& length, bool& eos, sample_t* buffer)
{ {
AUD_Specs specs = m_reader->getSpecs(); const AUD_Specs specs = m_reader->getSpecs();
int samplesize = AUD_SAMPLE_SIZE(specs);
int len = length; int len = length;
m_reader->read(len, buffer); m_reader->read(length, eos, buffer);
if(len < length && m_left) if(length < len && eos && m_left)
{ {
int pos = 0; int pos = length;
length = len;
if(m_buffer.getSize() < length * samplesize) while(pos < length && eos && m_left)
m_buffer.resize(length * samplesize);
sample_t* buf = m_buffer.getBuffer();
memcpy(buf + pos * specs.channels, buffer, len * samplesize);
pos += len;
while(pos < length && m_left)
{ {
if(m_left > 0) if(m_left > 0)
m_left--; m_left--;
@ -98,20 +89,15 @@ void AUD_LoopReader::read(int & length, sample_t* & buffer)
m_reader->seek(0); m_reader->seek(0);
len = length - pos; len = length - pos;
m_reader->read(len, buffer); m_reader->read(len, eos, buffer + pos * specs.channels);
// prevent endless loop // prevent endless loop
if(!len) if(!len)
break; break;
memcpy(buf + pos * specs.channels, buffer, len * samplesize);
pos += len; pos += len;
} }
length = pos; length = pos;
buffer = buf;
} }
else
length = len;
} }

@ -42,11 +42,6 @@
class AUD_LoopReader : public AUD_EffectReader class AUD_LoopReader : public AUD_EffectReader
{ {
private: private:
/**
* The playback buffer.
*/
AUD_Buffer m_buffer;
/** /**
* The loop count. * The loop count.
*/ */
@ -68,12 +63,12 @@ public:
* \param loop The desired loop count, negative values result in endless * \param loop The desired loop count, negative values result in endless
* looping. * looping.
*/ */
AUD_LoopReader(AUD_IReader* reader, int loop); AUD_LoopReader(AUD_Reference<AUD_IReader> reader, int loop);
virtual void seek(int position); virtual void seek(int position);
virtual int getLength() const; virtual int getLength() const;
virtual int getPosition() const; virtual int getPosition() const;
virtual void read(int & length, sample_t* & buffer); virtual void read(int& length, bool& eos, sample_t* buffer);
}; };
#endif //AUD_LOOPREADER #endif //AUD_LOOPREADER

@ -38,30 +38,26 @@
#define M_PI 3.14159265358979323846 #define M_PI 3.14159265358979323846
#endif #endif
AUD_LowpassFactory::AUD_LowpassFactory(AUD_IFactory* factory, float frequency, AUD_LowpassFactory::AUD_LowpassFactory(AUD_Reference<AUD_IFactory> factory, float frequency,
float Q) : float Q) :
AUD_EffectFactory(factory), AUD_DynamicIIRFilterFactory(factory),
m_frequency(frequency), m_frequency(frequency),
m_Q(Q) m_Q(Q)
{ {
} }
AUD_IReader* AUD_LowpassFactory::createReader() const void AUD_LowpassFactory::recalculateCoefficients(AUD_SampleRate rate,
std::vector<float> &b,
std::vector<float> &a)
{ {
AUD_IReader* reader = getReader(); float w0 = 2 * M_PI * m_frequency / rate;
// calculate coefficients
float w0 = 2 * M_PI * m_frequency / reader->getSpecs().rate;
float alpha = sin(w0) / (2 * m_Q); float alpha = sin(w0) / (2 * m_Q);
float norm = 1 + alpha; float norm = 1 + alpha;
float c = cos(w0); float c = cos(w0);
std::vector<float> a, b;
a.push_back(1); a.push_back(1);
a.push_back(-2 * c / norm); a.push_back(-2 * c / norm);
a.push_back((1 - alpha) / norm); a.push_back((1 - alpha) / norm);
b.push_back((1 - c) / (2 * norm)); b.push_back((1 - c) / (2 * norm));
b.push_back((1 - c) / norm); b.push_back((1 - c) / norm);
b.push_back(b[0]); b.push_back(b[0]);
return new AUD_IIRFilterReader(reader, b, a);
} }

@ -32,16 +32,16 @@
#ifndef AUD_LOWPASSFACTORY #ifndef AUD_LOWPASSFACTORY
#define AUD_LOWPASSFACTORY #define AUD_LOWPASSFACTORY
#include "AUD_EffectFactory.h" #include "AUD_DynamicIIRFilterFactory.h"
/** /**
* This factory creates a lowpass filter reader. * This factory creates a lowpass filter reader.
*/ */
class AUD_LowpassFactory : public AUD_EffectFactory class AUD_LowpassFactory : public AUD_DynamicIIRFilterFactory
{ {
private: private:
/** /**
* The attack value in seconds. * The cutoff frequency.
*/ */
const float m_frequency; const float m_frequency;
@ -61,9 +61,9 @@ public:
* \param frequency The cutoff frequency. * \param frequency The cutoff frequency.
* \param Q The Q factor. * \param Q The Q factor.
*/ */
AUD_LowpassFactory(AUD_IFactory* factory, float frequency, float Q = 1.0f); AUD_LowpassFactory(AUD_Reference<AUD_IFactory> factory, float frequency, float Q = 1.0f);
virtual AUD_IReader* createReader() const; virtual void recalculateCoefficients(AUD_SampleRate rate, std::vector<float> &b, std::vector<float> &a);
}; };
#endif //AUD_LOWPASSFACTORY #endif //AUD_LOWPASSFACTORY

@ -33,26 +33,16 @@
#include "AUD_DoubleReader.h" #include "AUD_DoubleReader.h"
#include "AUD_ReverseFactory.h" #include "AUD_ReverseFactory.h"
AUD_PingPongFactory::AUD_PingPongFactory(AUD_IFactory* factory) : AUD_PingPongFactory::AUD_PingPongFactory(AUD_Reference<AUD_IFactory> factory) :
AUD_EffectFactory(factory) AUD_EffectFactory(factory)
{ {
} }
AUD_IReader* AUD_PingPongFactory::createReader() const AUD_Reference<AUD_IReader> AUD_PingPongFactory::createReader()
{ {
AUD_IReader* reader = getReader(); AUD_Reference<AUD_IReader> reader = getReader();
AUD_IReader* reader2;
AUD_ReverseFactory factory(m_factory); AUD_ReverseFactory factory(m_factory);
AUD_Reference<AUD_IReader> reader2 = factory.createReader();
try
{
reader2 = factory.createReader();
}
catch(AUD_Exception&)
{
delete reader;
throw;
}
return new AUD_DoubleReader(reader, reader2); return new AUD_DoubleReader(reader, reader2);
} }

@ -36,7 +36,7 @@
/** /**
* This factory plays another factory first normal, then reversed. * This factory plays another factory first normal, then reversed.
* \note Readers from the underlying factory must be from the buffer type. * \note Readers from the underlying factory must be reversable with seeking.
*/ */
class AUD_PingPongFactory : public AUD_EffectFactory class AUD_PingPongFactory : public AUD_EffectFactory
{ {
@ -50,9 +50,9 @@ public:
* Creates a new ping pong factory. * Creates a new ping pong factory.
* \param factory The input factory. * \param factory The input factory.
*/ */
AUD_PingPongFactory(AUD_IFactory* factory); AUD_PingPongFactory(AUD_Reference<AUD_IFactory> factory);
virtual AUD_IReader* createReader() const; virtual AUD_Reference<AUD_IReader> createReader();
}; };
#endif //AUD_PINGPONGFACTORY #endif //AUD_PINGPONGFACTORY

@ -33,13 +33,13 @@
#include "AUD_PitchReader.h" #include "AUD_PitchReader.h"
#include "AUD_Space.h" #include "AUD_Space.h"
AUD_PitchFactory::AUD_PitchFactory(AUD_IFactory* factory, float pitch) : AUD_PitchFactory::AUD_PitchFactory(AUD_Reference<AUD_IFactory> factory, float pitch) :
AUD_EffectFactory(factory), AUD_EffectFactory(factory),
m_pitch(pitch) m_pitch(pitch)
{ {
} }
AUD_IReader* AUD_PitchFactory::createReader() const AUD_Reference<AUD_IReader> AUD_PitchFactory::createReader()
{ {
return new AUD_PitchReader(getReader(), m_pitch); return new AUD_PitchReader(getReader(), m_pitch);
} }

@ -55,9 +55,9 @@ public:
* \param factory The input factory. * \param factory The input factory.
* \param pitch The desired pitch. * \param pitch The desired pitch.
*/ */
AUD_PitchFactory(AUD_IFactory* factory, float pitch); AUD_PitchFactory(AUD_Reference<AUD_IFactory> factory, float pitch);
virtual AUD_IReader* createReader() const; virtual AUD_Reference<AUD_IReader> createReader();
}; };
#endif //AUD_PITCHFACTORY #endif //AUD_PITCHFACTORY

@ -31,7 +31,7 @@
#include "AUD_PitchReader.h" #include "AUD_PitchReader.h"
AUD_PitchReader::AUD_PitchReader(AUD_IReader* reader, float pitch) : AUD_PitchReader::AUD_PitchReader(AUD_Reference<AUD_IReader> reader, float pitch) :
AUD_EffectReader(reader), m_pitch(pitch) AUD_EffectReader(reader), m_pitch(pitch)
{ {
} }
@ -39,6 +39,16 @@ AUD_PitchReader::AUD_PitchReader(AUD_IReader* reader, float pitch) :
AUD_Specs AUD_PitchReader::getSpecs() const AUD_Specs AUD_PitchReader::getSpecs() const
{ {
AUD_Specs specs = m_reader->getSpecs(); AUD_Specs specs = m_reader->getSpecs();
specs.rate = (AUD_SampleRate)((int)(specs.rate * m_pitch)); specs.rate *= m_pitch;
return specs; return specs;
} }
float AUD_PitchReader::getPitch() const
{
return m_pitch;
}
void AUD_PitchReader::setPitch(float pitch)
{
m_pitch = pitch;
}

@ -43,7 +43,7 @@ private:
/** /**
* The pitch level. * The pitch level.
*/ */
const float m_pitch; float m_pitch;
// hide copy constructor and operator= // hide copy constructor and operator=
AUD_PitchReader(const AUD_PitchReader&); AUD_PitchReader(const AUD_PitchReader&);
@ -53,11 +53,23 @@ public:
/** /**
* Creates a new pitch reader. * Creates a new pitch reader.
* \param reader The reader to read from. * \param reader The reader to read from.
* \param pitch The size of the buffer. * \param pitch The pitch value.
*/ */
AUD_PitchReader(AUD_IReader* reader, float pitch); AUD_PitchReader(AUD_Reference<AUD_IReader> reader, float pitch);
virtual AUD_Specs getSpecs() const; virtual AUD_Specs getSpecs() const;
/**
* Retrieves the pitch.
* \return The current pitch value.
*/
float getPitch() const;
/**
* Sets the pitch.
* \param pitch The new pitch value.
*/
void setPitch(float pitch);
}; };
#endif //AUD_PITCHREADER #endif //AUD_PITCHREADER

@ -34,17 +34,17 @@
#include <cmath> #include <cmath>
sample_t rectifyFilter(AUD_CallbackIIRFilterReader* reader, void* useless) sample_t AUD_RectifyFactory::rectifyFilter(AUD_CallbackIIRFilterReader* reader, void* useless)
{ {
return fabs(reader->x(0)); return fabs(reader->x(0));
} }
AUD_RectifyFactory::AUD_RectifyFactory(AUD_IFactory* factory) : AUD_RectifyFactory::AUD_RectifyFactory(AUD_Reference<AUD_IFactory> factory) :
AUD_EffectFactory(factory) AUD_EffectFactory(factory)
{ {
} }
AUD_IReader* AUD_RectifyFactory::createReader() const AUD_Reference<AUD_IReader> AUD_RectifyFactory::createReader()
{ {
return new AUD_CallbackIIRFilterReader(getReader(), 1, 1, rectifyFilter); return new AUD_CallbackIIRFilterReader(getReader(), 1, 1, rectifyFilter);
} }

@ -33,6 +33,7 @@
#define AUD_RECTIFYFACTORY #define AUD_RECTIFYFACTORY
#include "AUD_EffectFactory.h" #include "AUD_EffectFactory.h"
class AUD_CallbackIIRFilterReader;
/** /**
* This factory rectifies another factory. * This factory rectifies another factory.
@ -49,9 +50,11 @@ public:
* Creates a new rectify factory. * Creates a new rectify factory.
* \param factory The input factory. * \param factory The input factory.
*/ */
AUD_RectifyFactory(AUD_IFactory* factory); AUD_RectifyFactory(AUD_Reference<AUD_IFactory> factory);
virtual AUD_IReader* createReader() const; virtual AUD_Reference<AUD_IReader> createReader();
static sample_t rectifyFilter(AUD_CallbackIIRFilterReader* reader, void* useless);
}; };
#endif //AUD_RECTIFYFACTORY #endif //AUD_RECTIFYFACTORY

@ -33,12 +33,12 @@
#include "AUD_ReverseReader.h" #include "AUD_ReverseReader.h"
#include "AUD_Space.h" #include "AUD_Space.h"
AUD_ReverseFactory::AUD_ReverseFactory(AUD_IFactory* factory) : AUD_ReverseFactory::AUD_ReverseFactory(AUD_Reference<AUD_IFactory> factory) :
AUD_EffectFactory(factory) AUD_EffectFactory(factory)
{ {
} }
AUD_IReader* AUD_ReverseFactory::createReader() const AUD_Reference<AUD_IReader> AUD_ReverseFactory::createReader()
{ {
return new AUD_ReverseReader(getReader()); return new AUD_ReverseReader(getReader());
} }

@ -36,7 +36,7 @@
/** /**
* This factory reads another factory reverted. * This factory reads another factory reverted.
* \note Readers from the underlying factory must be from the buffer type. * \note Readers from the underlying factory must be seekable.
*/ */
class AUD_ReverseFactory : public AUD_EffectFactory class AUD_ReverseFactory : public AUD_EffectFactory
{ {
@ -50,9 +50,9 @@ public:
* Creates a new reverse factory. * Creates a new reverse factory.
* \param factory The input factory. * \param factory The input factory.
*/ */
AUD_ReverseFactory(AUD_IFactory* factory); AUD_ReverseFactory(AUD_Reference<AUD_IFactory> factory);
virtual AUD_IReader* createReader() const; virtual AUD_Reference<AUD_IReader> createReader();
}; };
#endif //AUD_REVERSEFACTORY #endif //AUD_REVERSEFACTORY

@ -36,7 +36,7 @@
static const char* props_error = "AUD_ReverseReader: The reader has to be " static const char* props_error = "AUD_ReverseReader: The reader has to be "
"seekable and a finite length."; "seekable and a finite length.";
AUD_ReverseReader::AUD_ReverseReader(AUD_IReader* reader) : AUD_ReverseReader::AUD_ReverseReader(AUD_Reference<AUD_IReader> reader) :
AUD_EffectReader(reader), AUD_EffectReader(reader),
m_length(reader->getLength()), m_length(reader->getLength()),
m_position(0) m_position(0)
@ -60,7 +60,7 @@ int AUD_ReverseReader::getPosition() const
return m_position; return m_position;
} }
void AUD_ReverseReader::read(int & length, sample_t* & buffer) void AUD_ReverseReader::read(int& length, bool& eos, sample_t* buffer)
{ {
// first correct the length // first correct the length
if(m_position + length > m_length) if(m_position + length > m_length)
@ -69,39 +69,39 @@ void AUD_ReverseReader::read(int & length, sample_t* & buffer)
if(length <= 0) if(length <= 0)
{ {
length = 0; length = 0;
eos = true;
return; return;
} }
AUD_Specs specs = getSpecs(); const AUD_Specs specs = getSpecs();
int samplesize = AUD_SAMPLE_SIZE(specs); const int samplesize = AUD_SAMPLE_SIZE(specs);
// resize buffer if needed sample_t temp[AUD_CHANNEL_MAX];
if(m_buffer.getSize() < length * samplesize)
m_buffer.resize(length * samplesize);
buffer = m_buffer.getBuffer();
sample_t* buf;
int len = length; int len = length;
// read from reader // read from reader
m_reader->seek(m_length - m_position - len); m_reader->seek(m_length - m_position - len);
m_reader->read(len, buf); m_reader->read(len, eos, buffer);
// set null if reader didn't give enough data // set null if reader didn't give enough data
if(len < length) if(len < length)
{
memset(buffer, 0, (length - len) * samplesize); memset(buffer, 0, (length - len) * samplesize);
buffer += (length - len) * specs.channels;
}
// copy the samples reverted // copy the samples reverted
for(int i = 0; i < len; i++) for(int i = 0; i < length / 2; i++)
memcpy(buffer + i * specs.channels, {
buf + (len - 1 - i) * specs.channels, memcpy(temp,
buffer + (len - 1 - i) * specs.channels,
samplesize); samplesize);
memcpy(buffer + (len - 1 - i) * specs.channels,
buffer + i * specs.channels,
samplesize);
memcpy(buffer + i * specs.channels,
temp,
samplesize);
}
m_position += length; m_position += length;
eos = false;
buffer = m_buffer.getBuffer();
} }

@ -37,7 +37,7 @@
/** /**
* This class reads another reader from back to front. * This class reads another reader from back to front.
* \note The underlying reader must be a buffer. * \note The underlying reader must be seekable.
*/ */
class AUD_ReverseReader : public AUD_EffectReader class AUD_ReverseReader : public AUD_EffectReader
{ {
@ -52,11 +52,6 @@ private:
*/ */
int m_position; int m_position;
/**
* The playback buffer.
*/
AUD_Buffer m_buffer;
// hide copy constructor and operator= // hide copy constructor and operator=
AUD_ReverseReader(const AUD_ReverseReader&); AUD_ReverseReader(const AUD_ReverseReader&);
AUD_ReverseReader& operator=(const AUD_ReverseReader&); AUD_ReverseReader& operator=(const AUD_ReverseReader&);
@ -68,12 +63,12 @@ public:
* \exception AUD_Exception Thrown if the reader specified has an * \exception AUD_Exception Thrown if the reader specified has an
* undeterminable/infinite length or is not seekable. * undeterminable/infinite length or is not seekable.
*/ */
AUD_ReverseReader(AUD_IReader* reader); AUD_ReverseReader(AUD_Reference<AUD_IReader> reader);
virtual void seek(int position); virtual void seek(int position);
virtual int getLength() const; virtual int getLength() const;
virtual int getPosition() const; virtual int getPosition() const;
virtual void read(int & length, sample_t* & buffer); virtual void read(int& length, bool& eos, sample_t* buffer);
}; };
#endif //AUD_REVERSEREADER #endif //AUD_REVERSEREADER

@ -32,7 +32,7 @@
#include "AUD_SquareFactory.h" #include "AUD_SquareFactory.h"
#include "AUD_CallbackIIRFilterReader.h" #include "AUD_CallbackIIRFilterReader.h"
sample_t squareFilter(AUD_CallbackIIRFilterReader* reader, float* threshold) sample_t AUD_SquareFactory::squareFilter(AUD_CallbackIIRFilterReader* reader, float* threshold)
{ {
float in = reader->x(0); float in = reader->x(0);
if(in >= *threshold) if(in >= *threshold)
@ -43,12 +43,12 @@ sample_t squareFilter(AUD_CallbackIIRFilterReader* reader, float* threshold)
return 0; return 0;
} }
void endSquareFilter(float* threshold) void AUD_SquareFactory::endSquareFilter(float* threshold)
{ {
delete threshold; delete threshold;
} }
AUD_SquareFactory::AUD_SquareFactory(AUD_IFactory* factory, float threshold) : AUD_SquareFactory::AUD_SquareFactory(AUD_Reference<AUD_IFactory> factory, float threshold) :
AUD_EffectFactory(factory), AUD_EffectFactory(factory),
m_threshold(threshold) m_threshold(threshold)
{ {
@ -59,7 +59,7 @@ float AUD_SquareFactory::getThreshold() const
return m_threshold; return m_threshold;
} }
AUD_IReader* AUD_SquareFactory::createReader() const AUD_Reference<AUD_IReader> AUD_SquareFactory::createReader()
{ {
return new AUD_CallbackIIRFilterReader(getReader(), 1, 1, return new AUD_CallbackIIRFilterReader(getReader(), 1, 1,
(doFilterIIR) squareFilter, (doFilterIIR) squareFilter,

@ -33,6 +33,7 @@
#define AUD_SQUAREFACTORY #define AUD_SQUAREFACTORY
#include "AUD_EffectFactory.h" #include "AUD_EffectFactory.h"
class AUD_CallbackIIRFilterReader;
/** /**
* This factory Transforms any signal to a square signal. * This factory Transforms any signal to a square signal.
@ -55,14 +56,17 @@ public:
* \param factory The input factory. * \param factory The input factory.
* \param threshold The threshold. * \param threshold The threshold.
*/ */
AUD_SquareFactory(AUD_IFactory* factory, float threshold = 0.0f); AUD_SquareFactory(AUD_Reference<AUD_IFactory> factory, float threshold = 0.0f);
/** /**
* Returns the threshold. * Returns the threshold.
*/ */
float getThreshold() const; float getThreshold() const;
virtual AUD_IReader* createReader() const; virtual AUD_Reference<AUD_IReader> createReader();
static sample_t squareFilter(AUD_CallbackIIRFilterReader* reader, float* threshold);
static void endSquareFilter(float* threshold);
}; };
#endif //AUD_SQUAREFACTORY #endif //AUD_SQUAREFACTORY

@ -32,12 +32,12 @@
#include "AUD_SumFactory.h" #include "AUD_SumFactory.h"
#include "AUD_IIRFilterReader.h" #include "AUD_IIRFilterReader.h"
AUD_SumFactory::AUD_SumFactory(AUD_IFactory* factory) : AUD_SumFactory::AUD_SumFactory(AUD_Reference<AUD_IFactory> factory) :
AUD_EffectFactory(factory) AUD_EffectFactory(factory)
{ {
} }
AUD_IReader* AUD_SumFactory::createReader() const AUD_Reference<AUD_IReader> AUD_SumFactory::createReader()
{ {
std::vector<float> a, b; std::vector<float> a, b;
a.push_back(1); a.push_back(1);

@ -49,9 +49,9 @@ public:
* Creates a new sum factory. * Creates a new sum factory.
* \param factory The input factory. * \param factory The input factory.
*/ */
AUD_SumFactory(AUD_IFactory* factory); AUD_SumFactory(AUD_Reference<AUD_IFactory> factory);
virtual AUD_IReader* createReader() const; virtual AUD_Reference<AUD_IReader> createReader();
}; };
#endif //AUD_SUMFACTORY #endif //AUD_SUMFACTORY

@ -32,24 +32,15 @@
#include "AUD_SuperposeFactory.h" #include "AUD_SuperposeFactory.h"
#include "AUD_SuperposeReader.h" #include "AUD_SuperposeReader.h"
AUD_SuperposeFactory::AUD_SuperposeFactory(AUD_IFactory* factory1, AUD_IFactory* factory2) : AUD_SuperposeFactory::AUD_SuperposeFactory(AUD_Reference<AUD_IFactory> factory1, AUD_Reference<AUD_IFactory> factory2) :
m_factory1(factory1), m_factory2(factory2) m_factory1(factory1), m_factory2(factory2)
{ {
} }
AUD_IReader* AUD_SuperposeFactory::createReader() const AUD_Reference<AUD_IReader> AUD_SuperposeFactory::createReader()
{ {
AUD_IReader* reader1 = m_factory1->createReader(); AUD_Reference<AUD_IReader> reader1 = m_factory1->createReader();
AUD_IReader* reader2; AUD_Reference<AUD_IReader> reader2 = m_factory2->createReader();
try
{
reader2 = m_factory2->createReader();
}
catch(AUD_Exception&)
{
delete reader1;
throw;
}
return new AUD_SuperposeReader(reader1, reader2); return new AUD_SuperposeReader(reader1, reader2);
} }

@ -35,8 +35,9 @@
#include "AUD_IFactory.h" #include "AUD_IFactory.h"
/** /**
* This factory plays two other factories behind each other. * This factory mixes two other factories, playing them the same time.
* \note Readers from the underlying factories must have the same sample rate and channel count. * \note Readers from the underlying factories must have the same sample rate
* and channel count.
*/ */
class AUD_SuperposeFactory : public AUD_IFactory class AUD_SuperposeFactory : public AUD_IFactory
{ {
@ -44,12 +45,12 @@ private:
/** /**
* First played factory. * First played factory.
*/ */
AUD_IFactory* m_factory1; AUD_Reference<AUD_IFactory> m_factory1;
/** /**
* Second played factory. * Second played factory.
*/ */
AUD_IFactory* m_factory2; AUD_Reference<AUD_IFactory> m_factory2;
// hide copy constructor and operator= // hide copy constructor and operator=
AUD_SuperposeFactory(const AUD_SuperposeFactory&); AUD_SuperposeFactory(const AUD_SuperposeFactory&);
@ -61,9 +62,9 @@ public:
* \param factory1 The first input factory. * \param factory1 The first input factory.
* \param factory2 The second input factory. * \param factory2 The second input factory.
*/ */
AUD_SuperposeFactory(AUD_IFactory* factory1, AUD_IFactory* factory2); AUD_SuperposeFactory(AUD_Reference<AUD_IFactory> factory1, AUD_Reference<AUD_IFactory> factory2);
virtual AUD_IReader* createReader() const; virtual AUD_Reference<AUD_IReader> createReader();
}; };
#endif //AUD_SUPERPOSEFACTORY #endif //AUD_SUPERPOSEFACTORY

@ -36,30 +36,13 @@
static const char* specs_error = "AUD_SuperposeReader: Both readers have to " static const char* specs_error = "AUD_SuperposeReader: Both readers have to "
"have the same specs."; "have the same specs.";
AUD_SuperposeReader::AUD_SuperposeReader(AUD_IReader* reader1, AUD_IReader* reader2) : AUD_SuperposeReader::AUD_SuperposeReader(AUD_Reference<AUD_IReader> reader1, AUD_Reference<AUD_IReader> reader2) :
m_reader1(reader1), m_reader2(reader2) m_reader1(reader1), m_reader2(reader2)
{ {
try
{
AUD_Specs s1, s2;
s1 = reader1->getSpecs();
s2 = reader2->getSpecs();
if(memcmp(&s1, &s2, sizeof(AUD_Specs)))
AUD_THROW(AUD_ERROR_SPECS, specs_error);
}
catch(AUD_Exception&)
{
delete reader1;
delete reader2;
throw;
}
} }
AUD_SuperposeReader::~AUD_SuperposeReader() AUD_SuperposeReader::~AUD_SuperposeReader()
{ {
delete m_reader1;
delete m_reader2;
} }
bool AUD_SuperposeReader::isSeekable() const bool AUD_SuperposeReader::isSeekable() const
@ -94,28 +77,31 @@ AUD_Specs AUD_SuperposeReader::getSpecs() const
return m_reader1->getSpecs(); return m_reader1->getSpecs();
} }
void AUD_SuperposeReader::read(int & length, sample_t* & buffer) void AUD_SuperposeReader::read(int& length, bool& eos, sample_t* buffer)
{ {
AUD_Specs specs = m_reader1->getSpecs(); AUD_Specs specs = m_reader1->getSpecs();
AUD_Specs s2 = m_reader2->getSpecs();
if(!AUD_COMPARE_SPECS(specs, s2))
AUD_THROW(AUD_ERROR_SPECS, specs_error);
int samplesize = AUD_SAMPLE_SIZE(specs); int samplesize = AUD_SAMPLE_SIZE(specs);
if(m_buffer.getSize() < length * samplesize) m_buffer.assureSize(length * samplesize);
m_buffer.resize(length * samplesize);
buffer = m_buffer.getBuffer();
int len1 = length; int len1 = length;
sample_t* buf; m_reader1->read(len1, eos, buffer);
m_reader1->read(len1, buf);
memcpy(buffer, buf, len1 * samplesize);
if(len1 < length) if(len1 < length)
memset(buffer + len1 * specs.channels, 0, (length - len1) * samplesize); memset(buffer + len1 * specs.channels, 0, (length - len1) * samplesize);
int len2 = length; int len2 = length;
m_reader2->read(len2, buf); bool eos2;
sample_t* buf = m_buffer.getBuffer();
m_reader2->read(len2, eos2, buf);
for(int i = 0; i < len2 * specs.channels; i++) for(int i = 0; i < len2 * specs.channels; i++)
buffer[i] += buf[i]; buffer[i] += buf[i];
length = AUD_MAX(len1, len2); length = AUD_MAX(len1, len2);
eos &= eos2;
} }

@ -34,9 +34,10 @@
#include "AUD_IReader.h" #include "AUD_IReader.h"
#include "AUD_Buffer.h" #include "AUD_Buffer.h"
#include "AUD_Reference.h"
/** /**
* This reader plays two readers with the same specs sequently. * This reader plays two readers with the same specs in parallel.
*/ */
class AUD_SuperposeReader : public AUD_IReader class AUD_SuperposeReader : public AUD_IReader
{ {
@ -44,15 +45,15 @@ private:
/** /**
* The first reader. * The first reader.
*/ */
AUD_IReader* m_reader1; AUD_Reference<AUD_IReader> m_reader1;
/** /**
* The second reader. * The second reader.
*/ */
AUD_IReader* m_reader2; AUD_Reference<AUD_IReader> m_reader2;
/** /**
* The playback buffer for the intersecting part. * Buffer used for mixing.
*/ */
AUD_Buffer m_buffer; AUD_Buffer m_buffer;
@ -67,7 +68,7 @@ public:
* \param reader2 The second reader to read from. * \param reader2 The second reader to read from.
* \exception AUD_Exception Thrown if the specs from the readers differ. * \exception AUD_Exception Thrown if the specs from the readers differ.
*/ */
AUD_SuperposeReader(AUD_IReader* reader1, AUD_IReader* reader2); AUD_SuperposeReader(AUD_Reference<AUD_IReader> reader1, AUD_Reference<AUD_IReader> reader2);
/** /**
* Destroys the reader. * Destroys the reader.
@ -79,7 +80,7 @@ public:
virtual int getLength() const; virtual int getLength() const;
virtual int getPosition() const; virtual int getPosition() const;
virtual AUD_Specs getSpecs() const; virtual AUD_Specs getSpecs() const;
virtual void read(int & length, sample_t* & buffer); virtual void read(int& length, bool& eos, sample_t* buffer);
}; };
#endif //AUD_SUPERPOSEREADER #endif //AUD_SUPERPOSEREADER

@ -32,7 +32,7 @@
#include "AUD_VolumeFactory.h" #include "AUD_VolumeFactory.h"
#include "AUD_IIRFilterReader.h" #include "AUD_IIRFilterReader.h"
AUD_VolumeFactory::AUD_VolumeFactory(AUD_IFactory* factory, float volume) : AUD_VolumeFactory::AUD_VolumeFactory(AUD_Reference<AUD_IFactory> factory, float volume) :
AUD_EffectFactory(factory), AUD_EffectFactory(factory),
m_volume(volume) m_volume(volume)
{ {
@ -43,7 +43,7 @@ float AUD_VolumeFactory::getVolume() const
return m_volume; return m_volume;
} }
AUD_IReader* AUD_VolumeFactory::createReader() const AUD_Reference<AUD_IReader> AUD_VolumeFactory::createReader()
{ {
std::vector<float> a, b; std::vector<float> a, b;
a.push_back(1); a.push_back(1);

@ -57,14 +57,15 @@ public:
* \param factory The input factory. * \param factory The input factory.
* \param volume The desired volume. * \param volume The desired volume.
*/ */
AUD_VolumeFactory(AUD_IFactory* factory, float volume); AUD_VolumeFactory(AUD_Reference<AUD_IFactory> factory, float volume);
/** /**
* Returns the volume. * Returns the volume.
* \return The current volume.
*/ */
float getVolume() const; float getVolume() const;
virtual AUD_IReader* createReader() const; virtual AUD_Reference<AUD_IReader> createReader();
}; };
#endif //AUD_VOLUMEFACTORY #endif //AUD_VOLUMEFACTORY

File diff suppressed because it is too large Load Diff

@ -33,9 +33,11 @@
#define AUD_OPENALDEVICE #define AUD_OPENALDEVICE
#include "AUD_IDevice.h" #include "AUD_IDevice.h"
#include "AUD_IHandle.h"
#include "AUD_I3DDevice.h" #include "AUD_I3DDevice.h"
struct AUD_OpenALHandle; #include "AUD_I3DHandle.h"
struct AUD_OpenALBufferedFactory; #include "AUD_Buffer.h"
//struct AUD_OpenALBufferedFactory;
#include <AL/al.h> #include <AL/al.h>
#include <AL/alc.h> #include <AL/alc.h>
@ -48,6 +50,110 @@ struct AUD_OpenALBufferedFactory;
class AUD_OpenALDevice : public AUD_IDevice, public AUD_I3DDevice class AUD_OpenALDevice : public AUD_IDevice, public AUD_I3DDevice
{ {
private: private:
/// Saves the data for playback.
class AUD_OpenALHandle : public AUD_IHandle, public AUD_I3DHandle
{
public:
static const int CYCLE_BUFFERS = 3;
/// Whether it's a buffered or a streamed source.
bool m_isBuffered;
/// The reader source.
AUD_Reference<AUD_IReader> m_reader;
/// Whether to keep the source if end of it is reached.
bool m_keep;
/// OpenAL sample format.
ALenum m_format;
/// OpenAL source.
ALuint m_source;
/// OpenAL buffers.
ALuint m_buffers[CYCLE_BUFFERS];
/// The first buffer to be read next.
int m_current;
/// Whether the stream doesn't return any more data.
bool m_eos;
/// The loop count of the source.
int m_loopcount;
/// The stop callback.
stopCallback m_stop;
/// Stop callback data.
void* m_stop_data;
/// Orientation.
AUD_Quaternion m_orientation;
/// Current status of the handle
AUD_Status m_status;
/// Own device.
AUD_OpenALDevice* m_device;
public:
/**
* Creates a new OpenAL handle.
* \param device The OpenAL device the handle belongs to.
* \param format The AL format.
* \param reader The reader this handle plays.
* \param keep Whether to keep the handle alive when the reader ends.
*/
AUD_OpenALHandle(AUD_OpenALDevice* device, ALenum format, AUD_Reference<AUD_IReader> reader, bool keep);
virtual ~AUD_OpenALHandle() {}
virtual bool pause();
virtual bool resume();
virtual bool stop();
virtual bool getKeep();
virtual bool setKeep(bool keep);
virtual bool seek(float position);
virtual float getPosition();
virtual AUD_Status getStatus();
virtual float getVolume();
virtual bool setVolume(float volume);
virtual float getPitch();
virtual bool setPitch(float pitch);
virtual int getLoopCount();
virtual bool setLoopCount(int count);
virtual bool setStopCallback(stopCallback callback = 0, void* data = 0);
virtual AUD_Vector3 getSourceLocation();
virtual bool setSourceLocation(const AUD_Vector3& location);
virtual AUD_Vector3 getSourceVelocity();
virtual bool setSourceVelocity(const AUD_Vector3& velocity);
virtual AUD_Quaternion getSourceOrientation();
virtual bool setSourceOrientation(const AUD_Quaternion& orientation);
virtual bool isRelative();
virtual bool setRelative(bool relative);
virtual float getVolumeMaximum();
virtual bool setVolumeMaximum(float volume);
virtual float getVolumeMinimum();
virtual bool setVolumeMinimum(float volume);
virtual float getDistanceMaximum();
virtual bool setDistanceMaximum(float distance);
virtual float getDistanceReference();
virtual bool setDistanceReference(float distance);
virtual float getAttenuation();
virtual bool setAttenuation(float factor);
virtual float getConeAngleOuter();
virtual bool setConeAngleOuter(float angle);
virtual float getConeAngleInner();
virtual bool setConeAngleInner(float angle);
virtual float getConeVolumeOuter();
virtual bool setConeVolumeOuter(float volume);
};
typedef std::list<AUD_Reference<AUD_OpenALHandle> >::iterator AUD_HandleIterator;
/** /**
* The OpenAL device handle. * The OpenAL device handle.
*/ */
@ -71,17 +177,17 @@ private:
/** /**
* The list of sounds that are currently playing. * The list of sounds that are currently playing.
*/ */
std::list<AUD_OpenALHandle*>* m_playingSounds; std::list<AUD_Reference<AUD_OpenALHandle> > m_playingSounds;
/** /**
* The list of sounds that are currently paused. * The list of sounds that are currently paused.
*/ */
std::list<AUD_OpenALHandle*>* m_pausedSounds; std::list<AUD_Reference<AUD_OpenALHandle> > m_pausedSounds;
/** /**
* The list of buffered factories. * The list of buffered factories.
*/ */
std::list<AUD_OpenALBufferedFactory*>* m_bufferedFactories; //std::list<AUD_OpenALBufferedFactory*>* m_bufferedFactories;
/** /**
* The mutex for locking. * The mutex for locking.
@ -104,16 +210,20 @@ private:
int m_buffersize; int m_buffersize;
/** /**
* Starts the streaming thread. * Device buffer.
*/ */
void start(bool join = true); AUD_Buffer m_buffer;
/** /**
* Checks if a handle is valid. * Orientation.
* \param handle The handle to check.
* \return Whether the handle is valid.
*/ */
bool isValid(AUD_Handle* handle); AUD_Quaternion m_orientation;
/**
* Starts the streaming thread.
* \param Whether the previous thread should be joined.
*/
void start(bool join = true);
/** /**
* Gets the format according to the specs. * Gets the format according to the specs.
@ -147,27 +257,13 @@ public:
virtual ~AUD_OpenALDevice(); virtual ~AUD_OpenALDevice();
virtual AUD_DeviceSpecs getSpecs() const; virtual AUD_DeviceSpecs getSpecs() const;
virtual AUD_Handle* play(AUD_IReader* reader, bool keep = false); virtual AUD_Reference<AUD_IHandle> play(AUD_Reference<AUD_IReader> reader, bool keep = false);
virtual AUD_Handle* play(AUD_IFactory* factory, bool keep = false); virtual AUD_Reference<AUD_IHandle> play(AUD_Reference<AUD_IFactory> factory, bool keep = false);
virtual bool pause(AUD_Handle* handle); virtual void stopAll();
virtual bool resume(AUD_Handle* handle);
virtual bool stop(AUD_Handle* handle);
virtual bool getKeep(AUD_Handle* handle);
virtual bool setKeep(AUD_Handle* handle, bool keep);
virtual bool seek(AUD_Handle* handle, float position);
virtual float getPosition(AUD_Handle* handle);
virtual AUD_Status getStatus(AUD_Handle* handle);
virtual void lock(); virtual void lock();
virtual void unlock(); virtual void unlock();
virtual float getVolume() const; virtual float getVolume() const;
virtual void setVolume(float volume); virtual void setVolume(float volume);
virtual float getVolume(AUD_Handle* handle);
virtual bool setVolume(AUD_Handle* handle, float volume);
virtual float getPitch(AUD_Handle* handle);
virtual bool setPitch(AUD_Handle* handle, float pitch);
virtual int getLoopCount(AUD_Handle* handle);
virtual bool setLoopCount(AUD_Handle* handle, int count);
virtual bool setStopCallback(AUD_Handle* handle, stopCallback callback = NULL, void* data = NULL);
virtual AUD_Vector3 getListenerLocation() const; virtual AUD_Vector3 getListenerLocation() const;
virtual void setListenerLocation(const AUD_Vector3& location); virtual void setListenerLocation(const AUD_Vector3& location);
@ -181,30 +277,6 @@ public:
virtual void setDopplerFactor(float factor); virtual void setDopplerFactor(float factor);
virtual AUD_DistanceModel getDistanceModel() const; virtual AUD_DistanceModel getDistanceModel() const;
virtual void setDistanceModel(AUD_DistanceModel model); virtual void setDistanceModel(AUD_DistanceModel model);
virtual AUD_Vector3 getSourceLocation(AUD_Handle* handle);
virtual bool setSourceLocation(AUD_Handle* handle, const AUD_Vector3& location);
virtual AUD_Vector3 getSourceVelocity(AUD_Handle* handle);
virtual bool setSourceVelocity(AUD_Handle* handle, const AUD_Vector3& velocity);
virtual AUD_Quaternion getSourceOrientation(AUD_Handle* handle);
virtual bool setSourceOrientation(AUD_Handle* handle, const AUD_Quaternion& orientation);
virtual bool isRelative(AUD_Handle* handle);
virtual bool setRelative(AUD_Handle* handle, bool relative);
virtual float getVolumeMaximum(AUD_Handle* handle);
virtual bool setVolumeMaximum(AUD_Handle* handle, float volume);
virtual float getVolumeMinimum(AUD_Handle* handle);
virtual bool setVolumeMinimum(AUD_Handle* handle, float volume);
virtual float getDistanceMaximum(AUD_Handle* handle);
virtual bool setDistanceMaximum(AUD_Handle* handle, float distance);
virtual float getDistanceReference(AUD_Handle* handle);
virtual bool setDistanceReference(AUD_Handle* handle, float distance);
virtual float getAttenuation(AUD_Handle* handle);
virtual bool setAttenuation(AUD_Handle* handle, float factor);
virtual float getConeAngleOuter(AUD_Handle* handle);
virtual bool setConeAngleOuter(AUD_Handle* handle, float angle);
virtual float getConeAngleInner(AUD_Handle* handle);
virtual bool setConeAngleInner(AUD_Handle* handle, float angle);
virtual float getConeVolumeOuter(AUD_Handle* handle);
virtual bool setConeVolumeOuter(AUD_Handle* handle, float volume);
}; };
#endif //AUD_OPENALDEVICE #endif //AUD_OPENALDEVICE

File diff suppressed because it is too large Load Diff

@ -36,35 +36,38 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#include "AUD_IDevice.h"
#else #else
typedef void AUD_IFactory; typedef void AUD_IFactory;
typedef void AUD_IDevice; typedef void AUD_IDevice;
typedef void AUD_Handle; typedef void AUD_IHandle;
#endif #endif
typedef void AUD_Reference_AUD_IFactory;
typedef void AUD_Reference_AUD_IDevice;
typedef void AUD_Reference_AUD_IHandle;
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
PyObject* child_list; PyObject* child_list;
AUD_IFactory* factory; AUD_Reference_AUD_IFactory* factory;
} Factory; } Factory;
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
AUD_Handle* handle; AUD_Reference_AUD_IHandle* handle;
PyObject* device;
} Handle; } Handle;
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
AUD_IDevice* device; AUD_Reference_AUD_IDevice* device;
} Device; } Device;
PyMODINIT_FUNC PyMODINIT_FUNC
PyInit_aud(void); PyInit_aud(void);
extern PyObject * extern PyObject* Device_empty();
Device_empty(); extern PyObject* Factory_empty();
extern Factory* checkFactory(PyObject* factory);
#ifdef __cplusplus #ifdef __cplusplus
} }

@ -32,18 +32,13 @@
#include "AUD_SRCResampleFactory.h" #include "AUD_SRCResampleFactory.h"
#include "AUD_SRCResampleReader.h" #include "AUD_SRCResampleReader.h"
AUD_SRCResampleFactory::AUD_SRCResampleFactory(AUD_IFactory* factory, AUD_SRCResampleFactory::AUD_SRCResampleFactory(AUD_Reference<AUD_IFactory> factory,
AUD_DeviceSpecs specs) : AUD_DeviceSpecs specs) :
AUD_ResampleFactory(factory, specs) AUD_MixerFactory(factory, specs)
{ {
} }
AUD_IReader* AUD_SRCResampleFactory::createReader() const AUD_Reference<AUD_IReader> AUD_SRCResampleFactory::createReader()
{ {
AUD_IReader* reader = getReader(); return new AUD_SRCResampleReader(getReader(), m_specs.specs);
if(reader->getSpecs().rate != m_specs.rate)
reader = new AUD_SRCResampleReader(reader, m_specs.specs);
return reader;
} }

@ -32,13 +32,13 @@
#ifndef AUD_SRCRESAMPLEFACTORY #ifndef AUD_SRCRESAMPLEFACTORY
#define AUD_SRCRESAMPLEFACTORY #define AUD_SRCRESAMPLEFACTORY
#include "AUD_ResampleFactory.h" #include "AUD_MixerFactory.h"
/** /**
* This factory creates a resampling reader that uses libsamplerate for * This factory creates a resampling reader that uses libsamplerate for
* resampling. * resampling.
*/ */
class AUD_SRCResampleFactory : public AUD_ResampleFactory class AUD_SRCResampleFactory : public AUD_MixerFactory
{ {
private: private:
// hide copy constructor and operator= // hide copy constructor and operator=
@ -46,9 +46,14 @@ private:
AUD_SRCResampleFactory& operator=(const AUD_SRCResampleFactory&); AUD_SRCResampleFactory& operator=(const AUD_SRCResampleFactory&);
public: public:
AUD_SRCResampleFactory(AUD_IFactory* factory, AUD_DeviceSpecs specs); /**
* Creates a new factory.
* \param factory The input factory.
* \param specs The target specifications.
*/
AUD_SRCResampleFactory(AUD_Reference<AUD_IFactory> factory, AUD_DeviceSpecs specs);
virtual AUD_IReader* createReader() const; virtual AUD_Reference<AUD_IReader> createReader();
}; };
#endif //AUD_SRCRESAMPLEFACTORY #endif //AUD_SRCRESAMPLEFACTORY

@ -43,20 +43,16 @@ static long src_callback(void *cb_data, float **data)
static const char* state_error = "AUD_SRCResampleReader: SRC State couldn't be " static const char* state_error = "AUD_SRCResampleReader: SRC State couldn't be "
"created."; "created.";
AUD_SRCResampleReader::AUD_SRCResampleReader(AUD_IReader* reader, AUD_SRCResampleReader::AUD_SRCResampleReader(AUD_Reference<AUD_IReader> reader,
AUD_Specs specs) : AUD_Specs specs) :
AUD_EffectReader(reader), AUD_ResampleReader(reader, specs.rate),
m_sspecs(reader->getSpecs()), m_channels(reader->getSpecs().channels),
m_factor(double(specs.rate) / double(m_sspecs.rate)),
m_tspecs(specs),
m_position(0) m_position(0)
{ {
m_tspecs.channels = m_sspecs.channels;
int error; int error;
m_src = src_callback_new(src_callback, m_src = src_callback_new(src_callback,
SRC_SINC_MEDIUM_QUALITY, SRC_SINC_MEDIUM_QUALITY,
m_sspecs.channels, m_channels,
&error, &error,
this); this);
@ -74,25 +70,32 @@ AUD_SRCResampleReader::~AUD_SRCResampleReader()
long AUD_SRCResampleReader::doCallback(float** data) long AUD_SRCResampleReader::doCallback(float** data)
{ {
int length = m_buffer.getSize() / AUD_SAMPLE_SIZE(m_tspecs); AUD_Specs specs;
sample_t* buffer; specs.channels = m_channels;
specs.rate = m_rate;
m_reader->read(length, buffer); int length = m_buffer.getSize() / AUD_SAMPLE_SIZE(specs);
*data = m_buffer.getBuffer();
m_reader->read(length, m_eos, *data);
*data = buffer;
return length; return length;
} }
void AUD_SRCResampleReader::seek(int position) void AUD_SRCResampleReader::seek(int position)
{ {
m_reader->seek(position / m_factor); AUD_Specs specs = m_reader->getSpecs();
double factor = double(m_rate) / double(specs.rate);
m_reader->seek(position / factor);
src_reset(m_src); src_reset(m_src);
m_position = position; m_position = position;
} }
int AUD_SRCResampleReader::getLength() const int AUD_SRCResampleReader::getLength() const
{ {
return m_reader->getLength() * m_factor; AUD_Specs specs = m_reader->getSpecs();
double factor = double(m_rate) / double(specs.rate);
return m_reader->getLength() * factor;
} }
int AUD_SRCResampleReader::getPosition() const int AUD_SRCResampleReader::getPosition() const
@ -102,19 +105,48 @@ int AUD_SRCResampleReader::getPosition() const
AUD_Specs AUD_SRCResampleReader::getSpecs() const AUD_Specs AUD_SRCResampleReader::getSpecs() const
{ {
return m_tspecs; AUD_Specs specs = m_reader->getSpecs();
specs.rate = m_rate;
return specs;
} }
void AUD_SRCResampleReader::read(int & length, sample_t* & buffer) void AUD_SRCResampleReader::read(int& length, bool& eos, sample_t* buffer)
{ {
int size = length * AUD_SAMPLE_SIZE(m_tspecs); AUD_Specs specs = m_reader->getSpecs();
if(m_buffer.getSize() < size) double factor = double(m_rate) / double(specs.rate);
m_buffer.resize(size);
buffer = m_buffer.getBuffer(); specs.rate = m_rate;
length = src_callback_read(m_src, m_factor, length, buffer); int size = length;
m_buffer.assureSize(length * AUD_SAMPLE_SIZE(specs));
if(specs.channels != m_channels)
{
src_delete(m_src);
m_channels = specs.channels;
int error;
m_src = src_callback_new(src_callback,
SRC_SINC_MEDIUM_QUALITY,
m_channels,
&error,
this);
if(!m_src)
{
// XXX printf("%s\n", src_strerror(error));
AUD_THROW(AUD_ERROR_SRC, state_error);
}
}
m_eos = false;
length = src_callback_read(m_src, factor, length, buffer);
m_position += length; m_position += length;
eos = m_eos && (length < size);
} }

@ -32,7 +32,7 @@
#ifndef AUD_SRCRESAMPLEREADER #ifndef AUD_SRCRESAMPLEREADER
#define AUD_SRCRESAMPLEREADER #define AUD_SRCRESAMPLEREADER
#include "AUD_EffectReader.h" #include "AUD_ResampleReader.h"
#include "AUD_Buffer.h" #include "AUD_Buffer.h"
#include <samplerate.h> #include <samplerate.h>
@ -40,28 +40,18 @@
/** /**
* This resampling reader uses libsamplerate for resampling. * This resampling reader uses libsamplerate for resampling.
*/ */
class AUD_SRCResampleReader : public AUD_EffectReader class AUD_SRCResampleReader : public AUD_ResampleReader
{ {
private: private:
/**
* The sample specification of the source.
*/
const AUD_Specs m_sspecs;
/**
* The resampling factor.
*/
const double m_factor;
/** /**
* The sound output buffer. * The sound output buffer.
*/ */
AUD_Buffer m_buffer; AUD_Buffer m_buffer;
/** /**
* The target specification. * The reader channels.
*/ */
AUD_Specs m_tspecs; AUD_Channels m_channels;
/** /**
* The src state structure. * The src state structure.
@ -73,6 +63,11 @@ private:
*/ */
int m_position; int m_position;
/**
* Whether reader reached end of stream.
*/
bool m_eos;
// hide copy constructor and operator= // hide copy constructor and operator=
AUD_SRCResampleReader(const AUD_SRCResampleReader&); AUD_SRCResampleReader(const AUD_SRCResampleReader&);
AUD_SRCResampleReader& operator=(const AUD_SRCResampleReader&); AUD_SRCResampleReader& operator=(const AUD_SRCResampleReader&);
@ -85,7 +80,7 @@ public:
* \exception AUD_Exception Thrown if the source specification cannot be * \exception AUD_Exception Thrown if the source specification cannot be
* resampled to the target specification. * resampled to the target specification.
*/ */
AUD_SRCResampleReader(AUD_IReader* reader, AUD_Specs specs); AUD_SRCResampleReader(AUD_Reference<AUD_IReader> reader, AUD_Specs specs);
/** /**
* Destroys the reader. * Destroys the reader.
@ -104,7 +99,7 @@ public:
virtual int getLength() const; virtual int getLength() const;
virtual int getPosition() const; virtual int getPosition() const;
virtual AUD_Specs getSpecs() const; virtual AUD_Specs getSpecs() const;
virtual void read(int & length, sample_t* & buffer); virtual void read(int& length, bool& eos, sample_t* buffer);
}; };
#endif //AUD_SRCRESAMPLEREADER #endif //AUD_SRCRESAMPLEREADER

@ -36,7 +36,6 @@
#include "AUD_FFMPEGFactory.h" #include "AUD_FFMPEGFactory.h"
#include "AUD_FFMPEGReader.h" #include "AUD_FFMPEGReader.h"
#include "AUD_Buffer.h"
AUD_FFMPEGFactory::AUD_FFMPEGFactory(std::string filename) : AUD_FFMPEGFactory::AUD_FFMPEGFactory(std::string filename) :
m_filename(filename) m_filename(filename)
@ -46,13 +45,13 @@ AUD_FFMPEGFactory::AUD_FFMPEGFactory(std::string filename) :
AUD_FFMPEGFactory::AUD_FFMPEGFactory(const data_t* buffer, int size) : AUD_FFMPEGFactory::AUD_FFMPEGFactory(const data_t* buffer, int size) :
m_buffer(new AUD_Buffer(size)) m_buffer(new AUD_Buffer(size))
{ {
memcpy(m_buffer.get()->getBuffer(), buffer, size); memcpy(m_buffer->getBuffer(), buffer, size);
} }
AUD_IReader* AUD_FFMPEGFactory::createReader() const AUD_Reference<AUD_IReader> AUD_FFMPEGFactory::createReader()
{ {
if(m_buffer.get()) if(m_buffer.isNull())
return new AUD_FFMPEGReader(m_buffer);
else
return new AUD_FFMPEGReader(m_filename); return new AUD_FFMPEGReader(m_filename);
else
return new AUD_FFMPEGReader(m_buffer);
} }

@ -34,7 +34,7 @@
#include "AUD_IFactory.h" #include "AUD_IFactory.h"
#include "AUD_Reference.h" #include "AUD_Reference.h"
class AUD_Buffer; #include "AUD_Buffer.h"
#include <string> #include <string>
@ -74,7 +74,7 @@ public:
*/ */
AUD_FFMPEGFactory(const data_t* buffer, int size); AUD_FFMPEGFactory(const data_t* buffer, int size);
virtual AUD_IReader* createReader() const; virtual AUD_Reference<AUD_IReader> createReader();
}; };
#endif //AUD_FFMPEGFACTORY #endif //AUD_FFMPEGFACTORY

@ -39,6 +39,7 @@
extern "C" { extern "C" {
#include <libavcodec/avcodec.h> #include <libavcodec/avcodec.h>
#include <libavformat/avformat.h> #include <libavformat/avformat.h>
#include <libavformat/avio.h>
#include "ffmpeg_compat.h" #include "ffmpeg_compat.h"
} }
@ -176,11 +177,12 @@ static const char* fileopen_error = "AUD_FFMPEGReader: File couldn't be "
AUD_FFMPEGReader::AUD_FFMPEGReader(std::string filename) : AUD_FFMPEGReader::AUD_FFMPEGReader(std::string filename) :
m_pkgbuf(AVCODEC_MAX_AUDIO_FRAME_SIZE<<1), m_pkgbuf(AVCODEC_MAX_AUDIO_FRAME_SIZE<<1),
m_byteiocontext(NULL), m_formatCtx(NULL),
m_aviocontext(NULL),
m_membuf(NULL) m_membuf(NULL)
{ {
// open file // open file
if(av_open_input_file(&m_formatCtx, filename.c_str(), NULL, 0, NULL)!=0) if(avformat_open_input(&m_formatCtx, filename.c_str(), NULL, NULL)!=0)
AUD_THROW(AUD_ERROR_FILE, fileopen_error); AUD_THROW(AUD_ERROR_FILE, fileopen_error);
try try
@ -204,25 +206,20 @@ AUD_FFMPEGReader::AUD_FFMPEGReader(AUD_Reference<AUD_Buffer> buffer) :
{ {
m_membuf = reinterpret_cast<data_t*>(av_malloc(FF_MIN_BUFFER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE)); m_membuf = reinterpret_cast<data_t*>(av_malloc(FF_MIN_BUFFER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE));
m_byteiocontext = av_alloc_put_byte(m_membuf, FF_MIN_BUFFER_SIZE, 0, this, m_aviocontext = avio_alloc_context(m_membuf, FF_MIN_BUFFER_SIZE, 0, this,
read_packet, NULL, seek_packet); read_packet, NULL, seek_packet);
if(!m_byteiocontext) if(!m_aviocontext)
{ {
av_free(m_byteiocontext); av_free(m_aviocontext);
AUD_THROW(AUD_ERROR_FILE, fileopen_error); AUD_THROW(AUD_ERROR_FILE, fileopen_error);
} }
AVProbeData probe_data; m_formatCtx = avformat_alloc_context();
probe_data.filename = ""; m_formatCtx->pb = m_aviocontext;
probe_data.buf = reinterpret_cast<data_t*>(buffer.get()->getBuffer()); if(avformat_open_input(&m_formatCtx, "", NULL, NULL)!=0)
probe_data.buf_size = buffer.get()->getSize();
AVInputFormat* fmt = av_probe_input_format(&probe_data, 1);
// open stream
if(av_open_input_stream(&m_formatCtx, m_byteiocontext, "", fmt, NULL)!=0)
{ {
av_free(m_byteiocontext); av_free(m_aviocontext);
AUD_THROW(AUD_ERROR_FILE, streamopen_error); AUD_THROW(AUD_ERROR_FILE, streamopen_error);
} }
@ -233,7 +230,7 @@ AUD_FFMPEGReader::AUD_FFMPEGReader(AUD_Reference<AUD_Buffer> buffer) :
catch(AUD_Exception&) catch(AUD_Exception&)
{ {
av_close_input_stream(m_formatCtx); av_close_input_stream(m_formatCtx);
av_free(m_byteiocontext); av_free(m_aviocontext);
throw; throw;
} }
} }
@ -242,10 +239,10 @@ AUD_FFMPEGReader::~AUD_FFMPEGReader()
{ {
avcodec_close(m_codecCtx); avcodec_close(m_codecCtx);
if(m_byteiocontext) if(m_aviocontext)
{ {
av_close_input_stream(m_formatCtx); av_close_input_stream(m_formatCtx);
av_free(m_byteiocontext); av_free(m_aviocontext);
} }
else else
av_close_input_file(m_formatCtx); av_close_input_file(m_formatCtx);
@ -255,12 +252,12 @@ int AUD_FFMPEGReader::read_packet(void* opaque, uint8_t* buf, int buf_size)
{ {
AUD_FFMPEGReader* reader = reinterpret_cast<AUD_FFMPEGReader*>(opaque); AUD_FFMPEGReader* reader = reinterpret_cast<AUD_FFMPEGReader*>(opaque);
int size = AUD_MIN(buf_size, reader->m_membuffer.get()->getSize() - reader->m_membufferpos); int size = AUD_MIN(buf_size, reader->m_membuffer->getSize() - reader->m_membufferpos);
if(size < 0) if(size < 0)
return -1; return -1;
memcpy(buf, ((data_t*)reader->m_membuffer.get()->getBuffer()) + reader->m_membufferpos, size); memcpy(buf, ((data_t*)reader->m_membuffer->getBuffer()) + reader->m_membufferpos, size);
reader->m_membufferpos += size; reader->m_membufferpos += size;
return size; return size;
@ -276,10 +273,10 @@ int64_t AUD_FFMPEGReader::seek_packet(void* opaque, int64_t offset, int whence)
reader->m_membufferpos = 0; reader->m_membufferpos = 0;
break; break;
case SEEK_END: case SEEK_END:
reader->m_membufferpos = reader->m_membuffer.get()->getSize(); reader->m_membufferpos = reader->m_membuffer->getSize();
break; break;
case AVSEEK_SIZE: case AVSEEK_SIZE:
return reader->m_membuffer.get()->getSize(); return reader->m_membuffer->getSize();
} }
return (reader->m_membufferpos += offset); return (reader->m_membufferpos += offset);
@ -341,14 +338,15 @@ void AUD_FFMPEGReader::seek(int position)
{ {
// read until we're at the right position // read until we're at the right position
int length = AUD_DEFAULT_BUFFER_SIZE; int length = AUD_DEFAULT_BUFFER_SIZE;
sample_t* buffer; AUD_Buffer buffer(length * AUD_SAMPLE_SIZE(m_specs));
bool eos;
for(int len = position - m_position; for(int len = position - m_position;
length == AUD_DEFAULT_BUFFER_SIZE; length == AUD_DEFAULT_BUFFER_SIZE;
len -= AUD_DEFAULT_BUFFER_SIZE) len -= AUD_DEFAULT_BUFFER_SIZE)
{ {
if(len < AUD_DEFAULT_BUFFER_SIZE) if(len < AUD_DEFAULT_BUFFER_SIZE)
length = len; length = len;
read(length, buffer); read(length, eos, buffer.getBuffer());
} }
} }
} }
@ -381,7 +379,7 @@ AUD_Specs AUD_FFMPEGReader::getSpecs() const
return m_specs.specs; return m_specs.specs;
} }
void AUD_FFMPEGReader::read(int & length, sample_t* & buffer) void AUD_FFMPEGReader::read(int& length, bool& eos, sample_t* buffer)
{ {
// read packages and decode them // read packages and decode them
AVPacket packet; AVPacket packet;
@ -390,11 +388,7 @@ void AUD_FFMPEGReader::read(int & length, sample_t* & buffer)
int left = length; int left = length;
int sample_size = AUD_DEVICE_SAMPLE_SIZE(m_specs); int sample_size = AUD_DEVICE_SAMPLE_SIZE(m_specs);
// resize output buffer if necessary sample_t* buf = buffer;
if(m_buffer.getSize() < length * AUD_SAMPLE_SIZE(m_specs))
m_buffer.resize(length * AUD_SAMPLE_SIZE(m_specs));
buffer = m_buffer.getBuffer();
pkgbuf_pos = m_pkgbuf_left; pkgbuf_pos = m_pkgbuf_left;
m_pkgbuf_left = 0; m_pkgbuf_left = 0;
@ -402,9 +396,9 @@ void AUD_FFMPEGReader::read(int & length, sample_t* & buffer)
if(pkgbuf_pos > 0) if(pkgbuf_pos > 0)
{ {
data_size = AUD_MIN(pkgbuf_pos, left * sample_size); data_size = AUD_MIN(pkgbuf_pos, left * sample_size);
m_convert((data_t*) buffer, (data_t*) m_pkgbuf.getBuffer(), m_convert((data_t*) buf, (data_t*) m_pkgbuf.getBuffer(),
data_size / AUD_FORMAT_SIZE(m_specs.format)); data_size / AUD_FORMAT_SIZE(m_specs.format));
buffer += data_size / AUD_FORMAT_SIZE(m_specs.format); buf += data_size / AUD_FORMAT_SIZE(m_specs.format);
left -= data_size/sample_size; left -= data_size/sample_size;
} }
@ -419,9 +413,9 @@ void AUD_FFMPEGReader::read(int & length, sample_t* & buffer)
// copy to output buffer // copy to output buffer
data_size = AUD_MIN(pkgbuf_pos, left * sample_size); data_size = AUD_MIN(pkgbuf_pos, left * sample_size);
m_convert((data_t*) buffer, (data_t*) m_pkgbuf.getBuffer(), m_convert((data_t*) buf, (data_t*) m_pkgbuf.getBuffer(),
data_size / AUD_FORMAT_SIZE(m_specs.format)); data_size / AUD_FORMAT_SIZE(m_specs.format));
buffer += data_size / AUD_FORMAT_SIZE(m_specs.format); buf += data_size / AUD_FORMAT_SIZE(m_specs.format);
left -= data_size/sample_size; left -= data_size/sample_size;
} }
av_free_packet(&packet); av_free_packet(&packet);
@ -435,9 +429,8 @@ void AUD_FFMPEGReader::read(int & length, sample_t* & buffer)
pkgbuf_pos-data_size); pkgbuf_pos-data_size);
} }
buffer = m_buffer.getBuffer(); if((eos = (left > 0)))
if(left > 0)
length -= left; length -= left;
m_position += length; m_position += length;
} }

@ -49,8 +49,6 @@ extern "C" {
* \warning Seeking may not be accurate! Moreover the position is updated after * \warning Seeking may not be accurate! Moreover the position is updated after
* a buffer reading call. So calling getPosition right after seek * a buffer reading call. So calling getPosition right after seek
* normally results in a wrong value. * normally results in a wrong value.
* \warning Playback of an ogg with some outdated ffmpeg versions results in a
* segfault on windows.
*/ */
class AUD_FFMPEGReader : public AUD_IReader class AUD_FFMPEGReader : public AUD_IReader
{ {
@ -60,11 +58,6 @@ private:
*/ */
int m_position; int m_position;
/**
* The playback buffer.
*/
AUD_Buffer m_buffer;
/** /**
* The specification of the audio data. * The specification of the audio data.
*/ */
@ -91,9 +84,9 @@ private:
AVCodecContext* m_codecCtx; AVCodecContext* m_codecCtx;
/** /**
* The ByteIOContext to read the data from. * The AVIOContext to read the data from.
*/ */
ByteIOContext* m_byteiocontext; AVIOContext* m_aviocontext;
/** /**
* The stream ID in the file. * The stream ID in the file.
@ -167,7 +160,7 @@ public:
virtual int getLength() const; virtual int getLength() const;
virtual int getPosition() const; virtual int getPosition() const;
virtual AUD_Specs getSpecs() const; virtual AUD_Specs getSpecs() const;
virtual void read(int & length, sample_t* & buffer); virtual void read(int& length, bool& eos, sample_t* buffer);
}; };
#endif //AUD_FFMPEGREADER #endif //AUD_FFMPEGREADER

@ -0,0 +1,305 @@
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* Copyright 2009-2011 Jörg Hermann Müller
*
* This file is part of AudaSpace.
*
* Audaspace 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 2 of the License, or
* (at your option) any later version.
*
* AudaSpace 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 Audaspace; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file audaspace/ffmpeg/AUD_FFMPEGWriter.cpp
* \ingroup audffmpeg
*/
// needed for INT64_C
#ifndef __STDC_CONSTANT_MACROS
#define __STDC_CONSTANT_MACROS
#endif
#include "AUD_FFMPEGWriter.h"
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavformat/avio.h>
#include "ffmpeg_compat.h"
}
static const char* context_error = "AUD_FFMPEGWriter: Couldn't allocate context.";
static const char* codec_error = "AUD_FFMPEGWriter: Invalid codec or codec not found.";
static const char* stream_error = "AUD_FFMPEGWriter: Couldn't allocate stream.";
static const char* format_error = "AUD_FFMPEGWriter: Unsupported sample format.";
static const char* file_error = "AUD_FFMPEGWriter: File couldn't be written.";
static const char* write_error = "AUD_FFMPEGWriter: Error writing packet.";
AUD_FFMPEGWriter::AUD_FFMPEGWriter(std::string filename, AUD_DeviceSpecs specs, AUD_Container format, AUD_Codec codec, unsigned int bitrate) :
m_position(0),
m_specs(specs),
m_input_samples(0)
{
static const char* formats[] = { NULL, "ac3", "flac", "matroska", "mp2", "mp3", "ogg", "wav" };
if(avformat_alloc_output_context2(&m_formatCtx, NULL, formats[format], filename.c_str()))
AUD_THROW(AUD_ERROR_FFMPEG, context_error);
m_outputFmt = m_formatCtx->oformat;
switch(codec)
{
case AUD_CODEC_AAC:
m_outputFmt->audio_codec = CODEC_ID_AAC;
break;
case AUD_CODEC_AC3:
m_outputFmt->audio_codec = CODEC_ID_AC3;
break;
case AUD_CODEC_FLAC:
m_outputFmt->audio_codec = CODEC_ID_FLAC;
break;
case AUD_CODEC_MP2:
m_outputFmt->audio_codec = CODEC_ID_MP2;
break;
case AUD_CODEC_MP3:
m_outputFmt->audio_codec = CODEC_ID_MP3;
break;
case AUD_CODEC_PCM:
switch(specs.format)
{
case AUD_FORMAT_U8:
m_outputFmt->audio_codec = CODEC_ID_PCM_U8;
break;
case AUD_FORMAT_S16:
m_outputFmt->audio_codec = CODEC_ID_PCM_S16LE;
break;
case AUD_FORMAT_S24:
m_outputFmt->audio_codec = CODEC_ID_PCM_S24LE;
break;
case AUD_FORMAT_S32:
m_outputFmt->audio_codec = CODEC_ID_PCM_S32LE;
break;
case AUD_FORMAT_FLOAT32:
m_outputFmt->audio_codec = CODEC_ID_PCM_F32LE;
break;
case AUD_FORMAT_FLOAT64:
m_outputFmt->audio_codec = CODEC_ID_PCM_F64LE;
break;
default:
m_outputFmt->audio_codec = CODEC_ID_NONE;
break;
}
break;
case AUD_CODEC_VORBIS:
m_outputFmt->audio_codec = CODEC_ID_VORBIS;
break;
default:
m_outputFmt->audio_codec = CODEC_ID_NONE;
break;
}
try
{
if(m_outputFmt->audio_codec == CODEC_ID_NONE)
AUD_THROW(AUD_ERROR_SPECS, codec_error);
m_stream = av_new_stream(m_formatCtx, 0);
if(!m_stream)
AUD_THROW(AUD_ERROR_FFMPEG, stream_error);
m_codecCtx = m_stream->codec;
m_codecCtx->codec_id = m_outputFmt->audio_codec;
m_codecCtx->codec_type = AVMEDIA_TYPE_AUDIO;
m_codecCtx->bit_rate = bitrate;
m_codecCtx->sample_rate = int(m_specs.rate);
m_codecCtx->channels = m_specs.channels;
m_codecCtx->time_base.num = 1;
m_codecCtx->time_base.den = m_codecCtx->sample_rate;
switch(m_specs.format)
{
case AUD_FORMAT_U8:
m_convert = AUD_convert_float_u8;
m_codecCtx->sample_fmt = SAMPLE_FMT_U8;
break;
case AUD_FORMAT_S16:
m_convert = AUD_convert_float_s16;
m_codecCtx->sample_fmt = SAMPLE_FMT_S16;
break;
case AUD_FORMAT_S32:
m_convert = AUD_convert_float_s32;
m_codecCtx->sample_fmt = SAMPLE_FMT_S32;
break;
case AUD_FORMAT_FLOAT32:
m_convert = AUD_convert_copy<float>;
m_codecCtx->sample_fmt = SAMPLE_FMT_FLT;
break;
case AUD_FORMAT_FLOAT64:
m_convert = AUD_convert_float_double;
m_codecCtx->sample_fmt = SAMPLE_FMT_DBL;
break;
default:
AUD_THROW(AUD_ERROR_FFMPEG, format_error);
}
try
{
if(m_formatCtx->oformat->flags & AVFMT_GLOBALHEADER)
m_codecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;
AVCodec* codec = avcodec_find_encoder(m_codecCtx->codec_id);
if(!codec)
AUD_THROW(AUD_ERROR_FFMPEG, codec_error);
if(avcodec_open(m_codecCtx, codec))
AUD_THROW(AUD_ERROR_FFMPEG, codec_error);
m_output_buffer.resize(FF_MIN_BUFFER_SIZE);
int samplesize = AUD_MAX(AUD_SAMPLE_SIZE(m_specs), AUD_DEVICE_SAMPLE_SIZE(m_specs));
if(m_codecCtx->frame_size <= 1)
m_input_size = 0;
else
{
m_input_buffer.resize(m_codecCtx->frame_size * samplesize);
m_input_size = m_codecCtx->frame_size;
}
try
{
if(avio_open(&m_formatCtx->pb, filename.c_str(), AVIO_FLAG_WRITE))
AUD_THROW(AUD_ERROR_FILE, file_error);
avformat_write_header(m_formatCtx, NULL);
}
catch(AUD_Exception&)
{
avcodec_close(m_codecCtx);
av_freep(&m_formatCtx->streams[0]->codec);
throw;
}
}
catch(AUD_Exception&)
{
av_freep(&m_formatCtx->streams[0]);
throw;
}
}
catch(AUD_Exception&)
{
av_free(m_formatCtx);
throw;
}
}
AUD_FFMPEGWriter::~AUD_FFMPEGWriter()
{
// writte missing data
if(m_input_samples)
{
sample_t* buf = m_input_buffer.getBuffer();
memset(buf + m_specs.channels * m_input_samples, 0,
(m_input_size - m_input_samples) * AUD_DEVICE_SAMPLE_SIZE(m_specs));
encode(buf);
}
av_write_trailer(m_formatCtx);
avcodec_close(m_codecCtx);
av_freep(&m_formatCtx->streams[0]->codec);
av_freep(&m_formatCtx->streams[0]);
avio_close(m_formatCtx->pb);
av_free(m_formatCtx);
}
int AUD_FFMPEGWriter::getPosition() const
{
return m_position;
}
AUD_DeviceSpecs AUD_FFMPEGWriter::getSpecs() const
{
return m_specs;
}
void AUD_FFMPEGWriter::encode(sample_t* data)
{
sample_t* outbuf = m_output_buffer.getBuffer();
// convert first
if(m_input_size)
m_convert(reinterpret_cast<data_t*>(data), reinterpret_cast<data_t*>(data), m_input_size * m_specs.channels);
AVPacket packet;
av_init_packet(&packet);
packet.size = avcodec_encode_audio(m_codecCtx, reinterpret_cast<uint8_t*>(outbuf), m_output_buffer.getSize(), reinterpret_cast<short*>(data));
if(m_codecCtx->coded_frame && m_codecCtx->coded_frame->pts != AV_NOPTS_VALUE)
packet.pts = av_rescale_q(m_codecCtx->coded_frame->pts, m_codecCtx->time_base, m_stream->time_base);
packet.flags |= AV_PKT_FLAG_KEY;
packet.stream_index = m_stream->index;
packet.data = reinterpret_cast<uint8_t*>(outbuf);
if(av_interleaved_write_frame(m_formatCtx, &packet))
AUD_THROW(AUD_ERROR_FFMPEG, write_error);
}
void AUD_FFMPEGWriter::write(unsigned int length, sample_t* buffer)
{
unsigned int samplesize = AUD_SAMPLE_SIZE(m_specs);
if(m_input_size)
{
sample_t* inbuf = m_input_buffer.getBuffer();
while(length)
{
unsigned int len = AUD_MIN(m_input_size - m_input_samples, length);
memcpy(inbuf + m_input_samples * m_specs.channels, buffer, len * samplesize);
buffer += len * m_specs.channels;
m_input_samples += len;
m_position += len;
length -= len;
if(m_input_samples == m_input_size)
{
encode(inbuf);
m_input_samples = 0;
}
}
}
else // PCM data, can write directly!
{
int samplesize = AUD_SAMPLE_SIZE(m_specs);
if(m_output_buffer.getSize() != length * m_specs.channels * m_codecCtx->bits_per_coded_sample / 8)
m_output_buffer.resize(length * m_specs.channels * m_codecCtx->bits_per_coded_sample / 8);
m_input_buffer.assureSize(length * AUD_MAX(AUD_DEVICE_SAMPLE_SIZE(m_specs), samplesize));
sample_t* buf = m_input_buffer.getBuffer();
m_convert(reinterpret_cast<data_t*>(buf), reinterpret_cast<data_t*>(buffer), length * m_specs.channels);
encode(buf);
m_position += length;
}
}

@ -0,0 +1,140 @@
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* Copyright 2009-2011 Jörg Hermann Müller
*
* This file is part of AudaSpace.
*
* Audaspace 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 2 of the License, or
* (at your option) any later version.
*
* AudaSpace 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 Audaspace; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file audaspace/ffmpeg/AUD_FFMPEGWriter.h
* \ingroup audffmpeg
*/
#ifndef AUD_FFMPEGWRITER
#define AUD_FFMPEGWRITER
#include "AUD_ConverterFunctions.h"
#include "AUD_Buffer.h"
#include "AUD_IWriter.h"
#include <string>
struct AVCodecContext;
extern "C" {
#include <libavformat/avformat.h>
}
/**
* This class writes a sound file via ffmpeg.
*/
class AUD_FFMPEGWriter : public AUD_IWriter
{
private:
/**
* The current position in samples.
*/
int m_position;
/**
* The specification of the audio data.
*/
AUD_DeviceSpecs m_specs;
/**
* The AVFormatContext structure for using ffmpeg.
*/
AVFormatContext* m_formatCtx;
/**
* The AVCodecContext structure for using ffmpeg.
*/
AVCodecContext* m_codecCtx;
/**
* The AVOutputFormat structure for using ffmpeg.
*/
AVOutputFormat* m_outputFmt;
/**
* The AVStream structure for using ffmpeg.
*/
AVStream* m_stream;
/**
* The input buffer for the format converted data before encoding.
*/
AUD_Buffer m_input_buffer;
/**
* The output buffer for the encoded audio data.
*/
AUD_Buffer m_output_buffer;
/**
* The count of input samples we have so far.
*/
unsigned int m_input_samples;
/**
* The count of input samples necessary to encode a packet.
*/
unsigned int m_input_size;
/**
* Converter function.
*/
AUD_convert_f m_convert;
// hide copy constructor and operator=
AUD_FFMPEGWriter(const AUD_FFMPEGWriter&);
AUD_FFMPEGWriter& operator=(const AUD_FFMPEGWriter&);
/**
* Encodes to the output buffer.
* \param data Pointer to the data to encode.
*/
void encode(sample_t* data);
public:
/**
* Creates a new writer.
* \param filename The path to the file to be read.
* \param specs The file's audio specification.
* \param format The file's container format.
* \param codec The codec used for encoding the audio data.
* \param bitrate The bitrate for encoding.
* \exception AUD_Exception Thrown if the file specified does not exist or
* cannot be read with ffmpeg.
*/
AUD_FFMPEGWriter(std::string filename, AUD_DeviceSpecs specs, AUD_Container format, AUD_Codec codec, unsigned int bitrate);
/**
* Destroys the writer and closes the file.
*/
virtual ~AUD_FFMPEGWriter();
virtual int getPosition() const;
virtual AUD_DeviceSpecs getSpecs() const;
virtual void write(unsigned int length, sample_t* buffer);
};
#endif //AUD_FFMPEGWRITER

@ -71,8 +71,7 @@ void AUD_BandPassReader::read(int & length, sample_t* & buffer)
if(length > 0) if(length > 0)
{ {
if(length * AUD_SAMPLE_SIZE(specs) > m_buffer->getSize()) m_buffer->assureSize(length * AUD_SAMPLE_SIZE(specs));
m_buffer->resize(length * AUD_SAMPLE_SIZE(specs));
if(length != m_length) if(length != m_length)
{ {

@ -32,9 +32,188 @@
#ifndef AUD_3DMATH #ifndef AUD_3DMATH
#define AUD_3DMATH #define AUD_3DMATH
#include <cmath>
#include <cstring>
/**
* This class represents a 3 dimensional vector.
*/
class AUD_Vector3
{
private:
/**
* The vector components.
*/
union
{
float m_v[3];
struct
{
float m_x;
float m_y;
float m_z;
};
};
public:
/**
* Creates a new 3 dimensional vector.
* \param x The x component.
* \param y The y component.
* \param z The z component.
*/
inline AUD_Vector3(float x = 0, float y = 0, float z = 0) :
m_x(x), m_y(y), m_z(z)
{
}
/**
* Retrieves the x component of the vector.
* \return The x component.
*/
inline const float& x() const
{
return m_x;
}
/**
* Retrieves the y component of the vector.
* \return The y component.
*/
inline const float& y() const
{
return m_y;
}
/**
* Retrieves the z component of the vector.
* \return The z component.
*/
inline const float& z() const
{
return m_z;
}
/**
* Retrieves the components of the vector.
* \param destination Where the 3 float values should be saved to.
*/
inline void get(float* destination) const
{
memcpy(destination, m_v, sizeof(m_v));
}
/**
* Retrieves the components of the vector.
* \return The components as float[3].
*/
inline float* get()
{
return m_v;
}
/**
* Retrieves the components of the vector.
* \return The components as float[3].
*/
inline const float* get() const
{
return m_v;
}
/**
* Retrieves the length of the vector.
* \return The length of the vector.
*/
inline float length() const
{
return sqrt(m_x*m_x + m_y*m_y + m_z*m_z);
}
/**
* Retrieves the cross product.
* \param op The second operand.
* \return The cross product of the two vectors.
*/
inline AUD_Vector3 cross(const AUD_Vector3& op) const
{
return AUD_Vector3(m_y * op.m_z - m_z * op.m_y,
m_z * op.m_x - m_x * op.m_z,
m_x * op.m_y - m_y * op.m_x);
}
/**
* Retrieves the dot product.
* \param op The second operand.
* \return The dot product of the two vectors.
*/
inline float operator*(const AUD_Vector3& op) const
{
return m_x * op.m_x + m_y * op.m_y + m_z * op.m_z;
}
/**
* Retrieves the product with a scalar.
* \param op The second operand.
* \return The scaled vector.
*/
inline AUD_Vector3 operator*(const float& op) const
{
return AUD_Vector3(m_x * op, m_y * op, m_z * op);
}
/**
* Adds two vectors.
* \param op The second operand.
* \return The sum vector.
*/
inline AUD_Vector3 operator+(const AUD_Vector3& op) const
{
return AUD_Vector3(m_x + op.m_x, m_y + op.m_y, m_z + op.m_z);
}
/**
* Subtracts two vectors.
* \param op The second operand.
* \return The difference vector.
*/
inline AUD_Vector3 operator-(const AUD_Vector3& op) const
{
return AUD_Vector3(m_x - op.m_x, m_y - op.m_y, m_z - op.m_z);
}
/**
* Negates the vector.
* \return The vector facing in the opposite direction.
*/
inline AUD_Vector3 operator-() const
{
return AUD_Vector3(-m_x, -m_y, -m_z);
}
/**
* Subtracts the second vector.
* \param op The second operand.
* \return The difference vector.
*/
inline AUD_Vector3& operator-=(const AUD_Vector3& op)
{
m_x -= op.m_x;
m_y -= op.m_y;
m_z -= op.m_z;
return *this;
}
};
/**
* This class represents a quaternion used for 3D rotations.
*/
class AUD_Quaternion class AUD_Quaternion
{ {
private: private:
/**
* The quaternion components.
*/
union union
{ {
float m_v[4]; float m_v[4];
@ -55,7 +234,7 @@ public:
* \param y The y component. * \param y The y component.
* \param z The z component. * \param z The z component.
*/ */
inline AUD_Quaternion(float w, float x, float y, float z) : inline AUD_Quaternion(float w = 1, float x = 0, float y = 0, float z = 0) :
m_w(w), m_x(x), m_y(y), m_z(z) m_w(w), m_x(x), m_y(y), m_z(z)
{ {
} }
@ -102,10 +281,16 @@ public:
*/ */
inline void get(float* destination) const inline void get(float* destination) const
{ {
destination[0] = m_w; memcpy(destination, m_v, sizeof(m_v));
destination[1] = m_x; }
destination[2] = m_y;
destination[3] = m_z; /**
* Retrieves the components of the vector.
* \return The components as float[4].
*/
inline float* get()
{
return m_v;
} }
/** /**
@ -116,79 +301,29 @@ public:
{ {
return m_v; return m_v;
} }
};
class AUD_Vector3
{
private:
union
{
float m_v[3];
struct
{
float m_x;
float m_y;
float m_z;
};
};
public:
/** /**
* Creates a new 3 dimensional vector. * When the quaternion represents an orientation, this returns the negative
* \param x The x component. * z axis vector.
* \param y The y component. * \return The negative z axis vector.
* \param z The z component.
*/ */
inline AUD_Vector3(float x, float y, float z) : inline AUD_Vector3 getLookAt() const
m_x(x), m_y(y), m_z(z)
{ {
return AUD_Vector3(-2 * (m_w * m_y + m_x * m_z),
2 * (m_x * m_w - m_z * m_y),
2 * (m_x * m_x + m_y * m_y) - 1);
} }
/** /**
* Retrieves the x component of the vector. * When the quaternion represents an orientation, this returns the y axis
* \return The x component. * vector.
* \return The y axis vector.
*/ */
inline const float& x() const inline AUD_Vector3 getUp() const
{ {
return m_x; return AUD_Vector3(2 * (m_x * m_y - m_w * m_z),
} 1 - 2 * (m_x * m_x + m_z * m_z),
2 * (m_w * m_x + m_y * m_z));
/**
* Retrieves the y component of the vector.
* \return The y component.
*/
inline const float& y() const
{
return m_y;
}
/**
* Retrieves the z component of the vector.
* \return The z component.
*/
inline const float& z() const
{
return m_z;
}
/**
* Retrieves the components of the vector.
* \param destination Where the 3 float values should be saved to.
*/
inline void get(float* destination) const
{
destination[0] = m_x;
destination[1] = m_y;
destination[2] = m_z;
}
/**
* Retrieves the components of the vector.
* \return The components as float[3].
*/
inline const float* get() const
{
return m_v;
} }
}; };

@ -0,0 +1,159 @@
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* Copyright 2009-2011 Jörg Hermann Müller
*
* This file is part of AudaSpace.
*
* Audaspace 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 2 of the License, or
* (at your option) any later version.
*
* AudaSpace 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 Audaspace; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file audaspace/intern/AUD_AnimateableProperty.cpp
* \ingroup audaspaceintern
*/
#include "AUD_AnimateableProperty.h"
#include <cstring>
#include <cmath>
AUD_AnimateableProperty::AUD_AnimateableProperty(int count) :
AUD_Buffer(count * sizeof(float)), m_count(count), m_isAnimated(false)
{
memset(getBuffer(), 0, count * sizeof(float));
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&m_mutex, &attr);
pthread_mutexattr_destroy(&attr);
}
AUD_AnimateableProperty::~AUD_AnimateableProperty()
{
pthread_mutex_destroy(&m_mutex);
}
void AUD_AnimateableProperty::lock()
{
pthread_mutex_lock(&m_mutex);
}
void AUD_AnimateableProperty::unlock()
{
pthread_mutex_unlock(&m_mutex);
}
void AUD_AnimateableProperty::write(const float* data)
{
lock();
m_isAnimated = false;
memcpy(getBuffer(), data, m_count * sizeof(float));
unlock();
}
void AUD_AnimateableProperty::write(const float* data, int position, int count)
{
lock();
m_isAnimated = true;
int pos = getSize() / (sizeof(float) * m_count);
assureSize((count + position) * m_count * sizeof(float), true);
float* buf = getBuffer();
memcpy(buf + position * m_count, data, count * m_count * sizeof(float));
for(int i = pos; i < position; i++)
memcpy(buf + i * m_count, buf + (pos - 1) * m_count, m_count * sizeof(float));
unlock();
}
void AUD_AnimateableProperty::read(float position, float* out)
{
lock();
if(!m_isAnimated)
{
memcpy(out, getBuffer(), m_count * sizeof(float));
unlock();
return;
}
int last = getSize() / (sizeof(float) * m_count) - 1;
float t = position - floor(position);
if(position >= last)
{
position = last;
t = 0;
}
if(t == 0)
{
memcpy(out, getBuffer() + int(floor(position)) * m_count, m_count * sizeof(float));
}
else
{
int pos = int(floor(position)) * m_count;
float t2 = t * t;
float t3 = t2 * t;
float m0, m1;
float* p0;
float* p1 = getBuffer() + pos;
float* p2;
float* p3;
last *= m_count;
if(pos == 0)
p0 = p1;
else
p0 = p1 - m_count;
p2 = p1 + m_count;
if(pos + m_count == last)
p3 = p2;
else
p3 = p2 + m_count;
for(int i = 0; i < m_count; i++)
{
m0 = (p2[i] - p0[i]) / 2.0f;
m1 = (p3[i] - p1[i]) / 2.0f;
out[i] = (2 * t3 - 3 * t2 + 1) * p0[i] + (-2 * t3 + 3 * t2) * p1[i] +
(t3 - 2 * t2 + t) * m0 + (t3 - t2) * m1;
}
}
unlock();
}
bool AUD_AnimateableProperty::isAnimated() const
{
return m_isAnimated;
}

@ -0,0 +1,108 @@
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* Copyright 2009-2011 Jörg Hermann Müller
*
* This file is part of AudaSpace.
*
* Audaspace 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 2 of the License, or
* (at your option) any later version.
*
* AudaSpace 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 Audaspace; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file audaspace/intern/AUD_AnimateableProperty.h
* \ingroup audaspaceintern
*/
#ifndef AUD_ANIMATEABLEPROPERTY
#define AUD_ANIMATEABLEPROPERTY
#include "AUD_Buffer.h"
#include <pthread.h>
/**
* This class saves animation data for float properties.
*/
class AUD_AnimateableProperty : private AUD_Buffer
{
private:
/// The count of floats for a single property.
const int m_count;
/// Whether the property is animated or not.
bool m_isAnimated;
/// The mutex for locking.
pthread_mutex_t m_mutex;
// hide copy constructor and operator=
AUD_AnimateableProperty(const AUD_AnimateableProperty&);
AUD_AnimateableProperty& operator=(const AUD_AnimateableProperty&);
public:
/**
* Creates a new animateable property.
* \param count The count of floats for a single property.
*/
AUD_AnimateableProperty(int count = 1);
/**
* Destroys the animateable property.
*/
~AUD_AnimateableProperty();
/**
* Locks the property.
*/
void lock();
/**
* Unlocks the previously locked property.
*/
void unlock();
/**
* Writes the properties value and marks it non-animated.
* \param data The new value.
*/
void write(const float* data);
/**
* Writes the properties value and marks it animated.
* \param data The new value.
* \param position The position in the animation in frames.
* \param count The count of frames to write.
*/
void write(const float* data, int position, int count);
/**
* Reads the properties value.
* \param position The position in the animation in frames.
* \param[out] out Where to write the value to.
*/
void read(float position, float* out);
/**
* Returns whether the property is animated.
* \return Whether the property is animated.
*/
bool isAnimated() const;
};
#endif //AUD_ANIMATEABLEPROPERTY

@ -74,3 +74,9 @@ void AUD_Buffer::resize(int size, bool keep)
m_size = size; m_size = size;
} }
void AUD_Buffer::assureSize(int size, bool keep)
{
if(m_size < size)
resize(size, keep);
}

@ -80,6 +80,16 @@ public:
* the data at the end will be lost. * the data at the end will be lost.
*/ */
void resize(int size, bool keep = false); void resize(int size, bool keep = false);
/**
* Makes sure the buffer has a minimum size.
* If size is >= current size, nothing will happen.
* Otherwise the buffer is resized with keep as parameter.
* \param size The new minimum size of the buffer, measured in bytes.
* \param keep Whether to keep the old data. If the new buffer is smaller,
* the data at the end will be lost.
*/
void assureSize(int size, bool keep = false);
}; };
#endif //AUD_BUFFER #endif //AUD_BUFFER

@ -33,6 +33,8 @@
#include "AUD_Buffer.h" #include "AUD_Buffer.h"
#include "AUD_Space.h" #include "AUD_Space.h"
#include <cstring>
AUD_BufferReader::AUD_BufferReader(AUD_Reference<AUD_Buffer> buffer, AUD_BufferReader::AUD_BufferReader(AUD_Reference<AUD_Buffer> buffer,
AUD_Specs specs) : AUD_Specs specs) :
m_position(0), m_buffer(buffer), m_specs(specs) m_position(0), m_buffer(buffer), m_specs(specs)
@ -51,7 +53,7 @@ void AUD_BufferReader::seek(int position)
int AUD_BufferReader::getLength() const int AUD_BufferReader::getLength() const
{ {
return m_buffer.get()->getSize() / AUD_SAMPLE_SIZE(m_specs); return m_buffer->getSize() / AUD_SAMPLE_SIZE(m_specs);
} }
int AUD_BufferReader::getPosition() const int AUD_BufferReader::getPosition() const
@ -64,17 +66,27 @@ AUD_Specs AUD_BufferReader::getSpecs() const
return m_specs; return m_specs;
} }
void AUD_BufferReader::read(int & length, sample_t* & buffer) void AUD_BufferReader::read(int& length, bool& eos, sample_t* buffer)
{ {
eos = false;
int sample_size = AUD_SAMPLE_SIZE(m_specs); int sample_size = AUD_SAMPLE_SIZE(m_specs);
buffer = m_buffer.get()->getBuffer() + m_position * m_specs.channels; sample_t* buf = m_buffer->getBuffer() + m_position * m_specs.channels;
// in case the end of the buffer is reached // in case the end of the buffer is reached
if(m_buffer.get()->getSize() < (m_position + length) * sample_size) if(m_buffer->getSize() < (m_position + length) * sample_size)
length = m_buffer.get()->getSize() / sample_size - m_position; {
length = m_buffer->getSize() / sample_size - m_position;
eos = true;
}
if(length < 0) if(length < 0)
{
length = 0; length = 0;
return;
}
m_position += length; m_position += length;
memcpy(buffer, buf, length * sample_size);
} }

@ -76,7 +76,7 @@ public:
virtual int getLength() const; virtual int getLength() const;
virtual int getPosition() const; virtual int getPosition() const;
virtual AUD_Specs getSpecs() const; virtual AUD_Specs getSpecs() const;
virtual void read(int & length, sample_t* & buffer); virtual void read(int& length, bool& eos, sample_t* buffer);
}; };
#endif //AUD_BUFFERREADER #endif //AUD_BUFFERREADER

File diff suppressed because it is too large Load Diff

@ -31,12 +31,17 @@
#ifndef AUD_CAPI #ifndef AUD_CAPI
#define AUD_CAPI #define AUD_CAPI
#ifdef WITH_PYTHON
#include "Python.h"
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#include "AUD_Space.h" #include "AUD_Space.h"
/// Supported output devices.
typedef enum typedef enum
{ {
AUD_NULL_DEVICE = 0, AUD_NULL_DEVICE = 0,
@ -45,6 +50,7 @@ typedef enum
AUD_JACK_DEVICE AUD_JACK_DEVICE
} AUD_DeviceType; } AUD_DeviceType;
/// Sound information structure.
typedef struct typedef struct
{ {
AUD_Specs specs; AUD_Specs specs;
@ -53,9 +59,9 @@ typedef struct
#ifndef AUD_CAPI_IMPLEMENTATION #ifndef AUD_CAPI_IMPLEMENTATION
typedef void AUD_Sound; typedef void AUD_Sound;
typedef void AUD_Channel; typedef void AUD_Handle;
typedef void AUD_Device; typedef void AUD_Device;
typedef void AUD_SequencerEntry; typedef void AUD_SEntry;
typedef float (*AUD_volumeFunction)(void*, void*, float); typedef float (*AUD_volumeFunction)(void*, void*, float);
typedef void (*AUD_syncFunction)(void*, int, float); typedef void (*AUD_syncFunction)(void*, int, float);
#endif #endif
@ -118,6 +124,13 @@ extern AUD_Sound* AUD_loadBuffer(unsigned char* buffer, int size);
*/ */
extern AUD_Sound* AUD_bufferSound(AUD_Sound* sound); extern AUD_Sound* AUD_bufferSound(AUD_Sound* sound);
/**
* Rechannels the sound to be mono.
* \param sound The sound to rechannel.
* \return The mono sound.
*/
extern AUD_Sound* AUD_monoSound(AUD_Sound* sound);
/** /**
* Delays a sound. * Delays a sound.
* \param sound The sound to dealy. * \param sound The sound to dealy.
@ -155,7 +168,7 @@ extern AUD_Sound* AUD_loopSound(AUD_Sound* sound);
* \param loops The count of remaining loops, -1 for infinity. * \param loops The count of remaining loops, -1 for infinity.
* \return Whether the handle is valid. * \return Whether the handle is valid.
*/ */
extern int AUD_setLoop(AUD_Channel* handle, int loops); extern int AUD_setLoop(AUD_Handle* handle, int loops);
/** /**
* Rectifies a sound. * Rectifies a sound.
@ -177,28 +190,28 @@ extern void AUD_unload(AUD_Sound* sound);
* paused when its end has been reached. * paused when its end has been reached.
* \return A handle to the played back sound. * \return A handle to the played back sound.
*/ */
extern AUD_Channel* AUD_play(AUD_Sound* sound, int keep); extern AUD_Handle* AUD_play(AUD_Sound* sound, int keep);
/** /**
* Pauses a played back sound. * Pauses a played back sound.
* \param handle The handle to the sound. * \param handle The handle to the sound.
* \return Whether the handle has been playing or not. * \return Whether the handle has been playing or not.
*/ */
extern int AUD_pause(AUD_Channel* handle); extern int AUD_pause(AUD_Handle* handle);
/** /**
* Resumes a paused sound. * Resumes a paused sound.
* \param handle The handle to the sound. * \param handle The handle to the sound.
* \return Whether the handle has been paused or not. * \return Whether the handle has been paused or not.
*/ */
extern int AUD_resume(AUD_Channel* handle); extern int AUD_resume(AUD_Handle* handle);
/** /**
* Stops a playing or paused sound. * Stops a playing or paused sound.
* \param handle The handle to the sound. * \param handle The handle to the sound.
* \return Whether the handle has been valid or not. * \return Whether the handle has been valid or not.
*/ */
extern int AUD_stop(AUD_Channel* handle); extern int AUD_stop(AUD_Handle* handle);
/** /**
* Sets the end behaviour of a playing or paused sound. * Sets the end behaviour of a playing or paused sound.
@ -207,7 +220,7 @@ extern int AUD_stop(AUD_Channel* handle);
* paused when its end has been reached. * paused when its end has been reached.
* \return Whether the handle has been valid or not. * \return Whether the handle has been valid or not.
*/ */
extern int AUD_setKeep(AUD_Channel* handle, int keep); extern int AUD_setKeep(AUD_Handle* handle, int keep);
/** /**
* Seeks a playing or paused sound. * Seeks a playing or paused sound.
@ -215,7 +228,7 @@ extern int AUD_setKeep(AUD_Channel* handle, int keep);
* \param seekTo From where the sound file should be played back in seconds. * \param seekTo From where the sound file should be played back in seconds.
* \return Whether the handle has been valid or not. * \return Whether the handle has been valid or not.
*/ */
extern int AUD_seek(AUD_Channel* handle, float seekTo); extern int AUD_seek(AUD_Handle* handle, float seekTo);
/** /**
* Retrieves the playback position of a handle. * Retrieves the playback position of a handle.
@ -223,14 +236,14 @@ extern int AUD_seek(AUD_Channel* handle, float seekTo);
* \return The current playback position in seconds or 0.0 if the handle is * \return The current playback position in seconds or 0.0 if the handle is
* invalid. * invalid.
*/ */
extern float AUD_getPosition(AUD_Channel* handle); extern float AUD_getPosition(AUD_Handle* handle);
/** /**
* Returns the status of a playing, paused or stopped sound. * Returns the status of a playing, paused or stopped sound.
* \param handle The handle to the sound. * \param handle The handle to the sound.
* \return The status of the sound behind the handle. * \return The status of the sound behind the handle.
*/ */
extern AUD_Status AUD_getStatus(AUD_Channel* handle); extern AUD_Status AUD_getStatus(AUD_Handle* handle);
/** /**
* Sets the listener location. * Sets the listener location.
@ -277,7 +290,7 @@ extern int AUD_setDistanceModel(AUD_DistanceModel model);
* \param location The new location. * \param location The new location.
* \return Whether the action succeeded. * \return Whether the action succeeded.
*/ */
extern int AUD_setSourceLocation(AUD_Channel* handle, const float* location); extern int AUD_setSourceLocation(AUD_Handle* handle, const float* location);
/** /**
* Sets the velocity of a source. * Sets the velocity of a source.
@ -285,7 +298,7 @@ extern int AUD_setSourceLocation(AUD_Channel* handle, const float* location);
* \param velocity The new velocity. * \param velocity The new velocity.
* \return Whether the action succeeded. * \return Whether the action succeeded.
*/ */
extern int AUD_setSourceVelocity(AUD_Channel* handle, const float* velocity); extern int AUD_setSourceVelocity(AUD_Handle* handle, const float* velocity);
/** /**
* Sets the orientation of a source. * Sets the orientation of a source.
@ -293,7 +306,7 @@ extern int AUD_setSourceVelocity(AUD_Channel* handle, const float* velocity);
* \param orientation The new orientation as quaternion. * \param orientation The new orientation as quaternion.
* \return Whether the action succeeded. * \return Whether the action succeeded.
*/ */
extern int AUD_setSourceOrientation(AUD_Channel* handle, const float* orientation); extern int AUD_setSourceOrientation(AUD_Handle* handle, const float* orientation);
/** /**
* Sets whether the source location, velocity and orientation are relative * Sets whether the source location, velocity and orientation are relative
@ -302,7 +315,7 @@ extern int AUD_setSourceOrientation(AUD_Channel* handle, const float* orientatio
* \param relative Whether the source is relative. * \param relative Whether the source is relative.
* \return Whether the action succeeded. * \return Whether the action succeeded.
*/ */
extern int AUD_setRelative(AUD_Channel* handle, int relative); extern int AUD_setRelative(AUD_Handle* handle, int relative);
/** /**
* Sets the maximum volume of a source. * Sets the maximum volume of a source.
@ -310,7 +323,7 @@ extern int AUD_setRelative(AUD_Channel* handle, int relative);
* \param volume The new maximum volume. * \param volume The new maximum volume.
* \return Whether the action succeeded. * \return Whether the action succeeded.
*/ */
extern int AUD_setVolumeMaximum(AUD_Channel* handle, float volume); extern int AUD_setVolumeMaximum(AUD_Handle* handle, float volume);
/** /**
* Sets the minimum volume of a source. * Sets the minimum volume of a source.
@ -318,7 +331,7 @@ extern int AUD_setVolumeMaximum(AUD_Channel* handle, float volume);
* \param volume The new minimum volume. * \param volume The new minimum volume.
* \return Whether the action succeeded. * \return Whether the action succeeded.
*/ */
extern int AUD_setVolumeMinimum(AUD_Channel* handle, float volume); extern int AUD_setVolumeMinimum(AUD_Handle* handle, float volume);
/** /**
* Sets the maximum distance of a source. * Sets the maximum distance of a source.
@ -328,7 +341,7 @@ extern int AUD_setVolumeMinimum(AUD_Channel* handle, float volume);
* \param distance The new maximum distance. * \param distance The new maximum distance.
* \return Whether the action succeeded. * \return Whether the action succeeded.
*/ */
extern int AUD_setDistanceMaximum(AUD_Channel* handle, float distance); extern int AUD_setDistanceMaximum(AUD_Handle* handle, float distance);
/** /**
* Sets the reference distance of a source. * Sets the reference distance of a source.
@ -336,7 +349,7 @@ extern int AUD_setDistanceMaximum(AUD_Channel* handle, float distance);
* \param distance The new reference distance. * \param distance The new reference distance.
* \return Whether the action succeeded. * \return Whether the action succeeded.
*/ */
extern int AUD_setDistanceReference(AUD_Channel* handle, float distance); extern int AUD_setDistanceReference(AUD_Handle* handle, float distance);
/** /**
* Sets the attenuation of a source. * Sets the attenuation of a source.
@ -345,7 +358,7 @@ extern int AUD_setDistanceReference(AUD_Channel* handle, float distance);
* \param factor The new attenuation. * \param factor The new attenuation.
* \return Whether the action succeeded. * \return Whether the action succeeded.
*/ */
extern int AUD_setAttenuation(AUD_Channel* handle, float factor); extern int AUD_setAttenuation(AUD_Handle* handle, float factor);
/** /**
* Sets the outer angle of the cone of a source. * Sets the outer angle of the cone of a source.
@ -353,7 +366,7 @@ extern int AUD_setAttenuation(AUD_Channel* handle, float factor);
* \param angle The new outer angle of the cone. * \param angle The new outer angle of the cone.
* \return Whether the action succeeded. * \return Whether the action succeeded.
*/ */
extern int AUD_setConeAngleOuter(AUD_Channel* handle, float angle); extern int AUD_setConeAngleOuter(AUD_Handle* handle, float angle);
/** /**
* Sets the inner angle of the cone of a source. * Sets the inner angle of the cone of a source.
@ -361,7 +374,7 @@ extern int AUD_setConeAngleOuter(AUD_Channel* handle, float angle);
* \param angle The new inner angle of the cone. * \param angle The new inner angle of the cone.
* \return Whether the action succeeded. * \return Whether the action succeeded.
*/ */
extern int AUD_setConeAngleInner(AUD_Channel* handle, float angle); extern int AUD_setConeAngleInner(AUD_Handle* handle, float angle);
/** /**
* Sets the outer volume of the cone of a source. * Sets the outer volume of the cone of a source.
@ -371,7 +384,7 @@ extern int AUD_setConeAngleInner(AUD_Channel* handle, float angle);
* \param volume The new outer volume of the cone. * \param volume The new outer volume of the cone.
* \return Whether the action succeeded. * \return Whether the action succeeded.
*/ */
extern int AUD_setConeVolumeOuter(AUD_Channel* handle, float volume); extern int AUD_setConeVolumeOuter(AUD_Handle* handle, float volume);
/** /**
* Sets the volume of a played back sound. * Sets the volume of a played back sound.
@ -379,7 +392,7 @@ extern int AUD_setConeVolumeOuter(AUD_Channel* handle, float volume);
* \param volume The new volume, must be between 0.0 and 1.0. * \param volume The new volume, must be between 0.0 and 1.0.
* \return Whether the action succeeded. * \return Whether the action succeeded.
*/ */
extern int AUD_setSoundVolume(AUD_Channel* handle, float volume); extern int AUD_setSoundVolume(AUD_Handle* handle, float volume);
/** /**
* Sets the pitch of a played back sound. * Sets the pitch of a played back sound.
@ -387,7 +400,7 @@ extern int AUD_setSoundVolume(AUD_Channel* handle, float volume);
* \param pitch The new pitch. * \param pitch The new pitch.
* \return Whether the action succeeded. * \return Whether the action succeeded.
*/ */
extern int AUD_setSoundPitch(AUD_Channel* handle, float pitch); extern int AUD_setSoundPitch(AUD_Handle* handle, float pitch);
/** /**
* Opens a read device, with which audio data can be read. * Opens a read device, with which audio data can be read.
@ -411,18 +424,7 @@ extern int AUD_setDeviceVolume(AUD_Device* device, float volume);
* \param seek The position where the sound should be seeked to. * \param seek The position where the sound should be seeked to.
* \return A handle to the played back sound. * \return A handle to the played back sound.
*/ */
extern AUD_Channel* AUD_playDevice(AUD_Device* device, AUD_Sound* sound, float seek); extern AUD_Handle* AUD_playDevice(AUD_Device* device, AUD_Sound* sound, float seek);
/**
* Sets the volume of a played back sound of a read device.
* \param device The read device.
* \param handle The handle to the sound.
* \param volume The new volume, must be between 0.0 and 1.0.
* \return Whether the action succeeded.
*/
extern int AUD_setDeviceSoundVolume(AUD_Device* device,
AUD_Channel* handle,
float volume);
/** /**
* Reads the next samples into the supplied buffer. * Reads the next samples into the supplied buffer.
@ -448,7 +450,7 @@ extern void AUD_closeReadDevice(AUD_Device* device);
extern float* AUD_readSoundBuffer(const char* filename, float low, float high, extern float* AUD_readSoundBuffer(const char* filename, float low, float high,
float attack, float release, float threshold, float attack, float release, float threshold,
int accumulate, int additive, int square, int accumulate, int additive, int square,
float sthreshold, int samplerate, float sthreshold, double samplerate,
int* length); int* length);
/** /**
@ -457,43 +459,302 @@ extern float* AUD_readSoundBuffer(const char* filename, float low, float high,
* \param time The time in seconds. * \param time The time in seconds.
* \return The silence handle. * \return The silence handle.
*/ */
extern AUD_Channel* AUD_pauseAfter(AUD_Channel* handle, float seconds); extern AUD_Handle* AUD_pauseAfter(AUD_Handle* handle, float seconds);
extern AUD_Sound* AUD_createSequencer(int muted, void* data, AUD_volumeFunction volume); /**
* Creates a new sequenced sound scene.
* \param fps The FPS of the scene.
* \param muted Whether the scene is muted.
* \return The new sound scene.
*/
extern AUD_Sound* AUD_createSequencer(float fps, int muted);
/**
* Deletes a sound scene.
* \param sequencer The sound scene.
*/
extern void AUD_destroySequencer(AUD_Sound* sequencer); extern void AUD_destroySequencer(AUD_Sound* sequencer);
/**
* Sets the muting state of the scene.
* \param sequencer The sound scene.
* \param muted Whether the scene is muted.
*/
extern void AUD_setSequencerMuted(AUD_Sound* sequencer, int muted); extern void AUD_setSequencerMuted(AUD_Sound* sequencer, int muted);
extern AUD_SequencerEntry* AUD_addSequencer(AUD_Sound** sequencer, AUD_Sound* sound, /**
float begin, float end, float skip, void* data); * Sets the scene's FPS.
* \param sequencer The sound scene.
* \param fps The new FPS.
*/
extern void AUD_setSequencerFPS(AUD_Sound* sequencer, float fps);
extern void AUD_removeSequencer(AUD_Sound* sequencer, AUD_SequencerEntry* entry); /**
* Adds a new entry to the scene.
extern void AUD_moveSequencer(AUD_Sound* sequencer, AUD_SequencerEntry* entry, * \param sequencer The sound scene.
* \param sound The sound this entry should play.
* \param begin The start time.
* \param end The end time or a negative value if determined by the sound.
* \param skip How much seconds should be skipped at the beginning.
* \return The entry added.
*/
extern AUD_SEntry* AUD_addSequence(AUD_Sound* sequencer, AUD_Sound* sound,
float begin, float end, float skip); float begin, float end, float skip);
extern void AUD_muteSequencer(AUD_Sound* sequencer, AUD_SequencerEntry* entry, /**
char mute); * Removes an entry from the scene.
* \param sequencer The sound scene.
* \param entry The entry to remove.
*/
extern void AUD_removeSequence(AUD_Sound* sequencer, AUD_SEntry* entry);
extern int AUD_readSound(AUD_Sound* sound, sample_t* buffer, int length); /**
* Moves the entry.
* \param entry The sequenced entry.
* \param begin The new start time.
* \param end The new end time or a negative value if unknown.
* \param skip How many seconds to skip at the beginning.
*/
extern void AUD_moveSequence(AUD_SEntry* entry, float begin, float end, float skip);
/**
* Sets the muting state of the entry.
* \param entry The sequenced entry.
* \param mute Whether the entry should be muted or not.
*/
extern void AUD_muteSequence(AUD_SEntry* entry, char mute);
/**
* Sets whether the entrie's location, velocity and orientation are relative
* to the listener.
* \param entry The sequenced entry.
* \param relative Whether the source is relative.
* \return Whether the action succeeded.
*/
extern void AUD_setRelativeSequence(AUD_SEntry* entry, char relative);
/**
* Sets the sound of the entry.
* \param entry The sequenced entry.
* \param sound The new sound.
*/
extern void AUD_updateSequenceSound(AUD_SEntry* entry, AUD_Sound* sound);
/**
* Writes animation data to a sequenced entry.
* \param entry The sequenced entry.
* \param type The type of animation data.
* \param frame The frame this data is for.
* \param data The data to write.
* \param animated Whether the attribute is animated.
*/
extern void AUD_setSequenceAnimData(AUD_SEntry* entry, AUD_AnimateablePropertyType type, int frame, float* data, char animated);
/**
* Writes animation data to a sequenced entry.
* \param sequencer The sound scene.
* \param type The type of animation data.
* \param frame The frame this data is for.
* \param data The data to write.
* \param animated Whether the attribute is animated.
*/
extern void AUD_setSequencerAnimData(AUD_Sound* sequencer, AUD_AnimateablePropertyType type, int frame, float* data, char animated);
/**
* Updates all non-animated parameters of the entry.
* \param entry The sequenced entry.
* \param volume_max The maximum volume.
* \param volume_min The minimum volume.
* \param distance_max The maximum distance.
* \param distance_reference The reference distance.
* \param attenuation The attenuation.
* \param cone_angle_outer The outer cone opening angle.
* \param cone_angle_inner The inner cone opening angle.
* \param cone_volume_outer The volume outside the outer cone.
*/
extern void AUD_updateSequenceData(AUD_SEntry* entry, float volume_max, float volume_min,
float distance_max, float distance_reference, float attenuation,
float cone_angle_outer, float cone_angle_inner, float cone_volume_outer);
/**
* Updates all non-animated parameters of the entry.
* \param sequencer The sound scene.
* \param speed_of_sound The speed of sound for doppler calculation.
* \param factor The doppler factor to control the effect's strength.
* \param model The distance model for distance calculation.
*/
extern void AUD_updateSequencerData(AUD_Sound* sequencer, float speed_of_sound,
float factor, AUD_DistanceModel model);
/**
* Sets the audio output specification of the sound scene to the specs of the
* current playback device.
* \param sequencer The sound scene.
*/
extern void AUD_setSequencerDeviceSpecs(AUD_Sound* sequencer);
/**
* Sets the audio output specification of the sound scene.
* \param sequencer The sound scene.
* \param specs The new specification.
*/
extern void AUD_setSequencerSpecs(AUD_Sound* sequencer, AUD_Specs specs);
/**
* Seeks sequenced sound scene playback.
* \param handle Playback handle.
* \param time Time in seconds to seek to.
*/
extern void AUD_seekSequencer(AUD_Handle* handle, float time);
/**
* Returns the current sound scene playback time.
* \param handle Playback handle.
* \return The playback time in seconds.
*/
extern float AUD_getSequencerPosition(AUD_Handle* handle);
/**
* Starts the playback of jack transport if possible.
*/
extern void AUD_startPlayback(void); extern void AUD_startPlayback(void);
/**
* Stops the playback of jack transport if possible.
*/
extern void AUD_stopPlayback(void); extern void AUD_stopPlayback(void);
extern void AUD_seekSequencer(AUD_Channel* handle, float time);
extern float AUD_getSequencerPosition(AUD_Channel* handle);
#ifdef WITH_JACK #ifdef WITH_JACK
/**
* Sets the sync callback for jack transport.
* \param function The callback function.
* \param data The data parameter for the callback.
*/
extern void AUD_setSyncCallback(AUD_syncFunction function, void* data); extern void AUD_setSyncCallback(AUD_syncFunction function, void* data);
#endif #endif
/**
* Returns whether jack transport is currently playing.
* \return Whether jack transport is currently playing.
*/
extern int AUD_doesPlayback(void); extern int AUD_doesPlayback(void);
/**
* Reads a sound into a buffer for drawing at a specific sampling rate.
* \param sound The sound to read.
* \param buffer The buffer to write to. Must have a size of 3*4*length.
* \param length How many samples to read from the sound.
* \param samples_per_second How many samples to read per second of the sound.
* \return How many samples really have been read. Always <= length.
*/
extern int AUD_readSound(AUD_Sound* sound, sample_t* buffer, int length, int samples_per_second);
/**
* Copies a sound.
* \param sound Sound to copy.
* \return Copied sound.
*/
extern AUD_Sound* AUD_copy(AUD_Sound* sound);
/**
* Frees a handle.
* \param channel Handle to free.
*/
extern void AUD_freeHandle(AUD_Handle* channel);
/**
* Creates a new set.
* \return The new set.
*/
extern void* AUD_createSet(void);
/**
* Deletes a set.
* \param set The set to delete.
*/
extern void AUD_destroySet(void* set);
/**
* Removes an entry from a set.
* \param set The set work on.
* \param entry The entry to remove.
* \return Whether the entry was in the set or not.
*/
extern char AUD_removeSet(void* set, void* entry);
/**
* Adds a new entry to a set.
* \param set The set work on.
* \param entry The entry to add.
*/
extern void AUD_addSet(void* set, void* entry);
/**
* Removes one entry from a set and returns it.
* \param set The set work on.
* \return The entry or NULL if the set is empty.
*/
extern void* AUD_getSet(void* set);
/**
* Mixes a sound down into a file.
* \param sound The sound scene to mix down.
* \param start The start frame.
* \param length The count of frames to write.
* \param buffersize How many samples should be written at once.
* \param filename The file to write to.
* \param specs The file's audio specification.
* \param format The file's container format.
* \param codec The codec used for encoding the audio data.
* \param bitrate The bitrate for encoding.
* \return An error message or NULL in case of success.
*/
extern const char* AUD_mixdown(AUD_Sound* sound, unsigned int start, unsigned int length, unsigned int buffersize, const char* filename, AUD_DeviceSpecs specs, AUD_Container format, AUD_Codec codec, unsigned int bitrate);
/**
* Opens a read device and prepares it for mixdown of the sound scene.
* \param specs Output audio specifications.
* \param sequencer The sound scene to mix down.
* \param volume The overall mixdown volume.
* \param start The start time of the mixdown in the sound scene.
* \return The read device for the mixdown.
*/
extern AUD_Device* AUD_openMixdownDevice(AUD_DeviceSpecs specs, AUD_Sound* sequencer, float volume, float start);
#ifdef WITH_PYTHON
/**
* Retrieves the python factory of a sound.
* \param sound The sound factory.
* \return The python factory.
*/
extern PyObject* AUD_getPythonFactory(AUD_Sound* sound);
/**
* Retrieves the sound factory of a python factory.
* \param sound The python factory.
* \return The sound factory.
*/
extern AUD_Sound* AUD_getPythonSound(PyObject* sound);
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#include "AUD_Reference.h"
class AUD_IDevice;
class AUD_I3DDevice;
/**
* Returns the current playback device.
* \return The playback device.
*/
AUD_Reference<AUD_IDevice> AUD_getDevice();
/**
* Returns the current playback 3D device.
* \return The playback 3D device.
*/
AUD_I3DDevice* AUD_get3DDevice();
#endif #endif
#endif //AUD_CAPI #endif //AUD_CAPI

@ -34,79 +34,14 @@
#include <cstring> #include <cstring>
AUD_ChannelMapperFactory::AUD_ChannelMapperFactory(AUD_IFactory* factory, AUD_ChannelMapperFactory::AUD_ChannelMapperFactory(AUD_Reference<AUD_IFactory> factory,
AUD_DeviceSpecs specs) : AUD_DeviceSpecs specs) :
AUD_MixerFactory(factory, specs) AUD_MixerFactory(factory, specs)
{ {
memset(m_mapping, 0, sizeof(m_mapping));
} }
AUD_ChannelMapperFactory::~AUD_ChannelMapperFactory() AUD_Reference<AUD_IReader> AUD_ChannelMapperFactory::createReader()
{ {
for(int i = 1; i < 10; i++) AUD_Reference<AUD_IReader> reader = getReader();
deleteMapping(i); return new AUD_ChannelMapperReader(reader, m_specs.channels);
}
float** AUD_ChannelMapperFactory::getMapping(int ic)
{
ic--;
if(ic > 8 || ic < 0)
return 0;
if(m_mapping[ic])
{
int channels = -1;
while(m_mapping[ic][++channels] != 0);
if(channels != m_specs.channels)
deleteMapping(ic+1);
}
if(!m_mapping[ic])
{
int channels = m_specs.channels;
m_mapping[ic] = new float*[channels+1];
m_mapping[ic][channels] = 0;
for(int i = 0; i < channels; i++)
{
m_mapping[ic][i] = new float[ic+1];
for(int j = 0; j <= ic; j++)
m_mapping[ic][i][j] = ((i == j) || (channels == 1) ||
(ic == 0)) ? 1.0f : 0.0f;
}
}
return m_mapping[ic];
}
void AUD_ChannelMapperFactory::deleteMapping(int ic)
{
ic--;
if(ic > 8 || ic < 0)
return;
if(m_mapping[ic])
{
for(int i = 0; 1; i++)
{
if(m_mapping[ic][i] != 0)
{
delete[] m_mapping[ic][i];
}
else
break;
}
delete[] m_mapping[ic];
m_mapping[ic] = 0;
}
}
AUD_IReader* AUD_ChannelMapperFactory::createReader() const
{
AUD_IReader* reader = getReader();
int ic = reader->getSpecs().channels;
return new AUD_ChannelMapperReader(reader,
const_cast<AUD_ChannelMapperFactory*>(this)->getMapping(ic));
} }

@ -41,33 +41,19 @@
class AUD_ChannelMapperFactory : public AUD_MixerFactory class AUD_ChannelMapperFactory : public AUD_MixerFactory
{ {
private: private:
/**
* The mapping specification.
*/
float **m_mapping[9];
// hide copy constructor and operator= // hide copy constructor and operator=
AUD_ChannelMapperFactory(const AUD_ChannelMapperFactory&); AUD_ChannelMapperFactory(const AUD_ChannelMapperFactory&);
AUD_ChannelMapperFactory& operator=(const AUD_ChannelMapperFactory&); AUD_ChannelMapperFactory& operator=(const AUD_ChannelMapperFactory&);
public: public:
AUD_ChannelMapperFactory(AUD_IFactory* factory, AUD_DeviceSpecs specs);
virtual ~AUD_ChannelMapperFactory();
/** /**
* Returns the mapping array for editing. * Creates a new factory.
* \param ic The count of input channels the array should have. * \param factory The input factory.
* \note The count of output channels is read of the desired output specs. * \param specs The target specifications.
*/ */
float** getMapping(int ic); AUD_ChannelMapperFactory(AUD_Reference<AUD_IFactory> factory, AUD_DeviceSpecs specs);
/** virtual AUD_Reference<AUD_IReader> createReader();
* Deletes the current channel mapping.
*/
void deleteMapping(int ic);
virtual AUD_IReader* createReader() const;
}; };
#endif //AUD_CHANNELMAPPERFACTORY #endif //AUD_CHANNELMAPPERFACTORY

@ -28,74 +28,343 @@
* \ingroup audaspaceintern * \ingroup audaspaceintern
*/ */
#include <cmath>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#ifndef M_PI_2
#define M_PI_2 1.57079632679489661923
#endif
#include "AUD_ChannelMapperReader.h" #include "AUD_ChannelMapperReader.h"
AUD_ChannelMapperReader::AUD_ChannelMapperReader(AUD_IReader* reader, AUD_ChannelMapperReader::AUD_ChannelMapperReader(AUD_Reference<AUD_IReader> reader,
float **mapping) : AUD_Channels channels) :
AUD_EffectReader(reader) AUD_EffectReader(reader), m_target_channels(channels),
m_source_channels(AUD_CHANNELS_INVALID), m_mapping(0), m_map_size(0), m_mono_angle(0)
{ {
m_specs = reader->getSpecs();
int channels = -1;
m_rch = m_specs.channels;
while(mapping[++channels] != 0);
m_mapping = new float*[channels];
m_specs.channels = (AUD_Channels)channels;
float sum;
int i;
while(channels--)
{
m_mapping[channels] = new float[m_rch];
sum = 0.0f;
for(i=0; i < m_rch; i++)
sum += mapping[channels][i];
for(i=0; i < m_rch; i++)
m_mapping[channels][i] = sum > 0.0f ?
mapping[channels][i]/sum : 0.0f;
}
} }
AUD_ChannelMapperReader::~AUD_ChannelMapperReader() AUD_ChannelMapperReader::~AUD_ChannelMapperReader()
{ {
int channels = m_specs.channels; delete[] m_mapping;
}
while(channels--) void AUD_ChannelMapperReader::setChannels(AUD_Channels channels)
{
m_target_channels = channels;
calculateMapping();
}
void AUD_ChannelMapperReader::setMonoAngle(float angle)
{
if(angle != angle)
angle = 0;
m_mono_angle = angle;
if(m_source_channels == AUD_CHANNELS_MONO)
calculateMapping();
}
float AUD_ChannelMapperReader::angleDistance(float alpha, float beta)
{
alpha = fabs(alpha - beta);
if(alpha > M_PI)
alpha = fabs(alpha - 2 * M_PI);
return alpha;
}
void AUD_ChannelMapperReader::calculateMapping()
{
if(m_map_size < m_source_channels * m_target_channels)
{ {
delete[] m_mapping[channels]; delete[] m_mapping;
m_mapping = new float[m_source_channels * m_target_channels];
m_map_size = m_source_channels * m_target_channels;
} }
delete[] m_mapping; for(int i = 0; i < m_source_channels * m_target_channels; i++)
m_mapping[i] = 0;
const AUD_Channel* source_channels = CHANNEL_MAPS[m_source_channels - 1];
const AUD_Channel* target_channels = CHANNEL_MAPS[m_target_channels - 1];
int lfe = -1;
for(int i = 0; i < m_target_channels; i++)
{
if(target_channels[i] == AUD_CHANNEL_LFE)
{
lfe = i;
break;
}
}
const float* source_angles = CHANNEL_ANGLES[m_source_channels - 1];
const float* target_angles = CHANNEL_ANGLES[m_target_channels - 1];
if(m_source_channels == AUD_CHANNELS_MONO)
source_angles = &m_mono_angle;
int channel_min1, channel_min2;
float angle_min1, angle_min2, angle;
for(int i = 0; i < m_source_channels; i++)
{
if(source_channels[i] == AUD_CHANNEL_LFE)
{
if(lfe != -1)
m_mapping[lfe * m_source_channels + i] = 1;
continue;
}
channel_min1 = channel_min2 = -1;
angle_min1 = angle_min2 = 2 * M_PI;
for(int j = 0; j < m_target_channels; j++)
{
if(j == lfe)
continue;
angle = angleDistance(source_angles[i], target_angles[j]);
if(angle < angle_min1)
{
channel_min2 = channel_min1;
angle_min2 = angle_min1;
channel_min1 = j;
angle_min1 = angle;
}
else if(angle < angle_min2)
{
channel_min2 = j;
angle_min2 = angle;
}
}
angle = angle_min1 + angle_min2;
if(channel_min2 == -1 || angle == 0)
{
m_mapping[channel_min1 * m_source_channels + i] = 1;
}
else
{
m_mapping[channel_min1 * m_source_channels + i] = cos(M_PI_2 * angle_min1 / angle);
m_mapping[channel_min2 * m_source_channels + i] = cos(M_PI_2 * angle_min2 / angle);
}
}
/* AUD_XXX for(int i = 0; i < m_source_channels; i++)
{
for(int j = 0; j < m_target_channels; j++)
{
std::cout << m_mapping[i * m_source_channels + j] << " ";
}
std::cout << std::endl;
}*/
} }
AUD_Specs AUD_ChannelMapperReader::getSpecs() const AUD_Specs AUD_ChannelMapperReader::getSpecs() const
{ {
return m_specs; AUD_Specs specs = m_reader->getSpecs();
specs.channels = m_target_channels;
return specs;
} }
void AUD_ChannelMapperReader::read(int & length, sample_t* & buffer) void AUD_ChannelMapperReader::read(int& length, bool& eos, sample_t* buffer)
{ {
sample_t* in = buffer; AUD_Channels channels = m_reader->getSpecs().channels;
if(channels != m_source_channels)
{
m_source_channels = channels;
calculateMapping();
}
m_reader->read(length, in); if(m_source_channels == m_target_channels)
{
m_reader->read(length, eos, buffer);
return;
}
if(m_buffer.getSize() < length * AUD_SAMPLE_SIZE(m_specs)) m_buffer.assureSize(length * channels * sizeof(sample_t));
m_buffer.resize(length * AUD_SAMPLE_SIZE(m_specs));
sample_t* in = m_buffer.getBuffer();
m_reader->read(length, eos, in);
buffer = m_buffer.getBuffer();
sample_t sum; sample_t sum;
for(int i = 0; i < length; i++) for(int i = 0; i < length; i++)
{ {
for(int j = 0; j < m_specs.channels; j++) for(int j = 0; j < m_target_channels; j++)
{ {
sum = 0; sum = 0;
for(int k = 0; k < m_rch; k++) for(int k = 0; k < m_source_channels; k++)
sum += m_mapping[j][k] * in[i * m_rch + k]; sum += m_mapping[j * m_source_channels + k] * in[i * m_source_channels + k];
buffer[i * m_specs.channels + j] = sum; buffer[i * m_target_channels + j] = sum;
} }
} }
} }
const AUD_Channel AUD_ChannelMapperReader::MONO_MAP[] =
{
AUD_CHANNEL_FRONT_CENTER
};
const AUD_Channel AUD_ChannelMapperReader::STEREO_MAP[] =
{
AUD_CHANNEL_FRONT_LEFT,
AUD_CHANNEL_FRONT_RIGHT
};
const AUD_Channel AUD_ChannelMapperReader::STEREO_LFE_MAP[] =
{
AUD_CHANNEL_FRONT_LEFT,
AUD_CHANNEL_FRONT_RIGHT,
AUD_CHANNEL_LFE
};
const AUD_Channel AUD_ChannelMapperReader::SURROUND4_MAP[] =
{
AUD_CHANNEL_FRONT_LEFT,
AUD_CHANNEL_FRONT_RIGHT,
AUD_CHANNEL_REAR_LEFT,
AUD_CHANNEL_REAR_RIGHT
};
const AUD_Channel AUD_ChannelMapperReader::SURROUND5_MAP[] =
{
AUD_CHANNEL_FRONT_LEFT,
AUD_CHANNEL_FRONT_RIGHT,
AUD_CHANNEL_FRONT_CENTER,
AUD_CHANNEL_REAR_LEFT,
AUD_CHANNEL_REAR_RIGHT
};
const AUD_Channel AUD_ChannelMapperReader::SURROUND51_MAP[] =
{
AUD_CHANNEL_FRONT_LEFT,
AUD_CHANNEL_FRONT_RIGHT,
AUD_CHANNEL_FRONT_CENTER,
AUD_CHANNEL_LFE,
AUD_CHANNEL_REAR_LEFT,
AUD_CHANNEL_REAR_RIGHT
};
const AUD_Channel AUD_ChannelMapperReader::SURROUND61_MAP[] =
{
AUD_CHANNEL_FRONT_LEFT,
AUD_CHANNEL_FRONT_RIGHT,
AUD_CHANNEL_FRONT_CENTER,
AUD_CHANNEL_LFE,
AUD_CHANNEL_REAR_CENTER,
AUD_CHANNEL_REAR_LEFT,
AUD_CHANNEL_REAR_RIGHT
};
const AUD_Channel AUD_ChannelMapperReader::SURROUND71_MAP[] =
{
AUD_CHANNEL_FRONT_LEFT,
AUD_CHANNEL_FRONT_RIGHT,
AUD_CHANNEL_FRONT_CENTER,
AUD_CHANNEL_LFE,
AUD_CHANNEL_REAR_LEFT,
AUD_CHANNEL_REAR_RIGHT,
AUD_CHANNEL_SIDE_LEFT,
AUD_CHANNEL_SIDE_RIGHT
};
const AUD_Channel* AUD_ChannelMapperReader::CHANNEL_MAPS[] =
{
AUD_ChannelMapperReader::MONO_MAP,
AUD_ChannelMapperReader::STEREO_MAP,
AUD_ChannelMapperReader::STEREO_LFE_MAP,
AUD_ChannelMapperReader::SURROUND4_MAP,
AUD_ChannelMapperReader::SURROUND5_MAP,
AUD_ChannelMapperReader::SURROUND51_MAP,
AUD_ChannelMapperReader::SURROUND61_MAP,
AUD_ChannelMapperReader::SURROUND71_MAP
};
const float AUD_ChannelMapperReader::MONO_ANGLES[] =
{
0.0f * M_PI / 180.0f
};
const float AUD_ChannelMapperReader::STEREO_ANGLES[] =
{
-90.0f * M_PI / 180.0f,
90.0f * M_PI / 180.0f
};
const float AUD_ChannelMapperReader::STEREO_LFE_ANGLES[] =
{
-90.0f * M_PI / 180.0f,
90.0f * M_PI / 180.0f,
0.0f * M_PI / 180.0f
};
const float AUD_ChannelMapperReader::SURROUND4_ANGLES[] =
{
-45.0f * M_PI / 180.0f,
45.0f * M_PI / 180.0f,
-135.0f * M_PI / 180.0f,
135.0f * M_PI / 180.0f
};
const float AUD_ChannelMapperReader::SURROUND5_ANGLES[] =
{
-30.0f * M_PI / 180.0f,
30.0f * M_PI / 180.0f,
0.0f * M_PI / 180.0f,
-110.0f * M_PI / 180.0f,
110.0f * M_PI / 180.0f
};
const float AUD_ChannelMapperReader::SURROUND51_ANGLES[] =
{
-30.0f * M_PI / 180.0f,
30.0f * M_PI / 180.0f,
0.0f * M_PI / 180.0f,
0.0f * M_PI / 180.0f,
-110.0f * M_PI / 180.0f,
110.0f * M_PI / 180.0f
};
const float AUD_ChannelMapperReader::SURROUND61_ANGLES[] =
{
-30.0f * M_PI / 180.0f,
30.0f * M_PI / 180.0f,
0.0f * M_PI / 180.0f,
0.0f * M_PI / 180.0f,
180.0f * M_PI / 180.0f,
-110.0f * M_PI / 180.0f,
110.0f * M_PI / 180.0f
};
const float AUD_ChannelMapperReader::SURROUND71_ANGLES[] =
{
-30.0f * M_PI / 180.0f,
30.0f * M_PI / 180.0f,
0.0f * M_PI / 180.0f,
0.0f * M_PI / 180.0f,
-110.0f * M_PI / 180.0f,
110.0f * M_PI / 180.0f
-150.0f * M_PI / 180.0f,
150.0f * M_PI / 180.0f
};
const float* AUD_ChannelMapperReader::CHANNEL_ANGLES[] =
{
AUD_ChannelMapperReader::MONO_ANGLES,
AUD_ChannelMapperReader::STEREO_ANGLES,
AUD_ChannelMapperReader::STEREO_LFE_ANGLES,
AUD_ChannelMapperReader::SURROUND4_ANGLES,
AUD_ChannelMapperReader::SURROUND5_ANGLES,
AUD_ChannelMapperReader::SURROUND51_ANGLES,
AUD_ChannelMapperReader::SURROUND61_ANGLES,
AUD_ChannelMapperReader::SURROUND71_ANGLES
};

@ -43,44 +43,96 @@ class AUD_ChannelMapperReader : public AUD_EffectReader
{ {
private: private:
/** /**
* The sound output buffer. * The sound reading buffer.
*/ */
AUD_Buffer m_buffer; AUD_Buffer m_buffer;
/** /**
* The output specification. * The output specification.
*/ */
AUD_Specs m_specs; AUD_Channels m_target_channels;
/** /**
* The channel count of the reader. * The channel count of the reader.
*/ */
int m_rch; AUD_Channels m_source_channels;
/** /**
* The mapping specification. * The mapping specification.
*/ */
float **m_mapping; float* m_mapping;
/**
* The size of the mapping.
*/
int m_map_size;
/**
* The mono source angle.
*/
float m_mono_angle;
static const AUD_Channel MONO_MAP[];
static const AUD_Channel STEREO_MAP[];
static const AUD_Channel STEREO_LFE_MAP[];
static const AUD_Channel SURROUND4_MAP[];
static const AUD_Channel SURROUND5_MAP[];
static const AUD_Channel SURROUND51_MAP[];
static const AUD_Channel SURROUND61_MAP[];
static const AUD_Channel SURROUND71_MAP[];
static const AUD_Channel* CHANNEL_MAPS[];
static const float MONO_ANGLES[];
static const float STEREO_ANGLES[];
static const float STEREO_LFE_ANGLES[];
static const float SURROUND4_ANGLES[];
static const float SURROUND5_ANGLES[];
static const float SURROUND51_ANGLES[];
static const float SURROUND61_ANGLES[];
static const float SURROUND71_ANGLES[];
static const float* CHANNEL_ANGLES[];
// hide copy constructor and operator= // hide copy constructor and operator=
AUD_ChannelMapperReader(const AUD_ChannelMapperReader&); AUD_ChannelMapperReader(const AUD_ChannelMapperReader&);
AUD_ChannelMapperReader& operator=(const AUD_ChannelMapperReader&); AUD_ChannelMapperReader& operator=(const AUD_ChannelMapperReader&);
/**
* Calculates the mapping matrix.
*/
void calculateMapping();
/**
* Calculates the distance between two angles.
*/
float angleDistance(float alpha, float beta);
public: public:
/** /**
* Creates a channel mapper reader. * Creates a channel mapper reader.
* \param reader The reader to map. * \param reader The reader to map.
* \param mapping The mapping specification as two dimensional float array. * \param mapping The mapping specification as two dimensional float array.
*/ */
AUD_ChannelMapperReader(AUD_IReader* reader, float **mapping); AUD_ChannelMapperReader(AUD_Reference<AUD_IReader> reader, AUD_Channels channels);
/** /**
* Destroys the reader. * Destroys the reader.
*/ */
~AUD_ChannelMapperReader(); ~AUD_ChannelMapperReader();
/**
* Sets the requested channel output count.
* \param channels The channel output count.
*/
void setChannels(AUD_Channels channels);
/**
* Sets the angle for mono sources.
* \param angle The angle for mono sources.
*/
void setMonoAngle(float angle);
virtual AUD_Specs getSpecs() const; virtual AUD_Specs getSpecs() const;
virtual void read(int & length, sample_t* & buffer); virtual void read(int& length, bool& eos, sample_t* buffer);
}; };
#endif //AUD_CHANNELMAPPERREADER #endif //AUD_CHANNELMAPPERREADER

@ -32,15 +32,15 @@
#include "AUD_ConverterFactory.h" #include "AUD_ConverterFactory.h"
#include "AUD_ConverterReader.h" #include "AUD_ConverterReader.h"
AUD_ConverterFactory::AUD_ConverterFactory(AUD_IFactory* factory, AUD_ConverterFactory::AUD_ConverterFactory(AUD_Reference<AUD_IFactory> factory,
AUD_DeviceSpecs specs) : AUD_DeviceSpecs specs) :
AUD_MixerFactory(factory, specs) AUD_MixerFactory(factory, specs)
{ {
} }
AUD_IReader* AUD_ConverterFactory::createReader() const AUD_Reference<AUD_IReader> AUD_ConverterFactory::createReader()
{ {
AUD_IReader* reader = getReader(); AUD_Reference<AUD_IReader> reader = getReader();
if(m_specs.format != AUD_FORMAT_FLOAT32) if(m_specs.format != AUD_FORMAT_FLOAT32)
reader = new AUD_ConverterReader(reader, m_specs); reader = new AUD_ConverterReader(reader, m_specs);

@ -46,9 +46,14 @@ private:
AUD_ConverterFactory& operator=(const AUD_ConverterFactory&); AUD_ConverterFactory& operator=(const AUD_ConverterFactory&);
public: public:
AUD_ConverterFactory(AUD_IFactory* factory, AUD_DeviceSpecs specs); /**
* Creates a new factory.
* \param factory The input factory.
* \param specs The target specifications.
*/
AUD_ConverterFactory(AUD_Reference<AUD_IFactory> factory, AUD_DeviceSpecs specs);
virtual AUD_IReader* createReader() const; virtual AUD_Reference<AUD_IReader> createReader();
}; };
#endif //AUD_CONVERTERFACTORY #endif //AUD_CONVERTERFACTORY

Some files were not shown because too many files have changed in this diff Show More