Audaspace: merging modulator effect from upstream.
This commit is contained in:
parent
acc20b117d
commit
322abc1428
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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<ISound>(new Modulator(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound), *reinterpret_cast<std::shared_ptr<ISound>*>(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
|
||||
},
|
||||
|
|
|
@ -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<ISound> m_sound1;
|
||||
|
||||
/**
|
||||
* Second played sound.
|
||||
*/
|
||||
std::shared_ptr<ISound> 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<ISound> sound1, std::shared_ptr<ISound> sound2);
|
||||
|
||||
virtual std::shared_ptr<IReader> createReader();
|
||||
};
|
||||
|
||||
AUD_NAMESPACE_END
|
|
@ -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 <memory>
|
||||
|
||||
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<IReader> m_reader1;
|
||||
|
||||
/**
|
||||
* The second reader.
|
||||
*/
|
||||
std::shared_ptr<IReader> 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<IReader> reader1, std::shared_ptr<IReader> 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
|
|
@ -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<ISound> sound1, std::shared_ptr<ISound> sound2) :
|
||||
m_sound1(sound1), m_sound2(sound2)
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<IReader> Modulator::createReader()
|
||||
{
|
||||
std::shared_ptr<IReader> reader1 = m_sound1->createReader();
|
||||
std::shared_ptr<IReader> reader2 = m_sound2->createReader();
|
||||
|
||||
return std::shared_ptr<IReader>(new ModulatorReader(reader1, reader2));
|
||||
}
|
||||
|
||||
AUD_NAMESPACE_END
|
|
@ -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 <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
AUD_NAMESPACE_BEGIN
|
||||
|
||||
ModulatorReader::ModulatorReader(std::shared_ptr<IReader> reader1, std::shared_ptr<IReader> 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
|
Loading…
Reference in New Issue