From 322abc14285e7722d98d4503c09d032cf2b22f6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20M=C3=BCller?= Date: Wed, 3 Apr 2019 19:56:25 +0200 Subject: Audaspace: merging modulator effect from upstream. --- extern/audaspace/CMakeLists.txt | 4 ++ extern/audaspace/bindings/C/AUD_Sound.cpp | 16 +++++ extern/audaspace/bindings/C/AUD_Sound.h | 8 +++ extern/audaspace/bindings/python/PySound.cpp | 45 +++++++++++++ extern/audaspace/include/fx/Modulator.h | 62 +++++++++++++++++ extern/audaspace/include/fx/ModulatorReader.h | 79 ++++++++++++++++++++++ extern/audaspace/src/fx/Modulator.cpp | 35 ++++++++++ extern/audaspace/src/fx/ModulatorReader.cpp | 95 +++++++++++++++++++++++++++ 8 files changed, 344 insertions(+) create mode 100644 extern/audaspace/include/fx/Modulator.h create mode 100644 extern/audaspace/include/fx/ModulatorReader.h create mode 100644 extern/audaspace/src/fx/Modulator.cpp create mode 100644 extern/audaspace/src/fx/ModulatorReader.cpp (limited to 'extern/audaspace') diff --git a/extern/audaspace/CMakeLists.txt b/extern/audaspace/CMakeLists.txt index de701a16500..c9f709b8c10 100644 --- a/extern/audaspace/CMakeLists.txt +++ b/extern/audaspace/CMakeLists.txt @@ -73,6 +73,8 @@ set(SRC src/fx/LoopReader.cpp src/fx/LowpassCalculator.cpp src/fx/Lowpass.cpp + src/fx/Modulator.cpp + src/fx/ModulatorReader.cpp src/fx/MutableReader.cpp src/fx/MutableSound.cpp src/fx/Pitch.cpp @@ -181,6 +183,8 @@ set(PUBLIC_HDR include/fx/LoopReader.h include/fx/LowpassCalculator.h include/fx/Lowpass.h + include/fx/Modulator.h + include/fx/ModulatorReader.h include/fx/MutableReader.h include/fx/MutableSound.h include/fx/Pitch.h diff --git a/extern/audaspace/bindings/C/AUD_Sound.cpp b/extern/audaspace/bindings/C/AUD_Sound.cpp index 1f40f5c608b..00a59f4c67f 100644 --- a/extern/audaspace/bindings/C/AUD_Sound.cpp +++ b/extern/audaspace/bindings/C/AUD_Sound.cpp @@ -32,6 +32,7 @@ #include "fx/Limiter.h" #include "fx/Loop.h" #include "fx/Lowpass.h" +#include "fx/Modulator.h" #include "fx/Pitch.h" #include "fx/Reverse.h" #include "fx/Sum.h" @@ -465,6 +466,21 @@ AUD_API AUD_Sound* AUD_Sound_lowpass(AUD_Sound* sound, float frequency, float Q) } } +AUD_API AUD_Sound* AUD_Sound_modulate(AUD_Sound* first, AUD_Sound* second) +{ + assert(first); + assert(second); + + try + { + return new AUD_Sound(new Modulator(*first, *second)); + } + catch(Exception&) + { + return nullptr; + } +} + AUD_API AUD_Sound* AUD_Sound_pitch(AUD_Sound* sound, float factor) { assert(sound); diff --git a/extern/audaspace/bindings/C/AUD_Sound.h b/extern/audaspace/bindings/C/AUD_Sound.h index b18e3c3a8eb..66d6c53cc37 100644 --- a/extern/audaspace/bindings/C/AUD_Sound.h +++ b/extern/audaspace/bindings/C/AUD_Sound.h @@ -246,6 +246,14 @@ extern AUD_API AUD_Sound* AUD_Sound_loop(AUD_Sound* sound, int count); */ extern AUD_API AUD_Sound* AUD_Sound_lowpass(AUD_Sound* sound, float frequency, float Q); +/** + * Modulates two sound, which means multiplying the sound samples. + * \param first The first sound. + * \param second The second sound. + * \return A handle of the modulated sound. + */ +extern AUD_API AUD_Sound* AUD_Sound_modulate(AUD_Sound* first, AUD_Sound* second); + /** * Changes the pitch of a sound. * \param sound The sound to change. diff --git a/extern/audaspace/bindings/python/PySound.cpp b/extern/audaspace/bindings/python/PySound.cpp index 82c6036012b..17fcdbeb938 100644 --- a/extern/audaspace/bindings/python/PySound.cpp +++ b/extern/audaspace/bindings/python/PySound.cpp @@ -42,6 +42,7 @@ #include "fx/Limiter.h" #include "fx/Loop.h" #include "fx/Lowpass.h" +#include "fx/Modulator.h" #include "fx/MutableSound.h" #include "fx/Pitch.h" #include "fx/Reverse.h" @@ -1129,6 +1130,47 @@ Sound_lowpass(Sound* self, PyObject* args) return (PyObject *)parent; } +PyDoc_STRVAR(M_aud_Sound_modulate_doc, + "modulate(sound)\n\n" + "Modulates two factories.\n\n" + ":arg sound: The sound to modulate over the other.\n" + ":type sound: :class:`Sound`\n" + ":return: The created :class:`Sound` object.\n" + ":rtype: :class:`Sound`\n\n" + ".. note:: The two factories have to have the same specifications " + "(channels and samplerate)."); + +static PyObject * +Sound_modulate(Sound* self, PyObject* object) +{ + PyTypeObject* type = Py_TYPE(self); + + if(!PyObject_TypeCheck(object, type)) + { + PyErr_SetString(PyExc_TypeError, "Object is not of type Sound!"); + return nullptr; + } + + Sound* parent = (Sound*)type->tp_alloc(type, 0); + Sound* child = (Sound*)object; + + if(parent != nullptr) + { + try + { + parent->sound = new std::shared_ptr(new Modulator(*reinterpret_cast*>(self->sound), *reinterpret_cast*>(child->sound))); + } + catch(Exception& e) + { + Py_DECREF(parent); + PyErr_SetString(AUDError, e.what()); + return nullptr; + } + } + + return (PyObject *)parent; +} + PyDoc_STRVAR(M_aud_Sound_pitch_doc, "pitch(factor)\n\n" "Changes the pitch of a sound with a specific factor.\n\n" @@ -1791,6 +1833,9 @@ static PyMethodDef Sound_methods[] = { {"lowpass", (PyCFunction)Sound_lowpass, METH_VARARGS, M_aud_Sound_lowpass_doc }, + {"modulate", (PyCFunction)Sound_modulate, METH_O, + M_aud_Sound_modulate_doc + }, {"pitch", (PyCFunction)Sound_pitch, METH_VARARGS, M_aud_Sound_pitch_doc }, diff --git a/extern/audaspace/include/fx/Modulator.h b/extern/audaspace/include/fx/Modulator.h new file mode 100644 index 00000000000..db79d4aae84 --- /dev/null +++ b/extern/audaspace/include/fx/Modulator.h @@ -0,0 +1,62 @@ +/******************************************************************************* + * 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. + ******************************************************************************/ + +#pragma once + +/** + * @file Modulator.h + * @ingroup fx + * The Modulator class. + */ + +#include "ISound.h" + +AUD_NAMESPACE_BEGIN + +/** + * This sound plays two other factories, playing them the same time and modulating/multiplying them. + * \note Readers from the underlying factories must have the same sample rate + * and channel count. + */ +class AUD_API Modulator : public ISound +{ +private: + /** + * First played sound. + */ + std::shared_ptr m_sound1; + + /** + * Second played sound. + */ + std::shared_ptr m_sound2; + + // delete copy constructor and operator= + Modulator(const Modulator&) = delete; + Modulator& operator=(const Modulator&) = delete; + +public: + /** + * Creates a new modulator sound. + * \param sound1 The first input sound. + * \param sound2 The second input sound. + */ + Modulator(std::shared_ptr sound1, std::shared_ptr sound2); + + virtual std::shared_ptr createReader(); +}; + +AUD_NAMESPACE_END diff --git a/extern/audaspace/include/fx/ModulatorReader.h b/extern/audaspace/include/fx/ModulatorReader.h new file mode 100644 index 00000000000..40cc84332a9 --- /dev/null +++ b/extern/audaspace/include/fx/ModulatorReader.h @@ -0,0 +1,79 @@ +/******************************************************************************* + * 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. + ******************************************************************************/ + +#pragma once + +/** + * @file ModulatorReader.h + * @ingroup fx + * The ModulatorReader class. + */ + +#include "IReader.h" +#include "util/Buffer.h" + +#include + +AUD_NAMESPACE_BEGIN + +/** + * This reader plays two readers with the same specs in parallel multiplying their samples. + */ +class AUD_API ModulatorReader : public IReader +{ +private: + /** + * The first reader. + */ + std::shared_ptr m_reader1; + + /** + * The second reader. + */ + std::shared_ptr m_reader2; + + /** + * Buffer used for mixing. + */ + Buffer m_buffer; + + // delete copy constructor and operator= + ModulatorReader(const ModulatorReader&) = delete; + ModulatorReader& operator=(const ModulatorReader&) = delete; + +public: + /** + * Creates a new modulator reader. + * \param reader1 The first reader to read from. + * \param reader2 The second reader to read from. + * \exception Exception Thrown if the specs from the readers differ. + */ + ModulatorReader(std::shared_ptr reader1, std::shared_ptr reader2); + + /** + * Destroys the reader. + */ + virtual ~ModulatorReader(); + + virtual bool isSeekable() const; + virtual void seek(int position); + virtual int getLength() const; + virtual int getPosition() const; + virtual Specs getSpecs() const; + virtual void read(int& length, bool& eos, sample_t* buffer); +}; + +AUD_NAMESPACE_END diff --git a/extern/audaspace/src/fx/Modulator.cpp b/extern/audaspace/src/fx/Modulator.cpp new file mode 100644 index 00000000000..a1af1b8c012 --- /dev/null +++ b/extern/audaspace/src/fx/Modulator.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/Modulator.h" +#include "fx/ModulatorReader.h" + +AUD_NAMESPACE_BEGIN + +Modulator::Modulator(std::shared_ptr sound1, std::shared_ptr sound2) : + m_sound1(sound1), m_sound2(sound2) +{ +} + +std::shared_ptr Modulator::createReader() +{ + std::shared_ptr reader1 = m_sound1->createReader(); + std::shared_ptr reader2 = m_sound2->createReader(); + + return std::shared_ptr(new ModulatorReader(reader1, reader2)); +} + +AUD_NAMESPACE_END diff --git a/extern/audaspace/src/fx/ModulatorReader.cpp b/extern/audaspace/src/fx/ModulatorReader.cpp new file mode 100644 index 00000000000..c17cee08239 --- /dev/null +++ b/extern/audaspace/src/fx/ModulatorReader.cpp @@ -0,0 +1,95 @@ +/******************************************************************************* + * 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/ModulatorReader.h" +#include "Exception.h" + +#include +#include + +AUD_NAMESPACE_BEGIN + +ModulatorReader::ModulatorReader(std::shared_ptr reader1, std::shared_ptr reader2) : + m_reader1(reader1), m_reader2(reader2) +{ +} + +ModulatorReader::~ModulatorReader() +{ +} + +bool ModulatorReader::isSeekable() const +{ + return m_reader1->isSeekable() && m_reader2->isSeekable(); +} + +void ModulatorReader::seek(int position) +{ + m_reader1->seek(position); + m_reader2->seek(position); +} + +int ModulatorReader::getLength() const +{ + int len1 = m_reader1->getLength(); + int len2 = m_reader2->getLength(); + if((len1 < 0) || (len2 < 0)) + return -1; + return std::min(len1, len2); +} + +int ModulatorReader::getPosition() const +{ + int pos1 = m_reader1->getPosition(); + int pos2 = m_reader2->getPosition(); + return std::max(pos1, pos2); +} + +Specs ModulatorReader::getSpecs() const +{ + return m_reader1->getSpecs(); +} + +void ModulatorReader::read(int& length, bool& eos, sample_t* buffer) +{ + Specs specs = m_reader1->getSpecs(); + Specs s2 = m_reader2->getSpecs(); + if(!AUD_COMPARE_SPECS(specs, s2)) + AUD_THROW(StateException, "Two readers with different specifiactions cannot be modulated."); + + int samplesize = AUD_SAMPLE_SIZE(specs); + + m_buffer.assureSize(length * samplesize); + + int len1 = length; + m_reader1->read(len1, eos, buffer); + + if(len1 < length) + std::memset(buffer + len1 * specs.channels, 0, (length - len1) * samplesize); + + int len2 = length; + bool eos2; + sample_t* buf = m_buffer.getBuffer(); + m_reader2->read(len2, eos2, buf); + + for(int i = 0; i < len2 * specs.channels; i++) + buffer[i] *= buf[i]; + + length = std::max(len1, len2); + eos &= eos2; +} + +AUD_NAMESPACE_END -- cgit v1.2.3