From 986267300ba42a5c99d2802cd701803dd558e389 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20M=C3=BCller?= Date: Fri, 18 Aug 2017 08:24:12 +0200 Subject: Audaspace: Moving audaspace 1.3 into extern. Deleting the old internal audaspace. Major changes from there are: - The whole library was refactored to use C++11. - Many stability and performance improvements. - Major Python API refactor: - Most requested: Play self generated sounds using numpy arrays. - For games: Sound list, random sounds and dynamic music. - Writing sounds to files. - Sequencing API. - Opening sound devices, eg. Jack. - Ability to choose different OpenAL devices in the user settings. --- extern/audaspace/src/fx/ADSR.cpp | 73 +++++ extern/audaspace/src/fx/ADSRReader.cpp | 115 +++++++ extern/audaspace/src/fx/Accumulator.cpp | 54 ++++ extern/audaspace/src/fx/BaseIIRFilterReader.cpp | 125 ++++++++ extern/audaspace/src/fx/BinauralReader.cpp | 255 +++++++++++++++ extern/audaspace/src/fx/BinauralSound.cpp | 60 ++++ extern/audaspace/src/fx/Butterworth.cpp | 28 ++ extern/audaspace/src/fx/ButterworthCalculator.cpp | 54 ++++ .../audaspace/src/fx/CallbackIIRFilterReader.cpp | 38 +++ extern/audaspace/src/fx/Convolver.cpp | 156 ++++++++++ extern/audaspace/src/fx/ConvolverReader.cpp | 203 ++++++++++++ extern/audaspace/src/fx/ConvolverSound.cpp | 50 +++ extern/audaspace/src/fx/Delay.cpp | 38 +++ extern/audaspace/src/fx/DelayReader.cpp | 87 ++++++ extern/audaspace/src/fx/DynamicIIRFilter.cpp | 35 +++ extern/audaspace/src/fx/DynamicIIRFilterReader.cpp | 36 +++ extern/audaspace/src/fx/DynamicMusic.cpp | 346 +++++++++++++++++++++ extern/audaspace/src/fx/Effect.cpp | 35 +++ extern/audaspace/src/fx/EffectReader.cpp | 60 ++++ extern/audaspace/src/fx/Envelope.cpp | 71 +++++ extern/audaspace/src/fx/FFTConvolver.cpp | 214 +++++++++++++ extern/audaspace/src/fx/Fader.cpp | 49 +++ extern/audaspace/src/fx/FaderReader.cpp | 76 +++++ extern/audaspace/src/fx/HRTF.cpp | 122 ++++++++ extern/audaspace/src/fx/HRTFLoaderUnix.cpp | 89 ++++++ extern/audaspace/src/fx/HRTFLoaderWindows.cpp | 93 ++++++ extern/audaspace/src/fx/Highpass.cpp | 28 ++ extern/audaspace/src/fx/HighpassCalculator.cpp | 43 +++ extern/audaspace/src/fx/IIRFilter.cpp | 32 ++ extern/audaspace/src/fx/IIRFilterReader.cpp | 53 ++++ extern/audaspace/src/fx/ImpulseResponse.cpp | 97 ++++++ extern/audaspace/src/fx/Limiter.cpp | 45 +++ extern/audaspace/src/fx/LimiterReader.cpp | 139 +++++++++ extern/audaspace/src/fx/Loop.cpp | 38 +++ extern/audaspace/src/fx/LoopReader.cpp | 91 ++++++ extern/audaspace/src/fx/Lowpass.cpp | 27 ++ extern/audaspace/src/fx/LowpassCalculator.cpp | 43 +++ extern/audaspace/src/fx/MutableReader.cpp | 64 ++++ extern/audaspace/src/fx/MutableSound.cpp | 35 +++ extern/audaspace/src/fx/Pitch.cpp | 33 ++ extern/audaspace/src/fx/PitchReader.cpp | 44 +++ extern/audaspace/src/fx/PlaybackCategory.cpp | 144 +++++++++ extern/audaspace/src/fx/PlaybackManager.cpp | 186 +++++++++++ extern/audaspace/src/fx/Reverse.cpp | 32 ++ extern/audaspace/src/fx/ReverseReader.cpp | 88 ++++++ extern/audaspace/src/fx/SoundList.cpp | 84 +++++ extern/audaspace/src/fx/Source.cpp | 71 +++++ extern/audaspace/src/fx/Sum.cpp | 36 +++ extern/audaspace/src/fx/Threshold.cpp | 54 ++++ extern/audaspace/src/fx/Volume.cpp | 41 +++ extern/audaspace/src/fx/VolumeReader.cpp | 60 ++++ extern/audaspace/src/fx/VolumeSound.cpp | 45 +++ extern/audaspace/src/fx/VolumeStorage.cpp | 39 +++ 53 files changed, 4254 insertions(+) create mode 100644 extern/audaspace/src/fx/ADSR.cpp create mode 100644 extern/audaspace/src/fx/ADSRReader.cpp create mode 100644 extern/audaspace/src/fx/Accumulator.cpp create mode 100644 extern/audaspace/src/fx/BaseIIRFilterReader.cpp create mode 100644 extern/audaspace/src/fx/BinauralReader.cpp create mode 100644 extern/audaspace/src/fx/BinauralSound.cpp create mode 100644 extern/audaspace/src/fx/Butterworth.cpp create mode 100644 extern/audaspace/src/fx/ButterworthCalculator.cpp create mode 100644 extern/audaspace/src/fx/CallbackIIRFilterReader.cpp create mode 100644 extern/audaspace/src/fx/Convolver.cpp create mode 100644 extern/audaspace/src/fx/ConvolverReader.cpp create mode 100644 extern/audaspace/src/fx/ConvolverSound.cpp create mode 100644 extern/audaspace/src/fx/Delay.cpp create mode 100644 extern/audaspace/src/fx/DelayReader.cpp create mode 100644 extern/audaspace/src/fx/DynamicIIRFilter.cpp create mode 100644 extern/audaspace/src/fx/DynamicIIRFilterReader.cpp create mode 100644 extern/audaspace/src/fx/DynamicMusic.cpp create mode 100644 extern/audaspace/src/fx/Effect.cpp create mode 100644 extern/audaspace/src/fx/EffectReader.cpp create mode 100644 extern/audaspace/src/fx/Envelope.cpp create mode 100644 extern/audaspace/src/fx/FFTConvolver.cpp create mode 100644 extern/audaspace/src/fx/Fader.cpp create mode 100644 extern/audaspace/src/fx/FaderReader.cpp create mode 100644 extern/audaspace/src/fx/HRTF.cpp create mode 100644 extern/audaspace/src/fx/HRTFLoaderUnix.cpp create mode 100644 extern/audaspace/src/fx/HRTFLoaderWindows.cpp create mode 100644 extern/audaspace/src/fx/Highpass.cpp create mode 100644 extern/audaspace/src/fx/HighpassCalculator.cpp create mode 100644 extern/audaspace/src/fx/IIRFilter.cpp create mode 100644 extern/audaspace/src/fx/IIRFilterReader.cpp create mode 100644 extern/audaspace/src/fx/ImpulseResponse.cpp create mode 100644 extern/audaspace/src/fx/Limiter.cpp create mode 100644 extern/audaspace/src/fx/LimiterReader.cpp create mode 100644 extern/audaspace/src/fx/Loop.cpp create mode 100644 extern/audaspace/src/fx/LoopReader.cpp create mode 100644 extern/audaspace/src/fx/Lowpass.cpp create mode 100644 extern/audaspace/src/fx/LowpassCalculator.cpp create mode 100644 extern/audaspace/src/fx/MutableReader.cpp create mode 100644 extern/audaspace/src/fx/MutableSound.cpp create mode 100644 extern/audaspace/src/fx/Pitch.cpp create mode 100644 extern/audaspace/src/fx/PitchReader.cpp create mode 100644 extern/audaspace/src/fx/PlaybackCategory.cpp create mode 100644 extern/audaspace/src/fx/PlaybackManager.cpp create mode 100644 extern/audaspace/src/fx/Reverse.cpp create mode 100644 extern/audaspace/src/fx/ReverseReader.cpp create mode 100644 extern/audaspace/src/fx/SoundList.cpp create mode 100644 extern/audaspace/src/fx/Source.cpp create mode 100644 extern/audaspace/src/fx/Sum.cpp create mode 100644 extern/audaspace/src/fx/Threshold.cpp create mode 100644 extern/audaspace/src/fx/Volume.cpp create mode 100644 extern/audaspace/src/fx/VolumeReader.cpp create mode 100644 extern/audaspace/src/fx/VolumeSound.cpp create mode 100644 extern/audaspace/src/fx/VolumeStorage.cpp (limited to 'extern/audaspace/src/fx') 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 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 ADSR::createReader() +{ + return std::shared_ptr(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 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 sound, + bool additive) : + Effect(sound), + m_additive(additive) +{ +} + +std::shared_ptr Accumulator::createReader() +{ + return std::shared_ptr(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 + +AUD_NAMESPACE_BEGIN + +BaseIIRFilterReader::BaseIIRFilterReader(std::shared_ptr 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 +#include +#include + +#define NUM_OUTCHANNELS 2 +#define NUM_CONVOLVERS 4 +#define CROSSFADE_SAMPLES 1024 + +AUD_NAMESPACE_BEGIN +BinauralReader::BinauralReader(std::shared_ptr reader, std::shared_ptr hrtfs, std::shared_ptr source, std::shared_ptr threadPool, std::shared_ptr 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(new Convolver(irs.first->getChannel(0), irs.first->getLength(), m_threadPool, plan))); + else + m_convolvers.push_back(std::unique_ptr(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 + +AUD_NAMESPACE_BEGIN + +BinauralSound::BinauralSound(std::shared_ptr sound, std::shared_ptr hrtfs, std::shared_ptr source, std::shared_ptr threadPool) : + BinauralSound(sound, hrtfs, source, threadPool, std::make_shared(0.0)) +{ +} + +BinauralSound::BinauralSound(std::shared_ptr sound, std::shared_ptr hrtfs, std::shared_ptr source, std::shared_ptr threadPool, std::shared_ptr plan) : + m_sound(sound), m_hrtfs(hrtfs), m_source(source), m_threadPool(threadPool), m_plan(plan) +{ +} + +std::shared_ptr BinauralSound::createReader() +{ + return std::make_shared(m_sound->createReader(), m_hrtfs, m_source, m_threadPool, m_plan); +} + +std::shared_ptr BinauralSound::getHRTFs() +{ + return m_hrtfs; +} + +void BinauralSound::setHRTFs(std::shared_ptr hrtfs) +{ + m_hrtfs = hrtfs; +} + +std::shared_ptr BinauralSound::getSource() +{ + return m_source; +} + +void BinauralSound::setSource(std::shared_ptr 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 sound, float frequency) : + DynamicIIRFilter(sound, std::shared_ptr(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 + +#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 &b, std::vector &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 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 +#include +#include +#include + +AUD_NAMESPACE_BEGIN +Convolver::Convolver(std::shared_ptr>>>> ir, int irLength, std::shared_ptr threadPool, std::shared_ptr 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(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(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*>(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*>(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>>>> Convolver::getImpulseResponse() +{ + return m_irBuffers; +} + +void Convolver::setImpulseResponse(std::shared_ptr>>>> 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*>(m_delayLine[i]), reinterpret_cast*>(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 +#include +#include +#include + +AUD_NAMESPACE_BEGIN +ConvolverReader::ConvolverReader(std::shared_ptr reader, std::shared_ptr ir, std::shared_ptr threadPool, std::shared_ptr 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(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(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 + +AUD_NAMESPACE_BEGIN + +ConvolverSound::ConvolverSound(std::shared_ptr sound, std::shared_ptr impulseResponse, std::shared_ptr threadPool) : + ConvolverSound(sound, impulseResponse, threadPool, std::make_shared(0.0)) +{ +} + +ConvolverSound::ConvolverSound(std::shared_ptr sound, std::shared_ptr impulseResponse, std::shared_ptr threadPool, std::shared_ptr plan) : + m_sound(sound), m_impulseResponse(impulseResponse), m_threadPool(threadPool), m_plan(plan) +{ +} + +std::shared_ptr ConvolverSound::createReader() +{ + return std::make_shared(m_sound->createReader(), m_impulseResponse, m_threadPool, m_plan); +} + +std::shared_ptr ConvolverSound::getImpulseResponse() +{ + return m_impulseResponse; +} + +void ConvolverSound::setImpulseResponse(std::shared_ptr 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 sound, float delay) : + Effect(sound), + m_delay(delay) +{ +} + +float Delay::getDelay() const +{ + return m_delay; +} + +std::shared_ptr Delay::createReader() +{ + return std::shared_ptr(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 + +AUD_NAMESPACE_BEGIN + +DelayReader::DelayReader(std::shared_ptr 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 sound, + std::shared_ptr calculator) : + Effect(sound), + m_calculator(calculator) +{ +} + +std::shared_ptr DynamicIIRFilter::createReader() +{ + return std::shared_ptr(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 reader, std::shared_ptr calculator) : + IIRFilterReader(reader, std::vector(), std::vector()), + m_calculator(calculator) +{ + sampleRateChanged(reader->getSpecs().rate); +} + +void DynamicIIRFilterReader::sampleRateChanged(SampleRate rate) +{ + std::vector 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 +#include + +AUD_NAMESPACE_BEGIN + +DynamicMusic::DynamicMusic(std::shared_ptr 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>(1, nullptr)); +} + +DynamicMusic::~DynamicMusic() +{ + stop(); +} + +int DynamicMusic::addScene(std::shared_ptr sound) +{ + std::vector> 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 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(volumegetVolume()) + 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(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(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 sound) +{ + m_sound = sound; +} + +Effect::~Effect() +{ +} + +std::shared_ptr 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 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 + +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 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 Envelope::createReader() +{ + std::shared_ptr reader = getReader(); + + EnvelopeParameters* param = new EnvelopeParameters(); + param->arthreshold = m_arthreshold; + param->attack = std::pow(m_arthreshold, 1.0f/(static_cast(reader->getSpecs().rate) * m_attack)); + param->release = std::pow(m_arthreshold, 1.0f/(static_cast(reader->getSpecs().rate) * m_release)); + param->threshold = m_threshold; + + return std::shared_ptr(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 +#include + +AUD_NAMESPACE_BEGIN + +FFTConvolver::FFTConvolver(std::shared_ptr>> ir, std::shared_ptr 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*>(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*>(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*>(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*>(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* inBuffer, std::complex* 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* accBuffer, int& length, fftwf_complex* transformedData) +{ + if(length > m_L || length <= 0) + { + length = 0; + return; + } + if(m_inBuffer == nullptr) + m_inBuffer = reinterpret_cast*>(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>> ir) +{ + clear(); + m_irBuffer = ir; +} + +std::shared_ptr>> 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 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 Fader::createReader() +{ + return std::shared_ptr(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 + +AUD_NAMESPACE_BEGIN + +FaderReader::FaderReader(std::shared_ptr 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 + +AUD_NAMESPACE_BEGIN +HRTF::HRTF() : + HRTF(std::make_shared(0.0)) +{ +} + +HRTF::HRTF(std::shared_ptr plan) : + m_plan(plan) +{ + m_specs.channels = CHANNELS_INVALID; + m_specs.rate = 0; + m_empty = true; +} + +bool HRTF::addImpulseResponse(std::shared_ptr 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, m_plan); + m_specs.channels = CHANNELS_MONO; + m_specs.rate = spec.rate; + m_empty = false; + return true; +} + +std::pair, std::shared_ptr> 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 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 +#include + +AUD_NAMESPACE_BEGIN + +std::shared_ptr HRTFLoader::loadLeftHRTFs(std::shared_ptr plan, const std::string& fileExtension, const std::string& path) +{ + std::shared_ptr hrtfs(std::make_shared(plan)); + loadHRTFs(hrtfs, 'L', fileExtension, path); + return hrtfs; +} + +std::shared_ptr HRTFLoader::loadRightHRTFs(std::shared_ptr plan, const std::string& fileExtension, const std::string& path) +{ + std::shared_ptr hrtfs(std::make_shared(plan)); + loadHRTFs(hrtfs, 'R', fileExtension, path); + return hrtfs; +} + +std::shared_ptr HRTFLoader::loadLeftHRTFs(const std::string& fileExtension, const std::string& path) +{ + std::shared_ptr hrtfs(std::make_shared()); + loadHRTFs(hrtfs, 'L', fileExtension, path); + return hrtfs; +} + +std::shared_ptr HRTFLoader::loadRightHRTFs(const std::string& fileExtension, const std::string& path) +{ + std::shared_ptr hrtfs(std::make_shared()); + loadHRTFs(hrtfs, 'R', fileExtension, path); + return hrtfs; +} + +void HRTFLoader::loadHRTFs(std::shared_ptr 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(std::make_shared(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 +#include + +AUD_NAMESPACE_BEGIN + +std::shared_ptr HRTFLoader::loadLeftHRTFs(std::shared_ptr plan, const std::string& fileExtension, const std::string& path) +{ + std::shared_ptr hrtfs(std::make_shared(plan)); + loadHRTFs(hrtfs, 'L', fileExtension, path); + return hrtfs; +} + +std::shared_ptr HRTFLoader::loadRightHRTFs(std::shared_ptr plan, const std::string& fileExtension, const std::string& path) +{ + std::shared_ptr hrtfs(std::make_shared(plan)); + loadHRTFs(hrtfs, 'R', fileExtension, path); + return hrtfs; +} + +std::shared_ptr HRTFLoader::loadLeftHRTFs(const std::string& fileExtension, const std::string& path) +{ + std::shared_ptr hrtfs(std::make_shared()); + loadHRTFs(hrtfs, 'L', fileExtension, path); + return hrtfs; +} + +std::shared_ptr HRTFLoader::loadRightHRTFs(const std::string& fileExtension, const std::string& path) +{ + std::shared_ptr hrtfs(std::make_shared()); + loadHRTFs(hrtfs, 'R', fileExtension, path); + return hrtfs; +} + +void HRTFLoader::loadHRTFs(std::shared_ptr 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(std::make_shared(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 sound, float frequency, float Q) : + DynamicIIRFilter(sound, std::shared_ptr(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 + +AUD_NAMESPACE_BEGIN + +HighpassCalculator::HighpassCalculator(float frequency, float Q) : + m_frequency(frequency), + m_Q(Q) +{ +} + +void HighpassCalculator::recalculateCoefficients(SampleRate rate, std::vector &b, std::vector &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 sound, const std::vector& b, const std::vector& a) : + Effect(sound), m_a(a), m_b(b) +{ +} + +std::shared_ptr IIRFilter::createReader() +{ + return std::shared_ptr(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 reader, const std::vector& b, const std::vector& 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& b, const std::vector& 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 +#include +#include +#include + +AUD_NAMESPACE_BEGIN +ImpulseResponse::ImpulseResponse(std::shared_ptr impulseResponse) : + ImpulseResponse(impulseResponse, std::make_shared(0.0)) +{ +} + +ImpulseResponse::ImpulseResponse(std::shared_ptr impulseResponse, std::shared_ptr 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>>>> ImpulseResponse::getChannel(int n) +{ + return m_processedIR[n]; +} + +void ImpulseResponse::processImpulseResponse(std::shared_ptr reader, std::shared_ptr 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>>>>()); + for(int j = 0; j < numParts; j++) + (*m_processedIR[i]).push_back(std::make_shared>>((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*>(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 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 Limiter::createReader() +{ + return std::shared_ptr(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 + +AUD_NAMESPACE_BEGIN + +LimiterReader::LimiterReader(std::shared_ptr 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 sound, int loop) : + Effect(sound), + m_loop(loop) +{ +} + +int Loop::getLoop() const +{ + return m_loop; +} + +std::shared_ptr Loop::createReader() +{ + return std::shared_ptr(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 + +AUD_NAMESPACE_BEGIN + +LoopReader::LoopReader(std::shared_ptr 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 sound, float frequency, float Q) : + DynamicIIRFilter(sound, std::shared_ptr(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 + +AUD_NAMESPACE_BEGIN + +LowpassCalculator::LowpassCalculator(float frequency, float Q) : + m_frequency(frequency), + m_Q(Q) +{ +} + +void LowpassCalculator::recalculateCoefficients(SampleRate rate, std::vector &b, std::vector &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 + +AUD_NAMESPACE_BEGIN + +MutableReader::MutableReader(std::shared_ptr 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 + +AUD_NAMESPACE_BEGIN + +MutableSound::MutableSound(std::shared_ptr sound) : +m_sound(sound) +{ +} + +std::shared_ptr MutableSound::createReader() +{ + return std::make_shared(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 sound, float pitch) : + Effect(sound), + m_pitch(pitch) +{ +} + +std::shared_ptr Pitch::createReader() +{ + return std::shared_ptr(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 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 device) : + m_device(device), m_volumeStorage(std::make_shared(1.0f)), m_status(STATUS_PLAYING), m_currentID(0) +{ +} + +PlaybackCategory::~PlaybackCategory() +{ + stop(); +} + +std::shared_ptr PlaybackCategory::play(std::shared_ptr sound) +{ + std::shared_ptr vs(std::make_shared(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 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(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 + +AUD_NAMESPACE_BEGIN +PlaybackManager::PlaybackManager(std::shared_ptr device) : + m_device(device), m_currentKey(0) +{ +} + +unsigned int PlaybackManager::addCategory(std::shared_ptr 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 category = std::make_shared(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 PlaybackManager::play(std::shared_ptr sound, unsigned int catKey) +{ + auto iter = m_categories.find(catKey); + std::shared_ptr category; + + if(iter != m_categories.end()) + { + category = iter->second; + } + else + { + category = std::make_shared(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 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 sound) : + Effect(sound) +{ +} + +std::shared_ptr Reverse::createReader() +{ + return std::shared_ptr(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 + +AUD_NAMESPACE_BEGIN + +ReverseReader::ReverseReader(std::shared_ptr 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 +#include +#include + +AUD_NAMESPACE_BEGIN + +SoundList::SoundList(bool random) : +m_random(random) +{ + std::srand(time(NULL)); +} + +SoundList::SoundList(std::vector>& list, bool random) : +m_list(list), m_random(random) +{ + std::srand(time(NULL)); +} + +std::shared_ptr 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 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 + +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 sound) : + Effect(sound) +{ +} + +std::shared_ptr Sum::createReader() +{ + std::vector a, b; + a.push_back(1); + a.push_back(-1); + b.push_back(1); + return std::shared_ptr(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 sound, float threshold) : + Effect(sound), + m_threshold(threshold) +{ +} + +float Threshold::getThreshold() const +{ + return m_threshold; +} + +std::shared_ptr Threshold::createReader() +{ + return std::shared_ptr(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 sound, float volume) : + Effect(sound), + m_volume(volume) +{ +} + +float Volume::getVolume() const +{ + return m_volume; +} + +std::shared_ptr Volume::createReader() +{ + std::vector a, b; + a.push_back(1); + b.push_back(m_volume); + return std::shared_ptr(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 + +AUD_NAMESPACE_BEGIN + +VolumeReader::VolumeReader(std::shared_ptr reader, std::shared_ptr 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 + +AUD_NAMESPACE_BEGIN + +VolumeSound::VolumeSound(std::shared_ptr sound, std::shared_ptr volumeStorage) : + m_sound(sound), m_volumeStorage(volumeStorage) +{ +} + +std::shared_ptr VolumeSound::createReader() +{ + return std::make_shared(m_sound->createReader(), m_volumeStorage); +} + +std::shared_ptr VolumeSound::getSharedVolume() +{ + return m_volumeStorage; +} + +void VolumeSound::setSharedVolume(std::shared_ptr 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 -- cgit v1.2.3