diff options
Diffstat (limited to 'extern/audaspace/bindings/python/PySound.cpp')
-rw-r--r-- | extern/audaspace/bindings/python/PySound.cpp | 1966 |
1 files changed, 0 insertions, 1966 deletions
diff --git a/extern/audaspace/bindings/python/PySound.cpp b/extern/audaspace/bindings/python/PySound.cpp deleted file mode 100644 index 2ab1974be49..00000000000 --- a/extern/audaspace/bindings/python/PySound.cpp +++ /dev/null @@ -1,1966 +0,0 @@ -/******************************************************************************* - * 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 "PySound.h" -#include "PySource.h" -#include "PyThreadPool.h" - -#ifdef WITH_CONVOLUTION -#include "PyHRTF.h" -#include "PyImpulseResponse.h" -#endif - -#include "Exception.h" -#include "file/File.h" -#include "file/FileWriter.h" -#include "util/StreamBuffer.h" -#include "generator/Sawtooth.h" -#include "generator/Silence.h" -#include "generator/Sine.h" -#include "generator/Square.h" -#include "generator/Triangle.h" -#include "fx/Accumulator.h" -#include "fx/ADSR.h" -#include "fx/Delay.h" -#include "fx/Envelope.h" -#include "fx/Fader.h" -#include "fx/Highpass.h" -#include "fx/IIRFilter.h" -#include "fx/Limiter.h" -#include "fx/Loop.h" -#include "fx/Lowpass.h" -#include "fx/MutableSound.h" -#include "fx/Pitch.h" -#include "fx/Reverse.h" -#include "fx/SoundList.h" -#include "fx/Sum.h" -#include "fx/Threshold.h" -#include "fx/Volume.h" -#include "respec/ChannelMapper.h" -#include "respec/ChannelMapperReader.h" -#include "respec/LinearResample.h" -#include "respec/JOSResample.h" -#include "respec/JOSResampleReader.h" -#include "sequence/Double.h" -#include "sequence/PingPong.h" -#include "sequence/Superpose.h" - -#ifdef WITH_CONVOLUTION -#include "fx/BinauralSound.h" -#include "fx/ConvolverSound.h" -#endif - -#include <cstring> -#include <structmember.h> -#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION -#include <numpy/ndarrayobject.h> - -using namespace aud; - -extern PyObject* AUDError; - -static void -Sound_dealloc(Sound* self) -{ - if(self->sound) - delete reinterpret_cast<std::shared_ptr<ISound>*>(self->sound); - Py_TYPE(self)->tp_free((PyObject *)self); -} - -static PyObject * -Sound_new(PyTypeObject* type, PyObject* args, PyObject* kwds) -{ - Sound* self; - - self = (Sound*)type->tp_alloc(type, 0); - if(self != nullptr) - { - static const char* kwlist[] = {"filename", nullptr}; - const char* filename = nullptr; - - if(!PyArg_ParseTupleAndKeywords(args, kwds, "s:Sound", const_cast<char**>(kwlist), &filename)) - { - Py_DECREF(self); - return nullptr; - } - - try - { - self->sound = new std::shared_ptr<ISound>(new File(filename)); - } - catch(Exception& e) - { - Py_DECREF(self); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)self; -} - -PyDoc_STRVAR(M_aud_Sound_data_doc, - "data()\n\n" - "Retrieves the data of the sound as numpy array.\n\n" - ":return: A two dimensional numpy float array.\n" - ":rtype: :class:`numpy.ndarray`\n\n" - ".. note:: Best efficiency with cached sounds."); - -static PyObject * -Sound_data(Sound* self) -{ - std::shared_ptr<ISound> sound = *reinterpret_cast<std::shared_ptr<ISound>*>(self->sound); - - auto stream_buffer = std::dynamic_pointer_cast<StreamBuffer>(sound); - if(!stream_buffer) - stream_buffer = std::make_shared<StreamBuffer>(sound); - Specs specs = stream_buffer->getSpecs(); - auto buffer = stream_buffer->getBuffer(); - - npy_intp dimensions[2]; - dimensions[0] = buffer->getSize() / AUD_SAMPLE_SIZE(specs); - dimensions[1] = specs.channels; - - PyArrayObject* array = reinterpret_cast<PyArrayObject*>(PyArray_SimpleNew(2, dimensions, NPY_FLOAT)); - - sample_t* data = reinterpret_cast<sample_t*>(PyArray_DATA(array)); - - std::memcpy(data, buffer->getBuffer(), buffer->getSize()); - - Py_INCREF(array); - - return reinterpret_cast<PyObject*>(array); -} - -PyDoc_STRVAR(M_aud_Sound_write_doc, - "write(filename, rate, channels, format, container, codec, bitrate, buffersize)\n\n" - "Writes the sound to a file.\n\n" - ":arg filename: The path to write to.\n" - ":type filename: string\n" - ":arg rate: The sample rate to write with.\n" - ":type rate: int\n" - ":arg channels: The number of channels to write with.\n" - ":type channels: int\n" - ":arg format: The sample format to write with.\n" - ":type format: int\n" - ":arg container: The container format for the file.\n" - ":type container: int\n" - ":arg codec: The codec to use in the file.\n" - ":type codec: int\n" - ":arg bitrate: The bitrate to write with.\n" - ":type bitrate: int\n" - ":arg buffersize: The size of the writing buffer.\n" - ":type buffersize: int\n"); - -static PyObject * -Sound_write(Sound* self, PyObject* args, PyObject* kwds) -{ - const char* filename = nullptr; - int rate = RATE_INVALID; - Channels channels = CHANNELS_INVALID; - SampleFormat format = FORMAT_INVALID; - Container container = CONTAINER_INVALID; - Codec codec = CODEC_INVALID; - int bitrate = 0; - int buffersize = 0; - - static const char* kwlist[] = {"filename", "rate", "channels", "format", "container", "codec", "bitrate", "buffersize", nullptr}; - - if(!PyArg_ParseTupleAndKeywords(args, kwds, "s|iiiiiii:write", const_cast<char**>(kwlist), &filename, &rate, &channels, &format, &container, &codec, &bitrate, &buffersize)) - return nullptr; - - try - { - std::shared_ptr<IReader> reader = (*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound))->createReader(); - - DeviceSpecs specs; - specs.specs = reader->getSpecs(); - - if((rate != RATE_INVALID) && (specs.rate != rate)) - { - specs.rate = rate; - reader = std::make_shared<JOSResampleReader>(reader, rate); - } - - if((channels != CHANNELS_INVALID) && (specs.channels != channels)) - { - specs.channels = channels; - reader = std::make_shared<ChannelMapperReader>(reader, channels); - } - - if(format == FORMAT_INVALID) - format = FORMAT_S16; - specs.format = format; - - const char* invalid_container_error = "Container could not be determined from filename."; - - if(container == CONTAINER_INVALID) - { - std::string path = filename; - - if(path.length() < 4) - { - PyErr_SetString(AUDError, invalid_container_error); - return nullptr; - } - - std::string extension = path.substr(path.length() - 4); - - if(extension == ".ac3") - container = CONTAINER_AC3; - else if(extension == "flac") - container = CONTAINER_FLAC; - else if(extension == ".mkv") - container = CONTAINER_MATROSKA; - else if(extension == ".mp2") - container = CONTAINER_MP2; - else if(extension == ".mp3") - container = CONTAINER_MP3; - else if(extension == ".ogg") - container = CONTAINER_OGG; - else if(extension == ".wav") - container = CONTAINER_WAV; - else - { - PyErr_SetString(AUDError, invalid_container_error); - return nullptr; - } - } - - if(codec == CODEC_INVALID) - { - switch(container) - { - case CONTAINER_AC3: - codec = CODEC_AC3; - break; - case CONTAINER_FLAC: - codec = CODEC_FLAC; - break; - case CONTAINER_MATROSKA: - codec = CODEC_OPUS; - break; - case CONTAINER_MP2: - codec = CODEC_MP2; - break; - case CONTAINER_MP3: - codec = CODEC_MP3; - break; - case CONTAINER_OGG: - codec = CODEC_VORBIS; - break; - case CONTAINER_WAV: - codec = CODEC_PCM; - break; - default: - PyErr_SetString(AUDError, "Unknown container, cannot select default codec."); - return nullptr; - } - } - - if(buffersize <= 0) - buffersize = AUD_DEFAULT_BUFFER_SIZE; - - std::shared_ptr<IWriter> writer = FileWriter::createWriter(filename, specs, container, codec, bitrate); - FileWriter::writeReader(reader, writer, 0, buffersize); - } - catch(Exception& e) - { - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - - Py_RETURN_NONE; -} - -PyDoc_STRVAR(M_aud_Sound_buffer_doc, - "buffer(data, rate)\n\n" - "Creates a sound from a data buffer.\n\n" - ":arg data: The data as two dimensional numpy array.\n" - ":type data: numpy.ndarray\n" - ":arg rate: The sample rate.\n" - ":type rate: double\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`"); - -static PyObject * -Sound_buffer(PyTypeObject* type, PyObject* args) -{ - PyArrayObject* array = nullptr; - double rate = RATE_INVALID; - - if(!PyArg_ParseTuple(args, "Od:buffer", &array, &rate)) - return nullptr; - - if((!PyObject_TypeCheck(reinterpret_cast<PyObject*>(array), &PyArray_Type)) || (PyArray_TYPE(array) != NPY_FLOAT)) - { - PyErr_SetString(PyExc_TypeError, "The data needs to be supplied as float32 numpy array!"); - return nullptr; - } - - if(PyArray_NDIM(array) > 2) - { - PyErr_SetString(PyExc_TypeError, "The array needs to have one or two dimensions!"); - return nullptr; - } - - if(rate <= 0) - { - PyErr_SetString(PyExc_TypeError, "The sample rate has to be positive!"); - return nullptr; - } - - Specs specs; - specs.rate = rate; - specs.channels = CHANNELS_MONO; - - if(PyArray_NDIM(array) == 2) - specs.channels = static_cast<Channels>(PyArray_DIM(array, 1)); - - int size = PyArray_DIM(array, 0) * AUD_SAMPLE_SIZE(specs); - - std::shared_ptr<Buffer> buffer = std::make_shared<Buffer>(size); - - std::memcpy(buffer->getBuffer(), PyArray_DATA(array), size); - - Sound* self; - - self = (Sound*)type->tp_alloc(type, 0); - if(self != nullptr) - { - try - { - self->sound = new std::shared_ptr<StreamBuffer>(new StreamBuffer(buffer, specs)); - } - catch(Exception& e) - { - Py_DECREF(self); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)self; -} - -PyDoc_STRVAR(M_aud_Sound_cache_doc, - "cache()\n\n" - "Caches a sound into RAM.\n" - "This saves CPU usage needed for decoding and file access if the " - "underlying sound reads from a file on the harddisk, but it " - "consumes a lot of memory.\n\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`\n\n" - ".. note:: Only known-length factories can be buffered.\n\n" - ".. warning:: Raw PCM data needs a lot of space, only buffer " - "short factories."); - -static PyObject * -Sound_cache(Sound* self) -{ - 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 StreamBuffer(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound))); - } - catch(Exception& e) - { - Py_DECREF(parent); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)parent; -} - -PyDoc_STRVAR(M_aud_Sound_file_doc, - "file(filename)\n\n" - "Creates a sound object of a sound file.\n\n" - ":arg filename: Path of the file.\n" - ":type filename: string\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`\n\n" - ".. warning:: If the file doesn't exist or can't be read you will " - "not get an exception immediately, but when you try to start " - "playback of that sound."); - -static PyObject * -Sound_file(PyTypeObject* type, PyObject* args) -{ - const char* filename = nullptr; - - if(!PyArg_ParseTuple(args, "s:file", &filename)) - return nullptr; - - Sound* self; - - self = (Sound*)type->tp_alloc(type, 0); - if(self != nullptr) - { - try - { - self->sound = new std::shared_ptr<ISound>(new File(filename)); - } - catch(Exception& e) - { - Py_DECREF(self); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)self; -} - -PyDoc_STRVAR(M_aud_Sound_sawtooth_doc, - "sawtooth(frequency, rate=48000)\n\n" - "Creates a sawtooth sound which plays a sawtooth wave.\n\n" - ":arg frequency: The frequency of the sawtooth wave in Hz.\n" - ":type frequency: float\n" - ":arg rate: The sampling rate in Hz. It's recommended to set this " - "value to the playback device's samling rate to avoid resamping.\n" - ":type rate: int\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`"); - -static PyObject * -Sound_sawtooth(PyTypeObject* type, PyObject* args) -{ - float frequency; - double rate = 48000; - - if(!PyArg_ParseTuple(args, "f|d:sawtooth", &frequency, &rate)) - return nullptr; - - Sound* self; - - self = (Sound*)type->tp_alloc(type, 0); - if(self != nullptr) - { - try - { - self->sound = new std::shared_ptr<ISound>(new Sawtooth(frequency, (SampleRate)rate)); - } - catch(Exception& e) - { - Py_DECREF(self); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)self; -} - -PyDoc_STRVAR(M_aud_Sound_silence_doc, - "silence()\n\n" - "Creates a silence sound which plays simple silence.\n\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`"); - -static PyObject * -Sound_silence(PyTypeObject* type) -{ - Sound* self; - - self = (Sound*)type->tp_alloc(type, 0); - if(self != nullptr) - { - try - { - self->sound = new std::shared_ptr<ISound>(new Silence()); - } - catch(Exception& e) - { - Py_DECREF(self); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)self; -} - -PyDoc_STRVAR(M_aud_Sound_sine_doc, - "sine(frequency, rate=48000)\n\n" - "Creates a sine sound which plays a sine wave.\n\n" - ":arg frequency: The frequency of the sine wave in Hz.\n" - ":type frequency: float\n" - ":arg rate: The sampling rate in Hz. It's recommended to set this " - "value to the playback device's samling rate to avoid resamping.\n" - ":type rate: int\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`"); - -static PyObject * -Sound_sine(PyTypeObject* type, PyObject* args) -{ - float frequency; - double rate = 48000; - - if(!PyArg_ParseTuple(args, "f|d:sine", &frequency, &rate)) - return nullptr; - - Sound* self; - - self = (Sound*)type->tp_alloc(type, 0); - if(self != nullptr) - { - try - { - self->sound = new std::shared_ptr<ISound>(new Sine(frequency, (SampleRate)rate)); - } - catch(Exception& e) - { - Py_DECREF(self); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)self; -} - -PyDoc_STRVAR(M_aud_Sound_square_doc, - "square(frequency, rate=48000)\n\n" - "Creates a square sound which plays a square wave.\n\n" - ":arg frequency: The frequency of the square wave in Hz.\n" - ":type frequency: float\n" - ":arg rate: The sampling rate in Hz. It's recommended to set this " - "value to the playback device's samling rate to avoid resamping.\n" - ":type rate: int\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`"); - -static PyObject * -Sound_square(PyTypeObject* type, PyObject* args) -{ - float frequency; - double rate = 48000; - - if(!PyArg_ParseTuple(args, "f|d:square", &frequency, &rate)) - return nullptr; - - Sound* self; - - self = (Sound*)type->tp_alloc(type, 0); - if(self != nullptr) - { - try - { - self->sound = new std::shared_ptr<ISound>(new Square(frequency, (SampleRate)rate)); - } - catch(Exception& e) - { - Py_DECREF(self); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)self; -} - -PyDoc_STRVAR(M_aud_Sound_triangle_doc, - "triangle(frequency, rate=48000)\n\n" - "Creates a triangle sound which plays a triangle wave.\n\n" - ":arg frequency: The frequency of the triangle wave in Hz.\n" - ":type frequency: float\n" - ":arg rate: The sampling rate in Hz. It's recommended to set this " - "value to the playback device's samling rate to avoid resamping.\n" - ":type rate: int\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`"); - -static PyObject * -Sound_triangle(PyTypeObject* type, PyObject* args) -{ - float frequency; - double rate = 48000; - - if(!PyArg_ParseTuple(args, "f|d:triangle", &frequency, &rate)) - return nullptr; - - Sound* self; - - self = (Sound*)type->tp_alloc(type, 0); - if(self != nullptr) - { - try - { - self->sound = new std::shared_ptr<ISound>(new Triangle(frequency, (SampleRate)rate)); - } - catch(Exception& e) - { - Py_DECREF(self); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)self; -} - -PyDoc_STRVAR(M_aud_Sound_accumulate_doc, - "accumulate(additive=False)\n\n" - "Accumulates a sound by summing over positive input differences thus generating a monotonic sigal. " - "If additivity is set to true negative input differences get added too, but positive ones with a factor of two. " - "Note that with additivity the signal is not monotonic anymore.\n\n" - ":arg additive: Whether the accumulation should be additive or not.\n" - ":type time: bool\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`"); - -static PyObject * -Sound_accumulate(Sound* self, PyObject* args) -{ - bool additive = false; - PyObject* additiveo; - - if(!PyArg_ParseTuple(args, "|O:accumulate", &additiveo)) - return nullptr; - - PyTypeObject* type = Py_TYPE(self); - Sound* parent = (Sound*)type->tp_alloc(type, 0); - - if(parent != nullptr) - { - if(additiveo != nullptr) - { - if(!PyBool_Check(additiveo)) - { - PyErr_SetString(PyExc_TypeError, "additive is not a boolean!"); - return nullptr; - } - - additive = additiveo == Py_True; - } - - try - { - parent->sound = new std::shared_ptr<ISound>(new Accumulator(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound), additive)); - } - catch(Exception& e) - { - Py_DECREF(parent); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)parent; -} - -PyDoc_STRVAR(M_aud_Sound_ADSR_doc, - "ADSR(attack,decay,sustain,release)\n\n" - "Attack-Decay-Sustain-Release envelopes the volume of a sound. " - "Note: there is currently no way to trigger the release with this API.\n\n" - ":arg attack: The attack time in seconds.\n" - ":type attack: float\n" - ":arg decay: The decay time in seconds.\n" - ":type decay: float\n" - ":arg sustain: The sustain level.\n" - ":type sustain: float\n" - ":arg release: The release level.\n" - ":type release: float\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`"); - -static PyObject * -Sound_ADSR(Sound* self, PyObject* args) -{ - float attack, decay, sustain, release; - - if(!PyArg_ParseTuple(args, "ffff:ADSR", &attack, &decay, &sustain, &release)) - return nullptr; - - 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 ADSR(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound), attack, decay, sustain, release)); - } - catch(Exception& e) - { - Py_DECREF(parent); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)parent; -} - -PyDoc_STRVAR(M_aud_Sound_delay_doc, - "delay(time)\n\n" - "Delays by playing adding silence in front of the other sound's " - "data.\n\n" - ":arg time: How many seconds of silence should be added before " - "the sound.\n" - ":type time: float\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`"); - -static PyObject * -Sound_delay(Sound* self, PyObject* args) -{ - float delay; - - if(!PyArg_ParseTuple(args, "f:delay", &delay)) - return nullptr; - - 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 Delay(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound), delay)); - } - catch(Exception& e) - { - Py_DECREF(parent); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)parent; -} - -PyDoc_STRVAR(M_aud_Sound_envelope_doc, - "envelope(attack, release, threshold, arthreshold)\n\n" - "Delays by playing adding silence in front of the other sound's " - "data.\n\n" - ":arg attack: The attack factor.\n" - ":type attack: float\n" - ":arg release: The release factor.\n" - ":type release: float\n" - ":arg threshold: The general threshold value.\n" - ":type threshold: float\n" - ":arg arthreshold: The attack/release threshold value.\n" - ":type arthreshold: float\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`"); - -static PyObject * -Sound_envelope(Sound* self, PyObject* args) -{ - float attack, release, threshold, arthreshold; - - if(!PyArg_ParseTuple(args, "ffff:envelope", &attack, &release, &threshold, &arthreshold)) - return nullptr; - - 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 Envelope(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound), attack, release, threshold, arthreshold)); - } - catch(Exception& e) - { - Py_DECREF(parent); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)parent; -} - -PyDoc_STRVAR(M_aud_Sound_fadein_doc, - "fadein(start, length)\n\n" - "Fades a sound in by raising the volume linearly in the given " - "time interval.\n\n" - ":arg start: Time in seconds when the fading should start.\n" - ":type start: float\n" - ":arg length: Time in seconds how long the fading should last.\n" - ":type length: float\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`\n\n" - ".. note:: Before the fade starts it plays silence."); - -static PyObject * -Sound_fadein(Sound* self, PyObject* args) -{ - float start, length; - - if(!PyArg_ParseTuple(args, "ff:fadein", &start, &length)) - return nullptr; - - 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 Fader(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound), FADE_IN, start, length)); - } - catch(Exception& e) - { - Py_DECREF(parent); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)parent; -} - -PyDoc_STRVAR(M_aud_Sound_fadeout_doc, - "fadeout(start, length)\n\n" - "Fades a sound in by lowering the volume linearly in the given " - "time interval.\n\n" - ":arg start: Time in seconds when the fading should start.\n" - ":type start: float\n" - ":arg length: Time in seconds how long the fading should last.\n" - ":type length: float\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`\n\n" - ".. note:: After the fade this sound plays silence, so that " - "the length of the sound is not altered."); - -static PyObject * -Sound_fadeout(Sound* self, PyObject* args) -{ - float start, length; - - if(!PyArg_ParseTuple(args, "ff:fadeout", &start, &length)) - return nullptr; - - 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 Fader(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound), FADE_OUT, start, length)); - } - catch(Exception& e) - { - Py_DECREF(parent); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)parent; -} - -PyDoc_STRVAR(M_aud_Sound_filter_doc, - "filter(b, a = (1))\n\n" - "Filters a sound with the supplied IIR filter coefficients.\n" - "Without the second parameter you'll get a FIR filter.\n" - "If the first value of the a sequence is 0 it will be set to 1 " - "automatically.\n" - "If the first value of the a sequence is neither 0 nor 1, all " - "filter coefficients will be scaled by this value so that it is 1 " - "in the end, you don't have to scale yourself.\n\n" - ":arg b: The nominator filter coefficients.\n" - ":type b: sequence of float\n" - ":arg a: The denominator filter coefficients.\n" - ":type a: sequence of float\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`"); - -static PyObject * -Sound_filter(Sound* self, PyObject* args) -{ - PyObject* py_b; - PyObject* py_a = nullptr; - Py_ssize_t py_a_len; - Py_ssize_t py_b_len; - - if(!PyArg_ParseTuple(args, "O|O:filter", &py_b, &py_a)) - return nullptr; - - if(!PySequence_Check(py_b) || (py_a != nullptr && !PySequence_Check(py_a))) - { - PyErr_SetString(PyExc_TypeError, "Parameter is not a sequence!"); - return nullptr; - } - - py_a_len= py_a ? PySequence_Size(py_a) : 0; - py_b_len= PySequence_Size(py_b); - - if(!py_b_len || ((py_a != nullptr) && !py_a_len)) - { - PyErr_SetString(PyExc_ValueError, "The sequence has to contain at least one value!"); - return nullptr; - } - - std::vector<float> a, b; - PyObject* py_value; - float value; - - for(Py_ssize_t i = 0; i < py_b_len; i++) - { - py_value = PySequence_GetItem(py_b, i); - value= (float)PyFloat_AsDouble(py_value); - Py_DECREF(py_value); - - if(value == -1.0f && PyErr_Occurred()) { - return nullptr; - } - - b.push_back(value); - } - - if(py_a) - { - for(Py_ssize_t i = 0; i < py_a_len; i++) - { - py_value = PySequence_GetItem(py_a, i); - value= (float)PyFloat_AsDouble(py_value); - Py_DECREF(py_value); - - if(value == -1.0f && PyErr_Occurred()) { - return nullptr; - } - - a.push_back(value); - } - - if(a[0] == 0) - a[0] = 1; - } - else - a.push_back(1); - - 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 IIRFilter(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound), b, a)); - } - catch(Exception& e) - { - Py_DECREF(parent); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)parent; -} - -PyDoc_STRVAR(M_aud_Sound_highpass_doc, - "highpass(frequency, Q=0.5)\n\n" - "Creates a second order highpass filter based on the transfer " - "function H(s) = s^2 / (s^2 + s/Q + 1)\n\n" - ":arg frequency: The cut off trequency of the highpass.\n" - ":type frequency: float\n" - ":arg Q: Q factor of the lowpass.\n" - ":type Q: float\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`"); - -static PyObject * -Sound_highpass(Sound* self, PyObject* args) -{ - float frequency; - float Q = 0.5; - - if(!PyArg_ParseTuple(args, "f|f:highpass", &frequency, &Q)) - return nullptr; - - 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 Highpass(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound), frequency, Q)); - } - catch(Exception& e) - { - Py_DECREF(parent); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)parent; -} - -PyDoc_STRVAR(M_aud_Sound_limit_doc, - "limit(start, end)\n\n" - "Limits a sound within a specific start and end time.\n\n" - ":arg start: Start time in seconds.\n" - ":type start: float\n" - ":arg end: End time in seconds.\n" - ":type end: float\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`"); - -static PyObject * -Sound_limit(Sound* self, PyObject* args) -{ - float start, end; - - if(!PyArg_ParseTuple(args, "ff:limit", &start, &end)) - return nullptr; - - 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 Limiter(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound), start, end)); - } - catch(Exception& e) - { - Py_DECREF(parent); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)parent; -} - -PyDoc_STRVAR(M_aud_Sound_loop_doc, - "loop(count)\n\n" - "Loops a sound.\n\n" - ":arg count: How often the sound should be looped. " - "Negative values mean endlessly.\n" - ":type count: integer\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`\n\n" - ".. note:: This is a filter function, you might consider using " - ":attr:`Handle.loop_count` instead."); - -static PyObject * -Sound_loop(Sound* self, PyObject* args) -{ - int loop; - - if(!PyArg_ParseTuple(args, "i:loop", &loop)) - return nullptr; - - 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 Loop(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound), loop)); - } - catch(Exception& e) - { - Py_DECREF(parent); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)parent; -} - -PyDoc_STRVAR(M_aud_Sound_lowpass_doc, - "lowpass(frequency, Q=0.5)\n\n" - "Creates a second order lowpass filter based on the transfer " - "function H(s) = 1 / (s^2 + s/Q + 1)\n\n" - ":arg frequency: The cut off trequency of the lowpass.\n" - ":type frequency: float\n" - ":arg Q: Q factor of the lowpass.\n" - ":type Q: float\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`"); - -static PyObject * -Sound_lowpass(Sound* self, PyObject* args) -{ - float frequency; - float Q = 0.5; - - if(!PyArg_ParseTuple(args, "f|f:lowpass", &frequency, &Q)) - return nullptr; - - 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 Lowpass(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound), frequency, Q)); - } - 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" - ":arg factor: The factor to change the pitch with.\n" - ":type factor: float\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`\n\n" - ".. note:: This is done by changing the sample rate of the " - "underlying sound, which has to be an integer, so the factor " - "value rounded and the factor may not be 100 % accurate.\n\n" - ".. note:: This is a filter function, you might consider using " - ":attr:`Handle.pitch` instead."); - -static PyObject * -Sound_pitch(Sound* self, PyObject* args) -{ - float factor; - - if(!PyArg_ParseTuple(args, "f:pitch", &factor)) - return nullptr; - - 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 Pitch(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound), factor)); - } - catch(Exception& e) - { - Py_DECREF(parent); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)parent; -} - -PyDoc_STRVAR(M_aud_Sound_rechannel_doc, - "rechannel(channels)\n\n" - "Rechannels the sound.\n\n" - ":arg channels: The new channel configuration.\n" - ":type channels: int\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`"); - -static PyObject * -Sound_rechannel(Sound* self, PyObject* args) -{ - int channels; - - if(!PyArg_ParseTuple(args, "i:rechannel", &channels)) - return nullptr; - - PyTypeObject* type = Py_TYPE(self); - Sound* parent = (Sound*)type->tp_alloc(type, 0); - - if(parent != nullptr) - { - try - { - DeviceSpecs specs; - specs.channels = static_cast<Channels>(channels); - specs.rate = RATE_INVALID; - specs.format = FORMAT_INVALID; - parent->sound = new std::shared_ptr<ISound>(new ChannelMapper(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound), specs)); - } - catch(Exception& e) - { - Py_DECREF(parent); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)parent; -} - -PyDoc_STRVAR(M_aud_Sound_resample_doc, - "resample(rate, high_quality)\n\n" - "Resamples the sound.\n\n" - ":arg rate: The new sample rate.\n" - ":type rate: double\n" - ":arg high_quality: When true use a higher quality but slower resampler.\n" - ":type high_quality: bool\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`"); - -static PyObject * -Sound_resample(Sound* self, PyObject* args) -{ - double rate; - PyObject* high_qualityo; - bool high_quality = false; - - if(!PyArg_ParseTuple(args, "d|O:resample", &rate, &high_qualityo)) - return nullptr; - - if(!PyBool_Check(high_qualityo)) - { - PyErr_SetString(PyExc_TypeError, "high_quality is not a boolean!"); - return nullptr; - } - - high_quality = high_qualityo == Py_True; - - PyTypeObject* type = Py_TYPE(self); - Sound* parent = (Sound*)type->tp_alloc(type, 0); - - if(parent != nullptr) - { - try - { - DeviceSpecs specs; - specs.channels = CHANNELS_INVALID; - specs.rate = rate; - specs.format = FORMAT_INVALID; - if(high_quality) - parent->sound = new std::shared_ptr<ISound>(new JOSResample(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound), specs)); - else - parent->sound = new std::shared_ptr<ISound>(new LinearResample(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound), specs)); - } - catch(Exception& e) - { - Py_DECREF(parent); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)parent; -} - -PyDoc_STRVAR(M_aud_Sound_reverse_doc, - "reverse()\n\n" - "Plays a sound reversed.\n\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`\n\n" - ".. note:: The sound has to have a finite length and has to be " - "seekable. It's recommended to use this only with factories with " - "fast and accurate seeking, which is not true for encoded audio " - "files, such ones should be buffered using :meth:`cache` before " - "being played reversed.\n\n" - ".. warning:: If seeking is not accurate in the underlying sound " - "you'll likely hear skips/jumps/cracks."); - -static PyObject * -Sound_reverse(Sound* self) -{ - 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 Reverse(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound))); - } - catch(Exception& e) - { - Py_DECREF(parent); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)parent; -} - -PyDoc_STRVAR(M_aud_Sound_sum_doc, - "sum()\n\n" - "Sums the samples of a sound.\n\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`"); - -static PyObject * -Sound_sum(Sound* self) -{ - 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 Sum(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound))); - } - catch(Exception& e) - { - Py_DECREF(parent); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)parent; -} - -PyDoc_STRVAR(M_aud_Sound_threshold_doc, - "threshold(threshold = 0)\n\n" - "Makes a threshold wave out of an audio wave by setting all samples " - "with a amplitude >= threshold to 1, all <= -threshold to -1 and " - "all between to 0.\n\n" - ":arg threshold: Threshold value over which an amplitude counts " - "non-zero.\n" - ":type threshold: float\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`"); - -static PyObject * -Sound_threshold(Sound* self, PyObject* args) -{ - float threshold = 0; - - if(!PyArg_ParseTuple(args, "|f:threshold", &threshold)) - return nullptr; - - 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 Threshold(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound), threshold)); - } - catch(Exception& e) - { - Py_DECREF(parent); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)parent; -} - -PyDoc_STRVAR(M_aud_Sound_volume_doc, - "volume(volume)\n\n" - "Changes the volume of a sound.\n\n" - ":arg volume: The new volume..\n" - ":type volume: float\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`\n\n" - ".. note:: Should be in the range [0, 1] to avoid clipping.\n\n" - ".. note:: This is a filter function, you might consider using " - ":attr:`Handle.volume` instead."); - -static PyObject * -Sound_volume(Sound* self, PyObject* args) -{ - float volume; - - if(!PyArg_ParseTuple(args, "f:volume", &volume)) - return nullptr; - - 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 Volume(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound), volume)); - } - catch(Exception& e) - { - Py_DECREF(parent); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)parent; -} - -PyDoc_STRVAR(M_aud_Sound_join_doc, - "join(sound)\n\n" - "Plays two factories in sequence.\n\n" - ":arg sound: The sound to play second.\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_join(Sound* self, PyObject* object) -{ - PyTypeObject* type = Py_TYPE(self); - - if(!PyObject_TypeCheck(object, type)) - { - PyErr_SetString(PyExc_TypeError, "Object has to be of type Sound!"); - return nullptr; - } - - Sound* parent; - Sound* child = (Sound*)object; - - parent = (Sound*)type->tp_alloc(type, 0); - if(parent != nullptr) - { - try - { - parent->sound = new std::shared_ptr<ISound>(new Double(*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_mix_doc, - "mix(sound)\n\n" - "Mixes two factories.\n\n" - ":arg sound: The sound to mix 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_mix(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 Superpose(*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_pingpong_doc, - "pingpong()\n\n" - "Plays a sound forward and then backward.\n" - "This is like joining a sound with its reverse.\n\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`"); - -static PyObject * -Sound_pingpong(Sound* self) -{ - 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 PingPong(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound))); - } - catch(Exception& e) - { - Py_DECREF(parent); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)parent; -} - -PyDoc_STRVAR(M_aud_Sound_list_doc, - "list()\n\n" - "Creates an empty sound list that can contain several sounds.\n\n" - ":arg random: wether the playback will be random or not.\n" - ":type random: int\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`"); - -static PyObject * -Sound_list(PyTypeObject* type, PyObject* args) -{ - int random; - - if(!PyArg_ParseTuple(args, "i:random", &random)) - return nullptr; - - Sound* self; - - self = (Sound*)type->tp_alloc(type, 0); - if(self != nullptr) - { - try - { - self->sound = new std::shared_ptr<ISound>(new SoundList(random)); - } - catch(Exception& e) - { - Py_DECREF(self); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)self; -} - -PyDoc_STRVAR(M_aud_Sound_mutable_doc, - "mutable()\n\n" - "Creates a sound that will be restarted when sought backwards.\n" - "If the original sound is a sound list, the playing sound can change.\n\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`"); - -static PyObject * -Sound_mutable(Sound* self) -{ - 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 MutableSound(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound))); - } - catch(Exception& e) - { - Py_DECREF(parent); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)parent; -} - -PyDoc_STRVAR(M_aud_Sound_list_addSound_doc, - "addSound(sound)\n\n" - "Adds a new sound to a sound list.\n\n" - ":arg sound: The sound that will be added to the list.\n" - ":type sound: :class:`Sound`\n\n" - ".. note:: You can only add a sound to a sound list."); - -static PyObject * -Sound_list_addSound(Sound* self, PyObject* object) -{ - PyTypeObject* type = Py_TYPE(self); - - if(!PyObject_TypeCheck(object, type)) - { - PyErr_SetString(PyExc_TypeError, "Object has to be of type Sound!"); - return nullptr; - } - - Sound* child = (Sound*)object; - try - { - (*reinterpret_cast<std::shared_ptr<SoundList>*>(self->sound))->addSound(*reinterpret_cast<std::shared_ptr<ISound>*>(child->sound)); - Py_RETURN_NONE; - } - catch(Exception& e) - { - PyErr_SetString(AUDError, e.what()); - return nullptr; - } -} - -#ifdef WITH_CONVOLUTION - -PyDoc_STRVAR(M_aud_Sound_convolver_doc, - "convolver()\n\n" - "Creates a sound that will apply convolution to another sound.\n\n" - ":arg impulseResponse: The filter with which convolve the sound.\n" - ":type impulseResponse: :class:`ImpulseResponse`\n" - ":arg threadPool: A thread pool used to parallelize convolution.\n" - ":type threadPool: :class:`ThreadPool`\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`"); - -static PyObject * -Sound_convolver(Sound* self, PyObject* args) -{ - PyTypeObject* type = Py_TYPE(self); - - PyObject* object1; - PyObject* object2; - - if(!PyArg_ParseTuple(args, "OO:convolver", &object1, &object2)) - return nullptr; - - ImpulseResponseP* filter = checkImpulseResponse(object1); - if(!filter) - return nullptr; - - ThreadPoolP* threadPool = checkThreadPool(object2); - if(!threadPool) - return nullptr; - - Sound* parent; - parent = (Sound*)type->tp_alloc(type, 0); - - if(parent != nullptr) - { - try - { - parent->sound = new std::shared_ptr<ISound>(new ConvolverSound(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound), *reinterpret_cast<std::shared_ptr<ImpulseResponse>*>(filter->impulseResponse), *reinterpret_cast<std::shared_ptr<ThreadPool>*>(threadPool->threadPool))); - } - catch(Exception& e) - { - Py_DECREF(parent); - PyErr_SetString(AUDError, e.what()); - return nullptr; - } - } - - return (PyObject *)parent; -} - -PyDoc_STRVAR(M_aud_Sound_binaural_doc, - "convolver()\n\n" - "Creates a binaural sound using another sound as source. The original sound must be mono\n\n" - ":arg hrtfs: An HRTF set.\n" - ":type hrtf: :class:`HRTF`\n" - ":arg source: An object representing the source position of the sound.\n" - ":type source: :class:`Source`\n" - ":arg threadPool: A thread pool used to parallelize convolution.\n" - ":type threadPool: :class:`ThreadPool`\n" - ":return: The created :class:`Sound` object.\n" - ":rtype: :class:`Sound`"); - -static PyObject * -Sound_binaural(Sound* self, PyObject* args) -{ - PyTypeObject* type = Py_TYPE(self); - - PyObject* object1; - PyObject* object2; - PyObject* object3; - - if(!PyArg_ParseTuple(args, "OOO:binaural", &object1, &object2, &object3)) - return nullptr; - - HRTFP* hrtfs = checkHRTF(object1); - if(!hrtfs) - return nullptr; - - SourceP* source = checkSource(object2); - if(!hrtfs) - return nullptr; - - ThreadPoolP* threadPool = checkThreadPool(object3); - if(!threadPool) - return nullptr; - - Sound* parent; - parent = (Sound*)type->tp_alloc(type, 0); - - if(parent != nullptr) - { - try - { - parent->sound = new std::shared_ptr<ISound>(new BinauralSound(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound), *reinterpret_cast<std::shared_ptr<HRTF>*>(hrtfs->hrtf), *reinterpret_cast<std::shared_ptr<Source>*>(source->source), *reinterpret_cast<std::shared_ptr<ThreadPool>*>(threadPool->threadPool))); - } - 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 - }, - {"write", (PyCFunction)Sound_write, METH_VARARGS | METH_KEYWORDS, - M_aud_Sound_write_doc - }, - {"buffer", (PyCFunction)Sound_buffer, METH_VARARGS | METH_CLASS, - M_aud_Sound_buffer_doc - }, - {"cache", (PyCFunction)Sound_cache, METH_NOARGS, - M_aud_Sound_cache_doc - }, - {"file", (PyCFunction)Sound_file, METH_VARARGS | METH_CLASS, - M_aud_Sound_file_doc - }, - {"sawtooth", (PyCFunction)Sound_sawtooth, METH_VARARGS | METH_CLASS, - M_aud_Sound_sawtooth_doc - }, - {"silence", (PyCFunction)Sound_silence, METH_NOARGS | METH_CLASS, - M_aud_Sound_silence_doc - }, - {"sine", (PyCFunction)Sound_sine, METH_VARARGS | METH_CLASS, - M_aud_Sound_sine_doc - }, - {"square", (PyCFunction)Sound_square, METH_VARARGS | METH_CLASS, - M_aud_Sound_square_doc - }, - {"triangle", (PyCFunction)Sound_triangle, METH_VARARGS | METH_CLASS, - M_aud_Sound_triangle_doc - }, - {"accumulate", (PyCFunction)Sound_accumulate, METH_VARARGS, - M_aud_Sound_accumulate_doc - }, - {"ADSR", (PyCFunction)Sound_ADSR, METH_VARARGS, - M_aud_Sound_ADSR_doc - }, - {"delay", (PyCFunction)Sound_delay, METH_VARARGS, - M_aud_Sound_delay_doc - }, - {"envelope", (PyCFunction)Sound_envelope, METH_VARARGS, - M_aud_Sound_envelope_doc - }, - {"fadein", (PyCFunction)Sound_fadein, METH_VARARGS, - M_aud_Sound_fadein_doc - }, - {"fadeout", (PyCFunction)Sound_fadeout, METH_VARARGS, - M_aud_Sound_fadeout_doc - }, - {"filter", (PyCFunction)Sound_filter, METH_VARARGS, - M_aud_Sound_filter_doc - }, - {"highpass", (PyCFunction)Sound_highpass, METH_VARARGS, - M_aud_Sound_highpass_doc - }, - {"limit", (PyCFunction)Sound_limit, METH_VARARGS, - M_aud_Sound_limit_doc - }, - {"loop", (PyCFunction)Sound_loop, METH_VARARGS, - M_aud_Sound_loop_doc - }, - {"lowpass", (PyCFunction)Sound_lowpass, METH_VARARGS, - M_aud_Sound_lowpass_doc - }, - {"pitch", (PyCFunction)Sound_pitch, METH_VARARGS, - M_aud_Sound_pitch_doc - }, - {"rechannel", (PyCFunction)Sound_rechannel, METH_VARARGS, - M_aud_Sound_rechannel_doc - }, - {"resample", (PyCFunction)Sound_resample, METH_VARARGS, - M_aud_Sound_resample_doc - }, - {"reverse", (PyCFunction)Sound_reverse, METH_NOARGS, - M_aud_Sound_reverse_doc - }, - {"sum", (PyCFunction)Sound_sum, METH_NOARGS, - M_aud_Sound_sum_doc - }, - {"threshold", (PyCFunction)Sound_threshold, METH_VARARGS, - M_aud_Sound_threshold_doc - }, - {"volume", (PyCFunction)Sound_volume, METH_VARARGS, - M_aud_Sound_volume_doc - }, - {"join", (PyCFunction)Sound_join, METH_O, - M_aud_Sound_join_doc - }, - {"mix", (PyCFunction)Sound_mix, METH_O, - M_aud_Sound_mix_doc - }, - { "pingpong", (PyCFunction)Sound_pingpong, METH_NOARGS, - M_aud_Sound_pingpong_doc - }, - { "list", (PyCFunction)Sound_list, METH_VARARGS | METH_CLASS, - M_aud_Sound_list_doc - }, - { "mutable", (PyCFunction)Sound_mutable, METH_NOARGS, - M_aud_Sound_mutable_doc - }, - { "addSound", (PyCFunction)Sound_list_addSound, METH_O, - M_aud_Sound_list_addSound_doc - }, -#ifdef WITH_CONVOLUTION - { "convolver", (PyCFunction)Sound_convolver, METH_VARARGS, - M_aud_Sound_convolver_doc - }, - { "binaural", (PyCFunction)Sound_binaural, METH_VARARGS, - M_aud_Sound_binaural_doc - }, -#endif - {nullptr} /* Sentinel */ -}; - -PyDoc_STRVAR(M_aud_Sound_specs_doc, - "The sample specification of the sound as a tuple with rate and channel count."); - -static PyObject * -Sound_get_specs(Sound* self, void* nothing) -{ - try - { - Specs specs = (*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound))->createReader()->getSpecs(); - return Py_BuildValue("(di)", specs.rate, specs.channels); - } - catch(Exception& e) - { - PyErr_SetString(AUDError, e.what()); - return nullptr; - } -} - -PyDoc_STRVAR(M_aud_Sound_length_doc, - "The sample specification of the sound as a tuple with rate and channel count."); - -static PyObject * -Sound_get_length(Sound* self, void* nothing) -{ - try - { - int length = (*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound))->createReader()->getLength(); - return Py_BuildValue("i", length); - } - catch(Exception& e) - { - PyErr_SetString(AUDError, e.what()); - return nullptr; - } -} - -static PyGetSetDef Sound_properties[] = { - {(char*)"specs", (getter)Sound_get_specs, nullptr, - M_aud_Sound_specs_doc, nullptr }, - {(char*)"length", (getter)Sound_get_length, nullptr, - M_aud_Sound_length_doc, nullptr }, - {nullptr} /* Sentinel */ -}; - -PyDoc_STRVAR(M_aud_Sound_doc, - "Sound objects are immutable and represent a sound that can be " - "played simultaneously multiple times. They are called factories " - "because they create reader objects internally that are used for " - "playback."); - -PyTypeObject SoundType = { - PyVarObject_HEAD_INIT(nullptr, 0) - "aud.Sound", /* tp_name */ - sizeof(Sound), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)Sound_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_Sound_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - Sound_methods, /* tp_methods */ - 0, /* tp_members */ - Sound_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 */ - Sound_new, /* tp_new */ -}; - -AUD_API PyObject* Sound_empty() -{ - return SoundType.tp_alloc(&SoundType, 0); -} - -AUD_API Sound* checkSound(PyObject* sound) -{ - if(!PyObject_TypeCheck(sound, &SoundType)) - { - PyErr_SetString(PyExc_TypeError, "Object is not of type Sound!"); - return nullptr; - } - - return (Sound*)sound; -} - - -bool initializeSound() -{ - import_array(); - - return PyType_Ready(&SoundType) >= 0; -} - - -void addSoundToModule(PyObject* module) -{ - Py_INCREF(&SoundType); - PyModule_AddObject(module, "Sound", (PyObject *)&SoundType); -} |