Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Tönne <lukas.toenne@gmail.com>2017-08-19 14:02:03 +0300
committerLukas Tönne <lukas.toenne@gmail.com>2017-08-19 14:02:03 +0300
commit45f0f3dc0457a53a25103784f0e0d100c7a17cbe (patch)
tree94767d8e4fa6ea23f2bbd2274f239ecbbdc5931a /extern/audaspace/src/fx
parent0d67f8d5c46fcc97cbb0544ef7d8c3c0056025c4 (diff)
parent9a262ed47ecb1c9f43053b0653364c59d9595fdf (diff)
Merge branch 'blender2.8' into strand_editmode
Diffstat (limited to 'extern/audaspace/src/fx')
-rw-r--r--extern/audaspace/src/fx/ADSR.cpp73
-rw-r--r--extern/audaspace/src/fx/ADSRReader.cpp115
-rw-r--r--extern/audaspace/src/fx/Accumulator.cpp54
-rw-r--r--extern/audaspace/src/fx/BaseIIRFilterReader.cpp125
-rw-r--r--extern/audaspace/src/fx/BinauralReader.cpp255
-rw-r--r--extern/audaspace/src/fx/BinauralSound.cpp60
-rw-r--r--extern/audaspace/src/fx/Butterworth.cpp28
-rw-r--r--extern/audaspace/src/fx/ButterworthCalculator.cpp54
-rw-r--r--extern/audaspace/src/fx/CallbackIIRFilterReader.cpp38
-rw-r--r--extern/audaspace/src/fx/Convolver.cpp156
-rw-r--r--extern/audaspace/src/fx/ConvolverReader.cpp203
-rw-r--r--extern/audaspace/src/fx/ConvolverSound.cpp50
-rw-r--r--extern/audaspace/src/fx/Delay.cpp38
-rw-r--r--extern/audaspace/src/fx/DelayReader.cpp87
-rw-r--r--extern/audaspace/src/fx/DynamicIIRFilter.cpp35
-rw-r--r--extern/audaspace/src/fx/DynamicIIRFilterReader.cpp36
-rw-r--r--extern/audaspace/src/fx/DynamicMusic.cpp346
-rw-r--r--extern/audaspace/src/fx/Effect.cpp35
-rw-r--r--extern/audaspace/src/fx/EffectReader.cpp60
-rw-r--r--extern/audaspace/src/fx/Envelope.cpp71
-rw-r--r--extern/audaspace/src/fx/FFTConvolver.cpp214
-rw-r--r--extern/audaspace/src/fx/Fader.cpp49
-rw-r--r--extern/audaspace/src/fx/FaderReader.cpp76
-rw-r--r--extern/audaspace/src/fx/HRTF.cpp122
-rw-r--r--extern/audaspace/src/fx/HRTFLoaderUnix.cpp89
-rw-r--r--extern/audaspace/src/fx/HRTFLoaderWindows.cpp93
-rw-r--r--extern/audaspace/src/fx/Highpass.cpp28
-rw-r--r--extern/audaspace/src/fx/HighpassCalculator.cpp43
-rw-r--r--extern/audaspace/src/fx/IIRFilter.cpp32
-rw-r--r--extern/audaspace/src/fx/IIRFilterReader.cpp53
-rw-r--r--extern/audaspace/src/fx/ImpulseResponse.cpp97
-rw-r--r--extern/audaspace/src/fx/Limiter.cpp45
-rw-r--r--extern/audaspace/src/fx/LimiterReader.cpp139
-rw-r--r--extern/audaspace/src/fx/Loop.cpp38
-rw-r--r--extern/audaspace/src/fx/LoopReader.cpp91
-rw-r--r--extern/audaspace/src/fx/Lowpass.cpp27
-rw-r--r--extern/audaspace/src/fx/LowpassCalculator.cpp43
-rw-r--r--extern/audaspace/src/fx/MutableReader.cpp64
-rw-r--r--extern/audaspace/src/fx/MutableSound.cpp35
-rw-r--r--extern/audaspace/src/fx/Pitch.cpp33
-rw-r--r--extern/audaspace/src/fx/PitchReader.cpp44
-rw-r--r--extern/audaspace/src/fx/PlaybackCategory.cpp144
-rw-r--r--extern/audaspace/src/fx/PlaybackManager.cpp186
-rw-r--r--extern/audaspace/src/fx/Reverse.cpp32
-rw-r--r--extern/audaspace/src/fx/ReverseReader.cpp88
-rw-r--r--extern/audaspace/src/fx/SoundList.cpp84
-rw-r--r--extern/audaspace/src/fx/Source.cpp71
-rw-r--r--extern/audaspace/src/fx/Sum.cpp36
-rw-r--r--extern/audaspace/src/fx/Threshold.cpp54
-rw-r--r--extern/audaspace/src/fx/Volume.cpp41
-rw-r--r--extern/audaspace/src/fx/VolumeReader.cpp60
-rw-r--r--extern/audaspace/src/fx/VolumeSound.cpp45
-rw-r--r--extern/audaspace/src/fx/VolumeStorage.cpp39
53 files changed, 4254 insertions, 0 deletions
diff --git a/extern/audaspace/src/fx/ADSR.cpp b/extern/audaspace/src/fx/ADSR.cpp
new file mode 100644
index 00000000000..f147affda72
--- /dev/null
+++ b/extern/audaspace/src/fx/ADSR.cpp
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/ADSR.h"
+#include "fx/ADSRReader.h"
+
+AUD_NAMESPACE_BEGIN
+
+ADSR::ADSR(std::shared_ptr<ISound> sound, float attack, float decay, float sustain, float release) :
+ Effect(sound),
+ m_attack(attack), m_decay(decay), m_sustain(sustain), m_release(release)
+{
+}
+
+float ADSR::getAttack() const
+{
+ return m_attack;
+}
+
+void ADSR::setAttack(float attack)
+{
+ m_attack = attack;
+}
+
+float ADSR::getDecay() const
+{
+ return m_decay;
+}
+
+void ADSR::setDecay(float decay)
+{
+ m_decay = decay;
+}
+
+float ADSR::getSustain() const
+{
+ return m_sustain;
+}
+
+void ADSR::setSustain(float sustain)
+{
+ m_sustain = sustain;
+}
+
+float ADSR::getRelease() const
+{
+ return m_release;
+}
+
+void ADSR::setRelease(float release)
+{
+ m_release = release;
+}
+
+std::shared_ptr<IReader> ADSR::createReader()
+{
+ return std::shared_ptr<IReader>(new ADSRReader(getReader(), m_attack, m_decay, m_sustain, m_release));
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/ADSRReader.cpp b/extern/audaspace/src/fx/ADSRReader.cpp
new file mode 100644
index 00000000000..6499b55468e
--- /dev/null
+++ b/extern/audaspace/src/fx/ADSRReader.cpp
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/ADSRReader.h"
+
+AUD_NAMESPACE_BEGIN
+
+ADSRReader::ADSRReader(std::shared_ptr<IReader> reader, float attack, float decay, float sustain, float release) :
+ EffectReader(reader),
+ m_attack(attack), m_decay(decay), m_sustain(sustain), m_release(release)
+{
+ nextState(ADSR_STATE_ATTACK);
+}
+
+ADSRReader::~ADSRReader()
+{
+}
+
+void ADSRReader::nextState(ADSRState state)
+{
+ m_state = state;
+
+ switch(m_state)
+ {
+ case ADSR_STATE_ATTACK:
+ m_level = 0;
+ if(m_attack <= 0)
+ {
+ nextState(ADSR_STATE_DECAY);
+ return;
+ }
+ return;
+ case ADSR_STATE_DECAY:
+ if(m_decay <= 0)
+ {
+ nextState(ADSR_STATE_SUSTAIN);
+ return;
+ }
+ if(m_level > 1.0)
+ m_level = 1 - (m_level - 1) * m_attack / m_decay * (1 - m_sustain);
+ if(m_level <= m_sustain)
+ nextState(ADSR_STATE_SUSTAIN);
+ break;
+ case ADSR_STATE_SUSTAIN:
+ m_level = m_sustain;
+ break;
+ case ADSR_STATE_RELEASE:
+ if(m_release <= 0)
+ {
+ nextState(ADSR_STATE_INVALID);
+ return;
+ }
+ break;
+ case ADSR_STATE_INVALID:
+ break;
+ }
+}
+
+void ADSRReader::read(int & length, bool &eos, sample_t* buffer)
+{
+ Specs specs = m_reader->getSpecs();
+ m_reader->read(length, eos, buffer);
+
+ for(int i = 0; i < length; i++)
+ {
+ for(int channel = 0; channel < specs.channels; channel++)
+ {
+ buffer[i * specs.channels + channel] *= m_level;
+ }
+
+ switch(m_state)
+ {
+ case ADSR_STATE_ATTACK:
+ m_level += 1 / m_attack / specs.rate;
+ if(m_level >= 1)
+ nextState(ADSR_STATE_DECAY);
+ break;
+ case ADSR_STATE_DECAY:
+ m_level -= (1 - m_sustain) / m_decay / specs.rate;
+ if(m_level <= m_sustain)
+ nextState(ADSR_STATE_SUSTAIN);
+ break;
+ case ADSR_STATE_SUSTAIN:
+ break;
+ case ADSR_STATE_RELEASE:
+ m_level -= m_sustain / m_release / specs.rate ;
+ if(m_level <= 0)
+ nextState(ADSR_STATE_INVALID);
+ break;
+ case ADSR_STATE_INVALID:
+ length = i;
+ return;
+ }
+ }
+}
+
+void ADSRReader::release()
+{
+ nextState(ADSR_STATE_RELEASE);
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/Accumulator.cpp b/extern/audaspace/src/fx/Accumulator.cpp
new file mode 100644
index 00000000000..ba8e6a2841e
--- /dev/null
+++ b/extern/audaspace/src/fx/Accumulator.cpp
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/Accumulator.h"
+#include "fx/CallbackIIRFilterReader.h"
+
+AUD_NAMESPACE_BEGIN
+
+sample_t Accumulator::accumulatorFilterAdditive(CallbackIIRFilterReader* reader, void* useless)
+{
+ float in = reader->x(0);
+ float lastin = reader->x(-1);
+ float out = reader->y(-1) + in - lastin;
+ if(in > lastin)
+ out += in - lastin;
+ return out;
+}
+
+sample_t Accumulator::accumulatorFilter(CallbackIIRFilterReader* reader, void* useless)
+{
+ float in = reader->x(0);
+ float lastin = reader->x(-1);
+ float out = reader->y(-1);
+ if(in > lastin)
+ out += in - lastin;
+ return out;
+}
+
+Accumulator::Accumulator(std::shared_ptr<ISound> sound,
+ bool additive) :
+ Effect(sound),
+ m_additive(additive)
+{
+}
+
+std::shared_ptr<IReader> Accumulator::createReader()
+{
+ return std::shared_ptr<IReader>(new CallbackIIRFilterReader(getReader(), 2, 2, m_additive ? accumulatorFilterAdditive : accumulatorFilter));
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/BaseIIRFilterReader.cpp b/extern/audaspace/src/fx/BaseIIRFilterReader.cpp
new file mode 100644
index 00000000000..6505e5ea600
--- /dev/null
+++ b/extern/audaspace/src/fx/BaseIIRFilterReader.cpp
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/BaseIIRFilterReader.h"
+
+#include <cstring>
+
+AUD_NAMESPACE_BEGIN
+
+BaseIIRFilterReader::BaseIIRFilterReader(std::shared_ptr<IReader> reader, int in, int out) :
+ EffectReader(reader),
+ m_specs(reader->getSpecs()),
+ m_xlen(in), m_ylen(out),
+ m_xpos(0), m_ypos(0), m_channel(0)
+{
+ m_x = new sample_t[m_xlen * m_specs.channels];
+ m_y = new sample_t[m_ylen * m_specs.channels];
+
+ std::memset(m_x, 0, sizeof(sample_t) * m_xlen * m_specs.channels);
+ std::memset(m_y, 0, sizeof(sample_t) * m_ylen * m_specs.channels);
+}
+
+BaseIIRFilterReader::~BaseIIRFilterReader()
+{
+ delete[] m_x;
+ delete[] m_y;
+}
+
+void BaseIIRFilterReader::setLengths(int in, int out)
+{
+ if(in != m_xlen)
+ {
+ sample_t* xn = new sample_t[in * m_specs.channels];
+ std::memset(xn, 0, sizeof(sample_t) * in * m_specs.channels);
+
+ for(m_channel = 0; m_channel < m_specs.channels; m_channel++)
+ {
+ for(int i = 1; i <= in && i <= m_xlen; i++)
+ {
+ xn[(in - i) * m_specs.channels + m_channel] = x(-i);
+ }
+ }
+
+ delete[] m_x;
+ m_x = xn;
+ m_xpos = 0;
+ m_xlen = in;
+ }
+
+ if(out != m_ylen)
+ {
+ sample_t* yn = new sample_t[out * m_specs.channels];
+ std::memset(yn, 0, sizeof(sample_t) * out * m_specs.channels);
+
+ for(m_channel = 0; m_channel < m_specs.channels; m_channel++)
+ {
+ for(int i = 1; i <= out && i <= m_ylen; i++)
+ {
+ yn[(out - i) * m_specs.channels + m_channel] = y(-i);
+ }
+ }
+
+ delete[] m_y;
+ m_y = yn;
+ m_ypos = 0;
+ m_ylen = out;
+ }
+}
+
+void BaseIIRFilterReader::read(int& length, bool& eos, sample_t* buffer)
+{
+ 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];
+
+ std::memset(m_x, 0, sizeof(sample_t) * m_xlen * m_specs.channels);
+ std::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++)
+ {
+ m_x[m_xpos * m_specs.channels + m_channel] = buffer[i * m_specs.channels + m_channel];
+ m_y[m_ypos * m_specs.channels + m_channel] = buffer[i * m_specs.channels + m_channel] = filter();
+
+ m_xpos = m_xlen ? (m_xpos + 1) % m_xlen : 0;
+ m_ypos = m_ylen ? (m_ypos + 1) % m_ylen : 0;
+ }
+ }
+}
+
+void BaseIIRFilterReader::sampleRateChanged(SampleRate rate)
+{
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/BinauralReader.cpp b/extern/audaspace/src/fx/BinauralReader.cpp
new file mode 100644
index 00000000000..2792adada8a
--- /dev/null
+++ b/extern/audaspace/src/fx/BinauralReader.cpp
@@ -0,0 +1,255 @@
+/*******************************************************************************
+* Copyright 2015-2016 Juan Francisco Crespo Galán
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+******************************************************************************/
+
+#include "fx/BinauralReader.h"
+#include "Exception.h"
+
+#include <cstring>
+#include <cstdlib>
+#include <algorithm>
+
+#define NUM_OUTCHANNELS 2
+#define NUM_CONVOLVERS 4
+#define CROSSFADE_SAMPLES 1024
+
+AUD_NAMESPACE_BEGIN
+BinauralReader::BinauralReader(std::shared_ptr<IReader> reader, std::shared_ptr<HRTF> hrtfs, std::shared_ptr<Source> source, std::shared_ptr<ThreadPool> threadPool, std::shared_ptr<FFTPlan> plan) :
+ m_reader(reader), m_hrtfs(hrtfs), m_source(source), m_N(plan->getSize()), m_threadPool(threadPool), m_position(0), m_eosReader(false), m_eosTail(false), m_transition(false), m_transPos(CROSSFADE_SAMPLES*NUM_OUTCHANNELS)
+{
+ if(m_hrtfs->isEmpty())
+ AUD_THROW(StateException, "The provided HRTF object is empty");
+ if(m_reader->getSpecs().channels != 1)
+ AUD_THROW(StateException, "The sound must have only one channel");
+ if(m_reader->getSpecs().rate != m_hrtfs->getSpecs().rate)
+ AUD_THROW(StateException, "The sound and the HRTFs must have the same rate");
+ m_M = m_L = m_N / 2;
+
+ m_RealAzimuth = m_Azimuth = m_source->getAzimuth();
+ m_RealElevation = m_Elevation = m_source->getElevation();
+ auto irs = m_hrtfs->getImpulseResponse(m_RealAzimuth, m_RealElevation);
+ for(unsigned int i = 0; i < NUM_CONVOLVERS; i++)
+ if(i%NUM_OUTCHANNELS==0)
+ m_convolvers.push_back(std::unique_ptr<Convolver>(new Convolver(irs.first->getChannel(0), irs.first->getLength(), m_threadPool, plan)));
+ else
+ m_convolvers.push_back(std::unique_ptr<Convolver>(new Convolver(irs.second->getChannel(0), irs.second->getLength(), m_threadPool, plan)));
+ m_futures.resize(NUM_CONVOLVERS);
+
+ m_outBuffer = (sample_t*)std::malloc(m_L*NUM_OUTCHANNELS*sizeof(sample_t));
+ m_eOutBufLen = m_outBufLen = m_outBufferPos = m_L * NUM_OUTCHANNELS;
+ m_inBuffer = (sample_t*)std::malloc(m_L * sizeof(sample_t));
+ for(int i = 0; i < NUM_CONVOLVERS; i++)
+ m_vecOut.push_back((sample_t*)std::calloc(m_L, sizeof(sample_t)));
+}
+
+BinauralReader::~BinauralReader()
+{
+ std::free(m_outBuffer);
+ std::free(m_inBuffer);
+ for(int i = 0; i < m_vecOut.size(); i++)
+ std::free(m_vecOut[i]);
+}
+
+bool BinauralReader::isSeekable() const
+{
+ return m_reader->isSeekable();
+}
+
+void BinauralReader::seek(int position)
+{
+ m_position = position;
+ m_reader->seek(position);
+ for(int i = 0; i < NUM_CONVOLVERS; i++)
+ m_convolvers[i]->reset();
+ m_eosTail = false;
+ m_eosReader = false;
+ m_outBufferPos = m_eOutBufLen = m_outBufLen;
+ m_transition = false;
+ m_transPos = CROSSFADE_SAMPLES*NUM_OUTCHANNELS;
+}
+
+int BinauralReader::getLength() const
+{
+ return m_reader->getLength();
+}
+
+int BinauralReader::getPosition() const
+{
+ return m_position;
+}
+
+Specs BinauralReader::getSpecs() const
+{
+ Specs specs = m_reader->getSpecs();
+ specs.channels = CHANNELS_STEREO;
+ return specs;
+}
+
+void BinauralReader::read(int& length, bool& eos, sample_t* buffer)
+{
+ int samples = 0;
+ int iteration = 0;
+ if(length <= 0)
+ {
+ length = 0;
+ eos = (m_eosTail && m_outBufferPos >= m_eOutBufLen);
+ return;
+ }
+
+ eos = false;
+ int writePos = 0;
+ do
+ {
+ int bufRest = m_eOutBufLen - m_outBufferPos;
+ int writeLength = std::min((length*NUM_OUTCHANNELS) - writePos, m_eOutBufLen + bufRest);
+ if(bufRest < writeLength || (m_eOutBufLen == 0 && m_eosTail))
+ {
+ if(bufRest > 0)
+ std::memcpy(buffer + writePos, m_outBuffer + m_outBufferPos, bufRest*sizeof(sample_t));
+ if(!m_eosTail)
+ {
+ int n = NUM_OUTCHANNELS;
+ if(m_transition)
+ n = NUM_CONVOLVERS;
+ else if(checkSource())
+ n = NUM_CONVOLVERS;
+ loadBuffer(n);
+
+ int len = std::min(std::abs(writeLength - bufRest), m_eOutBufLen);
+ std::memcpy(buffer + writePos + bufRest, m_outBuffer, len*sizeof(sample_t));
+ samples += len;
+ m_outBufferPos = len;
+ writeLength = std::min((length*NUM_OUTCHANNELS) - writePos, m_eOutBufLen + bufRest);
+ }
+ else
+ {
+ m_outBufferPos += bufRest;
+ length = (writePos+bufRest) / NUM_OUTCHANNELS;
+ eos = true;
+ return;
+ }
+ }
+ else
+ {
+ std::memcpy(buffer + writePos, m_outBuffer + m_outBufferPos, writeLength*sizeof(sample_t));
+ m_outBufferPos += writeLength;
+ }
+ writePos += writeLength;
+ iteration++;
+ } while(writePos < length*NUM_OUTCHANNELS);
+ m_position += length;
+}
+
+bool BinauralReader::checkSource()
+{
+ if((m_Azimuth != m_source->getAzimuth() || m_Elevation != m_source->getElevation()) && (!m_eosReader && !m_eosTail))
+ {
+ float az = m_Azimuth = m_source->getAzimuth();
+ float el = m_Elevation = m_source->getElevation();
+ auto irs = m_hrtfs->getImpulseResponse(az, el);
+ if(az != m_RealAzimuth || el != m_RealElevation)
+ {
+ m_RealAzimuth = az;
+ m_RealElevation = el;
+ for(int i = 0; i < NUM_OUTCHANNELS; i++)
+ {
+ auto temp = std::move(m_convolvers[i]);
+ m_convolvers[i] = std::move(m_convolvers[i + NUM_OUTCHANNELS]);
+ m_convolvers[i + NUM_OUTCHANNELS] = std::move(temp);
+ }
+ for(int i = 0; i < NUM_OUTCHANNELS; i++)
+ if(i%NUM_OUTCHANNELS == 0)
+ m_convolvers[i]->setImpulseResponse(irs.first->getChannel(0));
+ else
+ m_convolvers[i]->setImpulseResponse(irs.second->getChannel(0));
+
+ m_transPos = CROSSFADE_SAMPLES*NUM_OUTCHANNELS;
+ m_transition = true;
+ return true;
+ }
+ }
+ return false;
+}
+
+void BinauralReader::loadBuffer(int nConvolvers)
+{
+ m_lastLengthIn = m_L;
+ m_reader->read(m_lastLengthIn, m_eosReader, m_inBuffer);
+ if(!m_eosReader || m_lastLengthIn > 0)
+ {
+ int len = m_lastLengthIn;
+ for(int i = 0; i < nConvolvers; i++)
+ m_futures[i] = m_threadPool->enqueue(&BinauralReader::threadFunction, this, i, true);
+ for(int i = 0; i < nConvolvers; i++)
+ len = m_futures[i].get();
+
+ joinByChannel(0, len, nConvolvers);
+ m_eOutBufLen = len*NUM_OUTCHANNELS;
+ }
+ else if(!m_eosTail)
+ {
+ int len = m_lastLengthIn = m_L;
+ for(int i = 0; i < nConvolvers; i++)
+ m_futures[i] = m_threadPool->enqueue(&BinauralReader::threadFunction, this, i, false);
+ for(int i = 0; i < nConvolvers; i++)
+ len = m_futures[i].get();
+
+ joinByChannel(0, len, nConvolvers);
+ m_eOutBufLen = len*NUM_OUTCHANNELS;
+ }
+}
+
+void BinauralReader::joinByChannel(int start, int len, int nConvolvers)
+{
+ int k = 0;
+ float vol = 0;
+ const int l = CROSSFADE_SAMPLES*NUM_OUTCHANNELS;
+ for(int i = 0; i < len*NUM_OUTCHANNELS; i += NUM_OUTCHANNELS)
+ {
+ if(m_transition)
+ {
+ vol = (m_transPos - i) / (float)l;
+ if(vol > 1.0f)
+ vol = 1.0f;
+ else if(vol < 0.0f)
+ vol = 0.0f;
+ }
+
+ for(int j = 0; j < NUM_OUTCHANNELS; j++)
+ m_outBuffer[i + j + start] = ((m_vecOut[j][k] * (1.0f - vol)) + (m_vecOut[j + NUM_OUTCHANNELS][k] * vol))*m_source->getVolume();
+ k++;
+ }
+ if(m_transition)
+ {
+ m_transPos -= len*NUM_OUTCHANNELS;
+ if(m_transPos <= 0)
+ {
+ m_transition = false;
+ m_transPos = l;
+ }
+ }
+}
+
+int BinauralReader::threadFunction(int id, bool input)
+{
+ int l = m_lastLengthIn;
+ if(input)
+ m_convolvers[id]->getNext(m_inBuffer, m_vecOut[id], l, m_eosTail);
+ else
+ m_convolvers[id]->getNext(nullptr, m_vecOut[id], l, m_eosTail);
+ return l;
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/BinauralSound.cpp b/extern/audaspace/src/fx/BinauralSound.cpp
new file mode 100644
index 00000000000..7b9508c9944
--- /dev/null
+++ b/extern/audaspace/src/fx/BinauralSound.cpp
@@ -0,0 +1,60 @@
+/*******************************************************************************
+* Copyright 2015-2016 Juan Francisco Crespo Galán
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+******************************************************************************/
+
+#include "fx/BinauralSound.h"
+#include "fx/BinauralReader.h"
+#include "Exception.h"
+
+#include <cstring>
+
+AUD_NAMESPACE_BEGIN
+
+BinauralSound::BinauralSound(std::shared_ptr<ISound> sound, std::shared_ptr<HRTF> hrtfs, std::shared_ptr<Source> source, std::shared_ptr<ThreadPool> threadPool) :
+ BinauralSound(sound, hrtfs, source, threadPool, std::make_shared<FFTPlan>(0.0))
+{
+}
+
+BinauralSound::BinauralSound(std::shared_ptr<ISound> sound, std::shared_ptr<HRTF> hrtfs, std::shared_ptr<Source> source, std::shared_ptr<ThreadPool> threadPool, std::shared_ptr<FFTPlan> plan) :
+ m_sound(sound), m_hrtfs(hrtfs), m_source(source), m_threadPool(threadPool), m_plan(plan)
+{
+}
+
+std::shared_ptr<IReader> BinauralSound::createReader()
+{
+ return std::make_shared<BinauralReader>(m_sound->createReader(), m_hrtfs, m_source, m_threadPool, m_plan);
+}
+
+std::shared_ptr<HRTF> BinauralSound::getHRTFs()
+{
+ return m_hrtfs;
+}
+
+void BinauralSound::setHRTFs(std::shared_ptr<HRTF> hrtfs)
+{
+ m_hrtfs = hrtfs;
+}
+
+std::shared_ptr<Source> BinauralSound::getSource()
+{
+ return m_source;
+}
+
+void BinauralSound::setSource(std::shared_ptr<Source> source)
+{
+ m_source = source;
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/Butterworth.cpp b/extern/audaspace/src/fx/Butterworth.cpp
new file mode 100644
index 00000000000..1d86cd799b8
--- /dev/null
+++ b/extern/audaspace/src/fx/Butterworth.cpp
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/Butterworth.h"
+#include "fx/ButterworthCalculator.h"
+
+AUD_NAMESPACE_BEGIN
+
+Butterworth::Butterworth(std::shared_ptr<ISound> sound, float frequency) :
+ DynamicIIRFilter(sound, std::shared_ptr<IDynamicIIRFilterCalculator>(new ButterworthCalculator(frequency)))
+{
+}
+
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/ButterworthCalculator.cpp b/extern/audaspace/src/fx/ButterworthCalculator.cpp
new file mode 100644
index 00000000000..f249fd45f15
--- /dev/null
+++ b/extern/audaspace/src/fx/ButterworthCalculator.cpp
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/ButterworthCalculator.h"
+
+#include <cmath>
+
+#define BWPB41 0.76536686473
+#define BWPB42 1.84775906502
+
+AUD_NAMESPACE_BEGIN
+
+ButterworthCalculator::ButterworthCalculator(float frequency) :
+ m_frequency(frequency)
+{
+}
+
+void ButterworthCalculator::recalculateCoefficients(SampleRate rate, std::vector<float> &b, std::vector<float> &a)
+{
+ float omega = 2 * std::tan(m_frequency * M_PI / rate);
+ float o2 = omega * omega;
+ float o4 = o2 * o2;
+ float x1 = o2 + 2.0f * (float)BWPB41 * omega + 4.0f;
+ float x2 = o2 + 2.0f * (float)BWPB42 * omega + 4.0f;
+ float y1 = o2 - 2.0f * (float)BWPB41 * omega + 4.0f;
+ float y2 = o2 - 2.0f * (float)BWPB42 * omega + 4.0f;
+ float o228 = 2.0f * o2 - 8.0f;
+ float norm = x1 * x2;
+ a.push_back(1);
+ a.push_back((x1 + x2) * o228 / norm);
+ a.push_back((x1 * y2 + x2 * y1 + o228 * o228) / norm);
+ a.push_back((y1 + y2) * o228 / norm);
+ a.push_back(y1 * y2 / norm);
+ b.push_back(o4 / norm);
+ b.push_back(4 * o4 / norm);
+ b.push_back(6 * o4 / norm);
+ b.push_back(b[1]);
+ b.push_back(b[0]);
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/CallbackIIRFilterReader.cpp b/extern/audaspace/src/fx/CallbackIIRFilterReader.cpp
new file mode 100644
index 00000000000..f24b6b6c9ec
--- /dev/null
+++ b/extern/audaspace/src/fx/CallbackIIRFilterReader.cpp
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/CallbackIIRFilterReader.h"
+
+AUD_NAMESPACE_BEGIN
+
+CallbackIIRFilterReader::CallbackIIRFilterReader(std::shared_ptr<IReader> reader, int in, int out, doFilterIIR doFilter, endFilterIIR endFilter, void* data) :
+ BaseIIRFilterReader(reader, in, out),
+ m_filter(doFilter), m_endFilter(endFilter), m_data(data)
+{
+}
+
+CallbackIIRFilterReader::~CallbackIIRFilterReader()
+{
+ if(m_endFilter)
+ m_endFilter(m_data);
+}
+
+sample_t CallbackIIRFilterReader::filter()
+{
+ return m_filter(this, m_data);
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/Convolver.cpp b/extern/audaspace/src/fx/Convolver.cpp
new file mode 100644
index 00000000000..24b205e9282
--- /dev/null
+++ b/extern/audaspace/src/fx/Convolver.cpp
@@ -0,0 +1,156 @@
+/*******************************************************************************
+* Copyright 2015-2016 Juan Francisco Crespo Galán
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+******************************************************************************/
+
+#include "fx/Convolver.h"
+
+#include <cmath>
+#include <cstdlib>
+#include <algorithm>
+#include <cstring>
+
+AUD_NAMESPACE_BEGIN
+Convolver::Convolver(std::shared_ptr<std::vector<std::shared_ptr<std::vector<std::complex<sample_t>>>>> ir, int irLength, std::shared_ptr<ThreadPool> threadPool, std::shared_ptr<FFTPlan> plan) :
+ m_N(plan->getSize()), m_M(plan->getSize()/2), m_L(plan->getSize()/2), m_irBuffers(ir), m_irLength(irLength), m_threadPool(threadPool), m_numThreads(std::min(threadPool->getNumOfThreads(), static_cast<unsigned int>(m_irBuffers->size() - 1))), m_tailCounter(0), m_eos(false)
+
+{
+ m_resetFlag = false;
+ m_futures.resize(m_numThreads);
+ for(int i = 0; i < m_irBuffers->size(); i++)
+ {
+ m_fftConvolvers.push_back(std::unique_ptr<FFTConvolver>(new FFTConvolver((*m_irBuffers)[i], plan)));
+ m_delayLine.push_front((fftwf_complex*)std::calloc((m_N / 2) + 1, sizeof(fftwf_complex)));
+ }
+
+ m_accBuffer = (fftwf_complex*)std::calloc((m_N / 2) + 1, sizeof(fftwf_complex));
+ for(int i = 0; i < m_numThreads; i++)
+ m_threadAccBuffers.push_back((fftwf_complex*)std::calloc((m_N / 2) + 1, sizeof(fftwf_complex)));
+}
+
+Convolver::~Convolver()
+{
+ m_resetFlag = true;
+ for(auto &fut : m_futures)
+ if(fut.valid())
+ fut.get();
+
+ std::free(m_accBuffer);
+ for(auto buf : m_threadAccBuffers)
+ std::free(buf);
+ while(!m_delayLine.empty())
+ {
+ std::free(m_delayLine.front());
+ m_delayLine.pop_front();
+ }
+}
+
+void Convolver::getNext(sample_t* inBuffer, sample_t* outBuffer, int& length, bool& eos)
+{
+ if(length > m_L)
+ {
+ length = 0;
+ eos = m_eos;
+ return;
+ }
+ if(m_eos)
+ {
+ eos = m_eos;
+ length = 0;
+ return;
+ }
+
+ eos = false;
+ for(auto &fut : m_futures)
+ if(fut.valid())
+ fut.get();
+
+ if(inBuffer != nullptr)
+ m_fftConvolvers[0]->getNextFDL(inBuffer, reinterpret_cast<std::complex<sample_t>*>(m_accBuffer), length, m_delayLine[0]);
+ else
+ {
+ m_tailCounter++;
+ std::memset(outBuffer, 0, m_L*sizeof(sample_t));
+ m_fftConvolvers[0]->getNextFDL(outBuffer, reinterpret_cast<std::complex<sample_t>*>(m_accBuffer), length, m_delayLine[0]);
+ }
+ m_delayLine.push_front(m_delayLine.back());
+ m_delayLine.pop_back();
+ length = m_L;
+ m_fftConvolvers[0]->IFFT_FDL(m_accBuffer, outBuffer, length);
+ std::memset(m_accBuffer, 0, ((m_N / 2) + 1)*sizeof(fftwf_complex));
+
+ if(m_tailCounter >= m_delayLine.size() && inBuffer == nullptr)
+ {
+ eos = m_eos = true;
+ length = m_irLength%m_M;
+ if(length == 0)
+ length = m_M;
+ }
+ else
+ for(int i = 0; i < m_futures.size(); i++)
+ m_futures[i] = m_threadPool->enqueue(&Convolver::threadFunction, this, i);
+}
+
+void Convolver::reset()
+{
+ m_resetFlag = true;
+ for(auto &fut : m_futures)
+ if(fut.valid())
+ fut.get();
+
+ for(int i = 0; i < m_delayLine.size();i++)
+ std::memset(m_delayLine[i], 0, ((m_N / 2) + 1)*sizeof(fftwf_complex));
+ for(int i = 0; i < m_fftConvolvers.size(); i++)
+ m_fftConvolvers[i]->clear();
+ std::memset(m_accBuffer, 0, ((m_N / 2) + 1)*sizeof(fftwf_complex));
+ m_tailCounter = 0;
+ m_eos = false;
+ m_resetFlag = false;
+}
+
+std::shared_ptr<std::vector<std::shared_ptr<std::vector<std::complex<sample_t>>>>> Convolver::getImpulseResponse()
+{
+ return m_irBuffers;
+}
+
+void Convolver::setImpulseResponse(std::shared_ptr<std::vector<std::shared_ptr<std::vector<std::complex<sample_t>>>>> ir)
+{
+ reset();
+ m_irBuffers = ir;
+ for(int i = 0; i < m_irBuffers->size(); i++)
+ m_fftConvolvers[i]->setImpulseResponse((*m_irBuffers)[i]);
+}
+
+bool Convolver::threadFunction(int id)
+{
+ int total = m_irBuffers->size();
+ int share = std::ceil(((float)total - 1) / (float)m_numThreads);
+ int start = id*share + 1;
+ int end = std::min(start + share, total);
+
+ std::memset(m_threadAccBuffers[id], 0, ((m_N / 2) + 1)*sizeof(fftwf_complex));
+
+ for(int i = start; i < end && !m_resetFlag; i++)
+ m_fftConvolvers[i]->getNextFDL(reinterpret_cast<std::complex<sample_t>*>(m_delayLine[i]), reinterpret_cast<std::complex<sample_t>*>(m_threadAccBuffers[id]));
+
+ m_sumMutex.lock();
+ for(int i = 0; (i < m_N / 2 + 1) && !m_resetFlag; i++)
+ {
+ m_accBuffer[i][0] += m_threadAccBuffers[id][i][0];
+ m_accBuffer[i][1] += m_threadAccBuffers[id][i][1];
+ }
+ m_sumMutex.unlock();
+ return true;
+}
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/ConvolverReader.cpp b/extern/audaspace/src/fx/ConvolverReader.cpp
new file mode 100644
index 00000000000..d5d9050f9a1
--- /dev/null
+++ b/extern/audaspace/src/fx/ConvolverReader.cpp
@@ -0,0 +1,203 @@
+/*******************************************************************************
+* Copyright 2015-2016 Juan Francisco Crespo Galán
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+******************************************************************************/
+
+#include "fx/ConvolverReader.h"
+#include "Exception.h"
+
+#include <cstring>
+#include <algorithm>
+#include <cmath>
+#include <cstdlib>
+
+AUD_NAMESPACE_BEGIN
+ConvolverReader::ConvolverReader(std::shared_ptr<IReader> reader, std::shared_ptr<ImpulseResponse> ir, std::shared_ptr<ThreadPool> threadPool, std::shared_ptr<FFTPlan> plan) :
+ m_reader(reader), m_ir(ir), m_N(plan->getSize()), m_eosReader(false), m_eosTail(false), m_inChannels(reader->getSpecs().channels), m_irChannels(ir->getSpecs().channels), m_threadPool(threadPool), m_position(0)
+{
+ m_nChannelThreads = std::min((int)threadPool->getNumOfThreads(), m_inChannels);
+ m_futures.resize(m_nChannelThreads);
+
+ int irLength = m_ir->getLength();
+ if(m_irChannels != 1 && m_irChannels != m_inChannels)
+ AUD_THROW(StateException, "The impulse response and the sound must either have the same amount of channels or the impulse response must be mono");
+ if(m_reader->getSpecs().rate != m_ir->getSpecs().rate)
+ AUD_THROW(StateException, "The sound and the impulse response. must have the same rate");
+
+ m_M = m_L = m_N / 2;
+
+ if(m_irChannels > 1)
+ for(int i = 0; i < m_inChannels; i++)
+ m_convolvers.push_back(std::unique_ptr<Convolver>(new Convolver(ir->getChannel(i), irLength, m_threadPool, plan)));
+ else
+ for(int i = 0; i < m_inChannels; i++)
+ m_convolvers.push_back(std::unique_ptr<Convolver>(new Convolver(ir->getChannel(0), irLength, m_threadPool, plan)));
+
+ for(int i = 0; i < m_inChannels; i++)
+ m_vecInOut.push_back((sample_t*)std::malloc(m_L*sizeof(sample_t)));
+ m_outBuffer = (sample_t*)std::malloc(m_L*m_inChannels*sizeof(sample_t));
+ m_outBufLen = m_eOutBufLen = m_outBufferPos = m_L*m_inChannels;
+}
+
+ConvolverReader::~ConvolverReader()
+{
+ std::free(m_outBuffer);
+ for(int i = 0; i < m_inChannels; i++)
+ std::free(m_vecInOut[i]);
+}
+
+bool ConvolverReader::isSeekable() const
+{
+ return m_reader->isSeekable();
+}
+
+void ConvolverReader::seek(int position)
+{
+ m_position = position;
+ m_reader->seek(position);
+ for(int i = 0; i < m_inChannels; i++)
+ m_convolvers[i]->reset();
+ m_eosTail = false;
+ m_eosReader = false;
+ m_outBufferPos = m_eOutBufLen = m_outBufLen;
+}
+
+int ConvolverReader::getLength() const
+{
+ return m_reader->getLength();
+}
+
+int ConvolverReader::getPosition() const
+{
+ return m_position;
+}
+
+Specs ConvolverReader::getSpecs() const
+{
+ return m_reader->getSpecs();
+}
+
+void ConvolverReader::read(int& length, bool& eos, sample_t* buffer)
+{
+ if(length <= 0)
+ {
+ length = 0;
+ eos = (m_eosTail && m_outBufferPos >= m_eOutBufLen);
+ return;
+ }
+ eos = false;
+ int writePos = 0;
+ do
+ {
+ int bufRest = m_eOutBufLen - m_outBufferPos;
+ int writeLength = std::min((length*m_inChannels) - writePos, m_eOutBufLen + bufRest);
+ if(bufRest < writeLength || (m_eOutBufLen == 0 && m_eosTail))
+ {
+ if(bufRest > 0)
+ std::memcpy(buffer + writePos, m_outBuffer + m_outBufferPos, bufRest*sizeof(sample_t));
+ if(!m_eosTail)
+ {
+ loadBuffer();
+ int len = std::min(std::abs(writeLength - bufRest), m_eOutBufLen);
+ std::memcpy(buffer + writePos + bufRest, m_outBuffer, len*sizeof(sample_t));
+ m_outBufferPos = len;
+ writeLength = std::min((length*m_inChannels) - writePos, m_eOutBufLen + bufRest);
+ }
+ else
+ {
+ m_outBufferPos += bufRest;
+ length = (writePos + bufRest) / m_inChannels;
+ eos = true;
+ return;
+ }
+ }
+ else
+ {
+ std::memcpy(buffer + writePos, m_outBuffer + m_outBufferPos, writeLength*sizeof(sample_t));
+ m_outBufferPos += writeLength;
+ }
+ writePos += writeLength;
+ } while(writePos < length*m_inChannels);
+ m_position += length;
+}
+
+void ConvolverReader::loadBuffer()
+{
+ m_lastLengthIn = m_L;
+ m_reader->read(m_lastLengthIn, m_eosReader, m_outBuffer);
+ if(!m_eosReader || m_lastLengthIn>0)
+ {
+ divideByChannel(m_outBuffer, m_lastLengthIn*m_inChannels);
+ int len = m_lastLengthIn;
+
+ for(int i = 0; i < m_futures.size(); i++)
+ m_futures[i] = m_threadPool->enqueue(&ConvolverReader::threadFunction, this, i, true);
+ for(auto &fut : m_futures)
+ len = fut.get();
+
+ joinByChannel(0, len);
+ m_eOutBufLen = len*m_inChannels;
+ }
+ else if(!m_eosTail)
+ {
+ int len = m_lastLengthIn = m_L;
+ for(int i = 0; i < m_futures.size(); i++)
+ m_futures[i] = m_threadPool->enqueue(&ConvolverReader::threadFunction, this, i, false);
+ for(auto &fut : m_futures)
+ len = fut.get();
+
+ joinByChannel(0, len);
+ m_eOutBufLen = len*m_inChannels;
+ }
+}
+
+void ConvolverReader::divideByChannel(const sample_t* buffer, int len)
+{
+ int k = 0;
+ for(int i = 0; i < len; i += m_inChannels)
+ {
+ for(int j = 0; j < m_inChannels; j++)
+ m_vecInOut[j][k] = buffer[i + j];
+ k++;
+ }
+}
+
+void ConvolverReader::joinByChannel(int start, int len)
+{
+ int k = 0;
+ for(int i = 0; i < len*m_inChannels; i += m_inChannels)
+ {
+ for(int j = 0; j < m_vecInOut.size(); j++)
+ m_outBuffer[i + j + start] = m_vecInOut[j][k];
+ k++;
+ }
+}
+
+int ConvolverReader::threadFunction(int id, bool input)
+{
+ int share = std::ceil((float)m_inChannels / (float)m_nChannelThreads);
+ int start = id*share;
+ int end = std::min(start + share, m_inChannels);
+
+ int l=m_lastLengthIn;
+ for(int i = start; i < end; i++)
+ if(input)
+ m_convolvers[i]->getNext(m_vecInOut[i], m_vecInOut[i], l, m_eosTail);
+ else
+ m_convolvers[i]->getNext(nullptr, m_vecInOut[i], l, m_eosTail);
+
+ return l;
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/ConvolverSound.cpp b/extern/audaspace/src/fx/ConvolverSound.cpp
new file mode 100644
index 00000000000..9bdf5a66652
--- /dev/null
+++ b/extern/audaspace/src/fx/ConvolverSound.cpp
@@ -0,0 +1,50 @@
+/*******************************************************************************
+* Copyright 2015-2016 Juan Francisco Crespo Galán
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+******************************************************************************/
+
+#include "fx/ConvolverSound.h"
+#include "fx/ConvolverReader.h"
+#include "Exception.h"
+
+#include <cstring>
+
+AUD_NAMESPACE_BEGIN
+
+ConvolverSound::ConvolverSound(std::shared_ptr<ISound> sound, std::shared_ptr<ImpulseResponse> impulseResponse, std::shared_ptr<ThreadPool> threadPool) :
+ ConvolverSound(sound, impulseResponse, threadPool, std::make_shared<FFTPlan>(0.0))
+{
+}
+
+ConvolverSound::ConvolverSound(std::shared_ptr<ISound> sound, std::shared_ptr<ImpulseResponse> impulseResponse, std::shared_ptr<ThreadPool> threadPool, std::shared_ptr<FFTPlan> plan) :
+ m_sound(sound), m_impulseResponse(impulseResponse), m_threadPool(threadPool), m_plan(plan)
+{
+}
+
+std::shared_ptr<IReader> ConvolverSound::createReader()
+{
+ return std::make_shared<ConvolverReader>(m_sound->createReader(), m_impulseResponse, m_threadPool, m_plan);
+}
+
+std::shared_ptr<ImpulseResponse> ConvolverSound::getImpulseResponse()
+{
+ return m_impulseResponse;
+}
+
+void ConvolverSound::setImpulseResponse(std::shared_ptr<ImpulseResponse> impulseResponse)
+{
+ m_impulseResponse = impulseResponse;
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/Delay.cpp b/extern/audaspace/src/fx/Delay.cpp
new file mode 100644
index 00000000000..e2a82299bc0
--- /dev/null
+++ b/extern/audaspace/src/fx/Delay.cpp
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/Delay.h"
+#include "fx/DelayReader.h"
+
+AUD_NAMESPACE_BEGIN
+
+Delay::Delay(std::shared_ptr<ISound> sound, float delay) :
+ Effect(sound),
+ m_delay(delay)
+{
+}
+
+float Delay::getDelay() const
+{
+ return m_delay;
+}
+
+std::shared_ptr<IReader> Delay::createReader()
+{
+ return std::shared_ptr<IReader>(new DelayReader(getReader(), m_delay));
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/DelayReader.cpp b/extern/audaspace/src/fx/DelayReader.cpp
new file mode 100644
index 00000000000..530aed69cba
--- /dev/null
+++ b/extern/audaspace/src/fx/DelayReader.cpp
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/DelayReader.h"
+
+#include <cstring>
+
+AUD_NAMESPACE_BEGIN
+
+DelayReader::DelayReader(std::shared_ptr<IReader> reader, float delay) :
+ EffectReader(reader),
+ m_delay(int((SampleRate)delay * reader->getSpecs().rate)),
+ m_remdelay(int((SampleRate)delay * reader->getSpecs().rate))
+{
+}
+
+void DelayReader::seek(int position)
+{
+ if(position < m_delay)
+ {
+ m_remdelay = m_delay - position;
+ m_reader->seek(0);
+ }
+ else
+ {
+ m_remdelay = 0;
+ m_reader->seek(position - m_delay);
+ }
+}
+
+int DelayReader::getLength() const
+{
+ int len = m_reader->getLength();
+ if(len < 0)
+ return len;
+ return len + m_delay;
+}
+
+int DelayReader::getPosition() const
+{
+ if(m_remdelay > 0)
+ return m_delay - m_remdelay;
+ return m_reader->getPosition() + m_delay;
+}
+
+void DelayReader::read(int& length, bool& eos, sample_t* buffer)
+{
+ if(m_remdelay > 0)
+ {
+ Specs specs = m_reader->getSpecs();
+ int samplesize = AUD_SAMPLE_SIZE(specs);
+
+ if(length > m_remdelay)
+ {
+ std::memset(buffer, 0, m_remdelay * samplesize);
+
+ int len = length - m_remdelay;
+ m_reader->read(len, eos, buffer + m_remdelay * specs.channels);
+
+ length = m_remdelay + len;
+
+ m_remdelay = 0;
+ }
+ else
+ {
+ std::memset(buffer, 0, length * samplesize);
+ m_remdelay -= length;
+ }
+ }
+ else
+ m_reader->read(length, eos, buffer);
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/DynamicIIRFilter.cpp b/extern/audaspace/src/fx/DynamicIIRFilter.cpp
new file mode 100644
index 00000000000..02a8b0b65ac
--- /dev/null
+++ b/extern/audaspace/src/fx/DynamicIIRFilter.cpp
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/DynamicIIRFilter.h"
+#include "fx/DynamicIIRFilterReader.h"
+
+AUD_NAMESPACE_BEGIN
+
+DynamicIIRFilter::DynamicIIRFilter(std::shared_ptr<ISound> sound,
+ std::shared_ptr<IDynamicIIRFilterCalculator> calculator) :
+ Effect(sound),
+ m_calculator(calculator)
+{
+}
+
+std::shared_ptr<IReader> DynamicIIRFilter::createReader()
+{
+ return std::shared_ptr<IReader>(new DynamicIIRFilterReader(getReader(), m_calculator));
+}
+
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/DynamicIIRFilterReader.cpp b/extern/audaspace/src/fx/DynamicIIRFilterReader.cpp
new file mode 100644
index 00000000000..948b467aaa4
--- /dev/null
+++ b/extern/audaspace/src/fx/DynamicIIRFilterReader.cpp
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/DynamicIIRFilterReader.h"
+#include "fx/IDynamicIIRFilterCalculator.h"
+
+AUD_NAMESPACE_BEGIN
+
+DynamicIIRFilterReader::DynamicIIRFilterReader(std::shared_ptr<IReader> reader, std::shared_ptr<IDynamicIIRFilterCalculator> calculator) :
+ IIRFilterReader(reader, std::vector<float>(), std::vector<float>()),
+ m_calculator(calculator)
+{
+ sampleRateChanged(reader->getSpecs().rate);
+}
+
+void DynamicIIRFilterReader::sampleRateChanged(SampleRate rate)
+{
+ std::vector<float> a, b;
+ m_calculator->recalculateCoefficients(rate, b, a);
+ setCoefficients(b, a);
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/DynamicMusic.cpp b/extern/audaspace/src/fx/DynamicMusic.cpp
new file mode 100644
index 00000000000..b77cd749576
--- /dev/null
+++ b/extern/audaspace/src/fx/DynamicMusic.cpp
@@ -0,0 +1,346 @@
+/*******************************************************************************
+* Copyright 2015-2016 Juan Francisco Crespo Galán
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+******************************************************************************/
+
+#include "fx/DynamicMusic.h"
+#include "generator/Silence.h"
+#include "fx/Fader.h"
+#include "fx/Limiter.h"
+
+#include <mutex>
+#include <condition_variable>
+
+AUD_NAMESPACE_BEGIN
+
+DynamicMusic::DynamicMusic(std::shared_ptr<IDevice> device) :
+m_device(device), m_fadeTime(1.0f)
+{
+ m_id = 0;
+ m_transitioning = false;
+ m_stopThread = false;
+ m_volume = m_device->getVolume();
+ m_scenes.push_back(std::vector<std::shared_ptr<ISound>>(1, nullptr));
+}
+
+DynamicMusic::~DynamicMusic()
+{
+ stop();
+}
+
+int DynamicMusic::addScene(std::shared_ptr<ISound> sound)
+{
+ std::vector<std::shared_ptr<ISound>> v;
+ m_scenes.push_back(v);
+ for(int i = 0; i < m_scenes.size()-1; i++)
+ m_scenes.back().push_back(nullptr);
+ for(int i = 0; i < m_scenes.size()-1; i++)
+ m_scenes[i].push_back(nullptr);
+ m_scenes.back().push_back(sound);
+
+ return m_scenes.size() - 1;
+}
+
+bool DynamicMusic::changeScene(int id)
+{
+ if(id >= m_scenes.size() || m_transitioning)
+ return false;
+ else
+ {
+ if(m_fadeThread.joinable())
+ m_fadeThread.join();
+ m_device->lock();
+ if(id == m_id)
+ {
+ m_currentHandle->setVolume(m_volume);
+ m_currentHandle->setLoopCount(-1);
+ }
+ else
+ {
+ m_soundTarget = id;
+ if(m_scenes[m_id][id] == nullptr)
+ {
+ m_stopThread = false;
+ if((m_scenes[m_id][m_id] != nullptr && m_currentHandle->getStatus() != STATUS_INVALID) || m_scenes[m_soundTarget][m_soundTarget] != nullptr)
+ {
+ m_transitioning = true;
+ if(m_scenes[m_id][m_id] == nullptr || m_currentHandle->getStatus() == STATUS_INVALID)
+ {
+ m_device->lock();
+ m_currentHandle = m_device->play(m_scenes[m_soundTarget][m_soundTarget]);
+ m_currentHandle->setVolume(0.0f);
+ m_currentHandle->setLoopCount(-1);
+ m_device->unlock();
+ m_fadeThread = std::thread(&DynamicMusic::fadeInThread, this);
+ }
+ else
+ {
+ if(m_scenes[m_soundTarget][m_soundTarget] != nullptr)
+ {
+ m_device->lock();
+ m_transitionHandle = m_currentHandle;
+ m_currentHandle = m_device->play(m_scenes[m_soundTarget][m_soundTarget]);
+ m_currentHandle->setVolume(0.0f);
+ m_currentHandle->setLoopCount(-1);
+ m_device->unlock();
+ m_fadeThread = std::thread(&DynamicMusic::crossfadeThread, this);
+ }
+ else
+ {
+ m_transitionHandle = m_currentHandle;
+ m_currentHandle = nullptr;
+ m_fadeThread = std::thread(&DynamicMusic::fadeOutThread, this);
+ }
+ }
+ }
+ }
+ else
+ {
+ if(m_scenes[m_id][m_id] == nullptr || m_currentHandle->getStatus() == STATUS_INVALID)
+ transitionCallback(this);
+ else
+ {
+ m_currentHandle->setLoopCount(0);
+ m_currentHandle->setStopCallback(transitionCallback, this);
+ }
+ }
+ }
+ m_device->unlock();
+ return true;
+ }
+}
+
+int DynamicMusic::getScene()
+{
+ return m_id;
+}
+
+bool DynamicMusic::addTransition(int init, int end, std::shared_ptr<ISound> sound)
+{
+ if(init != end && init < m_scenes.size() && end < m_scenes.size() && init >= 0 && end >= 0)
+ {
+ m_scenes[init][end] = sound;
+ return true;
+ }
+ return false;
+}
+
+void DynamicMusic::setFadeTime(float seconds)
+{
+ m_device->lock();
+ m_fadeTime = seconds;
+ m_device->unlock();
+}
+
+float DynamicMusic::getFadeTime()
+{
+ return m_fadeTime;
+}
+
+bool DynamicMusic::resume()
+{
+ bool result = false, resultTrans = false;
+
+ if(m_currentHandle != nullptr)
+ result = m_currentHandle->resume();
+ if(m_transitionHandle != nullptr)
+ resultTrans = m_transitionHandle->resume();
+
+ return result || resultTrans;
+}
+
+bool DynamicMusic::pause()
+{
+ bool result = false, resultTrans = false;
+
+ if(m_currentHandle != nullptr)
+ result = m_currentHandle->pause();
+ if(m_transitionHandle != nullptr)
+ resultTrans = m_transitionHandle->pause();
+
+ return result || resultTrans;
+}
+
+bool DynamicMusic::seek(float position)
+{
+ bool result;
+
+ if(m_currentHandle != nullptr)
+ {
+ result = m_currentHandle->seek(position);
+ if(m_transitionHandle != nullptr && result == true)
+ m_transitionHandle->stop();
+ }
+
+ return result;
+}
+
+float DynamicMusic::getPosition()
+{
+ float result = 0.0f;
+
+ if(m_currentHandle != nullptr)
+ result = m_currentHandle->getPosition();
+
+ return result;
+}
+
+float DynamicMusic::getVolume()
+{
+ return m_volume;
+}
+
+bool DynamicMusic::setVolume(float volume)
+{
+ m_volume = volume;
+ bool result = false, resultTrans = false;
+
+ if(m_currentHandle != nullptr)
+ result = m_currentHandle->setVolume(volume);
+ if(m_transitionHandle != nullptr)
+ {
+ m_device->lock();
+ if(volume<m_transitionHandle->getVolume())
+ resultTrans = m_transitionHandle->setVolume(0.0f);
+ m_device->unlock();
+ }
+ if(m_currentHandle == nullptr && m_transitionHandle == nullptr)
+ result = true;
+
+ return result || resultTrans;
+}
+
+Status DynamicMusic::getStatus()
+{
+ if(m_currentHandle != nullptr)
+ {
+ Status result = m_currentHandle->getStatus();
+ return result;
+ }
+ else
+ return STATUS_INVALID;
+}
+
+bool DynamicMusic::stop()
+{
+ m_stopThread = true;
+ bool result = false, resultTrans = false;
+
+ if(m_currentHandle != nullptr)
+ result = m_currentHandle->stop();
+ if(m_transitionHandle != nullptr)
+
+ resultTrans = m_transitionHandle->stop();
+
+ if(m_fadeThread.joinable())
+ m_fadeThread.join();
+ m_id = 0;
+
+ return result || resultTrans;
+}
+
+void DynamicMusic::transitionCallback(void* player)
+{
+ auto dat = reinterpret_cast<DynamicMusic*>(player);
+ dat->m_transitioning = true;
+ dat->m_device->lock();
+ dat->m_currentHandle = dat->m_device->play(dat->m_scenes[dat->m_id][dat->m_soundTarget]);
+ dat->m_currentHandle->setVolume(dat->m_volume);
+ if(dat->m_scenes[dat->m_soundTarget][dat->m_soundTarget] != nullptr)
+ dat->m_currentHandle->setStopCallback(sceneCallback, player);
+ dat->m_device->unlock();
+}
+
+void DynamicMusic::sceneCallback(void* player)
+{
+ auto dat = reinterpret_cast<DynamicMusic*>(player);
+ dat->m_device->lock();
+ dat->m_currentHandle = dat->m_device->play(dat->m_scenes[dat->m_soundTarget][dat->m_soundTarget]);
+ dat->m_currentHandle->setVolume(dat->m_volume);
+ dat->m_currentHandle->setLoopCount(-1);
+ dat->m_device->unlock();
+ dat->m_id = int(dat->m_soundTarget);
+ dat->m_soundTarget = -1;
+ dat->m_transitioning = false;
+}
+
+void DynamicMusic::crossfadeThread()
+{
+ float currentVol = m_transitionHandle->getVolume();
+ float nextVol = m_currentHandle->getVolume();
+ float increment;
+
+ while(nextVol < m_volume && !m_stopThread)
+ {
+ increment = (m_volume / (m_fadeTime * 1000)) * 20;
+ currentVol -= increment;
+ nextVol += increment;
+ if(currentVol < 0)
+ currentVol = 0;
+ if(nextVol > m_volume)
+ nextVol = m_volume;
+ m_transitionHandle->setVolume(currentVol);
+ m_currentHandle->setVolume(nextVol);
+ std::this_thread::sleep_for(std::chrono::milliseconds(20));
+ }
+ if(m_stopThread)
+ m_transitionHandle->setVolume(m_volume);
+
+ m_transitionHandle->stop();
+
+ m_id = int(m_soundTarget);
+ m_transitioning = false;
+}
+
+void DynamicMusic::fadeInThread()
+{
+ float nextVol = m_currentHandle->getVolume();
+ float increment;
+
+ while(nextVol < m_volume && !m_stopThread)
+ {
+ increment = (m_volume / (m_fadeTime * 1000)) * 20;
+ nextVol += increment;
+ if(nextVol > m_volume)
+ nextVol = m_volume;
+ m_currentHandle->setVolume(nextVol);
+ std::this_thread::sleep_for(std::chrono::milliseconds(20));
+ }
+ if(m_stopThread)
+ m_currentHandle->setVolume(m_volume);
+
+ m_id = int(m_soundTarget);
+ m_transitioning = false;
+}
+
+void DynamicMusic::fadeOutThread()
+{
+ float currentVol = m_transitionHandle->getVolume();
+ float increment;
+
+ while(currentVol > 0.0f && !m_stopThread)
+ {
+ increment = (m_volume / (m_fadeTime * 1000)) * 20;
+ currentVol -= increment;
+ if(currentVol < 0)
+ currentVol = 0;
+ m_transitionHandle->setVolume(currentVol);
+ std::this_thread::sleep_for(std::chrono::milliseconds(20));
+ }
+
+ m_transitionHandle->stop();
+ m_id = int(m_soundTarget);
+ m_transitioning = false;
+}
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/Effect.cpp b/extern/audaspace/src/fx/Effect.cpp
new file mode 100644
index 00000000000..af59ba440f9
--- /dev/null
+++ b/extern/audaspace/src/fx/Effect.cpp
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/Effect.h"
+
+AUD_NAMESPACE_BEGIN
+
+Effect::Effect(std::shared_ptr<ISound> sound)
+{
+ m_sound = sound;
+}
+
+Effect::~Effect()
+{
+}
+
+std::shared_ptr<ISound> Effect::getSound() const
+{
+ return m_sound;
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/EffectReader.cpp b/extern/audaspace/src/fx/EffectReader.cpp
new file mode 100644
index 00000000000..93a9d3cbf1c
--- /dev/null
+++ b/extern/audaspace/src/fx/EffectReader.cpp
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/EffectReader.h"
+
+AUD_NAMESPACE_BEGIN
+
+EffectReader::EffectReader(std::shared_ptr<IReader> reader)
+{
+ m_reader = reader;
+}
+
+EffectReader::~EffectReader()
+{
+}
+
+bool EffectReader::isSeekable() const
+{
+ return m_reader->isSeekable();
+}
+
+void EffectReader::seek(int position)
+{
+ m_reader->seek(position);
+}
+
+int EffectReader::getLength() const
+{
+ return m_reader->getLength();
+}
+
+int EffectReader::getPosition() const
+{
+ return m_reader->getPosition();
+}
+
+Specs EffectReader::getSpecs() const
+{
+ return m_reader->getSpecs();
+}
+
+void EffectReader::read(int& length, bool& eos, sample_t* buffer)
+{
+ m_reader->read(length, eos, buffer);
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/Envelope.cpp b/extern/audaspace/src/fx/Envelope.cpp
new file mode 100644
index 00000000000..0637706c0a9
--- /dev/null
+++ b/extern/audaspace/src/fx/Envelope.cpp
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/Envelope.h"
+#include "fx/CallbackIIRFilterReader.h"
+
+#include <cmath>
+
+AUD_NAMESPACE_BEGIN
+
+struct EnvelopeParameters
+{
+ float attack;
+ float release;
+ float threshold;
+ float arthreshold;
+};
+
+sample_t Envelope::envelopeFilter(CallbackIIRFilterReader* reader, EnvelopeParameters* param)
+{
+ float in = std::fabs(reader->x(0));
+ float out = reader->y(-1);
+ if(in < param->threshold)
+ in = 0.0f;
+ return (in > out ? param->attack : param->release) * (out - in) + in;
+}
+
+void Envelope::endEnvelopeFilter(EnvelopeParameters* param)
+{
+ delete param;
+}
+
+Envelope::Envelope(std::shared_ptr<ISound> sound, float attack, float release, float threshold, float arthreshold) :
+ Effect(sound),
+ m_attack(attack),
+ m_release(release),
+ m_threshold(threshold),
+ m_arthreshold(arthreshold)
+{
+}
+
+std::shared_ptr<IReader> Envelope::createReader()
+{
+ std::shared_ptr<IReader> reader = getReader();
+
+ EnvelopeParameters* param = new EnvelopeParameters();
+ param->arthreshold = m_arthreshold;
+ param->attack = std::pow(m_arthreshold, 1.0f/(static_cast<float>(reader->getSpecs().rate) * m_attack));
+ param->release = std::pow(m_arthreshold, 1.0f/(static_cast<float>(reader->getSpecs().rate) * m_release));
+ param->threshold = m_threshold;
+
+ return std::shared_ptr<IReader>(new CallbackIIRFilterReader(reader, 1, 2,
+ (doFilterIIR) envelopeFilter,
+ (endFilterIIR) endEnvelopeFilter,
+ param));
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/FFTConvolver.cpp b/extern/audaspace/src/fx/FFTConvolver.cpp
new file mode 100644
index 00000000000..868a1ebbaf3
--- /dev/null
+++ b/extern/audaspace/src/fx/FFTConvolver.cpp
@@ -0,0 +1,214 @@
+/*******************************************************************************
+* Copyright 2015-2016 Juan Francisco Crespo Galán
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+******************************************************************************/
+
+#include "fx/FFTConvolver.h"
+
+#include <cstring>
+#include <cstdlib>
+
+AUD_NAMESPACE_BEGIN
+
+FFTConvolver::FFTConvolver(std::shared_ptr<std::vector<std::complex<sample_t>>> ir, std::shared_ptr<FFTPlan> plan) :
+ m_plan(plan), m_N(plan->getSize()), m_M(plan->getSize()/2), m_L(plan->getSize()/2), m_tailPos(0), m_irBuffer(ir)
+{
+ m_tail = (float*)calloc(m_M - 1, sizeof(float));
+ m_realBufLen = ((m_N / 2) + 1) * 2;
+ m_inBuffer = nullptr;
+ m_shiftBuffer = (sample_t*)std::calloc(m_N, sizeof(sample_t));
+}
+
+FFTConvolver::~FFTConvolver()
+{
+ std::free(m_tail);
+ std::free(m_shiftBuffer);
+ if(m_inBuffer != nullptr)
+ m_plan->freeBuffer(m_inBuffer);
+}
+
+void FFTConvolver::getNext(const sample_t* inBuffer, sample_t* outBuffer, int& length)
+{
+ if(length > m_L || length <= 0)
+ {
+ length = 0;
+ return;
+ }
+ if(m_inBuffer == nullptr)
+ m_inBuffer = reinterpret_cast<std::complex<sample_t>*>(m_plan->getBuffer());
+
+ std::memset(m_inBuffer, 0, m_realBufLen * sizeof(fftwf_complex));
+ std::memcpy(m_inBuffer, inBuffer, length*sizeof(sample_t));
+
+ m_plan->FFT(m_inBuffer);
+ for(int i = 0; i < m_realBufLen / 2; i++)
+ {
+ m_inBuffer[i] = m_inBuffer[i] * (*m_irBuffer)[i] / sample_t(m_N);
+ }
+ m_plan->IFFT(m_inBuffer);
+
+ for(int i = 0; i < m_M - 1; i++)
+ ((float*)m_inBuffer)[i] += m_tail[i];
+
+ for(int i = 0; i < m_M - 1; i++)
+ m_tail[i] = ((float*)m_inBuffer)[i + length];
+
+ std::memcpy(outBuffer, m_inBuffer, length * sizeof(sample_t));
+}
+
+void FFTConvolver::getNext(const sample_t* inBuffer, sample_t* outBuffer, int& length, fftwf_complex* transformedData)
+{
+ if(length > m_L || length <= 0)
+ {
+ length = 0;
+ return;
+ }
+ if(m_inBuffer == nullptr)
+ m_inBuffer = reinterpret_cast<std::complex<sample_t>*>(m_plan->getBuffer());
+
+ std::memset(m_inBuffer, 0, m_realBufLen * sizeof(fftwf_complex));
+ std::memcpy(m_inBuffer, inBuffer, length*sizeof(sample_t));
+
+ m_plan->FFT(m_inBuffer);
+ std::memcpy(transformedData, m_inBuffer, (m_realBufLen / 2)*sizeof(fftwf_complex));
+ for(int i = 0; i < m_realBufLen / 2; i++)
+ {
+ m_inBuffer[i] = m_inBuffer[i] * (*m_irBuffer)[i] / sample_t(m_N);
+ }
+ m_plan->IFFT(m_inBuffer);
+
+ for(int i = 0; i < m_M - 1; i++)
+ ((float*)m_inBuffer)[i] += m_tail[i];
+
+ for(int i = 0; i < m_M - 1; i++)
+ m_tail[i] = ((float*)m_inBuffer)[i + length];
+
+ std::memcpy(outBuffer, m_inBuffer, length * sizeof(sample_t));
+}
+
+void FFTConvolver::getNext(const fftwf_complex* inBuffer, sample_t* outBuffer, int& length)
+{
+ if(length > m_L || length <= 0)
+ {
+ length = 0;
+ return;
+ }
+ if(m_inBuffer == nullptr)
+ m_inBuffer = reinterpret_cast<std::complex<sample_t>*>(m_plan->getBuffer());
+
+ std::memset(m_inBuffer, 0, m_realBufLen * sizeof(fftwf_complex));
+ for(int i = 0; i < m_realBufLen / 2; i++)
+ {
+ m_inBuffer[i] = m_inBuffer[i] * (*m_irBuffer)[i] / sample_t(m_N);
+ }
+ m_plan->IFFT(m_inBuffer);
+
+ for(int i = 0; i < m_M - 1; i++)
+ ((float*)m_inBuffer)[i] += m_tail[i];
+
+ for(int i = 0; i < m_M - 1; i++)
+ m_tail[i] = ((float*)m_inBuffer)[i + length];
+
+ std::memcpy(outBuffer, m_inBuffer, length * sizeof(sample_t));
+}
+
+void FFTConvolver::getTail(int& length, bool& eos, sample_t* buffer)
+{
+ if(length <= 0)
+ {
+ length = 0;
+ eos = m_tailPos >= m_M - 1;
+ return;
+ }
+
+ eos = false;
+ if(m_tailPos + length > m_M - 1)
+ {
+ length = m_M - 1 - m_tailPos;
+ if(length < 0)
+ length = 0;
+ eos = true;
+ m_tailPos = m_M - 1;
+ }
+ else
+ m_tailPos += length;
+ std::memcpy(buffer, m_tail, length*sizeof(sample_t));
+}
+
+void FFTConvolver::clear()
+{
+ std::memset(m_shiftBuffer, 0, m_N * sizeof(sample_t));
+ std::memset(m_tail, 0, m_M - 1);
+}
+
+void FFTConvolver::IFFT_FDL(const fftwf_complex* inBuffer, sample_t* outBuffer, int& length)
+{
+ if(length > m_L || length <= 0)
+ {
+ length = 0;
+ return;
+ }
+ if(m_inBuffer == nullptr)
+ m_inBuffer = reinterpret_cast<std::complex<sample_t>*>(m_plan->getBuffer());
+
+ std::memset(m_inBuffer, 0, m_realBufLen * sizeof(fftwf_complex));
+ std::memcpy(m_inBuffer, inBuffer, (m_realBufLen / 2)*sizeof(fftwf_complex));
+ m_plan->IFFT(m_inBuffer);
+ std::memcpy(outBuffer, ((sample_t*)m_inBuffer)+m_L, length*sizeof(sample_t));
+}
+
+void FFTConvolver::getNextFDL(const std::complex<sample_t>* inBuffer, std::complex<sample_t>* accBuffer)
+{
+ for(int i = 0; i < m_realBufLen / 2; i++)
+ {
+ accBuffer[i] += (inBuffer[i] * (*m_irBuffer)[i]) / sample_t(m_N);
+ }
+}
+
+void FFTConvolver::getNextFDL(const sample_t* inBuffer, std::complex<sample_t>* accBuffer, int& length, fftwf_complex* transformedData)
+{
+ if(length > m_L || length <= 0)
+ {
+ length = 0;
+ return;
+ }
+ if(m_inBuffer == nullptr)
+ m_inBuffer = reinterpret_cast<std::complex<sample_t>*>(m_plan->getBuffer());
+
+ std::memcpy(m_shiftBuffer, m_shiftBuffer + m_L, m_L*sizeof(sample_t));
+ std::memcpy(m_shiftBuffer + m_L, inBuffer, length*sizeof(sample_t));
+
+ std::memset(m_inBuffer, 0, m_realBufLen * sizeof(fftwf_complex));
+ std::memcpy(m_inBuffer, m_shiftBuffer, (m_L+length)*sizeof(sample_t));
+
+ m_plan->FFT(m_inBuffer);
+ std::memcpy(transformedData, m_inBuffer, (m_realBufLen / 2)*sizeof(fftwf_complex));
+ for(int i = 0; i < m_realBufLen / 2; i++)
+ {
+ accBuffer[i] += (m_inBuffer[i] * (*m_irBuffer)[i]) / sample_t(m_N);
+ }
+}
+
+
+void FFTConvolver::setImpulseResponse(std::shared_ptr<std::vector<std::complex<sample_t>>> ir)
+{
+ clear();
+ m_irBuffer = ir;
+}
+
+std::shared_ptr<std::vector<std::complex<sample_t>>> FFTConvolver::getImpulseResponse()
+{
+ return m_irBuffer;
+}
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/Fader.cpp b/extern/audaspace/src/fx/Fader.cpp
new file mode 100644
index 00000000000..041d8369a01
--- /dev/null
+++ b/extern/audaspace/src/fx/Fader.cpp
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/Fader.h"
+
+AUD_NAMESPACE_BEGIN
+
+Fader::Fader(std::shared_ptr<ISound> sound, FadeType type, float start, float length) :
+ Effect(sound),
+ m_type(type),
+ m_start(start),
+ m_length(length)
+{
+}
+
+FadeType Fader::getType() const
+{
+ return m_type;
+}
+
+float Fader::getStart() const
+{
+ return m_start;
+}
+
+float Fader::getLength() const
+{
+ return m_length;
+}
+
+std::shared_ptr<IReader> Fader::createReader()
+{
+ return std::shared_ptr<IReader>(new FaderReader(getReader(), m_type, m_start, m_length));
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/FaderReader.cpp b/extern/audaspace/src/fx/FaderReader.cpp
new file mode 100644
index 00000000000..b1e23b993f3
--- /dev/null
+++ b/extern/audaspace/src/fx/FaderReader.cpp
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/FaderReader.h"
+
+#include <cstring>
+
+AUD_NAMESPACE_BEGIN
+
+FaderReader::FaderReader(std::shared_ptr<IReader> reader, FadeType type, float start,float length) :
+ EffectReader(reader),
+ m_type(type),
+ m_start(start),
+ m_length(length)
+{
+}
+
+void FaderReader::read(int& length, bool& eos, sample_t* buffer)
+{
+ int position = m_reader->getPosition();
+ Specs specs = m_reader->getSpecs();
+ int samplesize = AUD_SAMPLE_SIZE(specs);
+
+ m_reader->read(length, eos, buffer);
+
+ if((position + length) / (float)specs.rate <= m_start)
+ {
+ if(m_type != FADE_OUT)
+ {
+ std::memset(buffer, 0, length * samplesize);
+ }
+ }
+ else if(position / (float)specs.rate >= m_start+m_length)
+ {
+ if(m_type == FADE_OUT)
+ {
+ std::memset(buffer, 0, length * samplesize);
+ }
+ }
+ else
+ {
+ float volume = 1.0f;
+
+ for(int i = 0; i < length * specs.channels; i++)
+ {
+ if(i % specs.channels == 0)
+ {
+ volume = (((position+i)/(float)specs.rate)-m_start) / m_length;
+ if(volume > 1.0f)
+ volume = 1.0f;
+ else if(volume < 0.0f)
+ volume = 0.0f;
+
+ if(m_type == FADE_OUT)
+ volume = 1.0f - volume;
+ }
+
+ buffer[i] = buffer[i] * volume;
+ }
+ }
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/HRTF.cpp b/extern/audaspace/src/fx/HRTF.cpp
new file mode 100644
index 00000000000..14ef3ad0912
--- /dev/null
+++ b/extern/audaspace/src/fx/HRTF.cpp
@@ -0,0 +1,122 @@
+/*******************************************************************************
+* Copyright 2015-2016 Juan Francisco Crespo Galán
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+******************************************************************************/
+
+#include "fx/HRTF.h"
+#include "Exception.h"
+
+#include <cmath>
+
+AUD_NAMESPACE_BEGIN
+HRTF::HRTF() :
+ HRTF(std::make_shared<FFTPlan>(0.0))
+{
+}
+
+HRTF::HRTF(std::shared_ptr<FFTPlan> plan) :
+ m_plan(plan)
+{
+ m_specs.channels = CHANNELS_INVALID;
+ m_specs.rate = 0;
+ m_empty = true;
+}
+
+bool HRTF::addImpulseResponse(std::shared_ptr<StreamBuffer> impulseResponse, float azimuth, float elevation)
+{
+ Specs spec = impulseResponse->getSpecs();
+
+ azimuth = std::fmod(azimuth, 360);
+ if(azimuth < 0)
+ azimuth += 360;
+
+ if((spec.channels != CHANNELS_MONO) || (spec.rate != m_specs.rate && m_specs.rate > 0.0))
+ return false;
+
+ m_hrtfs[elevation][azimuth] = std::make_shared<ImpulseResponse>(impulseResponse, m_plan);
+ m_specs.channels = CHANNELS_MONO;
+ m_specs.rate = spec.rate;
+ m_empty = false;
+ return true;
+}
+
+std::pair<std::shared_ptr<ImpulseResponse>, std::shared_ptr<ImpulseResponse>> HRTF::getImpulseResponse(float &azimuth, float &elevation)
+{
+ if(m_hrtfs.empty())
+ return std::make_pair(nullptr, nullptr);
+ azimuth = std::fmod(azimuth, 360);
+ if(azimuth < 0)
+ azimuth += 360;
+
+ std::shared_ptr<ImpulseResponse> R, L;
+ float az = 0, el = 0, dif=0, minDif=360;
+
+ for(auto elem : m_hrtfs)
+ {
+ dif = std::fabs(elevation - elem.first);
+ if(dif < minDif)
+ {
+ minDif = dif;
+ el = elem.first;
+ }
+ }
+ elevation = el;
+ dif = 0;
+ minDif = 360;
+
+ for(auto elem : m_hrtfs[elevation])
+ {
+ dif = std::fabs(azimuth - elem.first);
+ if(dif < minDif)
+ {
+ minDif = dif;
+ az = elem.first;
+ R = elem.second;
+ }
+ }
+ azimuth = az;
+ float azL = 360 - azimuth;
+ if(azL == 360)
+ azL = 0;
+
+ auto iter = m_hrtfs[elevation].find(azL);
+ if(iter != m_hrtfs[elevation].end())
+ L = iter->second;
+ else
+ {
+ dif = 0;
+ minDif = 360;
+ for(auto elem : m_hrtfs[elevation])
+ {
+ dif = std::fabs(azL - elem.first);
+ if(dif < minDif)
+ {
+ minDif = dif;
+ L = elem.second;
+ }
+ }
+ }
+ return std::make_pair(L, R);
+}
+
+Specs HRTF::getSpecs()
+{
+ return m_specs;
+}
+
+bool HRTF::isEmpty()
+{
+ return m_empty;
+}
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/HRTFLoaderUnix.cpp b/extern/audaspace/src/fx/HRTFLoaderUnix.cpp
new file mode 100644
index 00000000000..12a23913912
--- /dev/null
+++ b/extern/audaspace/src/fx/HRTFLoaderUnix.cpp
@@ -0,0 +1,89 @@
+/*******************************************************************************
+* Copyright 2015-2016 Juan Francisco Crespo Galán
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+******************************************************************************/
+
+#include "fx/HRTFLoader.h"
+#include "file/File.h"
+#include "Exception.h"
+
+#include <dirent.h>
+#include <exception>
+
+AUD_NAMESPACE_BEGIN
+
+std::shared_ptr<HRTF> HRTFLoader::loadLeftHRTFs(std::shared_ptr<FFTPlan> plan, const std::string& fileExtension, const std::string& path)
+{
+ std::shared_ptr<HRTF> hrtfs(std::make_shared<HRTF>(plan));
+ loadHRTFs(hrtfs, 'L', fileExtension, path);
+ return hrtfs;
+}
+
+std::shared_ptr<HRTF> HRTFLoader::loadRightHRTFs(std::shared_ptr<FFTPlan> plan, const std::string& fileExtension, const std::string& path)
+{
+ std::shared_ptr<HRTF> hrtfs(std::make_shared<HRTF>(plan));
+ loadHRTFs(hrtfs, 'R', fileExtension, path);
+ return hrtfs;
+}
+
+std::shared_ptr<HRTF> HRTFLoader::loadLeftHRTFs(const std::string& fileExtension, const std::string& path)
+{
+ std::shared_ptr<HRTF> hrtfs(std::make_shared<HRTF>());
+ loadHRTFs(hrtfs, 'L', fileExtension, path);
+ return hrtfs;
+}
+
+std::shared_ptr<HRTF> HRTFLoader::loadRightHRTFs(const std::string& fileExtension, const std::string& path)
+{
+ std::shared_ptr<HRTF> hrtfs(std::make_shared<HRTF>());
+ loadHRTFs(hrtfs, 'R', fileExtension, path);
+ return hrtfs;
+}
+
+void HRTFLoader::loadHRTFs(std::shared_ptr<HRTF> hrtfs, char ear, const std::string& fileExtension, const std::string& path)
+{
+ std::string readpath = path;
+ if(path == "")
+ readpath = ".";
+
+ DIR* dir = opendir(path.c_str());
+ if(!dir)
+ return;
+
+ float azim, elev;
+
+ while(dirent* entry = readdir(dir))
+ {
+ std::string filename = entry->d_name;
+ if(filename.front() == ear && filename.length() >= fileExtension.length() && filename.substr(filename.length() - fileExtension.length()) == fileExtension)
+ {
+ try
+ {
+ elev = std::stof(filename.substr(1, filename.find("e") - 1));
+ azim = std::stof(filename.substr(filename.find("e") + 1, filename.find("a") - filename.find("e") - 1));
+ if(ear == 'L')
+ azim = 360 - azim;
+ }
+ catch(std::exception& e)
+ {
+ AUD_THROW(FileException, "The HRTF name doesn't follow the naming scheme: " + filename);
+ }
+ hrtfs->addImpulseResponse(std::make_shared<StreamBuffer>(std::make_shared<File>(readpath + "/" + filename)), azim, elev);
+ }
+ }
+ closedir(dir);
+ return;
+}
+
+AUD_NAMESPACE_END \ No newline at end of file
diff --git a/extern/audaspace/src/fx/HRTFLoaderWindows.cpp b/extern/audaspace/src/fx/HRTFLoaderWindows.cpp
new file mode 100644
index 00000000000..148f1fa015d
--- /dev/null
+++ b/extern/audaspace/src/fx/HRTFLoaderWindows.cpp
@@ -0,0 +1,93 @@
+/*******************************************************************************
+* Copyright 2015-2016 Juan Francisco Crespo Galán
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+******************************************************************************/
+
+#include "fx/HRTFLoader.h"
+#include "file/File.h"
+#include "Exception.h"
+
+#include <windows.h>
+#include <exception>
+
+AUD_NAMESPACE_BEGIN
+
+std::shared_ptr<HRTF> HRTFLoader::loadLeftHRTFs(std::shared_ptr<FFTPlan> plan, const std::string& fileExtension, const std::string& path)
+{
+ std::shared_ptr<HRTF> hrtfs(std::make_shared<HRTF>(plan));
+ loadHRTFs(hrtfs, 'L', fileExtension, path);
+ return hrtfs;
+}
+
+std::shared_ptr<HRTF> HRTFLoader::loadRightHRTFs(std::shared_ptr<FFTPlan> plan, const std::string& fileExtension, const std::string& path)
+{
+ std::shared_ptr<HRTF> hrtfs(std::make_shared<HRTF>(plan));
+ loadHRTFs(hrtfs, 'R', fileExtension, path);
+ return hrtfs;
+}
+
+std::shared_ptr<HRTF> HRTFLoader::loadLeftHRTFs(const std::string& fileExtension, const std::string& path)
+{
+ std::shared_ptr<HRTF> hrtfs(std::make_shared<HRTF>());
+ loadHRTFs(hrtfs, 'L', fileExtension, path);
+ return hrtfs;
+}
+
+std::shared_ptr<HRTF> HRTFLoader::loadRightHRTFs(const std::string& fileExtension, const std::string& path)
+{
+ std::shared_ptr<HRTF> hrtfs(std::make_shared<HRTF>());
+ loadHRTFs(hrtfs, 'R', fileExtension, path);
+ return hrtfs;
+}
+
+void HRTFLoader::loadHRTFs(std::shared_ptr<HRTF> hrtfs, char ear, const std::string& fileExtension, const std::string& path)
+{
+ std::string readpath = path;
+ if(path == "")
+ readpath = ".";
+
+ WIN32_FIND_DATA entry;
+ bool found_file = true;
+ std::string search = readpath + "\\*";
+ HANDLE dir = FindFirstFile(search.c_str(), &entry);
+ if(dir == INVALID_HANDLE_VALUE)
+ return;
+
+ float azim, elev;
+
+ while(found_file)
+ {
+ std::string filename = entry.cFileName;
+ if(filename.front() == ear && filename.length() >= fileExtension.length() && filename.substr(filename.length() - fileExtension.length()) == fileExtension)
+ {
+ try
+ {
+ elev = std::stof(filename.substr(1, filename.find("e") - 1));
+ azim = std::stof(filename.substr(filename.find("e") + 1, filename.find("a") - filename.find("e") - 1));
+ if(ear == 'L')
+ azim = 360 - azim;
+ }
+ catch(std::exception& e)
+ {
+ AUD_THROW(FileException, "The HRTF name doesn't follow the naming scheme: " + filename);
+ }
+ hrtfs->addImpulseResponse(std::make_shared<StreamBuffer>(std::make_shared<File>(readpath + "/" + filename)), azim, elev);
+ }
+ found_file = FindNextFile(dir, &entry);
+ }
+ FindClose(dir);
+ return;
+}
+
+AUD_NAMESPACE_END \ No newline at end of file
diff --git a/extern/audaspace/src/fx/Highpass.cpp b/extern/audaspace/src/fx/Highpass.cpp
new file mode 100644
index 00000000000..2490d512078
--- /dev/null
+++ b/extern/audaspace/src/fx/Highpass.cpp
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/Highpass.h"
+#include "fx/IIRFilterReader.h"
+#include "fx/HighpassCalculator.h"
+
+AUD_NAMESPACE_BEGIN
+
+Highpass::Highpass(std::shared_ptr<ISound> sound, float frequency, float Q) :
+ DynamicIIRFilter(sound, std::shared_ptr<IDynamicIIRFilterCalculator>(new HighpassCalculator(frequency, Q)))
+{
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/HighpassCalculator.cpp b/extern/audaspace/src/fx/HighpassCalculator.cpp
new file mode 100644
index 00000000000..2b69efe2fa7
--- /dev/null
+++ b/extern/audaspace/src/fx/HighpassCalculator.cpp
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/HighpassCalculator.h"
+
+#include <cmath>
+
+AUD_NAMESPACE_BEGIN
+
+HighpassCalculator::HighpassCalculator(float frequency, float Q) :
+ m_frequency(frequency),
+ m_Q(Q)
+{
+}
+
+void HighpassCalculator::recalculateCoefficients(SampleRate rate, std::vector<float> &b, std::vector<float> &a)
+{
+ float w0 = 2.0 * M_PI * (SampleRate)m_frequency / rate;
+ float alpha = (float)(std::sin(w0) / (2.0 * (double)m_Q));
+ float norm = 1 + alpha;
+ float c = std::cos(w0);
+ a.push_back(1);
+ a.push_back(-2 * c / norm);
+ a.push_back((1 - alpha) / norm);
+ b.push_back((1 + c) / (2 * norm));
+ b.push_back((-1 - c) / norm);
+ b.push_back(b[0]);
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/IIRFilter.cpp b/extern/audaspace/src/fx/IIRFilter.cpp
new file mode 100644
index 00000000000..fce6d01e4bf
--- /dev/null
+++ b/extern/audaspace/src/fx/IIRFilter.cpp
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/IIRFilter.h"
+#include "fx/IIRFilterReader.h"
+
+AUD_NAMESPACE_BEGIN
+
+IIRFilter::IIRFilter(std::shared_ptr<ISound> sound, const std::vector<float>& b, const std::vector<float>& a) :
+ Effect(sound), m_a(a), m_b(b)
+{
+}
+
+std::shared_ptr<IReader> IIRFilter::createReader()
+{
+ return std::shared_ptr<IReader>(new IIRFilterReader(getReader(), m_b, m_a));
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/IIRFilterReader.cpp b/extern/audaspace/src/fx/IIRFilterReader.cpp
new file mode 100644
index 00000000000..8d879a85846
--- /dev/null
+++ b/extern/audaspace/src/fx/IIRFilterReader.cpp
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/IIRFilterReader.h"
+
+AUD_NAMESPACE_BEGIN
+
+IIRFilterReader::IIRFilterReader(std::shared_ptr<IReader> reader, const std::vector<float>& b, const std::vector<float>& a) :
+ BaseIIRFilterReader(reader, b.size(), a.size()), m_a(a), m_b(b)
+{
+ if(m_a.empty() == false)
+ {
+ for(int i = 1; i < m_a.size(); i++)
+ m_a[i] /= m_a[0];
+ for(int i = 0; i < m_b.size(); i++)
+ m_b[i] /= m_a[0];
+ m_a[0] = 1;
+ }
+}
+
+sample_t IIRFilterReader::filter()
+{
+ sample_t out = 0;
+
+ for(int i = 1; i < m_a.size(); i++)
+ out -= y(-i) * m_a[i];
+ for(int i = 0; i < m_b.size(); i++)
+ out += x(-i) * m_b[i];
+
+ return out;
+}
+
+void IIRFilterReader::setCoefficients(const std::vector<float>& b, const std::vector<float>& a)
+{
+ setLengths(b.size(), a.size());
+ m_a = a;
+ m_b = b;
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/ImpulseResponse.cpp b/extern/audaspace/src/fx/ImpulseResponse.cpp
new file mode 100644
index 00000000000..babb628eb7a
--- /dev/null
+++ b/extern/audaspace/src/fx/ImpulseResponse.cpp
@@ -0,0 +1,97 @@
+/*******************************************************************************
+* Copyright 2015-2016 Juan Francisco Crespo Galán
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+******************************************************************************/
+
+#include "fx/ImpulseResponse.h"
+
+#include <algorithm>
+#include <cstring>
+#include <cstdlib>
+#include <cmath>
+
+AUD_NAMESPACE_BEGIN
+ImpulseResponse::ImpulseResponse(std::shared_ptr<StreamBuffer> impulseResponse) :
+ ImpulseResponse(impulseResponse, std::make_shared<FFTPlan>(0.0))
+{
+}
+
+ImpulseResponse::ImpulseResponse(std::shared_ptr<StreamBuffer> impulseResponse, std::shared_ptr<FFTPlan> plan)
+{
+ auto reader = impulseResponse->createReader();
+ m_length = reader->getLength();
+ processImpulseResponse(impulseResponse->createReader(), plan);
+}
+
+Specs ImpulseResponse::getSpecs()
+{
+ return m_specs;
+}
+
+int ImpulseResponse::getLength()
+{
+ return m_length;
+}
+
+std::shared_ptr<std::vector<std::shared_ptr<std::vector<std::complex<sample_t>>>>> ImpulseResponse::getChannel(int n)
+{
+ return m_processedIR[n];
+}
+
+void ImpulseResponse::processImpulseResponse(std::shared_ptr<IReader> reader, std::shared_ptr<FFTPlan> plan)
+{
+ m_specs.channels = reader->getSpecs().channels;
+ m_specs.rate = reader->getSpecs().rate;
+ int N = plan->getSize();
+ bool eos = false;
+ int length = reader->getLength();
+ sample_t* buffer = (sample_t*)std::malloc(length * m_specs.channels * sizeof(sample_t));
+ int numParts = std::ceil((float)length / (plan->getSize() / 2));
+
+ for(int i = 0; i < m_specs.channels; i++)
+ {
+ m_processedIR.push_back(std::make_shared<std::vector<std::shared_ptr<std::vector<std::complex<sample_t>>>>>());
+ for(int j = 0; j < numParts; j++)
+ (*m_processedIR[i]).push_back(std::make_shared<std::vector<std::complex<sample_t>>>((N / 2) + 1));
+ }
+ length += reader->getSpecs().rate;
+ reader->read(length, eos, buffer);
+
+
+ void* bufferFFT = plan->getBuffer();
+ for(int i = 0; i < m_specs.channels; i++)
+ {
+ int partStart = 0;
+ for(int h = 0; h < numParts; h++)
+ {
+ int k = 0;
+ int len = std::min(partStart + ((N / 2)*m_specs.channels), length*m_specs.channels);
+ std::memset(bufferFFT, 0, ((N / 2) + 1) * 2 * sizeof(fftwf_complex));
+ for(int j = partStart; j < len; j += m_specs.channels)
+ {
+ ((float*)bufferFFT)[k] = buffer[j + i];
+ k++;
+ }
+ plan->FFT(bufferFFT);
+ for(int j = 0; j < (N / 2) + 1; j++)
+ {
+ (*(*m_processedIR[i])[h])[j] = reinterpret_cast<std::complex<sample_t>*>(bufferFFT)[j];
+ }
+ partStart += N / 2 * m_specs.channels;
+ }
+ }
+ plan->freeBuffer(bufferFFT);
+ std::free(buffer);
+}
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/Limiter.cpp b/extern/audaspace/src/fx/Limiter.cpp
new file mode 100644
index 00000000000..38a7288e8d7
--- /dev/null
+++ b/extern/audaspace/src/fx/Limiter.cpp
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/Limiter.h"
+#include "fx/LimiterReader.h"
+
+AUD_NAMESPACE_BEGIN
+
+Limiter::Limiter(std::shared_ptr<ISound> sound,
+ float start, float end) :
+ Effect(sound),
+ m_start(start),
+ m_end(end)
+{
+}
+
+float Limiter::getStart() const
+{
+ return m_start;
+}
+
+float Limiter::getEnd() const
+{
+ return m_end;
+}
+
+std::shared_ptr<IReader> Limiter::createReader()
+{
+ return std::shared_ptr<IReader>(new LimiterReader(getReader(), m_start, m_end));
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/LimiterReader.cpp b/extern/audaspace/src/fx/LimiterReader.cpp
new file mode 100644
index 00000000000..1d003c29679
--- /dev/null
+++ b/extern/audaspace/src/fx/LimiterReader.cpp
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/LimiterReader.h"
+#include "util/Buffer.h"
+
+#include <algorithm>
+
+AUD_NAMESPACE_BEGIN
+
+LimiterReader::LimiterReader(std::shared_ptr<IReader> reader, float start, float end) :
+ EffectReader(reader),
+ m_start(start),
+ m_end(end)
+{
+ if(m_start > 0)
+ {
+ Specs specs = m_reader->getSpecs();
+ Specs specs2;
+
+ if(m_reader->isSeekable())
+ m_reader->seek(m_start * specs.rate);
+ else
+ {
+ // skip first m_start samples by reading them
+ int length = AUD_DEFAULT_BUFFER_SIZE;
+ Buffer buffer(AUD_DEFAULT_BUFFER_SIZE * AUD_SAMPLE_SIZE(specs));
+ bool eos = false;
+ for(int len = m_start * specs.rate;
+ length > 0 && !eos;
+ len -= length)
+ {
+ if(len < AUD_DEFAULT_BUFFER_SIZE)
+ length = len;
+
+ 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));
+ }
+ }
+ }
+ }
+}
+
+void LimiterReader::seek(int position)
+{
+ m_reader->seek(position + m_start * m_reader->getSpecs().rate);
+}
+
+int LimiterReader::getLength() const
+{
+ int len = m_reader->getLength();
+ SampleRate rate = m_reader->getSpecs().rate;
+ if(len < 0 || (len > m_end * rate && m_end >= 0))
+ len = m_end * rate;
+ return len - m_start * rate;
+}
+
+int LimiterReader::getPosition() const
+{
+ int pos = m_reader->getPosition();
+ SampleRate rate = m_reader->getSpecs().rate;
+ return std::min(pos, int(m_end * rate)) - m_start * rate;
+}
+
+void LimiterReader::read(int& length, bool& eos, sample_t* buffer)
+{
+ eos = false;
+ if(m_end >= 0)
+ {
+ int position = m_reader->getPosition();
+ SampleRate rate = m_reader->getSpecs().rate;
+
+ if(position + length > m_end * rate)
+ {
+ length = m_end * rate - position;
+ eos = true;
+ }
+
+ if(position < int(m_start * rate))
+ {
+ int len2 = length;
+ for(int len = int(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)
+ {
+ length = 0;
+ return;
+ }
+ }
+ if(eos)
+ {
+ m_reader->read(length, eos, buffer);
+ eos = true;
+ }
+ else
+ m_reader->read(length, eos, buffer);
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/Loop.cpp b/extern/audaspace/src/fx/Loop.cpp
new file mode 100644
index 00000000000..1695fcf1662
--- /dev/null
+++ b/extern/audaspace/src/fx/Loop.cpp
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/Loop.h"
+#include "fx/LoopReader.h"
+
+AUD_NAMESPACE_BEGIN
+
+Loop::Loop(std::shared_ptr<ISound> sound, int loop) :
+ Effect(sound),
+ m_loop(loop)
+{
+}
+
+int Loop::getLoop() const
+{
+ return m_loop;
+}
+
+std::shared_ptr<IReader> Loop::createReader()
+{
+ return std::shared_ptr<IReader>(new LoopReader(getReader(), m_loop));
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/LoopReader.cpp b/extern/audaspace/src/fx/LoopReader.cpp
new file mode 100644
index 00000000000..2f13a5880eb
--- /dev/null
+++ b/extern/audaspace/src/fx/LoopReader.cpp
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/LoopReader.h"
+
+#include <cstring>
+
+AUD_NAMESPACE_BEGIN
+
+LoopReader::LoopReader(std::shared_ptr<IReader> reader, int loop) :
+ EffectReader(reader), m_count(loop), m_left(loop)
+{
+}
+
+void LoopReader::seek(int position)
+{
+ int len = m_reader->getLength();
+ if(len < 0)
+ m_reader->seek(position);
+ else
+ {
+ if(m_count >= 0)
+ {
+ m_left = m_count - (position / len);
+ if(m_left < 0)
+ m_left = 0;
+ }
+ m_reader->seek(position % len);
+ }
+}
+
+int LoopReader::getLength() const
+{
+ if(m_count < 0)
+ return -1;
+ return m_reader->getLength() * m_count;
+}
+
+int LoopReader::getPosition() const
+{
+ return m_reader->getPosition() * (m_count < 0 ? 1 : m_count);
+}
+
+void LoopReader::read(int& length, bool& eos, sample_t* buffer)
+{
+ const Specs specs = m_reader->getSpecs();
+
+ int len = length;
+
+ m_reader->read(length, eos, buffer);
+
+ if(length < len && eos && m_left)
+ {
+ int pos = length;
+ length = len;
+
+ while(pos < length && eos && m_left)
+ {
+ if(m_left > 0)
+ m_left--;
+
+ m_reader->seek(0);
+
+ len = length - pos;
+ m_reader->read(len, eos, buffer + pos * specs.channels);
+
+ // prevent endless loop
+ if(!len)
+ break;
+
+ pos += len;
+ }
+
+ length = pos;
+ }
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/Lowpass.cpp b/extern/audaspace/src/fx/Lowpass.cpp
new file mode 100644
index 00000000000..8c33291baa3
--- /dev/null
+++ b/extern/audaspace/src/fx/Lowpass.cpp
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/Lowpass.h"
+#include "fx/LowpassCalculator.h"
+
+AUD_NAMESPACE_BEGIN
+
+Lowpass::Lowpass(std::shared_ptr<ISound> sound, float frequency, float Q) :
+ DynamicIIRFilter(sound, std::shared_ptr<IDynamicIIRFilterCalculator>(new LowpassCalculator(frequency, Q)))
+{
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/LowpassCalculator.cpp b/extern/audaspace/src/fx/LowpassCalculator.cpp
new file mode 100644
index 00000000000..f2a53ed7514
--- /dev/null
+++ b/extern/audaspace/src/fx/LowpassCalculator.cpp
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/LowpassCalculator.h"
+
+#include <cmath>
+
+AUD_NAMESPACE_BEGIN
+
+LowpassCalculator::LowpassCalculator(float frequency, float Q) :
+ m_frequency(frequency),
+ m_Q(Q)
+{
+}
+
+void LowpassCalculator::recalculateCoefficients(SampleRate rate, std::vector<float> &b, std::vector<float> &a)
+{
+ float w0 = 2 * M_PI * m_frequency / rate;
+ float alpha = std::sin(w0) / (2 * m_Q);
+ float norm = 1 + alpha;
+ float c = std::cos(w0);
+ a.push_back(1);
+ a.push_back(-2 * c / norm);
+ a.push_back((1 - alpha) / norm);
+ b.push_back((1 - c) / (2 * norm));
+ b.push_back((1 - c) / norm);
+ b.push_back(b[0]);
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/MutableReader.cpp b/extern/audaspace/src/fx/MutableReader.cpp
new file mode 100644
index 00000000000..aa867d83f03
--- /dev/null
+++ b/extern/audaspace/src/fx/MutableReader.cpp
@@ -0,0 +1,64 @@
+/*******************************************************************************
+* Copyright 2015-2016 Juan Francisco Crespo Galán
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+******************************************************************************/
+
+#include "fx/MutableReader.h"
+
+#include <cstring>
+
+AUD_NAMESPACE_BEGIN
+
+MutableReader::MutableReader(std::shared_ptr<ISound> sound) :
+m_sound(sound)
+{
+ m_reader = m_sound->createReader();
+}
+
+bool MutableReader::isSeekable() const
+{
+ return m_reader->isSeekable();
+}
+
+void MutableReader::seek(int position)
+{
+ if(position < m_reader->getPosition())
+ {
+ m_reader = m_sound->createReader();
+ }
+ else
+ m_reader->seek(position);
+}
+
+int MutableReader::getLength() const
+{
+ return m_reader->getLength();
+}
+
+int MutableReader::getPosition() const
+{
+ return m_reader->getPosition();
+}
+
+Specs MutableReader::getSpecs() const
+{
+ return m_reader->getSpecs();
+}
+
+void MutableReader::read(int& length, bool& eos, sample_t* buffer)
+{
+ m_reader->read(length, eos, buffer);
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/MutableSound.cpp b/extern/audaspace/src/fx/MutableSound.cpp
new file mode 100644
index 00000000000..5326b640394
--- /dev/null
+++ b/extern/audaspace/src/fx/MutableSound.cpp
@@ -0,0 +1,35 @@
+/*******************************************************************************
+* Copyright 2015-2016 Juan Francisco Crespo Galán
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+******************************************************************************/
+
+#include "fx/MutableSound.h"
+#include "fx/MutableReader.h"
+#include "Exception.h"
+
+#include <cstring>
+
+AUD_NAMESPACE_BEGIN
+
+MutableSound::MutableSound(std::shared_ptr<ISound> sound) :
+m_sound(sound)
+{
+}
+
+std::shared_ptr<IReader> MutableSound::createReader()
+{
+ return std::make_shared<MutableReader>(m_sound);
+}
+
+AUD_NAMESPACE_END \ No newline at end of file
diff --git a/extern/audaspace/src/fx/Pitch.cpp b/extern/audaspace/src/fx/Pitch.cpp
new file mode 100644
index 00000000000..d7348a2d49e
--- /dev/null
+++ b/extern/audaspace/src/fx/Pitch.cpp
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/Pitch.h"
+#include "fx/PitchReader.h"
+
+AUD_NAMESPACE_BEGIN
+
+Pitch::Pitch(std::shared_ptr<ISound> sound, float pitch) :
+ Effect(sound),
+ m_pitch(pitch)
+{
+}
+
+std::shared_ptr<IReader> Pitch::createReader()
+{
+ return std::shared_ptr<IReader>(new PitchReader(getReader(), m_pitch));
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/PitchReader.cpp b/extern/audaspace/src/fx/PitchReader.cpp
new file mode 100644
index 00000000000..f44be0261e6
--- /dev/null
+++ b/extern/audaspace/src/fx/PitchReader.cpp
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/PitchReader.h"
+
+AUD_NAMESPACE_BEGIN
+
+PitchReader::PitchReader(std::shared_ptr<IReader> reader, float pitch) :
+ EffectReader(reader), m_pitch(pitch)
+{
+}
+
+Specs PitchReader::getSpecs() const
+{
+ Specs specs = m_reader->getSpecs();
+ specs.rate *= m_pitch;
+ return specs;
+}
+
+float PitchReader::getPitch() const
+{
+ return m_pitch;
+}
+
+void PitchReader::setPitch(float pitch)
+{
+ if(pitch > 0.0f)
+ m_pitch = pitch;
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/PlaybackCategory.cpp b/extern/audaspace/src/fx/PlaybackCategory.cpp
new file mode 100644
index 00000000000..e09a74c4017
--- /dev/null
+++ b/extern/audaspace/src/fx/PlaybackCategory.cpp
@@ -0,0 +1,144 @@
+/*******************************************************************************
+* Copyright 2015-2016 Juan Francisco Crespo Galán
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+******************************************************************************/
+
+#include "fx/PlaybackCategory.h"
+#include "fx/VolumeSound.h"
+
+AUD_NAMESPACE_BEGIN
+
+struct HandleData {
+ unsigned int id;
+ PlaybackCategory* category;
+};
+
+PlaybackCategory::PlaybackCategory(std::shared_ptr<IDevice> device) :
+ m_device(device), m_volumeStorage(std::make_shared<VolumeStorage>(1.0f)), m_status(STATUS_PLAYING), m_currentID(0)
+{
+}
+
+PlaybackCategory::~PlaybackCategory()
+{
+ stop();
+}
+
+std::shared_ptr<IHandle> PlaybackCategory::play(std::shared_ptr<ISound> sound)
+{
+ std::shared_ptr<ISound> vs(std::make_shared<VolumeSound>(sound, m_volumeStorage));
+ m_device->lock();
+ auto handle = m_device->play(vs);
+ if(handle == nullptr)
+ return nullptr;
+ switch (m_status)
+ {
+ case STATUS_PAUSED:
+ handle->pause();
+ break;
+ default:
+ m_status = STATUS_PLAYING;
+ };
+ m_handles[m_currentID] = handle;
+ HandleData* data = new HandleData;
+ data->category = this;
+ data->id = m_currentID;
+ handle->setStopCallback(cleanHandleCallback, data);
+ m_device->unlock();
+
+ m_currentID++;
+ return handle;
+}
+
+void PlaybackCategory::resume()
+{
+ m_device->lock();
+ for(auto i = m_handles.begin(); i != m_handles.end();)
+ {
+ if(i->second->getStatus() == STATUS_INVALID)
+ i = m_handles.erase(i);
+ else
+ {
+ i->second->resume();
+ i++;
+ }
+ }
+ m_device->unlock();
+ m_status = STATUS_PLAYING;
+}
+
+void PlaybackCategory::pause()
+{
+ m_device->lock();
+ for(auto i = m_handles.begin(); i != m_handles.end();)
+ {
+ if(i->second->getStatus() == STATUS_INVALID)
+ i = m_handles.erase(i);
+ else
+ {
+ i->second->pause();
+ i++;
+ }
+ }
+ m_device->unlock();
+ m_status = STATUS_PAUSED;
+}
+
+float PlaybackCategory::getVolume()
+{
+ return m_volumeStorage->getVolume();
+}
+
+void PlaybackCategory::setVolume(float volume)
+{
+ m_volumeStorage->setVolume(volume);
+}
+
+void PlaybackCategory::stop()
+{
+ m_device->lock();
+ for(auto i = m_handles.begin(); i != m_handles.end();)
+ {
+ i->second->stop();
+ if(i->second->getStatus() == STATUS_INVALID)
+ i = m_handles.erase(i);
+ else
+ i++;
+ }
+ m_device->unlock();
+ m_status = STATUS_STOPPED;
+}
+
+std::shared_ptr<VolumeStorage> PlaybackCategory::getSharedVolume()
+{
+ return m_volumeStorage;
+}
+
+void PlaybackCategory::cleanHandles()
+{
+ for(auto i = m_handles.begin(); i != m_handles.end();)
+ {
+ if(i->second->getStatus() == STATUS_INVALID)
+ i = m_handles.erase(i);
+ else
+ i++;
+ }
+}
+
+void PlaybackCategory::cleanHandleCallback(void* data)
+{
+ auto dat = reinterpret_cast<HandleData*>(data);
+ dat->category->m_handles.erase(dat->id);
+ delete dat;
+}
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/PlaybackManager.cpp b/extern/audaspace/src/fx/PlaybackManager.cpp
new file mode 100644
index 00000000000..0fbeeba04e2
--- /dev/null
+++ b/extern/audaspace/src/fx/PlaybackManager.cpp
@@ -0,0 +1,186 @@
+/*******************************************************************************
+* Copyright 2015-2016 Juan Francisco Crespo Galán
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+******************************************************************************/
+
+#include "fx/PlaybackManager.h"
+#include "fx/VolumeSound.h"
+
+#include <stdexcept>
+
+AUD_NAMESPACE_BEGIN
+PlaybackManager::PlaybackManager(std::shared_ptr<IDevice> device) :
+ m_device(device), m_currentKey(0)
+{
+}
+
+unsigned int PlaybackManager::addCategory(std::shared_ptr<PlaybackCategory> category)
+{
+ bool flag = true;
+ unsigned int k = -1;
+ do {
+ auto iter = m_categories.find(m_currentKey);
+ if(iter == m_categories.end())
+ {
+ m_categories[m_currentKey] = category;
+ k = m_currentKey;
+ m_currentKey++;
+ flag = false;
+ }
+ else
+ m_currentKey++;
+ } while(flag);
+
+ return k;
+}
+
+unsigned int PlaybackManager::addCategory(float volume)
+{
+ std::shared_ptr<PlaybackCategory> category = std::make_shared<PlaybackCategory>(m_device);
+ category->setVolume(volume);
+ bool flag = true;
+ unsigned int k = -1;
+ do {
+ auto iter = m_categories.find(m_currentKey);
+ if(iter == m_categories.end())
+ {
+ m_categories[m_currentKey] = category;
+ k = m_currentKey;
+ m_currentKey++;
+ flag = false;
+ }
+ else
+ m_currentKey++;
+ } while(flag);
+
+ return k;
+}
+
+std::shared_ptr<IHandle> PlaybackManager::play(std::shared_ptr<ISound> sound, unsigned int catKey)
+{
+ auto iter = m_categories.find(catKey);
+ std::shared_ptr<PlaybackCategory> category;
+
+ if(iter != m_categories.end())
+ {
+ category = iter->second;
+ }
+ else
+ {
+ category = std::make_shared<PlaybackCategory>(m_device);
+ m_categories[catKey] = category;
+ }
+ return category->play(sound);
+}
+
+bool PlaybackManager::resume(unsigned int catKey)
+{
+ auto iter = m_categories.find(catKey);
+
+ if(iter != m_categories.end())
+ {
+ iter->second->resume();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool PlaybackManager::pause(unsigned int catKey)
+{
+ auto iter = m_categories.find(catKey);
+
+ if(iter != m_categories.end())
+ {
+ iter->second->pause();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+float PlaybackManager::getVolume(unsigned int catKey)
+{
+ auto iter = m_categories.find(catKey);
+
+ if(iter != m_categories.end())
+ {
+ return iter->second->getVolume();
+ }
+ else
+ {
+ return -1.0;
+ }
+}
+
+bool PlaybackManager::setVolume(float volume, unsigned int catKey)
+{
+ auto iter = m_categories.find(catKey);
+
+ if(iter != m_categories.end())
+ {
+ iter->second->setVolume(volume);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool PlaybackManager::stop(unsigned int catKey)
+{
+ auto iter = m_categories.find(catKey);
+
+ if(iter != m_categories.end())
+ {
+ iter->second->stop();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void PlaybackManager::clean()
+{
+ for(auto cat : m_categories)
+ cat.second->cleanHandles();
+}
+
+bool PlaybackManager::clean(unsigned int catKey)
+{
+ auto iter = m_categories.find(catKey);
+
+ if(iter != m_categories.end())
+ {
+ iter->second->cleanHandles();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+std::shared_ptr<IDevice> PlaybackManager::getDevice()
+{
+ return m_device;
+}
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/Reverse.cpp b/extern/audaspace/src/fx/Reverse.cpp
new file mode 100644
index 00000000000..7d906056071
--- /dev/null
+++ b/extern/audaspace/src/fx/Reverse.cpp
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/Reverse.h"
+#include "fx/ReverseReader.h"
+
+AUD_NAMESPACE_BEGIN
+
+Reverse::Reverse(std::shared_ptr<ISound> sound) :
+ Effect(sound)
+{
+}
+
+std::shared_ptr<IReader> Reverse::createReader()
+{
+ return std::shared_ptr<IReader>(new ReverseReader(getReader()));
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/ReverseReader.cpp b/extern/audaspace/src/fx/ReverseReader.cpp
new file mode 100644
index 00000000000..19a1e25ce4f
--- /dev/null
+++ b/extern/audaspace/src/fx/ReverseReader.cpp
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/ReverseReader.h"
+#include "Exception.h"
+
+#include <cstring>
+
+AUD_NAMESPACE_BEGIN
+
+ReverseReader::ReverseReader(std::shared_ptr<IReader> reader) :
+ EffectReader(reader),
+ m_length(reader->getLength()),
+ m_position(0)
+{
+ if(m_length < 0 || !reader->isSeekable())
+ AUD_THROW(StateException, "A reader has to be seekable and have finite length to be reversible.");
+}
+
+void ReverseReader::seek(int position)
+{
+ m_position = position;
+}
+
+int ReverseReader::getLength() const
+{
+ return m_length;
+}
+
+int ReverseReader::getPosition() const
+{
+ return m_position;
+}
+
+void ReverseReader::read(int& length, bool& eos, sample_t* buffer)
+{
+ // first correct the length
+ if(m_position + length > m_length)
+ length = m_length - m_position;
+
+ if(length <= 0)
+ {
+ length = 0;
+ eos = true;
+ return;
+ }
+
+ const Specs specs = getSpecs();
+ const int samplesize = AUD_SAMPLE_SIZE(specs);
+
+ sample_t temp[CHANNEL_MAX];
+
+ int len = length;
+
+ // read from reader
+ m_reader->seek(m_length - m_position - len);
+ m_reader->read(len, eos, buffer);
+
+ // set null if reader didn't give enough data
+ if(len < length)
+ std::memset(buffer, 0, (length - len) * samplesize);
+
+ // copy the samples reverted
+ for(int i = 0; i < length / 2; i++)
+ {
+ std::memcpy(temp, buffer + (len - 1 - i) * specs.channels, samplesize);
+ std::memcpy(buffer + (len - 1 - i) * specs.channels, buffer + i * specs.channels, samplesize);
+ std::memcpy(buffer + i * specs.channels, temp, samplesize);
+ }
+
+ m_position += length;
+ eos = false;
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/SoundList.cpp b/extern/audaspace/src/fx/SoundList.cpp
new file mode 100644
index 00000000000..81239ca5baa
--- /dev/null
+++ b/extern/audaspace/src/fx/SoundList.cpp
@@ -0,0 +1,84 @@
+/*******************************************************************************
+* Copyright 2015-2016 Juan Francisco Crespo Galán
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+******************************************************************************/
+
+#include "fx/SoundList.h"
+#include "Exception.h"
+
+#include <cstring>
+#include <cstdlib>
+#include <chrono>
+
+AUD_NAMESPACE_BEGIN
+
+SoundList::SoundList(bool random) :
+m_random(random)
+{
+ std::srand(time(NULL));
+}
+
+SoundList::SoundList(std::vector<std::shared_ptr<ISound>>& list, bool random) :
+m_list(list), m_random(random)
+{
+ std::srand(time(NULL));
+}
+
+std::shared_ptr<IReader> SoundList::createReader()
+{
+ if(m_list.size() > 0)
+ {
+ m_mutex.lock();
+
+ if(!m_random){
+ m_index++;
+ if(m_index >= m_list.size())
+ m_index = 0;
+ }
+ else
+ {
+ int temp;
+ do{
+ temp = std::rand() % m_list.size();
+ } while(temp == m_index && m_list.size()>1);
+ m_index = temp;
+ }
+ auto reader = m_list[m_index]->createReader();
+ m_mutex.unlock();
+ return reader;
+ }
+ else
+ AUD_THROW(FileException, "The sound list is empty");
+}
+
+void SoundList::addSound(std::shared_ptr<ISound> sound)
+{
+ m_list.push_back(sound);
+}
+
+void SoundList::setRandomMode(bool random)
+{
+ m_random = random;
+}
+
+bool SoundList::getRandomMode()
+{
+ return m_random;
+}
+
+int SoundList::getSize()
+{
+ return m_list.size();
+}
+AUD_NAMESPACE_END \ No newline at end of file
diff --git a/extern/audaspace/src/fx/Source.cpp b/extern/audaspace/src/fx/Source.cpp
new file mode 100644
index 00000000000..354ed69674b
--- /dev/null
+++ b/extern/audaspace/src/fx/Source.cpp
@@ -0,0 +1,71 @@
+/*******************************************************************************
+* Copyright 2015-2016 Juan Francisco Crespo Galán
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+******************************************************************************/
+
+#include "fx/Source.h"
+
+#include <cmath>
+
+AUD_NAMESPACE_BEGIN
+Source::Source(float azimuth, float elevation, float distance) :
+ m_elevation(elevation), m_distance(distance)
+{
+ azimuth = std::fmod(azimuth, 360);
+ if(azimuth < 0)
+ azimuth += 360;
+ m_azimuth = azimuth;
+}
+
+float Source::getAzimuth()
+{
+ return m_azimuth;
+}
+
+float Source::getElevation()
+{
+ return m_elevation;
+}
+
+float Source::getDistance()
+{
+ return m_distance;
+}
+
+float Source::getVolume()
+{
+ float volume = 1.0f - m_distance;
+ if(volume < 0.0f)
+ volume = 0.0f;
+ return volume;
+}
+
+void Source::setAzimuth(float azimuth)
+{
+ azimuth = std::fmod(azimuth, 360);
+ if(azimuth < 0)
+ azimuth += 360;
+ m_azimuth = azimuth;
+}
+
+void Source::setElevation(float elevation)
+{
+ m_elevation = elevation;
+}
+
+void Source::setDistance(float distance)
+{
+ m_distance = distance;
+}
+AUD_NAMESPACE_END \ No newline at end of file
diff --git a/extern/audaspace/src/fx/Sum.cpp b/extern/audaspace/src/fx/Sum.cpp
new file mode 100644
index 00000000000..306bc5de953
--- /dev/null
+++ b/extern/audaspace/src/fx/Sum.cpp
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/Sum.h"
+#include "fx/IIRFilterReader.h"
+
+AUD_NAMESPACE_BEGIN
+
+Sum::Sum(std::shared_ptr<ISound> sound) :
+ Effect(sound)
+{
+}
+
+std::shared_ptr<IReader> Sum::createReader()
+{
+ std::vector<float> a, b;
+ a.push_back(1);
+ a.push_back(-1);
+ b.push_back(1);
+ return std::shared_ptr<IReader>(new IIRFilterReader(getReader(), b, a));
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/Threshold.cpp b/extern/audaspace/src/fx/Threshold.cpp
new file mode 100644
index 00000000000..03c4ae4c8a5
--- /dev/null
+++ b/extern/audaspace/src/fx/Threshold.cpp
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/Threshold.h"
+#include "fx/CallbackIIRFilterReader.h"
+
+AUD_NAMESPACE_BEGIN
+
+sample_t Threshold::thresholdFilter(CallbackIIRFilterReader* reader, float* threshold)
+{
+ float in = reader->x(0);
+ if(in >= *threshold)
+ return 1;
+ else if(in <= -*threshold)
+ return -1;
+ else
+ return 0;
+}
+
+void Threshold::endThresholdFilter(float* threshold)
+{
+ delete threshold;
+}
+
+Threshold::Threshold(std::shared_ptr<ISound> sound, float threshold) :
+ Effect(sound),
+ m_threshold(threshold)
+{
+}
+
+float Threshold::getThreshold() const
+{
+ return m_threshold;
+}
+
+std::shared_ptr<IReader> Threshold::createReader()
+{
+ return std::shared_ptr<IReader>(new CallbackIIRFilterReader(getReader(), 1, 0, doFilterIIR(thresholdFilter), endFilterIIR(endThresholdFilter), new float(m_threshold)));
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/Volume.cpp b/extern/audaspace/src/fx/Volume.cpp
new file mode 100644
index 00000000000..231f5856a6c
--- /dev/null
+++ b/extern/audaspace/src/fx/Volume.cpp
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "fx/Volume.h"
+#include "fx/IIRFilterReader.h"
+
+AUD_NAMESPACE_BEGIN
+
+Volume::Volume(std::shared_ptr<ISound> sound, float volume) :
+ Effect(sound),
+ m_volume(volume)
+{
+}
+
+float Volume::getVolume() const
+{
+ return m_volume;
+}
+
+std::shared_ptr<IReader> Volume::createReader()
+{
+ std::vector<float> a, b;
+ a.push_back(1);
+ b.push_back(m_volume);
+ return std::shared_ptr<IReader>(new IIRFilterReader(getReader(), b, a));
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/fx/VolumeReader.cpp b/extern/audaspace/src/fx/VolumeReader.cpp
new file mode 100644
index 00000000000..ac1d4882a87
--- /dev/null
+++ b/extern/audaspace/src/fx/VolumeReader.cpp
@@ -0,0 +1,60 @@
+/*******************************************************************************
+* Copyright 2015-2016 Juan Francisco Crespo Galán
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+******************************************************************************/
+
+#include "fx/VolumeReader.h"
+
+#include <cstring>
+
+AUD_NAMESPACE_BEGIN
+
+VolumeReader::VolumeReader(std::shared_ptr<IReader> reader, std::shared_ptr<VolumeStorage> volumeStorage) :
+ m_reader(reader), m_volumeStorage(volumeStorage)
+{
+}
+
+bool VolumeReader::isSeekable() const
+{
+ return m_reader->isSeekable();
+}
+
+void VolumeReader::seek(int position)
+{
+ m_reader->seek(position);
+}
+
+int VolumeReader::getLength() const
+{
+ return m_reader->getLength();
+}
+
+int VolumeReader::getPosition() const
+{
+ return m_reader->getPosition();
+}
+
+Specs VolumeReader::getSpecs() const
+{
+ return m_reader->getSpecs();
+}
+
+void VolumeReader::read(int& length, bool& eos, sample_t* buffer)
+{
+ m_reader->read(length, eos, buffer);
+ for(int i = 0; i < length * m_reader->getSpecs().channels; i++)
+ buffer[i] = buffer[i] * m_volumeStorage->getVolume();
+}
+
+AUD_NAMESPACE_END \ No newline at end of file
diff --git a/extern/audaspace/src/fx/VolumeSound.cpp b/extern/audaspace/src/fx/VolumeSound.cpp
new file mode 100644
index 00000000000..b7f96225682
--- /dev/null
+++ b/extern/audaspace/src/fx/VolumeSound.cpp
@@ -0,0 +1,45 @@
+/*******************************************************************************
+* Copyright 2015-2016 Juan Francisco Crespo Galán
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+******************************************************************************/
+
+#include "fx/VolumeSound.h"
+#include "fx/VolumeReader.h"
+#include "Exception.h"
+
+#include <cstring>
+
+AUD_NAMESPACE_BEGIN
+
+VolumeSound::VolumeSound(std::shared_ptr<ISound> sound, std::shared_ptr<VolumeStorage> volumeStorage) :
+ m_sound(sound), m_volumeStorage(volumeStorage)
+{
+}
+
+std::shared_ptr<IReader> VolumeSound::createReader()
+{
+ return std::make_shared<VolumeReader>(m_sound->createReader(), m_volumeStorage);
+}
+
+std::shared_ptr<VolumeStorage> VolumeSound::getSharedVolume()
+{
+ return m_volumeStorage;
+}
+
+void VolumeSound::setSharedVolume(std::shared_ptr<VolumeStorage> volumeStorage)
+{
+ m_volumeStorage = volumeStorage;
+}
+
+AUD_NAMESPACE_END \ No newline at end of file
diff --git a/extern/audaspace/src/fx/VolumeStorage.cpp b/extern/audaspace/src/fx/VolumeStorage.cpp
new file mode 100644
index 00000000000..4c5164d0ea1
--- /dev/null
+++ b/extern/audaspace/src/fx/VolumeStorage.cpp
@@ -0,0 +1,39 @@
+/*******************************************************************************
+* Copyright 2015-2016 Juan Francisco Crespo Galán
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+******************************************************************************/
+
+#include "fx/VolumeStorage.h"
+
+AUD_NAMESPACE_BEGIN
+VolumeStorage::VolumeStorage() :
+ m_volume(1.0f)
+{
+}
+
+VolumeStorage::VolumeStorage(float volume) :
+ m_volume(volume)
+{
+}
+
+float VolumeStorage::getVolume()
+{
+ return m_volume;
+}
+
+void VolumeStorage::setVolume(float volume)
+{
+ m_volume = volume;
+}
+AUD_NAMESPACE_END