Audaspace: porting changes from upstream.
This change introduces animated time stretching and pitch scaling. It also extends the Python API with AnimateableProperty. Note: to be used, this still needs rubberband. Credit: Kacey La
This commit is contained in:
2
extern/audaspace/AUTHORS
vendored
2
extern/audaspace/AUTHORS
vendored
@@ -27,7 +27,7 @@ The pipewire backend and many fixes have been provided by
|
||||
|
||||
- Sebastian Parborg
|
||||
|
||||
The rubberband integration (for time stretching and pitch scaling has been provided by
|
||||
The rubberband integration (for time stretching and pitch scaling) has been provided by
|
||||
|
||||
- Kacey La
|
||||
|
||||
|
||||
6
extern/audaspace/CMakeLists.txt
vendored
6
extern/audaspace/CMakeLists.txt
vendored
@@ -803,10 +803,14 @@ if(WITH_RUBBERBAND)
|
||||
set(RUBBERBAND_SRC
|
||||
src/fx/TimeStretchPitchScale.cpp
|
||||
src/fx/TimeStretchPitchScaleReader.cpp
|
||||
src/fx/AnimateableTimeStretchPitchScale.cpp
|
||||
src/fx/AnimateableTimeStretchPitchScaleReader.cpp
|
||||
)
|
||||
set(RUBBERBAND_HDR
|
||||
include/fx/TimeStretchPitchScale.h
|
||||
include/fx/TimeStretchPitchScaleReader.h
|
||||
include/fx/AnimateableTimeStretchPitchScale.h
|
||||
include/fx/AnimateableTimeStretchPitchScaleReader.h
|
||||
)
|
||||
|
||||
add_definitions(-DWITH_RUBBERBAND)
|
||||
@@ -1174,6 +1178,7 @@ endif()
|
||||
|
||||
if(WITH_PYTHON)
|
||||
set(PYTHON_SRC
|
||||
bindings/python/PyAnimateableProperty.cpp
|
||||
bindings/python/PyAPI.cpp
|
||||
bindings/python/PyDevice.cpp
|
||||
bindings/python/PyDynamicMusic.cpp
|
||||
@@ -1186,6 +1191,7 @@ if(WITH_PYTHON)
|
||||
bindings/python/PyThreadPool.cpp
|
||||
)
|
||||
set(PYTHON_HDR
|
||||
bindings/python/PyAnimateableProperty.h
|
||||
bindings/python/PyAPI.h
|
||||
bindings/python/PyDevice.h
|
||||
bindings/python/PyDynamicMusic.h
|
||||
|
||||
10
extern/audaspace/bindings/C/AUD_Sequence.h
vendored
10
extern/audaspace/bindings/C/AUD_Sequence.h
vendored
@@ -22,16 +22,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// Possible animatable properties for Sequence Factories and Entries.
|
||||
typedef enum
|
||||
{
|
||||
AUD_AP_VOLUME,
|
||||
AUD_AP_PANNING,
|
||||
AUD_AP_PITCH,
|
||||
AUD_AP_LOCATION,
|
||||
AUD_AP_ORIENTATION
|
||||
} AUD_AnimateablePropertyType;
|
||||
|
||||
/**
|
||||
* Creates a new sequenced sound scene.
|
||||
* \param fps The FPS of the scene.
|
||||
|
||||
50
extern/audaspace/bindings/C/AUD_Sound.cpp
vendored
50
extern/audaspace/bindings/C/AUD_Sound.cpp
vendored
@@ -59,6 +59,7 @@
|
||||
|
||||
#ifdef WITH_RUBBERBAND
|
||||
#include "fx/TimeStretchPitchScale.h"
|
||||
#include "fx/AnimateableTimeStretchPitchScale.h"
|
||||
#endif
|
||||
|
||||
#include <cassert>
|
||||
@@ -795,7 +796,7 @@ AUD_API AUD_Sound* AUD_Sound_equalize(AUD_Sound* sound, float *definition, int s
|
||||
#endif
|
||||
|
||||
#ifdef WITH_RUBBERBAND
|
||||
AUD_API AUD_Sound* AUD_Sound_timeStretchPitchScale(AUD_Sound* sound, double timeRatio, double pitchScale, AUD_StretcherQuality quality, bool preserveFormant)
|
||||
AUD_API AUD_Sound* AUD_Sound_timeStretchPitchScale(AUD_Sound* sound, double timeRatio, double pitchScale, AUD_StretcherQuality quality, char preserveFormant)
|
||||
{
|
||||
assert(sound);
|
||||
try
|
||||
@@ -807,4 +808,51 @@ AUD_API AUD_Sound* AUD_Sound_timeStretchPitchScale(AUD_Sound* sound, double time
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
AUD_API AUD_Sound* AUD_Sound_animateableTimeStretchPitchScale(AUD_Sound* sound, float fps, double timeRatio, double pitchScale, AUD_StretcherQuality quality, char preserveFormant)
|
||||
{
|
||||
assert(sound);
|
||||
try
|
||||
{
|
||||
return new AUD_Sound(new AnimateableTimeStretchPitchScale(*sound, fps, timeRatio, pitchScale, static_cast<StretcherQuality>(quality), preserveFormant));
|
||||
}
|
||||
catch(Exception&)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
AUD_API void AUD_Sound_animateableTimeStretchPitchScale_setConstantRangeAnimationData(AUD_Sound* sound, AUD_AnimateablePropertyType type, int frame_start, int frame_end,
|
||||
float* data)
|
||||
{
|
||||
std::shared_ptr<AnimateableProperty> prop = std::dynamic_pointer_cast<AnimateableTimeStretchPitchScale>(*sound)->getAnimProperty(static_cast<AnimateablePropertyType>(type));
|
||||
prop->writeConstantRange(data, frame_start, frame_end);
|
||||
}
|
||||
|
||||
AUD_API void AUD_Sound_animateableTimeStretchPitchScale_setAnimationData(AUD_Sound* sound, AUD_AnimateablePropertyType type, int frame, float* data, char animated)
|
||||
{
|
||||
std::shared_ptr<AnimateableProperty> prop = std::dynamic_pointer_cast<AnimateableTimeStretchPitchScale>(*sound)->getAnimProperty(static_cast<AnimateablePropertyType>(type));
|
||||
if(animated)
|
||||
{
|
||||
if(frame >= 0)
|
||||
prop->write(data, frame, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
prop->write(data);
|
||||
}
|
||||
}
|
||||
|
||||
AUD_API float AUD_Sound_animateableTimeStretchPitchScale_getFPS(AUD_Sound* sound)
|
||||
{
|
||||
assert(sound);
|
||||
return dynamic_cast<AnimateableTimeStretchPitchScale*>(sound->get())->getFPS();
|
||||
}
|
||||
|
||||
AUD_API void AUD_Sound_animateableTimeStretchPitchScale_setFPS(AUD_Sound* sound, float value)
|
||||
{
|
||||
assert(sound);
|
||||
dynamic_cast<AnimateableTimeStretchPitchScale*>(sound->get())->setFPS(value);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
50
extern/audaspace/bindings/C/AUD_Sound.h
vendored
50
extern/audaspace/bindings/C/AUD_Sound.h
vendored
@@ -419,7 +419,55 @@ extern AUD_API AUD_Sound* AUD_Sound_mutable(AUD_Sound* sound);
|
||||
* \param preserveFormant Whether to preserve the vocal formants for the stretcher.
|
||||
* \return A handle of the time-stretched, pitch scaled sound.
|
||||
*/
|
||||
extern AUD_API AUD_Sound* AUD_Sound_timeStretchPitchScale(AUD_Sound* sound, double timeRatio, double pitchScale, AUD_StretcherQuality quality, bool preserveFormant);
|
||||
extern AUD_API AUD_Sound* AUD_Sound_timeStretchPitchScale(AUD_Sound* sound, double timeRatio, double pitchScale, AUD_StretcherQuality quality, char preserveFormant);
|
||||
|
||||
/**
|
||||
* Time-stretches and pitch scales a sound with animation support
|
||||
* \param sound The handle of the sound.
|
||||
* \param fps The fps
|
||||
* \param timeRatio The initial factor by which to stretch or compress time.
|
||||
* \param pitchScale The initial factor by which to adjust the pitch.
|
||||
* \param quality The processing quality level of the stretcher.
|
||||
* \param preserveFormant Whether to preserve the vocal formants for the stretcher.
|
||||
* \return A handle of the time-stretched, pitch scaled sound.
|
||||
*/
|
||||
extern AUD_API AUD_Sound* AUD_Sound_animateableTimeStretchPitchScale(AUD_Sound* sound, float fps, double timeRatio, double pitchScale, AUD_StretcherQuality quality,
|
||||
char preserveFormant);
|
||||
|
||||
/**
|
||||
* Writes animation data to the AnimatableTimeStretchPitchScale effect
|
||||
* \param sequence The sound scene.
|
||||
* \param type The type of animation data.
|
||||
* \param frame_start Start of the frame range.
|
||||
* \param frame_end End of the frame range.
|
||||
* \param data The data to write.
|
||||
*/
|
||||
AUD_API void AUD_Sound_animateableTimeStretchPitchScale_setConstantRangeAnimationData(AUD_Sound* sound, AUD_AnimateablePropertyType type, int frame_start, int frame_end,
|
||||
float* data);
|
||||
|
||||
/**
|
||||
* Writes animation data to the AnimatableTimeStretchPitchScale effect
|
||||
* \param entry The sequenced entry.
|
||||
* \param type The type of animation data.
|
||||
* \param frame The frame this data is for.
|
||||
* \param data The data to write.
|
||||
* \param animated Whether the attribute is animated.
|
||||
*/
|
||||
extern AUD_API void AUD_Sound_animateableTimeStretchPitchScale_setAnimationData(AUD_Sound* sound, AUD_AnimateablePropertyType type, int frame, float* data, char animated);
|
||||
|
||||
/**
|
||||
* Sets the fps of an animated time-stretch, pitch-scaled sound.
|
||||
* \param sound The sound to set the fps from.
|
||||
* \param value The new fps to set.
|
||||
*/
|
||||
extern AUD_API void AUD_Sound_animateableTimeStretchPitchScale_setFPS(AUD_Sound* sound, AUD_AnimateablePropertyType type, int frame, float* data, char animated);
|
||||
|
||||
/**
|
||||
* Retrieves the fps of an animated time-stretch, pitch-scaled sound.
|
||||
* \param sequence The sound to get the fps from.
|
||||
* \return The fps of the sound.
|
||||
*/
|
||||
extern AUD_API float AUD_Sound_animateableTimeStretchPitchScale_getFPS(AUD_Sound* sequence);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
12
extern/audaspace/bindings/C/AUD_Types.h
vendored
12
extern/audaspace/bindings/C/AUD_Types.h
vendored
@@ -210,3 +210,15 @@ typedef enum
|
||||
AUD_STRETCHER_QUALITY_FAST = 1, /// Prioritize speed over audio quality
|
||||
AUD_STRETCHER_QUALITY_CONSISTENT = 2 /// Prioritize consistency for dynamic pitch changes
|
||||
} AUD_StretcherQuality;
|
||||
|
||||
/// Possible animatable properties for Sequence Factories and Entries.
|
||||
typedef enum
|
||||
{
|
||||
AUD_AP_VOLUME,
|
||||
AUD_AP_PANNING,
|
||||
AUD_AP_PITCH,
|
||||
AUD_AP_LOCATION,
|
||||
AUD_AP_ORIENTATION,
|
||||
AUD_AP_TIME_STRETCH,
|
||||
AUD_AP_PITCH_SCALE
|
||||
} AUD_AnimateablePropertyType;
|
||||
7
extern/audaspace/bindings/python/PyAPI.cpp
vendored
7
extern/audaspace/bindings/python/PyAPI.cpp
vendored
@@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
|
||||
#include "PyAnimateableProperty.h"
|
||||
#include "PyAPI.h"
|
||||
#include "PySound.h"
|
||||
#include "PyHandle.h"
|
||||
@@ -104,6 +105,9 @@ PyInit_aud()
|
||||
if(!initializeSource())
|
||||
return nullptr;
|
||||
|
||||
if(!initializeAnimateableProperty())
|
||||
return nullptr;
|
||||
|
||||
#ifdef WITH_CONVOLUTION
|
||||
if(!initializeImpulseResponse())
|
||||
return nullptr;
|
||||
@@ -116,6 +120,7 @@ PyInit_aud()
|
||||
if(module == nullptr)
|
||||
return nullptr;
|
||||
|
||||
addAnimateablePropertyToModule(module);
|
||||
addSoundToModule(module);
|
||||
addHandleToModule(module);
|
||||
addDeviceToModule(module);
|
||||
@@ -141,6 +146,8 @@ PyInit_aud()
|
||||
PY_MODULE_ADD_CONSTANT(module, AP_PITCH);
|
||||
PY_MODULE_ADD_CONSTANT(module, AP_LOCATION);
|
||||
PY_MODULE_ADD_CONSTANT(module, AP_ORIENTATION);
|
||||
PY_MODULE_ADD_CONSTANT(module, AP_TIME_STRETCH);
|
||||
PY_MODULE_ADD_CONSTANT(module, AP_PITCH_SCALE);
|
||||
// channels constants
|
||||
PY_MODULE_ADD_CONSTANT(module, CHANNELS_INVALID);
|
||||
PY_MODULE_ADD_CONSTANT(module, CHANNELS_MONO);
|
||||
|
||||
398
extern/audaspace/bindings/python/PyAnimateableProperty.cpp
vendored
Normal file
398
extern/audaspace/bindings/python/PyAnimateableProperty.cpp
vendored
Normal file
@@ -0,0 +1,398 @@
|
||||
/*******************************************************************************
|
||||
* Copyright 2009-2025 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 "PyAnimateableProperty.h"
|
||||
|
||||
#include "Exception.h"
|
||||
|
||||
#include "sequence/AnimateableProperty.h"
|
||||
|
||||
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
|
||||
#include <memory>
|
||||
|
||||
#include <numpy/ndarrayobject.h>
|
||||
|
||||
using namespace aud;
|
||||
|
||||
extern PyObject* AUDError;
|
||||
|
||||
static PyObject* AnimateableProperty_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
|
||||
{
|
||||
AnimateablePropertyP* self = (AnimateablePropertyP*) type->tp_alloc(type, 0);
|
||||
|
||||
int count;
|
||||
float value;
|
||||
|
||||
if(self != nullptr)
|
||||
{
|
||||
if(!PyArg_ParseTuple(args, "i|f:animateableProperty", &count, &value))
|
||||
return nullptr;
|
||||
|
||||
try
|
||||
{
|
||||
if(PyTuple_Size(args) == 1)
|
||||
{
|
||||
self->animateableProperty = new std::shared_ptr<aud::AnimateableProperty>(new aud::AnimateableProperty(count));
|
||||
}
|
||||
else
|
||||
{
|
||||
self->animateableProperty = new std::shared_ptr<aud::AnimateableProperty>(new aud::AnimateableProperty(count, value));
|
||||
}
|
||||
}
|
||||
catch(aud::Exception& e)
|
||||
{
|
||||
Py_DECREF(self);
|
||||
PyErr_SetString(AUDError, e.what());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return (PyObject*) self;
|
||||
}
|
||||
|
||||
static void AnimateableProperty_dealloc(AnimateablePropertyP* self)
|
||||
{
|
||||
if(self->animateableProperty)
|
||||
delete reinterpret_cast<std::shared_ptr<aud::AnimateableProperty>*>(self->animateableProperty);
|
||||
Py_TYPE(self)->tp_free((PyObject*) self);
|
||||
}
|
||||
|
||||
static PyObject* AnimateableProperty_read(AnimateablePropertyP* self, PyObject* args)
|
||||
{
|
||||
float position;
|
||||
|
||||
if(!PyArg_ParseTuple(args, "f", &position))
|
||||
return nullptr;
|
||||
|
||||
int count = (*reinterpret_cast<std::shared_ptr<aud::AnimateableProperty>*>(self->animateableProperty))->getCount();
|
||||
npy_intp dims[1] = {count};
|
||||
PyObject* np_array = PyArray_SimpleNew(1, dims, NPY_FLOAT32);
|
||||
if(!np_array)
|
||||
return nullptr;
|
||||
|
||||
float* out = static_cast<float*>(PyArray_DATA(reinterpret_cast<PyArrayObject*>(np_array)));
|
||||
|
||||
try
|
||||
{
|
||||
(*reinterpret_cast<std::shared_ptr<aud::AnimateableProperty>*>(self->animateableProperty))->read(position, out);
|
||||
return np_array;
|
||||
}
|
||||
catch(aud::Exception& e)
|
||||
{
|
||||
Py_DECREF(np_array);
|
||||
PyErr_SetString(AUDError, e.what());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(M_aud_AnimateableProperty_read_doc, ".. method:: read(position)\n\n"
|
||||
" Reads the properties value at the given position.\n\n"
|
||||
" :param position: The position in the animation in frames.\n"
|
||||
" :type position: float\n"
|
||||
" :return: A numpy array of values representing the properties value.\n"
|
||||
" :rtype: :class:`numpy.ndarray`\n");
|
||||
|
||||
static PyObject* AnimateableProperty_readSingle(AnimateablePropertyP* self, PyObject* args)
|
||||
{
|
||||
float position;
|
||||
|
||||
if(!PyArg_ParseTuple(args, "f", &position))
|
||||
return nullptr;
|
||||
|
||||
try
|
||||
{
|
||||
float value = (*reinterpret_cast<std::shared_ptr<aud::AnimateableProperty>*>(self->animateableProperty))->readSingle(position);
|
||||
return Py_BuildValue("f", value);
|
||||
}
|
||||
catch(aud::Exception& e)
|
||||
{
|
||||
PyErr_SetString(AUDError, e.what());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(M_aud_AnimateableProperty_readSingle_doc, ".. method:: readSingle(position)\n\n"
|
||||
" Reads the properties value at the given position, assuming there is exactly one value.\n\n"
|
||||
" :param position: The position in the animation in frames.\n"
|
||||
" :type position: float\n"
|
||||
" :return: The value at that position.\n"
|
||||
" :rtype: float\n\n");
|
||||
|
||||
static PyObject* AnimateableProperty_write(AnimateablePropertyP* self, PyObject* args)
|
||||
{
|
||||
PyObject* array_obj;
|
||||
int position = -1;
|
||||
|
||||
if(!PyArg_ParseTuple(args, "O|i", &array_obj, &position))
|
||||
return nullptr;
|
||||
|
||||
PyArrayObject* np_array = reinterpret_cast<PyArrayObject*>(PyArray_FROM_OTF(array_obj, NPY_FLOAT32, NPY_ARRAY_IN_ARRAY | NPY_ARRAY_FORCECAST));
|
||||
|
||||
if(!np_array)
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "data must be a numpy array of dtype float32");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto& prop = *reinterpret_cast<std::shared_ptr<aud::AnimateableProperty>*>(self->animateableProperty);
|
||||
int prop_count = prop->getCount();
|
||||
npy_intp size = PyArray_SIZE(np_array);
|
||||
|
||||
int ndim = PyArray_NDIM(np_array);
|
||||
|
||||
bool valid_shape = false;
|
||||
|
||||
// For 1D arrays, the total number of elements must be a multiple of the property count
|
||||
if(ndim == 1)
|
||||
{
|
||||
valid_shape = (size % prop_count == 0);
|
||||
}
|
||||
// For 2D arrays, the number of elements in the second dimension must be the property count
|
||||
else if(ndim == 2)
|
||||
{
|
||||
npy_intp* shape = PyArray_DIMS(np_array);
|
||||
valid_shape = (shape[1] == prop_count);
|
||||
}
|
||||
|
||||
if(!valid_shape)
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "array shape is invalid: must be 1D with length multiple of property count or 2D with the last dimension equal to property count");
|
||||
Py_DECREF(np_array);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int count = static_cast<int>(size / prop_count);
|
||||
|
||||
if(count < 1)
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "input array must have at least 1 element");
|
||||
Py_DECREF(np_array);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
float* data_ptr = reinterpret_cast<float*>(PyArray_DATA(np_array));
|
||||
try
|
||||
{
|
||||
if(position == -1)
|
||||
{
|
||||
if(count != 1)
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "input array must have exactly 1 element when position is not specified");
|
||||
Py_DECREF(np_array);
|
||||
return nullptr;
|
||||
}
|
||||
prop->write(data_ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
prop->write(data_ptr, position, count);
|
||||
}
|
||||
}
|
||||
catch(aud::Exception& e)
|
||||
{
|
||||
PyErr_SetString(AUDError, e.what());
|
||||
}
|
||||
|
||||
Py_DECREF(np_array);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(M_aud_AnimateableProperty_write_doc, ".. method:: write(data[, position])\n\n"
|
||||
" Writes the properties value.\n\n"
|
||||
" If `position` is also given, the property is marked animated and\n"
|
||||
" the values are written starting at `position`.\n\n"
|
||||
" :param data: numpy array of float32 values.\n"
|
||||
" :type data: numpy.ndarray\n"
|
||||
" :param position: The starting position in frames.\n"
|
||||
" :type position: int\n\n");
|
||||
|
||||
static PyObject* AnimateableProperty_writeConstantRange(AnimateablePropertyP* self, PyObject* args)
|
||||
{
|
||||
PyObject* array_obj;
|
||||
int position_start;
|
||||
int position_end;
|
||||
|
||||
if(!PyArg_ParseTuple(args, "Oii", &array_obj, &position_start, &position_end))
|
||||
return nullptr;
|
||||
|
||||
PyArrayObject* np_array = reinterpret_cast<PyArrayObject*>(PyArray_FROM_OTF(array_obj, NPY_FLOAT32, NPY_ARRAY_IN_ARRAY | NPY_ARRAY_FORCECAST));
|
||||
if(!np_array)
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "data must be a numpy array of dtype float32");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int ndim = PyArray_NDIM(np_array);
|
||||
if(ndim != 1)
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "data must be a 1D numpy array");
|
||||
Py_DECREF(np_array);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
float* data_ptr = reinterpret_cast<float*>(PyArray_DATA(np_array));
|
||||
|
||||
auto& prop = *reinterpret_cast<std::shared_ptr<aud::AnimateableProperty>*>(self->animateableProperty);
|
||||
int prop_count = prop->getCount();
|
||||
|
||||
npy_intp size = PyArray_SIZE(np_array);
|
||||
|
||||
if(size != prop_count)
|
||||
{
|
||||
PyErr_Format(PyExc_ValueError, "input array length (%lld) does not match property count (%d)", size, prop_count);
|
||||
Py_DECREF(np_array);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
prop->writeConstantRange(data_ptr, position_start, position_end);
|
||||
}
|
||||
catch(aud::Exception& e)
|
||||
{
|
||||
PyErr_SetString(AUDError, e.what());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Py_DECREF(np_array);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(M_aud_AnimateableProperty_writeConstantRange_doc, ".. method:: writeConstantRange(data, position_start, position_end)\n\n"
|
||||
" Fills the properties frame range with a constant value and marks it animated.\n\n"
|
||||
" :param data: numpy array of float values representing the constant value.\n"
|
||||
" :type data: numpy.ndarray\n"
|
||||
" :param position_start: The start position in frames.\n"
|
||||
" :type position_start: int\n"
|
||||
" :param position_end: The end position in frames.\n"
|
||||
" :type position_end: int\n\n");
|
||||
|
||||
static PyMethodDef AnimateableProperty_methods[] = {
|
||||
|
||||
{(char*) "read", (PyCFunction) AnimateableProperty_read, METH_VARARGS, M_aud_AnimateableProperty_read_doc},
|
||||
{(char*) "readSingle", (PyCFunction) AnimateableProperty_readSingle, METH_VARARGS, M_aud_AnimateableProperty_readSingle_doc},
|
||||
{(char*) "write", (PyCFunction) AnimateableProperty_write, METH_VARARGS, M_aud_AnimateableProperty_write_doc},
|
||||
{(char*) "writeConstantRange", (PyCFunction) AnimateableProperty_writeConstantRange, METH_VARARGS, M_aud_AnimateableProperty_writeConstantRange_doc},
|
||||
{nullptr} /* Sentinel */
|
||||
};
|
||||
|
||||
static PyObject* AnimateableProperty_get_count(AnimateablePropertyP* self, void* nothing)
|
||||
{
|
||||
try
|
||||
{
|
||||
int count = (*reinterpret_cast<std::shared_ptr<aud::AnimateableProperty>*>(self->animateableProperty))->getCount();
|
||||
return Py_BuildValue("i", count);
|
||||
}
|
||||
catch(aud::Exception& e)
|
||||
{
|
||||
PyErr_SetString(AUDError, e.what());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(M_aud_AnimateableProperty_count_doc, "The count of floats for a property.");
|
||||
|
||||
static PyObject* AnimateableProperty_get_animated(AnimateablePropertyP* self, void* nothing)
|
||||
{
|
||||
try
|
||||
{
|
||||
bool animated = (*reinterpret_cast<std::shared_ptr<aud::AnimateableProperty>*>(self->animateableProperty))->isAnimated();
|
||||
return PyBool_FromLong(animated);
|
||||
}
|
||||
catch(aud::Exception& e)
|
||||
{
|
||||
PyErr_SetString(AUDError, e.what());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(M_aud_AnimateableProperty_animated_doc, "Whether the property is animated.");
|
||||
|
||||
static PyGetSetDef AnimateableProperty_properties[] = {
|
||||
{(char*) "count", (getter) AnimateableProperty_get_count, nullptr, M_aud_AnimateableProperty_count_doc, nullptr},
|
||||
{(char*) "animated", (getter) AnimateableProperty_get_animated, nullptr, M_aud_AnimateableProperty_animated_doc, nullptr},
|
||||
{nullptr} /* Sentinel */
|
||||
};
|
||||
|
||||
PyDoc_STRVAR(M_aud_AnimateableProperty_doc, "An AnimateableProperty object stores an array of float values for animating sound properties (e.g. pan, volume, pitch-scale)");
|
||||
|
||||
// Note that AnimateablePropertyType name is already taken
|
||||
PyTypeObject AnimateablePropertyPyType = {
|
||||
PyVarObject_HEAD_INIT(nullptr, 0) "aud.AnimateableProperty", /* tp_name */
|
||||
sizeof(AnimateablePropertyP), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
(destructor) AnimateableProperty_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_reserved */
|
||||
0, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||
M_aud_AnimateableProperty_doc, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
AnimateableProperty_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
AnimateableProperty_properties, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
AnimateableProperty_new, /* tp_new */
|
||||
};
|
||||
|
||||
AUD_API PyObject* AnimateableProperty_empty()
|
||||
{
|
||||
return AnimateablePropertyPyType.tp_alloc(&AnimateablePropertyPyType, 0);
|
||||
}
|
||||
|
||||
AUD_API AnimateablePropertyP* checkAnimateableProperty(PyObject* animateableProperty)
|
||||
{
|
||||
if(!PyObject_TypeCheck(animateableProperty, &AnimateablePropertyPyType))
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "Object is not of type AnimateableProperty!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return (AnimateablePropertyP*) animateableProperty;
|
||||
}
|
||||
|
||||
bool initializeAnimateableProperty()
|
||||
{
|
||||
import_array1(false);
|
||||
return PyType_Ready(&AnimateablePropertyPyType) >= 0;
|
||||
}
|
||||
|
||||
void addAnimateablePropertyToModule(PyObject* module)
|
||||
{
|
||||
Py_INCREF(&AnimateablePropertyPyType);
|
||||
PyModule_AddObject(module, "AnimateableProperty", (PyObject*) &AnimateablePropertyPyType);
|
||||
}
|
||||
34
extern/audaspace/bindings/python/PyAnimateableProperty.h
vendored
Normal file
34
extern/audaspace/bindings/python/PyAnimateableProperty.h
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
/*******************************************************************************
|
||||
* Copyright 2009-2025 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
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#include "Audaspace.h"
|
||||
|
||||
typedef void Reference_AnimateableProperty;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PyObject_HEAD Reference_AnimateableProperty* animateableProperty;
|
||||
} AnimateablePropertyP;
|
||||
|
||||
extern AUD_API PyObject* AnimateableProperty_empty();
|
||||
extern AUD_API AnimateablePropertyP* checkAnimateableProperty(PyObject* animateableProperty);
|
||||
|
||||
bool initializeAnimateableProperty();
|
||||
void addAnimateablePropertyToModule(PyObject* module);
|
||||
@@ -98,7 +98,7 @@ PyDoc_STRVAR(M_aud_DynamicMusic_addTransition_doc,
|
||||
" :type end: int\n"
|
||||
" :arg transition: The transition sound.\n"
|
||||
" :type transition: :class:`Sound`\n"
|
||||
" :return: false if the ini or end scenes don't exist, true othrwise.\n"
|
||||
" :return: false if the ini or end scenes don't exist, true otherwise.\n"
|
||||
" :rtype: bool");
|
||||
|
||||
static PyObject *
|
||||
|
||||
@@ -189,7 +189,7 @@ PyDoc_STRVAR(M_aud_PlaybackManager_get_volume_doc,
|
||||
" Retrieves the volume of a category.\n\n"
|
||||
" :arg catKey: the key of the category.\n"
|
||||
" :type catKey: int\n"
|
||||
" :return: The volume of the cateogry.\n"
|
||||
" :return: The volume of the category.\n"
|
||||
" :rtype: float\n\n");
|
||||
|
||||
static PyObject *
|
||||
|
||||
133
extern/audaspace/bindings/python/PySound.cpp
vendored
133
extern/audaspace/bindings/python/PySound.cpp
vendored
@@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
|
||||
#include "PyAnimateableProperty.h"
|
||||
#include "PySound.h"
|
||||
#include "PySource.h"
|
||||
#include "PyThreadPool.h"
|
||||
@@ -66,6 +67,7 @@
|
||||
|
||||
|
||||
#ifdef WITH_RUBBERBAND
|
||||
#include "fx/AnimateableTimeStretchPitchScale.h"
|
||||
#include "fx/TimeStretchPitchScale.h"
|
||||
#endif
|
||||
|
||||
@@ -1794,10 +1796,10 @@ Sound_binaural(Sound* self, PyObject* args)
|
||||
|
||||
#ifdef WITH_RUBBERBAND
|
||||
|
||||
PyDoc_STRVAR(M_aud_Sound_timeStretchPitchScale_doc, ".. method:: timeStretchPitchScale(time_ratio, pitch_scale, quality, preserve_formant)\n\n"
|
||||
PyDoc_STRVAR(M_aud_Sound_timeStretchPitchScale_doc, ".. method:: timeStretchPitchScale(time_stretch, pitch_scale, quality, preserve_formant)\n\n"
|
||||
" Applies time-stretching and pitch-scaling to the sound.\n\n"
|
||||
" :arg time_ratio: The factor by which to stretch or compress time.\n"
|
||||
" :type time_ratio: float\n"
|
||||
" :arg time_stretch: The factor by which to stretch or compress time.\n"
|
||||
" :type time_stretch: float\n"
|
||||
" :arg pitch_scale: The factor by which to adjust the pitch.\n"
|
||||
" :type pitch_scale: float\n"
|
||||
" :arg quality: Rubberband stretcher quality (STRETCHER_QUALITY_*).\n"
|
||||
@@ -1806,18 +1808,22 @@ PyDoc_STRVAR(M_aud_Sound_timeStretchPitchScale_doc, ".. method:: timeStretchPitc
|
||||
" :type preserve_formant: bool\n"
|
||||
" :return: The created :class:`Sound` object.\n"
|
||||
" :rtype: :class:`Sound`");
|
||||
static PyObject *
|
||||
Sound_timeStretchPitchScale(Sound* self, PyObject* args)
|
||||
static PyObject* Sound_timeStretchPitchScale(Sound* self, PyObject* args, PyObject* kwds)
|
||||
{
|
||||
double time_ratio, pitch_scale;
|
||||
double time_stretch = 1.0;
|
||||
double pitch_scale = 1.0;
|
||||
int quality = 0;
|
||||
int preserve_formant = 0;
|
||||
if(!PyArg_ParseTuple(args, "dd|i|p:timeStretchPitchScale", &time_ratio, &pitch_scale, &quality, &preserve_formant))
|
||||
static const char* kwlist[] = {"time_stretch", "pitch_scale", "quality", "preserve_formant", nullptr};
|
||||
|
||||
if(!PyArg_ParseTupleAndKeywords(args, kwds, "|ddip:timeStretchPitchScale", const_cast<char**>(kwlist), &time_stretch, &pitch_scale, &quality, &preserve_formant))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(quality < 0 || quality > 2)
|
||||
{
|
||||
PyErr_WarnEx(PyExc_UserWarning, "Invalid quality value: using default (0 = HIGH)", 1);
|
||||
PyErr_WarnEx(PyExc_UserWarning, "Invalid quality value: using default (0 = STRETCHER_QUALITY_HIGH)", 1);
|
||||
quality = 0;
|
||||
}
|
||||
|
||||
@@ -1828,7 +1834,7 @@ Sound_timeStretchPitchScale(Sound* self, PyObject* args)
|
||||
{
|
||||
try
|
||||
{
|
||||
parent->sound = new std::shared_ptr<ISound>(new TimeStretchPitchScale(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound), time_ratio, pitch_scale,
|
||||
parent->sound = new std::shared_ptr<ISound>(new TimeStretchPitchScale(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound), time_stretch, pitch_scale,
|
||||
static_cast<StretcherQuality>(quality), preserve_formant != 0));
|
||||
}
|
||||
catch(Exception& e)
|
||||
@@ -1842,7 +1848,109 @@ Sound_timeStretchPitchScale(Sound* self, PyObject* args)
|
||||
return (PyObject*)parent;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(M_aud_Sound_animateableTimeStretchPitchScale_doc, ".. method:: animateableTimeStretchPitchScale(fps[, time_stretch, pitch_scale, quality, preserve_formant])\n\n"
|
||||
" Applies time-stretching and pitch-scaling to the sound.\n\n"
|
||||
" :arg fps: The FPS of the animation system.\n"
|
||||
" :type fps float\n"
|
||||
" :arg time_stretch: The factor by which to stretch or compress time.\n"
|
||||
" :type time_stretch: float or :class:`AnimateablePropertyP`\n"
|
||||
" :arg pitch_scale: The factor by which to adjust the pitch.\n"
|
||||
" :type pitch_scale: float or :class:`AnimateablePropertyP`\n "
|
||||
" :arg quality: Rubberband stretcher quality (STRETCHER_QUALITY_*).\n"
|
||||
" :type quality: int\n"
|
||||
" :arg preserve_formant: Whether to preserve the vocal formants during pitch-shifting.\n"
|
||||
" :type preserve_formant: bool\n"
|
||||
" :return: The created :class:`Sound` object.\n"
|
||||
" :rtype: :class:`Sound`");
|
||||
static PyObject* Sound_animateableTimeStretchPitchScale(Sound* self, PyObject* args, PyObject* kwds)
|
||||
{
|
||||
float fps;
|
||||
PyObject* object1 = Py_None;
|
||||
PyObject* object2 = Py_None;
|
||||
int quality = 0;
|
||||
int preserve_formant = 0;
|
||||
|
||||
static const char* kwlist[] = {"fps", "time_stretch", "pitch_scale", "quality", "preserve_formant", nullptr};
|
||||
|
||||
if(!PyArg_ParseTupleAndKeywords(args, kwds, "f|OOip:animateableTimeStretchPitchScale", const_cast<char**>(kwlist), &fps, &object1, &object2, &quality, &preserve_formant))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<aud::AnimateableProperty> time_stretch;
|
||||
std::shared_ptr<aud::AnimateableProperty> pitch_scale;
|
||||
|
||||
if(fps <= 0)
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "FPS must be greater 0!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(object1 == Py_None)
|
||||
{
|
||||
time_stretch = std::make_shared<aud::AnimateableProperty>(1, 1.0);
|
||||
}
|
||||
else if(PyNumber_Check(object1))
|
||||
{
|
||||
time_stretch = std::make_shared<aud::AnimateableProperty>(1, PyFloat_AsDouble(object1));
|
||||
}
|
||||
else
|
||||
{
|
||||
AnimateablePropertyP* time_stretch_prop = checkAnimateableProperty(object1);
|
||||
if(!time_stretch_prop)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
time_stretch = *reinterpret_cast<std::shared_ptr<aud::AnimateableProperty>*>(time_stretch_prop->animateableProperty);
|
||||
}
|
||||
|
||||
if(object2 == Py_None)
|
||||
{
|
||||
pitch_scale = std::make_shared<aud::AnimateableProperty>(1, 1.0);
|
||||
}
|
||||
else if(PyNumber_Check(object2))
|
||||
{
|
||||
pitch_scale = std::make_shared<aud::AnimateableProperty>(1, PyFloat_AsDouble(object2));
|
||||
}
|
||||
else
|
||||
{
|
||||
AnimateablePropertyP* pitch_scale_prop = checkAnimateableProperty(object2);
|
||||
if(!pitch_scale_prop)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
pitch_scale = *reinterpret_cast<std::shared_ptr<aud::AnimateableProperty>*>(pitch_scale_prop->animateableProperty);
|
||||
}
|
||||
|
||||
if(quality < 0 || quality > 2)
|
||||
{
|
||||
PyErr_WarnEx(PyExc_UserWarning, "Invalid quality value: using default (0 = STRETCHER_QUALITY_HIGH)", 1);
|
||||
quality = 0;
|
||||
}
|
||||
|
||||
PyTypeObject* type = Py_TYPE(self);
|
||||
Sound* parent = (Sound*) type->tp_alloc(type, 0);
|
||||
|
||||
if(parent != nullptr)
|
||||
{
|
||||
try
|
||||
{
|
||||
parent->sound = new std::shared_ptr<ISound>(new AnimateableTimeStretchPitchScale(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound), fps, time_stretch,
|
||||
pitch_scale, static_cast<StretcherQuality>(quality), preserve_formant != 0));
|
||||
}
|
||||
catch(Exception& e)
|
||||
{
|
||||
Py_DECREF(parent);
|
||||
PyErr_SetString(AUDError, e.what());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return (PyObject*) parent;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static PyMethodDef Sound_methods[] = {
|
||||
{"data", (PyCFunction)Sound_data, METH_NOARGS,
|
||||
M_aud_Sound_data_doc
|
||||
@@ -1958,9 +2066,10 @@ static PyMethodDef Sound_methods[] = {
|
||||
},
|
||||
#endif
|
||||
#ifdef WITH_RUBBERBAND
|
||||
{"timeStretchPitchScale", (PyCFunction)Sound_timeStretchPitchScale, METH_VARARGS,
|
||||
M_aud_Sound_timeStretchPitchScale_doc
|
||||
},
|
||||
{"timeStretchPitchScale", (PyCFunction)Sound_timeStretchPitchScale, METH_VARARGS | METH_KEYWORDS,
|
||||
M_aud_Sound_timeStretchPitchScale_doc},
|
||||
{"animateableTimeStretchPitchScale", (PyCFunction) Sound_animateableTimeStretchPitchScale, METH_VARARGS | METH_KEYWORDS,
|
||||
M_aud_Sound_animateableTimeStretchPitchScale_doc},
|
||||
#endif
|
||||
{nullptr} /* Sentinel */
|
||||
};
|
||||
|
||||
14
extern/audaspace/bindings/python/setup.py.in
vendored
14
extern/audaspace/bindings/python/setup.py.in
vendored
@@ -36,6 +36,14 @@ if sys.platform == 'win32':
|
||||
else:
|
||||
extra_args.append('-std=c++17')
|
||||
|
||||
macros = []
|
||||
|
||||
if '@WITH_FFTW@' == 'ON':
|
||||
macros.append(('WITH_CONVOLUTION', None))
|
||||
|
||||
if '@WITH_RUBBERBAND@' == 'ON':
|
||||
macros.append(('WITH_RUBBERBAND', None))
|
||||
|
||||
audaspace = Extension(
|
||||
'aud',
|
||||
include_dirs = ['@CMAKE_CURRENT_BINARY_DIR@', os.path.join(source_directory, '../../include'), numpy.get_include()] + (['@FFTW_INCLUDE_DIR@'] if '@WITH_FFTW@' == 'ON' else []),
|
||||
@@ -43,8 +51,8 @@ audaspace = Extension(
|
||||
library_dirs = ['.', 'Release', 'Debug'],
|
||||
language = 'c++',
|
||||
extra_compile_args = extra_args,
|
||||
define_macros = [('WITH_CONVOLUTION', None)] if '@WITH_FFTW@' == 'ON' else [],
|
||||
sources = [os.path.join(source_directory, file) for file in ['PyAPI.cpp', 'PyDevice.cpp', 'PyHandle.cpp', 'PySound.cpp', 'PySequenceEntry.cpp', 'PySequence.cpp', 'PyPlaybackManager.cpp', 'PyDynamicMusic.cpp', 'PyThreadPool.cpp', 'PySource.cpp'] + (['PyImpulseResponse.cpp', 'PyHRTF.cpp'] if '@WITH_FFTW@' == 'ON' else [])]
|
||||
define_macros = macros,
|
||||
sources = [os.path.join(source_directory, file) for file in ['PyAnimateableProperty.cpp', 'PyAPI.cpp', 'PyDevice.cpp', 'PyHandle.cpp', 'PySound.cpp', 'PySequenceEntry.cpp', 'PySequence.cpp', 'PyPlaybackManager.cpp', 'PyDynamicMusic.cpp', 'PyThreadPool.cpp', 'PySource.cpp'] + (['PyImpulseResponse.cpp', 'PyHRTF.cpp'] if '@WITH_FFTW@' == 'ON' else [])]
|
||||
)
|
||||
|
||||
setup(
|
||||
@@ -57,6 +65,6 @@ setup(
|
||||
license = 'Apache License 2.0',
|
||||
long_description = codecs.open(os.path.join(source_directory, '../../README.md'), 'r', 'utf-8').read(),
|
||||
ext_modules = [audaspace],
|
||||
headers = [os.path.join(source_directory, file) for file in ['PyAPI.h', 'PyDevice.h', 'PyHandle.h', 'PySound.h', 'PySequenceEntry.h', 'PySequence.h', 'PyPlaybackManager.h', 'PyDynamicMusic.h', 'PyThreadPool.h', 'PySource.h'] + (['PyImpulseResponse.h', 'PyHRTF.h'] if '@WITH_FFTW@' == 'ON' else [])] + ['Audaspace.h']
|
||||
headers = [os.path.join(source_directory, file) for file in ['PyAnimateableProperty.h', 'PyAPI.h', 'PyDevice.h', 'PyHandle.h', 'PySound.h', 'PySequenceEntry.h', 'PySequence.h', 'PyPlaybackManager.h', 'PyDynamicMusic.h', 'PyThreadPool.h', 'PySource.h'] + (['PyImpulseResponse.h', 'PyHRTF.h'] if '@WITH_FFTW@' == 'ON' else [])] + ['Audaspace.h']
|
||||
)
|
||||
|
||||
|
||||
123
extern/audaspace/include/fx/AnimateableTimeStretchPitchScale.h
vendored
Normal file
123
extern/audaspace/include/fx/AnimateableTimeStretchPitchScale.h
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
/*******************************************************************************
|
||||
* Copyright 2009-2025 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 AnimateableTimeStretchPitchScale.h
|
||||
* @ingroup fx
|
||||
* The AnimateableTimeStretchPitchScale class.
|
||||
*/
|
||||
|
||||
#include "fx/Effect.h"
|
||||
#include "fx/TimeStretchPitchScale.h"
|
||||
#include "sequence/AnimateableProperty.h"
|
||||
|
||||
AUD_NAMESPACE_BEGIN
|
||||
|
||||
/**
|
||||
* This sound allows a sound to be time-stretched and pitch scaled with animation support
|
||||
* \note The reader has to be seekable.
|
||||
*/
|
||||
class AUD_API AnimateableTimeStretchPitchScale : public Effect
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* The FPS of the animation system.
|
||||
*/
|
||||
float m_fps;
|
||||
|
||||
/**
|
||||
* The animateable time-stretch property.
|
||||
*/
|
||||
std::shared_ptr<AnimateableProperty> m_timeStretch;
|
||||
|
||||
/**
|
||||
* The animateable pitch-scale property.
|
||||
*/
|
||||
std::shared_ptr<AnimateableProperty> m_pitchScale;
|
||||
|
||||
/**
|
||||
* Rubberband stretcher quality options.
|
||||
*/
|
||||
StretcherQuality m_quality;
|
||||
|
||||
/**
|
||||
* Whether to preserve the vocal formants for the stretcher.
|
||||
*/
|
||||
bool m_preserveFormant;
|
||||
|
||||
// delete copy constructor and operator=
|
||||
AnimateableTimeStretchPitchScale(const AnimateableTimeStretchPitchScale&) = delete;
|
||||
AnimateableTimeStretchPitchScale& operator=(const AnimateableTimeStretchPitchScale&) = delete;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates a new time-stretch, pitch-scaled sound that can be animated.
|
||||
* \param sound The input sound.
|
||||
* \param fps The fps of the animation system.
|
||||
* \param timeRatio The starting factor by which to stretch or compress time.
|
||||
* \param pitchScale The starting factor by which to adjust the pitch.
|
||||
* \param quality The processing quality level of the stretcher.
|
||||
* \param preserveFormant Whether to preserve the vocal formants for the stretcher.
|
||||
*/
|
||||
AnimateableTimeStretchPitchScale(std::shared_ptr<ISound> sound, float fps, float timeStretch, float pitchScale, StretcherQuality quality, bool preserveFormant);
|
||||
|
||||
/**
|
||||
* Creates a new time-stretch, pitch-scaled sound that can be animated.
|
||||
* \param sound The input sound.
|
||||
* \param fps The fps of the anumation system.
|
||||
* \param timeRatio The animateable time-stretch property.
|
||||
* \param pitchScale The animateable pitch-scale property.
|
||||
* \param quality The processing quality level of the stretcher.
|
||||
* \param preserveFormant Whether to preserve the vocal formants for the stretcher.
|
||||
*/
|
||||
AnimateableTimeStretchPitchScale(std::shared_ptr<ISound> sound, float fps, std::shared_ptr<AnimateableProperty> timeStretch, std::shared_ptr<AnimateableProperty> pitchScale,
|
||||
StretcherQuality quality, bool preserveFormant);
|
||||
|
||||
/**
|
||||
* Returns whether formant preservation is enabled.
|
||||
*/
|
||||
bool getPreserveFormant() const;
|
||||
|
||||
/**
|
||||
* Returns the quality of the stretcher.
|
||||
*/
|
||||
StretcherQuality getStretcherQuality() const;
|
||||
|
||||
/**
|
||||
* Retrieves one of the animated properties of the sound.
|
||||
* \param type Which animated property to retrieve.
|
||||
* \return A shared pointer to the animated property
|
||||
*/
|
||||
std::shared_ptr<AnimateableProperty> getAnimProperty(AnimateablePropertyType type);
|
||||
|
||||
/**
|
||||
* Retrieves the animation system's FPS.
|
||||
* \return The animation system's FPS.
|
||||
*/
|
||||
float getFPS() const;
|
||||
|
||||
/**
|
||||
* Sets the animation system's FPS.
|
||||
* \param fps The new FPS.
|
||||
*/
|
||||
void setFPS(float fps);
|
||||
|
||||
virtual std::shared_ptr<IReader> createReader();
|
||||
};
|
||||
|
||||
AUD_NAMESPACE_END
|
||||
72
extern/audaspace/include/fx/AnimateableTimeStretchPitchScaleReader.h
vendored
Normal file
72
extern/audaspace/include/fx/AnimateableTimeStretchPitchScaleReader.h
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
/*******************************************************************************
|
||||
* Copyright 2009-2025 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 AnimateableTimeStretchPitchScaleReader.h
|
||||
* @ingroup fx
|
||||
* The AnimateableTimeStretchPitchScaleReader class.
|
||||
*/
|
||||
#include "fx/AnimateableTimeStretchPitchScale.h"
|
||||
#include "fx/TimeStretchPitchScaleReader.h"
|
||||
|
||||
AUD_NAMESPACE_BEGIN
|
||||
|
||||
/**
|
||||
* This class reads from another reader and applies time-stretching and pitch scaling with support for animating both properties.
|
||||
*/
|
||||
class AUD_API AnimateableTimeStretchPitchScaleReader : public TimeStretchPitchScaleReader
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* The FPS of the animation system.
|
||||
*/
|
||||
float m_fps;
|
||||
|
||||
/**
|
||||
* The animateable time-stretch property.
|
||||
*/
|
||||
std::shared_ptr<AnimateableProperty> m_timeStretch;
|
||||
|
||||
/**
|
||||
* The animateable pitch-scale property.
|
||||
*/
|
||||
std::shared_ptr<AnimateableProperty> m_pitchScale;
|
||||
|
||||
// delete copy constructor and operator=
|
||||
AnimateableTimeStretchPitchScaleReader(const AnimateableTimeStretchPitchScaleReader&) = delete;
|
||||
AnimateableTimeStretchPitchScaleReader& operator=(const AnimateableTimeStretchPitchScaleReader&) = delete;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates a new animateable time-stretch, pitch scale reader.
|
||||
* \param reader The input reader.
|
||||
* \param fps The FPS of the animation system.
|
||||
* \param timeStretch The animateable time-stretch property.
|
||||
* \param pitchScale The animateable pitch-scale property.
|
||||
* \param quality The stretcher quality options.
|
||||
* \param preserveFormant Whether to preserve vocal formants.
|
||||
*/
|
||||
AnimateableTimeStretchPitchScaleReader(std::shared_ptr<IReader> reader, float fp, std::shared_ptr<AnimateableProperty> timeStretch,
|
||||
std::shared_ptr<AnimateableProperty> pitchScale, StretcherQuality quality, bool preserveFormant);
|
||||
|
||||
virtual void read(int& length, bool& eos, sample_t* buffer) override;
|
||||
|
||||
virtual void seek(int position) override;
|
||||
};
|
||||
|
||||
AUD_NAMESPACE_END
|
||||
@@ -89,6 +89,12 @@ public:
|
||||
* Returns whether formant preservation is enabled.
|
||||
*/
|
||||
bool getPreserveFormant() const;
|
||||
|
||||
/**
|
||||
* Returns the quality of the stretcher.
|
||||
*/
|
||||
StretcherQuality getStretcherQuality() const;
|
||||
|
||||
virtual std::shared_ptr<IReader> createReader();
|
||||
};
|
||||
|
||||
|
||||
@@ -37,7 +37,9 @@ enum AnimateablePropertyType
|
||||
AP_PANNING,
|
||||
AP_PITCH,
|
||||
AP_LOCATION,
|
||||
AP_ORIENTATION
|
||||
AP_ORIENTATION,
|
||||
AP_TIME_STRETCH,
|
||||
AP_PITCH_SCALE
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -127,6 +129,13 @@ public:
|
||||
*/
|
||||
void read(float position, float* out);
|
||||
|
||||
/**
|
||||
* Reads the property's value at the specified position, assuming there is exactly one value
|
||||
* \param position The position in the animation in frames.
|
||||
* \return The value at the position.
|
||||
*/
|
||||
float readSingle(float position);
|
||||
|
||||
/**
|
||||
* Returns whether the property is animated.
|
||||
* \return Whether the property is animated.
|
||||
|
||||
78
extern/audaspace/src/fx/AnimateableTimeStretchPitchScale.cpp
vendored
Normal file
78
extern/audaspace/src/fx/AnimateableTimeStretchPitchScale.cpp
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
/*******************************************************************************
|
||||
* Copyright 2009-2025 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/AnimateableTimeStretchPitchScale.h"
|
||||
|
||||
#include "fx/AnimateableTimeStretchPitchScaleReader.h"
|
||||
|
||||
AUD_NAMESPACE_BEGIN
|
||||
|
||||
AnimateableTimeStretchPitchScale::AnimateableTimeStretchPitchScale(std::shared_ptr<ISound> sound, float fps, float timeStretch, float pitchScale, StretcherQuality quality,
|
||||
bool preserveFormant) :
|
||||
Effect(sound),
|
||||
m_fps(fps),
|
||||
m_timeStretch(std::make_shared<AnimateableProperty>(1, timeStretch)),
|
||||
m_pitchScale(std::make_shared<AnimateableProperty>(1, pitchScale)),
|
||||
m_quality(quality),
|
||||
m_preserveFormant(preserveFormant)
|
||||
{
|
||||
}
|
||||
|
||||
AnimateableTimeStretchPitchScale::AnimateableTimeStretchPitchScale(std::shared_ptr<ISound> sound, float fps, std::shared_ptr<AnimateableProperty> timeStretch,
|
||||
std::shared_ptr<AnimateableProperty> pitchScale, StretcherQuality quality, bool preserveFormant) :
|
||||
Effect(sound), m_fps(fps), m_timeStretch(timeStretch), m_pitchScale(pitchScale), m_quality(quality), m_preserveFormant(preserveFormant)
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<IReader> AnimateableTimeStretchPitchScale::createReader()
|
||||
{
|
||||
return std::make_shared<AnimateableTimeStretchPitchScaleReader>(getReader(), m_fps, m_timeStretch, m_pitchScale, m_quality, m_preserveFormant);
|
||||
}
|
||||
|
||||
bool AnimateableTimeStretchPitchScale::getPreserveFormant() const
|
||||
{
|
||||
return m_preserveFormant;
|
||||
}
|
||||
|
||||
StretcherQuality AnimateableTimeStretchPitchScale::getStretcherQuality() const
|
||||
{
|
||||
return m_quality;
|
||||
}
|
||||
|
||||
std::shared_ptr<AnimateableProperty> AnimateableTimeStretchPitchScale::getAnimProperty(AnimateablePropertyType type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case AP_TIME_STRETCH:
|
||||
return m_timeStretch;
|
||||
case AP_PITCH_SCALE:
|
||||
return m_pitchScale;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
float AnimateableTimeStretchPitchScale::getFPS() const
|
||||
{
|
||||
return m_fps;
|
||||
}
|
||||
|
||||
void AnimateableTimeStretchPitchScale::setFPS(float fps)
|
||||
{
|
||||
m_fps = fps;
|
||||
}
|
||||
|
||||
AUD_NAMESPACE_END
|
||||
58
extern/audaspace/src/fx/AnimateableTimeStretchPitchScaleReader.cpp
vendored
Normal file
58
extern/audaspace/src/fx/AnimateableTimeStretchPitchScaleReader.cpp
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
/*******************************************************************************
|
||||
* Copyright 2009-2025 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/AnimateableTimeStretchPitchScaleReader.h"
|
||||
|
||||
#include "IReader.h"
|
||||
|
||||
AUD_NAMESPACE_BEGIN
|
||||
|
||||
AnimateableTimeStretchPitchScaleReader::AnimateableTimeStretchPitchScaleReader(std::shared_ptr<IReader> reader, float fps, std::shared_ptr<AnimateableProperty> timeStretch,
|
||||
std::shared_ptr<AnimateableProperty> pitchScale, StretcherQuality quality, bool preserveFormant) :
|
||||
TimeStretchPitchScaleReader(reader, timeStretch->readSingle(0), pitchScale->readSingle(0), quality, preserveFormant),
|
||||
m_fps(fps),
|
||||
m_timeStretch(timeStretch),
|
||||
m_pitchScale(pitchScale)
|
||||
{
|
||||
}
|
||||
|
||||
void AnimateableTimeStretchPitchScaleReader::read(int& length, bool& eos, sample_t* buffer)
|
||||
{
|
||||
int position = getPosition();
|
||||
|
||||
double time = double(position) / double(m_reader->getSpecs().rate);
|
||||
float frame = time * m_fps;
|
||||
|
||||
float timeRatio = m_timeStretch->readSingle(frame);
|
||||
setTimeRatio(timeRatio);
|
||||
float pitchScale = m_pitchScale->readSingle(frame);
|
||||
setPitchScale(pitchScale);
|
||||
TimeStretchPitchScaleReader::read(length, eos, buffer);
|
||||
}
|
||||
|
||||
void AnimateableTimeStretchPitchScaleReader::seek(int position)
|
||||
{
|
||||
double time = double(position) / double(m_reader->getSpecs().rate);
|
||||
float frame = time * m_fps;
|
||||
|
||||
float timeRatio = m_timeStretch->readSingle(frame);
|
||||
setTimeRatio(timeRatio);
|
||||
float pitchScale = m_pitchScale->readSingle(frame);
|
||||
setPitchScale(pitchScale);
|
||||
TimeStretchPitchScaleReader::seek(position);
|
||||
}
|
||||
|
||||
AUD_NAMESPACE_END
|
||||
@@ -45,4 +45,9 @@ bool TimeStretchPitchScale::getPreserveFormant() const
|
||||
{
|
||||
return m_preserveFormant;
|
||||
}
|
||||
|
||||
StretcherQuality TimeStretchPitchScale::getStretcherQuality() const
|
||||
{
|
||||
return m_quality;
|
||||
}
|
||||
AUD_NAMESPACE_END
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "sequence/AnimateableProperty.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
#include <mutex>
|
||||
@@ -228,6 +229,14 @@ void AnimateableProperty::read(float position, float* out)
|
||||
}
|
||||
}
|
||||
|
||||
float AnimateableProperty::readSingle(float position)
|
||||
{
|
||||
assert(m_count == 1);
|
||||
float value;
|
||||
read(position, &value);
|
||||
return value;
|
||||
}
|
||||
|
||||
bool AnimateableProperty::isAnimated() const
|
||||
{
|
||||
return m_isAnimated;
|
||||
|
||||
Reference in New Issue
Block a user